Android SO逆向-数组与指针
来源:互联网 发布:浙师大行知学院怎么样 编辑:程序博客网 时间:2024/06/04 19:03
0x00
这一节主要分析一维数组、二维数组、数组指针和指针数组的汇编实现。
0x01
我们先直接看C++代码:
#include "com_example_ndkreverse3_Lesson3.h"#include <android/log.h>#define LOG_TAG "lesson3"#define ALOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))//参考http://blog.csdn.net/jltxgcy/article/details/17756391JNIEXPORT void JNICALL Java_com_example_ndkreverse3_Lesson3_main (JNIEnv * env, jobject jobject) {int a[] = {1,2,3,4,5,6};for(int i = 0; i< 6; i++) {ALOGD("a=%d\n", a[i]);}}JNIEXPORT void JNICALL Java_com_example_ndkreverse3_Lesson3_main1 (JNIEnv * env, jobject jobject) {int b[][3]={{1,2},{3,4,5}};for(int i = 0; i< 2; i++) {for(int j = 0; j < 3; j++) {ALOGD("b=%d\n", b[i][j]);}}}JNIEXPORT void JNICALL Java_com_example_ndkreverse3_Lesson3_main2 (JNIEnv * env, jobject jobject) {char *d[] = {"12","345","6789"};for(int i = 0; i< 3; i++) {for(int j = 0; j < 4; j++) {ALOGD("d=%d\n", *(*(d + i) + j));}}}JNIEXPORT void JNICALL Java_com_example_ndkreverse3_Lesson3_main3 (JNIEnv * env, jobject jobject) {int a[] = {1,2,3,4,5,6};int *p = a;for(int i = 0; i< 6; i++) {ALOGD("p=%d\n", *(p + i));}}JNIEXPORT void JNICALL Java_com_example_ndkreverse3_Lesson3_main4 (JNIEnv * env, jobject jobject) {int b[][3]={{1,2},{3,4,5}};int (*p)[3] = b;for(int i = 0; i< 2; i++) {for(int j = 0; j < 3; j++) {ALOGD("p=%d\n", *(*(p + i) + j));}}}
0x01
下面我们用ida打开so,分别对不同函数的汇编形式的代码做出解释。
Java_com_example_ndkreverse3_Lesson3_main:
.text:00000EC8 EXPORT Java_com_example_ndkreverse3_Lesson3_main.text:00000EC8 Java_com_example_ndkreverse3_Lesson3_main.text:00000EC8.text:00000EC8 var_2C = -0x2C.text:00000EC8 var_14 = -0x14.text:00000EC8.text:00000EC8 PUSH {R4-R6,LR}.text:00000ECA SUB SP, SP, #0x20 ;开发了0x20个地址空间作为存储堆栈的位置.text:00000ECC ADD R4, SP, #0x30+var_2C ;R4赋值为SP+4.text:00000ECE MOVS R1, R4 ;R1和R4的值一样.text:00000ED0 LDR R2, =(__stack_chk_guard_ptr - 0xED6) ;位于.got段中__stack_chk_guard_ptr相对于下一条PC指令的偏移,取出来赋值给R2.text:00000ED2 ADD R2, PC ; __stack_chk_guard_ptr ;R2中存放的是位于.got段中__stack_chk_guard_ptr的地址.text:00000ED4 LDR R2, [R2] ; __stack_chk_guard ;取地址中的内容,我们看下面代码,这个地址是__stack_chk_guard,这个地址运行时分配的.text:00000ED6 LDR R3, [R2] ;取这个地址中的内容,我在动态调试状态下得到的内容为6BCAA164.text:00000ED8 STR R3, [SP,#0x30+var_14] ;把这个值6BCAA164存放在SP+0x1C的位置.text:00000EDA LDR R3, =(unk_226C - 0xEE0) ;位于.rodata,unk_226C相对于下一条PC指令的偏移,取出来赋值给R3.text:00000EDC ADD R3, PC ; unk_226C ;R3存放的是位于.rodata段中unk_226C的地址.text:00000EDE LDMIA R3!, {R0,R5,R6} ;将R3地址堆栈中的内容依次赋值给R0,R5,R6.text:00000EE0 STMIA R1!, {R0,R5,R6} ;将R0,R5,R6的值分配存放到R1所指向的堆栈中,也就是刚才SUB SP,SP,#0x20,然后再加4的堆栈.text:00000EE2 LDMIA R3!, {R0,R5,R6} ;同理.text:00000EE4 STMIA R1!, {R0,R5,R6} ;同理,这样堆栈中就初始化好了1,2,3,4,5,6。PS:堆栈中存放6的下一个地址中的数值就是0x6BCAA164.text:00000EE6 MOVS R6, #0 ;R6初始化为9.text:00000EE8 ADDS R5, R2, #0 ;R5初始化为R2,也就是__stack_chk_guard的地址.text:00000EEA.text:00000EEA loc_EEA ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main+36j.text:00000EEA LDR R1, =(aLesson3 - 0xEF6).text:00000EEC LDR R2, =(aAD - 0xEF8).text:00000EEE LDR R3, [R4,R6] ;从堆栈中取数.text:00000EF0 MOVS R0, #3.text:00000EF2 ADD R1, PC ; "lesson3".text:00000EF4 ADD R2, PC ; "a=%d\n".text:00000EF6 ADDS R6, #4 ;为取下一个数做准备.text:00000EF8 BL j_j___android_log_print.text:00000EFC CMP R6, #0x18 ;R6和0x18做比较.text:00000EFE BNE loc_EEA ;如果不相等,就跳转到loc_EEA.text:00000F00 LDR R2, [SP,#0x30+var_14] ;否则取出原来存入堆栈中的内容,为0x6BCAA164.text:00000F02 LDR R3, [R5] ;从R5地址中取出的值赋值给R3,刚才R5被赋值为__stack_chk_guard的地址.text:00000F04 CMP R2, R3 ;比较R2和R3的值.text:00000F06 BEQ loc_F0C ;如果相等,就跳转到loc_F0C.text:00000F08 BL j_j___stack_chk_fail ;否则堆栈检查失败.text:00000F0C ; ---------------------------------------------------------------------------.text:00000F0C.text:00000F0C loc_F0C ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main+3Ej.text:00000F0C ADD SP, SP, #0x20.text:00000F0E POP {R4-R6,PC}
.text:00000F10 off_F10 DCD __stack_chk_guard_ptr - 0xED6.text:00000F10 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main+8r.text:00000F14 off_F14 DCD unk_226C - 0xEE0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main+12r.text:00000F18 off_F18 DCD aLesson3 - 0xEF6 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main:loc_EEAr.text:00000F18 ; "lesson3".text:00000F1C off_F1C DCD aAD - 0xEF8 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main+24r.text:00000F1C ; "a=%d\n"
.got:00003FAC __stack_chk_guard_ptr DCD __stack_chk_guard
.rodata:0000226C unk_226C DCB 1 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main+14o.rodata:0000226C ; Java_com_example_ndkreverse3_Lesson3_main+16o ....rodata:0000226D DCB 0.rodata:0000226E DCB 0.rodata:0000226F DCB 0.rodata:00002270 DCB 2.rodata:00002271 DCB 0.rodata:00002272 DCB 0.rodata:00002273 DCB 0.rodata:00002274 DCB 3.rodata:00002275 DCB 0.rodata:00002276 DCB 0.rodata:00002277 DCB 0.rodata:00002278 DCB 4.rodata:00002279 DCB 0.rodata:0000227A DCB 0.rodata:0000227B DCB 0.rodata:0000227C DCB 5.rodata:0000227D DCB 0.rodata:0000227E DCB 0.rodata:0000227F DCB 0.rodata:00002280 DCB 6.rodata:00002281 DCB 0.rodata:00002282 DCB 0.rodata:00002283 DCB 0
我们可以看到首先开辟了堆栈来存储数组元素,数组元素的初始化值被放在了.rodata中。里面还有堆栈保护的代码。详情请参考代码中的注释。
Java_com_example_ndkreverse3_Lesson3_main1:
.text:00000F20 EXPORT Java_com_example_ndkreverse3_Lesson3_main1.text:00000F20 Java_com_example_ndkreverse3_Lesson3_main1.text:00000F20.text:00000F20 s = -0x2C.text:00000F20 var_14 = -0x14.text:00000F20.text:00000F20 PUSH {R4-R6,LR}.text:00000F22 LDR R4, =(__stack_chk_guard_ptr - 0xF2C) .text:00000F24 SUB SP, SP, #0x20 ;开辟堆栈.text:00000F26 ADD R5, SP, #0x30+s.text:00000F28 ADD R4, PC ; __stack_chk_guard_ptr.text:00000F2A LDR R4, [R4] ; __stack_chk_guard.text:00000F2C MOVS R0, R5 ; s.text:00000F2E LDR R3, [R4].text:00000F30 MOVS R1, #0 ; c.text:00000F32 MOVS R2, #0x18 ; n.text:00000F34 STR R3, [SP,#0x30+var_14].text:00000F36 BL j_j_memset ;将s中前n个字节用 c(0) 替换并返回 s 。.text:00000F3A MOVS R3, #1.text:00000F3C STR R3, [SP,#0x30+s] ;初始化堆栈中的数组.text:00000F3E MOVS R3, #2.text:00000F40 STR R3, [R5,#4] ;[R5,#8]直接略过.text:00000F42 MOVS R3, #3.text:00000F44 STR R3, [R5,#0xC].text:00000F46 MOVS R3, #4.text:00000F48 STR R3, [R5,#0x10].text:00000F4A MOVS R3, #5.text:00000F4C MOVS R6, #0.text:00000F4E STR R3, [R5,#0x14].text:00000F50.text:00000F50 loc_F50 ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main1+44j.text:00000F50 LDR R1, =(aLesson3 - 0xF5C).text:00000F52 LDR R2, =(aBD - 0xF5E).text:00000F54 LDR R3, [R5,R6] ;取数组元素,R5是 sp - 0x20 + 0x4,分别取出1,2,0.text:00000F56 MOVS R0, #3.text:00000F58 ADD R1, PC ; "lesson3".text:00000F5A ADD R2, PC ; "b=%d\n".text:00000F5C ADDS R6, #4.text:00000F5E BL j_j___android_log_print.text:00000F62 CMP R6, #0xC ;R6的值与0xC的值比较.text:00000F64 BNE loc_F50 ;如果不相等,就跳转到loc_F50.text:00000F66 MOVS R6, #0 ;否则,继续运行.text:00000F68.text:00000F68 loc_F68 ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main1+5Ej.text:00000F68 LDR R1, =(aLesson3 - 0xF76).text:00000F6A LDR R2, =(aBD - 0xF78).text:00000F6C ADDS R3, R5, R6.text:00000F6E LDR R3, [R3,#0xC] ;取数组元素,分别取出3,4,5.text:00000F70 MOVS R0, #3.text:00000F72 ADD R1, PC ; "lesson3".text:00000F74 ADD R2, PC ; "b=%d\n".text:00000F76 ADDS R6, #4.text:00000F78 BL j_j___android_log_print.text:00000F7C CMP R6, #0xC.text:00000F7E BNE loc_F68 ;和loc_F50同理.text:00000F80 LDR R2, [SP,#0x30+var_14] .text:00000F82 LDR R3, [R4].text:00000F84 CMP R2, R3 ;堆栈检查.text:00000F86 BEQ loc_F8C.text:00000F88 BL j_j___stack_chk_fail.text:00000F8C ; ---------------------------------------------------------------------------.text:00000F8C.text:00000F8C loc_F8C ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main1+66j.text:00000F8C ADD SP, SP, #0x20.text:00000F8E POP {R4-R6,PC}
.text:00000F90 off_F90 DCD __stack_chk_guard_ptr - 0xF2C.text:00000F90 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main1+2r.text:00000F94 off_F94 DCD aLesson3 - 0xF5C ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main1:loc_F50r.text:00000F94 ; "lesson3".text:00000F98 off_F98 DCD aBD - 0xF5E ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main1+32r.text:00000F98 ; "b=%d\n".text:00000F9C off_F9C DCD aLesson3 - 0xF76 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main1:loc_F68r.text:00000F9C ; "lesson3".text:00000FA0 off_FA0 DCD aBD - 0xF78 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main1+4Ar.text:00000FA0 ; "b=%d\n"
.rodata:00002284 aLesson3 DCB "lesson3",0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main+2Ao.rodata:00002284 ; .text:off_F18o ....rodata:0000228C aAD DCB "a=%d",0xA,0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main+2Co.rodata:0000228C ; .text:off_F1Co ....rodata:00002292 aBD DCB "b=%d",0xA,0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main1+3Ao.rodata:00002292 ; Java_com_example_ndkreverse3_Lesson3_main1+54o ...我们看到二维数组的本质上和一维数组是一致的,这里二维数组初始化的值并不是存放在.rodata段中,而是用寄存器赋值。
Java_com_example_ndkreverse3_Lesson3_main2:
.text:00000FA4 EXPORT Java_com_example_ndkreverse3_Lesson3_main2.text:00000FA4 Java_com_example_ndkreverse3_Lesson3_main2.text:00000FA4.text:00000FA4 var_28 = -0x28.text:00000FA4 var_24 = -0x24.text:00000FA4 var_20 = -0x20.text:00000FA4 var_1C = -0x1C.text:00000FA4.text:00000FA4 LDR R3, =(__stack_chk_guard_ptr - 0xFAC).text:00000FA6 PUSH {R4-R7,LR}.text:00000FA8 ADD R3, PC ; __stack_chk_guard_ptr.text:00000FAA LDR R3, [R3] ; __stack_chk_guard.text:00000FAC SUB SP, SP, #0x14 ;开辟堆栈.text:00000FAE MOV R6, SP.text:00000FB0 MOVS R5, #0.text:00000FB2 MOVS R4, R3.text:00000FB4 LDR R2, [R3].text:00000FB6 STR R2, [SP,#0x28+var_1C] ;存入堆栈保护数值.text:00000FB8 LDR R2, =(a12 - 0xFBE).text:00000FBA ADD R2, PC ; "12" ;向堆栈中存入"12"的地址.text:00000FBC STR R2, [SP,#0x28+var_28].text:00000FBE LDR R2, =(a345 - 0xFC4).text:00000FC0 ADD R2, PC ; "345" ;向堆栈中存入"345"的地址.text:00000FC2 STR R2, [SP,#0x28+var_24].text:00000FC4 LDR R2, =(a6789 - 0xFCA).text:00000FC6 ADD R2, PC ; "6789" ;“向堆栈中村如6789”的地址.text:00000FC8 STR R2, [SP,#0x28+var_20].text:00000FCA.text:00000FCA loc_FCA ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main2+44j.text:00000FCA MOVS R7, #0.text:00000FCC.text:00000FCC loc_FCC ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main2+3Ej.text:00000FCC LDR R3, [R6,R5] ;从堆栈中取出首地址.text:00000FCE LDR R1, =(aLesson3 - 0xFDA).text:00000FD0 LDR R2, =(aDD - 0xFDC).text:00000FD2 LDRB R3, [R3,R7] ;从.rodata段中取出字符.text:00000FD4 MOVS R0, #3.text:00000FD6 ADD R1, PC ; "lesson3".text:00000FD8 ADD R2, PC ; "d=%d\n".text:00000FDA ADDS R7, #1 ;每次加1,取一个字符.text:00000FDC BL j_j___android_log_print.text:00000FE0 CMP R7, #4 ;.text:00000FE2 BNE loc_FCC ;第二层循环.text:00000FE4 ADDS R5, #4 ;取下一个指针,也是下一个字符串的首地址.text:00000FE6 CMP R5, #0xC.text:00000FE8 BNE loc_FCA ;第一层循环.text:00000FEA LDR R2, [SP,#0x28+var_1C].text:00000FEC LDR R3, [R4].text:00000FEE CMP R2, R3.text:00000FF0 BEQ loc_FF6.text:00000FF2 BL j_j___stack_chk_fail.text:00000FF6 ; ---------------------------------------------------------------------------.text:00000FF6.text:00000FF6 loc_FF6 ; CODE XREF: Java_com_example_ndkreverse3_Lesson3_main2+4Cj.text:00000FF6 ADD SP, SP, #0x14.text:00000FF8 POP {R4-R7,PC}
.rodata:00002284 a12 DCB "12",0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main2+16o.rodata:00002284 ; .text:off_1000o.rodata:00002287 a345 DCB "345",0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main2+1Co.rodata:00002287 ; .text:off_1004o.rodata:0000228B a6789 DCB "6789",0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main2+22o.rodata:0000228B ; .text:off_1008o.rodata:00002290 aDD DCB "d=%d",0xA,0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main2+34o.rodata:00002290 ; .text:off_1010o.rodata:00002296 aPD DCB "p=%d",0xA,0 ; DATA XREF: Java_com_example_ndkreverse3_Lesson3_main3+2Co.rodata:00002296 ; .text:off_1068o ...
指针数组的执行请参考代码中的注释,字符串依然存储在.rodata段中。依然是开辟堆栈空间去存储指针数组。
Java_com_example_ndkreverse3_Lesson3_main3(指针)和Java_com_example_ndkreverse3_Lesson3_main汇编代码是一致的。
Java_com_example_ndkreverse3_Lesson3_main4(数组指针)和Java_com_example_ndkreverse3_Lesson3_main1汇编代码是一致的。
0 0
- Android SO逆向-数组与指针
- C++逆向第十课-----数组与指针的寻址
- Android逆向分析--so文件
- Android SO逆向-多重继承
- Android so逆向基本知识总结
- 逆向输出数组---(指针)
- Android逆向so文件,调试加解读
- Android逆向so文件,调试加解读
- Android SO逆向1-ARM介绍
- Android SO逆向2-实例分析
- Android SO逆向2-实例分析
- Android SO逆向1-ARM介绍
- Android逆向so文件,调试加解读
- Android SO逆向1-ARM介绍
- Android 逆向调用so(一)
- Android 逆向破解之so加载时机
- Android 逆向apk的.so动态库
- Android SO逆向-对象的构造函数与析构函数
- Mybatis最入门---Mapper文件配置详解(下)
- android 关闭指定的activity
- cordova build android 补充
- transient的作用及使用方法
- shell 编程- -入门篇
- Android SO逆向-数组与指针
- Java static
- ida 使用 问题总结
- EventBus3.0 使用详解(一)
- 项目管理和代码托管平台GitLab
- t3-framework的thememagic能改变那些东西?
- extern -- 全局变量 -- 一种良好的结构
- ORA-08103: object no longer exists
- 微信开发<四> 事件处理