安卓程序逆向入门
Step2
将smali代码,翻译成java代码。主要包括两件事,第一件事翻译checker代码,顺便找一下满足checker条件的输入,使得Task1:的输出为true;第二件事是翻译encoder代码。当然在做第一件事的时候为了正确调试程序,需要翻译CheckBox代码。所有的java代码都存储在smali2java目录下。
2-1
翻译checker代码,通过找到满足条件的输入来确保代码翻译正确。
思路
仔细阅读smali代码,求助chatgpt和互联网资料。先将大段的代码改成java代码块,如循环结构,字符串处理代码块等。
- 这是一段循环结构的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;
}
}
- 接下来是一段字符串转化的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;
- 仔细分辨函数传参的值和寄存器中值的变化,这在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目录下。
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
寄存器中,之后操作的分别是
p1
和v2
。但是值得警惕的是,在之后的操作中v1
和p1
的值并没有改变;而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
javac逆向后代码运行结果