今天看android逆向方法中关于try块的处理,java代码如下:
private void tryCatch(int drumsticks, String peple) {
try {
int i = Integer.parseInt(peple);
try {
int m = drumsticks / i;
int n = drumsticks - m * i;
String str = String.format("共有%d只鸡腿,%d个人平分,每人可分得%d只,还剩下%d只",
drumsticks, i, m, n);
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
} catch (ArithmeticException e) {
Toast.makeText(MainActivity.this, "人数不能为0", Toast.LENGTH_SHORT).show();
}
} catch (NumberFormatException e) {
Toast.makeText(MainActivity.this, "无效的数值字符串", Toast.LENGTH_SHORT).show();
}
}
这个方法对应的smali代码如下:
0 (00000000) const/4 v9, 0
1 (00000002) invoke-static v12, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
2 (00000008) move-result v1
3 (0000000a) div-int v2, v11, v1
4 (0000000e) mul-int v5, v2, v1
5 (00000012) sub-int v3, v11, v5
6 (00000016) const-string v5, u'\u5171\u6709%d\u53ea\u9e21\u817f\uff0c%d\u4e2a\u4eba\u5e73\u5206\uff0c\u6bcf\u4eba\u53ef\u5206\u5f97%d\u53ea\uff0c\u8fd8\u5269\u4e0b%d\u53ea'
7 (0000001a) const/4 v6, 4
8 (0000001c) new-array v6, v6, [Ljava/lang/Object;
9 (00000020) const/4 v7, 0
10 (00000022) invoke-static v11, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
11 (00000028) move-result-object v8
12 (0000002a) aput-object v8, v6, v7
13 (0000002e) const/4 v7, 1
14 (00000030) invoke-static v1, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
15 (00000036) move-result-object v8
16 (00000038) aput-object v8, v6, v7
17 (0000003c) const/4 v7, 2
18 (0000003e) invoke-static v2, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
19 (00000044) move-result-object v8
20 (00000046) aput-object v8, v6, v7
21 (0000004a) const/4 v7, 3
22 (0000004c) invoke-static v3, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
23 (00000052) move-result-object v8
24 (00000054) aput-object v8, v6, v7
25 (00000058) invoke-static v5, v6, Ljava/lang/String;->format(Ljava/lang/String; [Ljava/lang/Object;)Ljava/lang/String;
26 (0000005e) move-result-object v4
27 (00000060) const/4 v5, 0
28 (00000062) invoke-static v10, v4, v5, Landroid/widget/Toast;->makeText(Landroid/content/Context; Ljava/lang/CharSequence; I)Landroid/widget/Toast;
29 (00000068) move-result-object v5
30 (0000006a) invoke-virtual v5, Landroid/widget/Toast;->show()V
31 (00000070) return-void
32 (00000072) move-exception v0
33 (00000074) const-string v5, u'\u4eba\u6570\u4e0d\u80fd\u4e3a0'
34 (00000078) const/4 v6, 0
35 (0000007a) invoke-static v10, v5, v6, Landroid/widget/Toast;->makeText(Landroid/content/Context; Ljava/lang/CharSequence; I)Landroid/widget/Toast;
36 (00000080) move-result-object v5
37 (00000082) invoke-virtual v5, Landroid/widget/Toast;->show()V
38 (00000088) goto -12
39 (0000008a) move-exception v0
40 (0000008c) const-string v5, u'\u65e0\u6548\u7684\u6570\u503c\u5b57\u7b26\u4e32'
41 (00000090) invoke-static v10, v5, v9, Landroid/widget/Toast;->makeText(Landroid/content/Context; Ljava/lang/CharSequence; I)Landroid/widget/Toast;
42 (00000096) move-result-object v5
43 (00000098) invoke-virtual v5, Landroid/widget/Toast;->show()V
44 (0000009e) goto
dexdump classes.dex >dump.txt后,tryCatch方法对应的内容如下:
name : 'tryCatch'
type : '(ILjava/lang/String;)V'
access : 0x0002 (PRIVATE)
code -
registers : 13
ins : 3
outs : 3
insns size : 80 16-bit code units
catches : 3
0x0001 - 0x0004
Ljava/lang/NumberFormatException; -> 0x0045
0x0005 - 0x0038
Ljava/lang/ArithmeticException; -> 0x0039
Ljava/lang/NumberFormatException; -> 0x0045
<strong><span style="color:#ff0000;">0x003a - 0x0044</span></strong>
Ljava/lang/NumberFormatException; -> 0x0045
dump.txt文件中的catches为3说明存在3个try块,但是上面java代码中却只是存在2个try语句,下面分析一下原因。
第三个try块的起始偏移地址和终止偏移地址(想对于函数的开始地址)分别为0x003a和0x0044,一个偏移地址单位是16bit,因此第三个try块的开始偏移地址是0x0070,终止偏移地址是0x0088,这个try块对应的smali代码为:
(00000070) return-void
32 (00000072) move-exception v0
33 (00000074) const-string v5, u'\u4eba\u6570\u4e0d\u80fd\u4e3a0'
34 (00000078) const/4 v6, 0
35 (0000007a) invoke-static v10, v5, v6, Landroid/widget/Toast;->makeText(Landroid/content/Context; Ljava/lang/CharSequence; I)Landroid/widget/Toast;
36 (00000080) move-result-object v5
37 (00000082) invoke-virtual v5, Landroid/widget/Toast;->show()V
38 (00000088) goto
根据smali代码得到的java代码为:
catch (ArithmeticException e) {
Toast.makeText(MainActivity.this, "人数不能为0", Toast.LENGTH_SHORT).show();
}
由此可以得出结论:第三个try块对应于java代码中第一个try语句对应的catch代码块
这也是可以理解的,如下catch块
catch (ArithmeticException e) {
Toast.makeText(MainActivity.this, "人数不能为0", Toast.LENGTH_SHORT).show();
}
在执行的时候,如果出现了异常,如下catch块能够照常捕获异常
catch (NumberFormatException e) {
Toast.makeText(MainActivity.this, "无效的数值字符串", Toast.LENGTH_SHORT).show();
}
在android中,一个try块的数据结构为:
typedef struct DexTry {
u4 startAddr; /* start address, in 16-bit code units */
u2 insnCount; /* instruction count, in 16-bit code units
*/
u2 handlerOff; /* offset in encoded handler data to
handlers */
} DexTry;
注意insnCount表示的不是这个try块的实际指令个数,而是这个try块占用的16bit的个数