struct packed-switch-payload{
ushort ident; //值固定为0x100
ushort size; //case数目
int first_key; //初始case的值
int[] targets; //每个case相对switch指令处的偏移
};
打开IDA Pro找到“packed-switch p1, :pswitch_data_0"指令位于0x2CB1A处,相应的机器码为”2B 02 13 00 00 00“,手动分析机器码如下:
2B 为packed-switch的OpCode
02 为寄存器p1
00000013为偏移量0x13
Dalvik中计算偏移量是以两个字节为单位,因此实际该指令指向的packed-switch-payload结构体的偏移量为0x2CB1A+2*0x13 = 0x2CB40。使用C32asm查看该处的数据,如下图所示:
第1个ident字段为0x100,标识packed-switch有效的case区域。第二个字段size为4,表明有4个case。第3个字段first_key为0,表明初始case值为0。第四个字段为偏移量,分别为0x6、0x9、0xC、0xF,加上packed-switch指令的偏移值0x2CB1A,计算可得:
case 0位置 = 0x2CB1A+2* 0x6 = 0x2CB26
case 1位置 = 0x2CB1A+2* 0x9 = 0x2CB2C
case 2位置 = 0x2CB1A+2* 0xC = 0x2CB32
case 3位置 = 0x2CB1A +2× 0xF = 0x2CB38
至此,有规律递增的switch分析就算是搞明白了。最后将这段smali代码整理为Java代码如下。
private String packedSwitch(int i){
String str = null;
switch(i) {
case 0:
str = "she is a baby";
break;
case 1:
str = "she is a girl";
break;
case 2:
str = "she is a woman";
break;
case 3:
str = "she is an obasan";
break;
default:
str = "she is a person";
break;
}
return str;
}
代码中的switch分支使用的是sparse-switch指令。按照分析packed-switch的方法,我们直接查看sswitch_data_0标号出的内容。可以看到“.sparse-switch”指令没有给出初始case的值,所有的case值都使用“case值->case标号”的形式给出。此处共有4个case,它们的内容都是构造一个字符串,然后跳转到goto_0标号处,代码架构上与packed-switch方式的switch分支一样。
sparse-switch指令在Dalvik中的格式如下:
sparse-switch vAA , +BBBBBBBB
指令后面的“+BBBBBBBB”被指明为一个sparse-switch-payload格式的偏移。它的格式如下。
struct sparse-switch-payload{
ushort ident; //值固定为0x0200
ushort size; //case数目
int[] keys; //每个case的值,顺序从低到高
int[] targets; //每个case相对switch指令处的偏移
};
同样的,打开IDA Pro找到“sparse-switch p1, :sswitch_data_0”指令位于0x2CB6A处,相应的机器码为“2C 02 13 00 00 00”,手动分析机器码如下:
2C 为sparse-switch的OpCode。
02 为寄存器p1。
00000013为偏移量0x13。
因此实际该指令指向的sparse-switch-payload结构体的偏移量为0x2CB6A + 2 * 0x13 = 0x2CB90。该处的数据如下图所示:
第1个ident字段为0x200,标识sparse-switch有效的case区域。第2个字段size为4,表明有4个case。第3个字段keys为4个case的值,分别为0x5、0xF、0x23、0x41。第4个字段分别为偏移量,分别为0x6、0x9、0xC、0xF,加上sparse-switch指令的偏移值0x2CB6A,计算可得:
case 0 位置 = 0x2CB6A + 2 * 0x6 = 0x2CB76
case 1 位置 = 0x2CB6A + 2 * 0x9 = 0x2CB7C
case 2 位置 = 0x2CB6A + 2 * 0xC = 0x2CB82
case 3 位置 = 0x2CB6A + 2 * 0xF = 0x2CB88
最后,将这段smali代码整理为Java代码如下:
private String sparseSwitch(int age){
String str = NULL;
switch(age) {
case 5:
str = "he is a baby";
break;
case 15:
str = "he is a student";
break;
case 35:
str = "he is a father";
break;
case 65:
str = "he is a grandpa";
break;
default:
str = "he is a person";
break;
}
return str;
}