0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

picoCTF 2019 writeup droids4

Last updated at Posted at 2025-12-17

droids4 (Reverse Engineering)

Reverse the pass, patch the file, get the flag. Check out this file.

添付ファイル
・four.apk

今までと同様に、エミュレータでアプリを起動する。
image.png

"you got this"とだけ書かれており、一切のヒントがないため、apktoolでファイルをデコンパイルした後、FlagstaffHill.smaliを確認する。

$ apktool d four.apk 
I: Using Apktool 2.7.0-dirty on four.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /home/colza/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...

FlaggstaffHill.smaliは以下のようになっていた。

.class public Lcom/hellocmu/picoctf/FlagstaffHill;
.super Ljava/lang/Object;
.source "FlagstaffHill.java"


# direct methods
.method public constructor <init>()V
    .locals 0

    .line 6
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    return-void
.end method

.method public static native cardamom(Ljava/lang/String;)Ljava/lang/String;
.end method

.method public static getFlag(Ljava/lang/String;Landroid/content/Context;)Ljava/lang/String;
    .locals 8
    .param p0, "input"    # Ljava/lang/String;
    .param p1, "ctx"    # Landroid/content/Context;

    .line 12
    new-instance v0, Ljava/lang/StringBuilder;

    const-string v1, "aaa"

    invoke-direct {v0, v1}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

    .line 13
    .local v0, "ace":Ljava/lang/StringBuilder;
    new-instance v2, Ljava/lang/StringBuilder;

    invoke-direct {v2, v1}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

    .line 14
    .local v2, "jack":Ljava/lang/StringBuilder;
    new-instance v3, Ljava/lang/StringBuilder;

    invoke-direct {v3, v1}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

    .line 15
    .local v3, "queen":Ljava/lang/StringBuilder;
    new-instance v4, Ljava/lang/StringBuilder;

    invoke-direct {v4, v1}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V

    move-object v1, v4

    .line 17
    .local v1, "king":Ljava/lang/StringBuilder;
    const/4 v4, 0x0

    invoke-virtual {v0, v4}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v5

    add-int/lit8 v5, v5, 0x4

    int-to-char v5, v5

    invoke-virtual {v0, v4, v5}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 18
    const/4 v5, 0x1

    invoke-virtual {v0, v5}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v6

    add-int/lit8 v6, v6, 0x13

    int-to-char v6, v6

    invoke-virtual {v0, v5, v6}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 19
    const/4 v6, 0x2

    invoke-virtual {v0, v6}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/lit8 v7, v7, 0x12

    int-to-char v7, v7

    invoke-virtual {v0, v6, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 21
    invoke-virtual {v2, v4}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/lit8 v7, v7, 0x7

    int-to-char v7, v7

    invoke-virtual {v2, v4, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 22
    invoke-virtual {v2, v5}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/2addr v7, v4

    int-to-char v7, v7

    invoke-virtual {v2, v5, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 23
    invoke-virtual {v2, v6}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/2addr v7, v5

    int-to-char v7, v7

    invoke-virtual {v2, v6, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 25
    invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/2addr v7, v4

    int-to-char v7, v7

    invoke-virtual {v3, v4, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 26
    invoke-virtual {v3, v5}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/lit8 v7, v7, 0xb

    int-to-char v7, v7

    invoke-virtual {v3, v5, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 27
    invoke-virtual {v3, v6}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/lit8 v7, v7, 0xf

    int-to-char v7, v7

    invoke-virtual {v3, v6, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 29
    invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v7

    add-int/lit8 v7, v7, 0xe

    int-to-char v7, v7

    invoke-virtual {v1, v4, v7}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 30
    invoke-virtual {v1, v5}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v4

    add-int/lit8 v4, v4, 0x14

    int-to-char v4, v4

    invoke-virtual {v1, v5, v4}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 31
    invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;->charAt(I)C

    move-result v4

    add-int/lit8 v4, v4, 0xf

    int-to-char v4, v4

    invoke-virtual {v1, v6, v4}, Ljava/lang/StringBuilder;->setCharAt(IC)V

    .line 33
    invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v4

    const-string v5, ""

    invoke-virtual {v5, v4}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v4

    invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v5

    invoke-virtual {v4, v5}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v4

    .line 34
    invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v5

    invoke-virtual {v4, v5}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v4

    invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v5

    invoke-virtual {v4, v5}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String;

    move-result-object v4

    .line 36
    .local v4, "password":Ljava/lang/String;
    invoke-virtual {p0, v4}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result v5

    if-eqz v5, :cond_0

    const-string v5, "call it"

    return-object v5

    .line 37
    :cond_0
    const-string v5, "NOPE"

    return-object v5
.end method

getFlag関数は入力文字とpasswordが一致するかを確認している。

line12~line17の部分で、まずStringBuilderを用いて"aaa"という文字を、ace, jack, queen, kingの4つの変数に代入している。
以降、line19までの部分で以下の処理をし、ace = etsとなる。

ace[0] = ace[0] + 0x4
ace[1] = ace[1] + 0x13
ace[2] = ace[2] + 0x12

line21~line23の部分で以下の処理をし、jack = habとなる。

jack[0] = jack[0] + 0x7
jack[1] = jack[1] + 0x0
jack[2] = jack[2] + 0x1

line25~line27の部分で以下の処理をし、queen = alpとなる。

queen[0] = queen[0] + 0x0
queen[1] = queen[1] + 0xb
queen[2] = queen[2] + 0xf

line29~line31の部分で以下の処理をし、king = oupとなる。

king[0] = king[0] + 0xe
king[1] = king[1] + 0x14
king[2] = king[2] + 0xf

line33~line36の部分で、concatでqueen+jack+ace+kingとなる文字列を作成し、これをpasswordと置いている。
よってpassword = alphabetsoupである。

エミュレータで起動したアプリにalphabetsoupを入力して、ボタンを押す。
image.png

"call it"と表示されたので、passwordがあっていることが確認できた。
call itと表示する部分のコードをフラグ出力関数を呼び出すように書き換える必要がある。
getFlag関数以外の謎関数はcardamomしかないので、次はcardamom関数を解析する。

cardamomが実装されているファイルを探す。

$ grep -R "cardamom" four/
grep: four/lib/arm64-v8a/libhellojni.so: binary file matches
grep: four/lib/armeabi-v7a/libhellojni.so: binary file matches
grep: four/lib/x86/libhellojni.so: binary file matches
grep: four/lib/x86_64/libhellojni.so: binary file matches
four/smali/com/hellocmu/picoctf/FlagstaffHill.smali:.method public static native cardamom(Ljava/lang/String;)Ljava/lang/String;

libhellojni.soというファイルに記述されていそうなので、これをghidraで確認する。
今回は、four/lib/x86_64/libhellojni.soを使った。

Symbol Treeからcardamomという文字列を含む関数名を探す。

undefined8
Java_com_hellocmu_picoctf_FlagstaffHill_cardamom
          (long *param_1,undefined8 param_2,undefined8 param_3)

{
  byte bVar1;
  undefined8 uVar2;
  char *local_50;
  
  uVar2 = (**(code **)(*param_1 + 0x548))(param_1,param_3,0);
  bVar1 = chervil(uVar2);
  (**(code **)(*param_1 + 0x550))(param_1,param_3,uVar2);
  if ((bVar1 & 1) == 0) {
    local_50 = "try again";
  }
  else {
    local_50 = (char *)pepper(uVar2);
  }
  uVar2 = (**(code **)(*param_1 + 0x538))(param_1,local_50);
  free(local_50);
  return uVar2;
}

param3がJavaから渡されたString引数だと考えられ、以下の部分でparam3の文字列を取得してポインタがuVar2に代入されていると考えられる。

uVar2 = (**(code **)(*param_1 + 0x548))(param_1,param_3,0);

chervil関数は入力文字が基準にあっているかを判断している。
その後、pepper関数を呼び出していることが分かる。

void pepper(char *param_1)

{
  char *pcVar1;
  size_t sVar2;
  
  pcVar1 = strdup(param_1);
  sVar2 = strlen(param_1);
  unscramble(&DAT_00101aa0,0x1f,pcVar1,sVar2 & 0xffffffff);
  return;
}

入力文字を使用して何らかの演算をしていることがわかる。おそらくDAT_00101aa0を入力文字を利用して復号している。
unscramble関数はdroids3のときと同じだったので、復号コードをそのまま利用しても良いが、今回はFlagstaffHill.smaliを書き換えることでフラグを出力させる。
書き換え内容は以下の通り。

# 書き換え前
# const-string v5, "call it"

# return-object v5

# 書き換え後
invoke-static {p0}, Lcom/hellocmu/picoctf/FlagstaffHill;->cardamom(Ljava/lang/String;)Ljava/lang/String;

move-result-object v0

return-object v0

これを再ビルドしてエミュレータで起動する。
ビルドするときにエラーが出たので、$ic_launcher_foreground__0.xmlとその参照元コードの削除をした。

$ apktool b four_edited --use-aapt2 -o four_edited.apk
I: Using Apktool 2.7.0-dirty
I: Checking whether sources has changed...
I: Checking whether resources has changed...
I: Building resources...
W: aapt: brut.common.BrutException: brut.common.BrutException: Could not extract resource: /prebuilt/linux/aapt2_64 (defaulting to $PATH binary)
I: Copying libs... (/lib)
I: Building apk file...
I: Copying unknown files/dir...
I: Built apk into: four_edited.apk

apktoolでビルドしたファイルには署名がないので、署名する。

$ wget https://github.com/patrickfav/uber-apk-signer/releases/download/v1.3.0/uber-apk-signer-1.3.0.jar
$ java -jar uber-apk-signer-1.3.0.jar --apk four_edited.apk

エミュレータに再ビルドしたapkファイルをインストールし、アプリを起動する。
alphabetsoupと入力して、ボタンを押す。
image.png

フラグが得られた。

picoCTF{not.particularly.silly}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?