ida动态调试so,在init_array和JNI_ONLOAD处下断点

Posted jltxgcy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ida动态调试so,在init_array和JNI_ONLOAD处下断点相关的知识,希望对你有一定的参考价值。

    本文涉及到的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]。

以上是关于ida动态调试so,在init_array和JNI_ONLOAD处下断点的主要内容,如果未能解决你的问题,请参考以下文章

安卓逆向11.IDA以Debug模式调试APK SO

Android SO动态调试之IDA

IDA 对 so 的动态调试

Android逆向 ida动态调试问题

IDA动态调试破解EXE文件与分析APK流程

IDA动态调试破解EXE文件与分析APK流程