一個簡單的 IDA f5插件問題分析
有人提出問題,以下匯編f5結果缺失代碼:
.text:00000C18 Java_com_a_b_c .text:00000C18 PUSH {R3,LR} .text:00000C1A CMP R2, #2 .text:00000C1C BEQ loc_C38 .text:00000C1E CMP R2, #3 .text:00000C20 BEQ loc_C2C .text:00000C22 CMP R2, #1 .text:00000C24 BNE loc_C32 .text:00000C26 LDR R1, =(aGoldVip - 0xC2C) .text:00000C28 ADD R1, PC ; "Gold Vip" .text:00000C2A B loc_C3C .text:00000C2C ; --------------------------------------------------------------------------- .text:00000C2C .text:00000C2C loc_C2C ; CODE XREF: Java_com_a_b_c+8 j .text:00000C2C LDR R1, =(aCopperVip - 0xC32) .text:00000C2E ADD R1, PC ; "Copper Vip" .text:00000C30 B loc_C3C .text:00000C32 ; --------------------------------------------------------------------------- .text:00000C32 .text:00000C32 loc_C32 ; CODE XREF: Java_com_a_b_c+C j .text:00000C32 LDR R1, =(aNormalUser - 0xC38) .text:00000C34 ADD R1, PC ; "Normal User" .text:00000C36 B loc_C3C .text:00000C38 ; --------------------------------------------------------------------------- .text:00000C38 .text:00000C38 loc_C38 ; CODE XREF: Java_com_a_b_c+4 j .text:00000C38 LDR R1, =(aSilveryVip - 0xC3E) .text:00000C3A ADD R1, PC ; "Silvery Vip" .text:00000C3C .text:00000C3C loc_C3C ; CODE XREF: Java_com_a_b_c+12 j .text:00000C3C ; Java_com_a_b_c+18 j ... .text:00000C3C LDR R2, [R0] .text:00000C3E MOVS R3, #0x29C .text:00000C42 LDR R3, [R2,R3] .text:00000C44 BLX R3 ; NewStringUTF .text:00000C46 POP {R3,PC} .text:00000C46 ; End of function Java_com_a_b_c
很容易從匯編看出,這是個簡單的 switch…case{} 代碼塊。在break時,跳轉到 loc_C3C 處。
但f5,其結果如下,明顯代碼缺失:
int __fastcall Java_com_a_b_c(int a1)
{
return (*(int (**)(void))(*(_DWORD *)a1 + 668))();
}
下面分析,為什麽代碼缺失。
由於 Java_com_a_b_c 是一個 jni 函數,所以 r0 為 JNIEnv*, r1 為 jobject。loc_C3C 位置有個blx r3的跳轉,分析一下這是個什麽調用。
首選將 r0 指向地址內容即 JNIEnv 賦值 r2,接著 ldr r3, [r2, r3] 將 r3 指向 JNIEnv + 0x29c 偏移的位置(JNINativeInterface 中第167個函數)。
通過查看 jni.h,此時 r3 實際指向的是 NewStringUTF 函數,這個函數有2個變量,分別是 r0:JNIEnv* 和 r1:char* 。其返回值是一個jstring類型。
也就是上面匯編代碼大致偽C是這樣:
jstring Java_com_a_b_c(JNIEnv *env, jobject thiz, jint x) { char *str = NULL; switch(x) { case 1: str = "Gold Vip"; break; case 2: str = "Silvery Vip"; break; case 3: str = "Copper Vip"; break; default: str = "Normal User"; break; } return (*env)->NewStringUTF(env, str); }
switch…case {} 結構去哪兒了? 其實這是ida f5插件的一個特性:***代碼優化***。由於使用了 blx r3寄存器跳轉,ida並不知道r3即NewStringUTF函數的原型,參數情況。也就不知道str參數會被NewStringUTF函數所使用。因此它認為switch…case {}中對str的賦值(如str = “Copper Vip”;)並沒有用,可以優化掉。
因此f5就找不到這段匯編對應的C了。
驗證一下f5是否存在代碼優化(與-O3編譯選項類似):
kiiim@ubuntu:~/Android_prj/re/jni_test$ cat test.c
int main()
{
int x = a();
}
int a()
{
int a = 123;
int b = 22;
return 123;
}
對應匯編:
.text:00008304 EXPORT a
.text:00008304 a ; CODE XREF: main+C p
.text:00008304
.text:00008304 var_C = -0xC
.text:00008304 var_8 = -8
.text:00008304 var_s0 = 0
.text:00008304
.text:00008304 STR R11, [SP,#-4+var_s0]!
.text:00008308 ADD R11, SP, #0
.text:0000830C SUB SP, SP, #0xC
.text:00008310 MOV R3, #0x7B #### int a = 123;
.text:00008314 STR R3, [R11,#var_8]
.text:00008318 MOV R3, #0x16 ### int b = 22; 明顯存在2個變量賦值代碼
.text:0000831C STR R3, [R11,#var_C]
.text:00008320 MOV R3, #0x7B
.text:00008324 MOV R0, R3
.text:00008328 SUB SP, R11, #0
.text:0000832C LDR R11, [SP+var_s0],#4
.text:00008330 BX LR
.text:00008330 ; End of function a
f5:
signed int a()
{
return 123;
}
那怎麽辦呢?其實很簡單,首先導入 JNINativeInterface 結構的函數原型信息。然後在f5窗口裏面, 重新設置 NewStringUTF 函數參數。
在函數上右鍵 ,*** Force call type ***:
一個簡單的 IDA f5插件問題分析