本文涉及到的apk。请在github下载https://github.com/jltxgcy/AliCrack/AliCrackme_2.apk。
0x00
怎样在JNI_ONLOAD下断点。參考安卓逆向学习笔记(5) - 在JNI_Onload 函数处下断点避开针对IDA Pro的反调试。最好使用模拟器调试,确保 Attach to process后,相应进程在DDMS中出现小红蜘蛛。
以下将怎样在init_array下断点,首先要找到so的init_array端。把so拖入ida,然后按Crtl+s,会出现该so的全部段。例如以下:
进入.init_array。例如以下:
当中sub_2378就是init_array的代码。
我们在这里下断点,详细调试的步骤和在JNI_ONLOAD下断点调试是一样的。參考安卓逆向学习笔记(5) - 在JNI_Onload 函数处下断点避开针对IDA Pro的反调试。网上有非常多其它方法在init_array下断点。比如Android安全–linker载入so流程。在.init下断点。我还是认为上面的方法比較方便。
调试时使用jdb -connect com.sun.jdi.SocketAttach:port=8700,hostname=localhost,有时会报例如以下错误:
此时,我们先观察DDMS。
使用jdb -connect com.sun.jdi.SocketAttach:port=8622,hostname=localhost就可以。
0x01
也讲一下ida静态分析so。
首先列出C++源代码:
#include "com_example_jnidemo_JniGg.h"int switch1(int a, int b, int i, int j, int k,int q){char *w = "i am winner in this year";switch (i){case 1:return a + b + j + k;break;case 2:return a - b;break;case 3:return a * b;break;case 4:return a / b;break;default:return a + b;break;}
}JNIEXPORT jstring JNICALL Java_com_example_jnidemo_JniGg_ggPrintHello(JNIEnv * env, jobject this)
{return (*env)->NewStringUTF(env, "Current Coin is -- ");}JNIEXPORT jint JNICALL Java_com_example_jnidemo_JniGg_getCoin(JNIEnv * env, jobject this)
{return switch1(1,2,1,4,5,6);}
编译成so。然后拖进ida进行分析。.text:00000E38 EXPORT Java_com_example_jnidemo_JniGg_getCoin
.text:00000E38 Java_com_example_jnidemo_JniGg_getCoin
.text:00000E38
.text:00000E38 var_10 = -0x10
.text:00000E38 var_C = -0xC
.text:00000E38
.text:00000E38 PUSH {LR}
.text:00000E3A SUB SP, SP, #0xC
.text:00000E3C MOVS R3, #5
.text:00000E3E STR R3, [SP,#0x10+var_10]
.text:00000E40 MOVS R3, #6
.text:00000E42 STR R3, [SP,#0x10+var_C]
.text:00000E44 MOVS R0, #1
.text:00000E46 MOVS R1, #2
.text:00000E48 MOVS R2, #1
.text:00000E4A MOVS R3, #4
.text:00000E4C BL switch1
.text:00000E50 ADD SP, SP, #0xC
.text:00000E52 POP {PC}
.text:00000E52 ; End of function Java_com_example_jnidemo_JniGg_getCoin
arm的參数传递规范,和函数中的局部变量定义规范,请參考ARM子函数定义中的參数放入寄存器的规则。这里使用R0,R1。R2,R3来传递前4个參数,使用堆栈来传递后两个參数。
.text:00000DEC
.text:00000DEC EXPORT switch1
.text:00000DEC switch1 ; CODE XREF: Java_com_example_jnidemo_JniGg_getCoin+14p
.text:00000DEC
.text:00000DEC arg_0 = 0
.text:00000DEC
.text:00000DEC PUSH {R4,LR}
.text:00000DEE ; 6: v5 = a3 - 1;
.text:00000DEE SUBS R2, #1
.text:00000DF0 ; 7: v6 = a1;
.text:00000DF0 MOVS R4, R0
.text:00000DF2 ; 8: result = a1 + a2;
.text:00000DF2 ADDS R0, R0, R1
.text:00000DF4 ; 9: if ( (unsigned int)v5 <= 3 )
.text:00000DF4 CMP R2, #3 ; switch 4 cases
.text:00000DF6 BHI def_DFA ; jumptable 00000DFA default case
.text:00000DF8 ; 11: result = v5;
.text:00000DF8 MOVS R0, R2
.text:00000DFA ; 12: switch ( v5 )
.text:00000DFA BL __gnu_thumb1_case_uqi ; switch jump
.text:00000DFA ; ---------------------------------------------------------------------------
.text:00000DFE jpt_DFA DCB 2 ; jump table for switch statement
.text:00000DFF DCB 0xA
.text:00000E00 DCB 7
.text:00000E01 DCB 0xC
.text:00000E02 ; ---------------------------------------------------------------------------
.text:00000E02 ; 15: result = v6 + a2 + a4 + a5;
.text:00000E02
.text:00000E02 loc_E02 ; CODE XREF: switch1+Ej
.text:00000E02 LDR R2, [SP,#8+arg_0] ; jumptable 00000DFA case 0
.text:00000E04 ADDS R4, R4, R1
.text:00000E06 ADDS R3, R4, R3
.text:00000E08 ; 16: break;
.text:00000E08 ADDS R0, R3, R2
.text:00000E0A
.text:00000E0A def_DFA ; CODE XREF: switch1+Aj
.text:00000E0A ; switch1+24j ...
.text:00000E0A POP {R4,PC} ; jumptable 00000DFA default case
.text:00000E0C ; ---------------------------------------------------------------------------
.text:00000E0C ; 18: result = a2 * v6;
.text:00000E0C
.text:00000E0C loc_E0C ; CODE XREF: switch1+Ej
.text:00000E0C MOVS R0, R1 ; jumptable 00000DFA case 2
.text:00000E0E MULS R0, R4
.text:00000E10 ; 19: break;
.text:00000E10 B def_DFA ; jumptable 00000DFA default case
.text:00000E12 ; ---------------------------------------------------------------------------
.text:00000E12 ; 21: result = v6 - a2;
.text:00000E12
.text:00000E12 loc_E12 ; CODE XREF: switch1+Ej
.text:00000E12 SUBS R0, R4, R1 ; jumptable 00000DFA case 1
.text:00000E14 ; 22: break;
.text:00000E14 B def_DFA ; jumptable 00000DFA default case
.text:00000E16 ; ---------------------------------------------------------------------------
.text:00000E16 ; 24: result = v6 / a2;
.text:00000E16
.text:00000E16 loc_E16 ; CODE XREF: switch1+Ej
.text:00000E16 MOVS R0, R4 ; jumptable 00000DFA case 3
.text:00000E18 BLX __divsi3
.text:00000E1C ; 25: break;
.text:00000E1C ; 26: default:
.text:00000E1C B def_DFA ; jumptable 00000DFA default case
.text:00000E1C ; End of function switch1
在这个函数中因为使用了R4作为局部变量,所以在開始时要把R4放入堆栈,为了返回后程序能够继续执行,所以把LR也压入了堆栈。这样堆栈地址就减去了8个字节(R4,LR都被压入堆栈)。所以取第一个參数要使用指令LDR R2, [SP,#8+arg_0]。