安卓程序逆向入门

Step2

将smali代码,翻译成java代码。主要包括两件事,第一件事翻译checker代码,顺便找一下满足checker条件的输入,使得Task1:的输出为true;第二件事是翻译encoder代码。当然在做第一件事的时候为了正确调试程序,需要翻译CheckBox代码。所有的java代码都存储在smali2java目录下。

2-1

翻译checker代码,通过找到满足条件的输入来确保代码翻译正确。

思路

仔细阅读smali代码,求助chatgpt和互联网资料。先将大段的代码改成java代码块,如循环结构,字符串处理代码块等。

  1. 这是一段循环结构的smali代码,他将被转化为如下java代码
.line 9
:goto_b
array-length v7, v6  # 获取字符数组的长度,并将结果存储到寄存器v7中
if-ge v0, v7, :cond_1f  # 如果v0 >= v7,则跳转到标签cond_1f
.line 10
aget-char v7, v6, v0  # 获取字符数组中索引为v0的字符,并将结果存储到寄存器v7中
const/16 v8, 0x78  # 将字符'x'的ASCII码(0x78)存储到寄存器v8中
if-ne v7, v8, :cond_1c  # 如果v7 != v8,则跳转到标签cond_1c
.line 11
add-int/lit8 v2, v2, 0x1  # 将寄存器v2加1
.line 12
if-ne v2, v5, :cond_19  # 如果v2 != v5(1),则跳转到标签cond_19
move v4, v0  # 将当前索引v0存储到寄存器v4中
.line 14
:cond_19
if-ne v2, v9, :cond_1c  # 如果v2 != v9(2),则跳转到标签cond_1c
move v3, v0  # 将当前索引v0存储到寄存器v3中
.line 9
:cond_1c
add-int/lit8 v0, v0, 0x1  # 将v0加
goto :goto_b  # 跳转到标签goto_b
for (int i = 0; i < charArray.length; i++) {
  char c = charArray[i];
  if (c == 'x') {
      countX++;
      if (countX==1) {
          firstXIndex = i;
      }else if (countX==2) 
          lastXIndex = i;
  }
}
  1. 接下来是一段字符串转化的smali代码转java的例子
new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/
checkBox.rawInfo = input;
  1. 仔细分辨函数传参的值和寄存器中值的变化,这在2-2中给我造成了不小的麻烦

一些在代码调试过程中使用到的命令行语句

./adb root
./adb push '/Users/aibot/Library/Mobile Documents/com~apple~CloudDocs/日常记录/暑期科研训练/proj3/lab3-1逆向(上)/smali/Box1.dex' /data/app
./adb shell  
cd /data/app
dalvikvm -cp Box.dex CheckBox  

javac CheckBox.java && java CheckBox
0keyx***x9**11
0keyx000x90011

结果

找到了正确的密码:``0keyxkeyx90011,或者更确切的说是0keyx*x911`。代码存储在smali2java目录下。

image20230629142237402

image20230629195138710

2-2编解码

阅读编解码smali文件,然后将它的逻辑用java语言实现。

思路

首先观察smali文件,发现getSalt, byteToHexString,byteArrayToHexString等方法的代码量比较小;而encoding, check等方法的的代码量较多。因此先翻译代码量小的方法。之后再翻译代码量较多的方法。

byteToHexString为例演示

.method private byteToHexString(B)Ljava/lang/String;
.registers 6
.prologue
.line 58
.line 59
if-gez p1, :cond_4
.line 61
and-int/lit16 p1, p1, 0xff
.line 63
:cond_4
div-int/lit8 v0, p1, 0x10
.line 64
rem-int/lit8 v1, p1, 0x10
.line 65
new-instance v2, Ljava/lang/StringBuilder;
invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
iget-object v3, p0, LEncoder;->hexDigits:[Ljava/lang/String;
aget-object v0, v3, v0
invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v0
iget-object v2, p0, LEncoder;->hexDigits:[Ljava/lang/String;
aget-object v1, v2, v1
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
return-object v0
.end method
private String byteToHexString(byte b) {
    int unsignedByte = b & 0xff;
    int highNibble = unsignedByte >>> 4;
    int lowNibble = unsignedByte & 0xf;
    return hexDigits[highNibble] + hexDigits[lowNibble];
}

通过分别取得一个字节高四位的值和低四位的值,并通过字典转化为字符。

接下来encoding为例,演示寄存器值的变化对代码逆向造成的影响。

.line 25
div-int/lit8 v4, v0, 0x3
invoke-virtual {v1, v4}, Ljava/lang/String;->charAt(I)C
move-result v4

encoding方法的第25行中出现对寄存器v1的操作,而在这行代码的前十几行都对v1没有操作。因此我找到函数初始化后对v1的操作

invoke-direct {p0}, LEncoder;->getSalt()Ljava/lang/String;
move-result-object v1
.line 17
new-instance v2, Ljava/lang/StringBuilder;
invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v2, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
invoke-virtual {v2, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

可以看到上述的代码只是将slat的值暂时存在v1寄存器中,之后操作的分别是

p1v2。但是值得警惕的是,在之后的操作中v1p1的值并没有改变;而v2的值更新了。但是我在翻译代码时将这一段smali翻译成了String inputWithSalt = input + getSalt();这里错误的没有显示存储getSalt()方法的返回值。之后使用inputWithSalt的值替代getSalt()的原值。造成了盐值无法传递,decoder无法成功解码的严重错误。花了很长时间才发现。当然也不得不吐槽一下smali的循环结构是真的又臭又长。

结果

dalvikvm安卓模拟器上运行结果

dalvikvm -cp Box.dex CheckBox  
18307130341
70f01081050670f90a40710a10e10080731130b714e18b08
dalvikvm -cp Box.dex CheckBox 70f01081050670f90a40710a10e10080731130b714e18b08

image20230629143537873

javac逆向后代码运行结果

image20230629195102625

posted @ 2023-08-16 17:18  Aibot  阅读(41)  评论(0编辑  收藏  举报