No.0
前言
smali代码是Dalvik虚拟机的寄存器语言. 我们在做安卓逆向的时候, 由于dex文件反汇编出来的都是smali代码, 所以能读懂smali语句和了解常见的语句结构是非常重要的, 下面介绍两种结构的smali代码.
No.1
常见语句结构
例如我们现在有一个软件, 这个软件里面有一个输入框, 可以输入数字, 然后有一个按钮用来判断用户输入的内容, 当数字大于0, 输出”他大于0”, 等于0的时候输出”他等于0”, 小于0的时候输出”他小于0”
public void onClick(View v) {
String s = binding.numberInputBox.getEditText().getText().toString();
String prompt = "";
try {
int a = Integer.parseInt(s);
if (a > 0) {
prompt = "他大于0";
} else if (a == 0) {
prompt = "他等于0";
} else {
prompt = "他小于0";
}
} catch (NumberFormatException e) {
prompt = "这不是一个数字";
} finally {
binding.resultDisplayTextBox.setText(prompt);
}
}
我们编译生成apk, 使用android killer进行反编译, 在smali_classes4comexamplemyapplicationFirstFragment$1.smali 里可以找到我们的代码
首先在这个文件中的第50行, 把numberInputBox储存到v0寄存器, 使用invoke-virtual调用numberInputBox的getEditText()获取到里面的输入框放到v0, 然后56行再调用获取到的输入框的getText()方法来获取里面的输入内容, 因为getText()返回的是EditText类型, 需要再调用toString()方法来把EditText转换为String类型, 最后放到v0寄存器.
No.2
if条件判断
在smali代码中, 条件判断使用的是if-cc命令, cc可以更换为任何条件 例如:
· if-lez vx, 地址 如果vx(v表示一个寄存器)里的值小于等于0, 则跳转到地址
· if-gez vx, 地址 如果vx大于等于0, 则跳转到地址
· if-eqz vx, 地址 如果vx等于0, 则跳转到地址
· if-nez vx, 地址 如果vx不等于0, 则跳转到地址
· if-gt vx, vy, 地址 如果vx大于vy, 则跳转到地址
· if-lt vx, vy, 地址 如果vx小于vy, 则跳转到地址
· if-eq vx, vy, 地址 如果vx等于vy, 则跳转到地址
· if-ne vx, vy, 地址 如果vx不等于vy, 则跳转到地址
第66行中, v1被赋予一个空字符串, 然后调用Integer类的静态方法parseInt(), 来解析v0
, 把结果传递给v2寄存器. 然后下面使用if-cc对v2进行判断.
首先使用if-lez把v2和0作比较, 如果v2小于等于0, 就跳转到:cond_0, 也就是第88行, v2大于0的时候不跳转, 继续执行. 到88行这里后又有一个判断if-nez v2, :cond_1, 如果v2不等于0, 跳转到:cond_1, 相当于v2小于0的时候跳转到:cond1, 等于0的时候不跳转, 继续执行. 然后每一个条件分支都有一个goto :goto_0, 表示分支结束之后使用goto语句跳转到:goto_0来跳出条件判断, 继续执行后续代码.
那么我们可以总结一下条件判断的基本结构, 使用if-cc做出判断, 然后跳转到特定分支, 在每个分支的末尾需要一个goto语句来跳出条件判断.
No.3
循环
现在我们修改一下代码, 让其功能变成输入一个数字, 然后求他从1到他本身的和.
public void onClick(View v) {
String s = binding.numberInputBox.getEditText().getText().toString();
String prompt = "";
try {
int a = Integer.parseInt(s);
int result = 0;
for (int i = 1; i <=a; i++) {
result += i;
}
prompt = String.valueOf(result);
} catch (NumberFormatException e) {
prompt = "这不是一个数字";
} finally {
binding.resultDisplayTextBox.setText(prompt);
}
}
我们使用android killer反编译这个软件, 在smali_classes4comexamplemyapplicationFirstFragment$1.smali找到我们的代码.
前面的代码都一样, 我们从第71行开始看, 这里调用parseInt解析输入框里的内容为数字放到放到v2, 然后定义了v3用来存放计算结果, 定义v4也就是for循环里面的i. 这里使用了判断语句if-gt v4, v2, :cond_0, 如果v4大于v2就跳转到:cond_0, 也就是跳出循环, 否则继续执行. 接下来的add-int/2addr v3, v4表示把每次循环的数相加到存放结果的v3, 相当于v3 = v3 + v4, 然后使用add-int/lit8 v4, v4, 0x1 相当于每次循环给v4也就是i加上了1, 最后使用goto :goto_0跳回到85行, 进行下次循环, 直到v4大于v2才跳出循环.
那么循环结构我们也可以总结一下, 循环的本质就是判断和跳转, 使用if-cc做判断, 如果不满足条件就跳回原来的地方再次执行语句, 一直到条件满足跳出循环.
PS:APP学员投稿
No.4
原文始发于微信公众号(隐雾安全):安卓逆向之常见结构的smali语句分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论