0x00 项目工程
项目地址:http://download.csdn.net/detail/jltxgcy/9602851。
下面列出核心代码:
#include "com_example_ndkplt_PLTUtils.h" #include <android/log.h> #include <stdio.h> #include <string.h> #include <dlfcn.h> #define LOG_TAG "PLTUtils" #define ALOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) //typedef int (*strlen_fun)(const char *); //strlen_fun global_strlen1 = (strlen_fun)strlen; //strlen_fun global_strlen2 = (strlen_fun)strlen; typedef void (*puts_fun)(const char *); puts_fun global_fun = (puts_fun)puts; JNIEXPORT jint JNICALL Java_com_example_ndkplt_PLTUtils_pltTest (JNIEnv *, jobject) { const char *str = "helloworld"; puts_fun local_fun = (puts_fun)puts; local_fun("call the method"); puts("[+]another call the method of puts from libc.\n"); global_fun("[+]call the method of puts from libc.\n"); return 0; } 0x01 分析生成的libPLTUtils.so讲上面的工程使用ndk-build编译生成libPLTUtils.so,这个就是上文Android SO文件结构及readelf命令用来分析的so。
通过arm-linux-androideabi-readelf -r ~/Public/libPLTUtils.so,得到:
Relocation section '.rel.dyn' at offset 0xc24 contains 10 entries: Offset Info Type Sym.Value Sym. Name 00003e80 00000017 R_ARM_RELATIVE 00003fb4 00000017 R_ARM_RELATIVE 00003fb8 00000017 R_ARM_RELATIVE 00003fbc 00000017 R_ARM_RELATIVE 00003fc0 00000017 R_ARM_RELATIVE 00003fc8 00000017 R_ARM_RELATIVE 00003fcc 00000017 R_ARM_RELATIVE 00004004 00000402 R_ARM_ABS32 00000000 puts 00003fc4 00000915 R_ARM_GLOB_DAT 00000000 __gnu_Unwind_Find_exid 00003fd0 00001f15 R_ARM_GLOB_DAT 00000000 __cxa_call_unexpected Relocation section '.rel.plt' at offset 0xc74 contains 8 entries: Offset Info Type Sym.Value Sym. Name 00003fe0 00000216 R_ARM_JUMP_SLOT 00000000 __cxa_atexit 00003fe4 00000116 R_ARM_JUMP_SLOT 00000000 __cxa_finalize 00003fe8 00000416 R_ARM_JUMP_SLOT 00000000 puts 00003fec 00000916 R_ARM_JUMP_SLOT 00000000 __gnu_Unwind_Find_exid 00003ff0 00000f16 R_ARM_JUMP_SLOT 00000000 abort 00003ff4 00001116 R_ARM_JUMP_SLOT 00000000 memcpy 00003ff8 00001c16 R_ARM_JUMP_SLOT 00000000 __cxa_begin_cleanup 00003ffc 00001d16 R_ARM_JUMP_SLOT 00000000 __cxa_type_match
R_ARM_JUMP_SLOT和R_ARM_GLOB_DAT属性的重定位地址一般位于GOT表,R_ARM_COPY和R_ARM_ABS32属性的重定位一般位于.data节或.text节中。
通过ida打开libPLTUtils.so,可以看到R_ARM_JUMP_SLOT属性,地址为0x00003FE8位于.got段中。而R_ARM_ABS32属性,地址为0x00004004位于.data段中。
.data:00004004 global_fun DCD __imp_puts ; DATA XREF: Java_com_example_ndkplt_PLTUtils_pltTest+18o .got:00003FE8 puts_ptr DCD __imp_puts ; DATA XREF: puts+8r 0x00004004和0x00003FE8这两个地址中的内容,是动态链接时被赋值为libc.so中puts函数的地址。 详细请参考 Android So加载深入分析.pdf 。
0x02 全局函数指针,局部函数指针,直接调用函数指针
先说局部函数指针和直接调用函数指针,他们的操作是一样的。用ida打开libPLTUtils.so,找到Java_com_example_ndkplt_PLTUtils_pltTest函数,下面列出的是动态调试状态下的arm汇编代码。
.text:4C57BD64 EXPORT Java_com_example_ndkplt_PLTUtils_pltTest .text:4C57BD64 Java_com_example_ndkplt_PLTUtils_pltTest .text:4C57BD64 .text:4C57BD64 ; FUNCTION CHUNK AT .text:4C57D2B8 SIZE 00000002 BYTES .text:4C57BD64 .text:4C57BD64 LDR R0, =(aCallTheMethod - 0x4C57BD6C) .text:4C57BD66 PUSH {R3,LR} .text:4C57BD68 ADD R0, PC ; "call the method" .text:4C57BD6A BL loc_4C57D2B8 .text:4C57BD6E ; --------------------------------------------------------------------------- .text:4C57BD6E LDR R0, =(aAnotherCallThe - 0x4C57BD74) .text:4C57BD70 ADD R0, PC ; "[+]another call the method of puts from"... .text:4C57BD72 BL loc_4C57D2B8 .text:4C57BD76 ; --------------------------------------------------------------------------- .text:4C57BD76 LDR R3, =(global_fun_ptr - 0x4C57BD7E) .text:4C57BD78 LDR R0, =(aCallTheMethodO - 0x4C57BD82) .text:4C57BD7A ADD R3, PC ; global_fun_ptr .text:4C57BD7C LDR R3, [R3] ; global_fun .text:4C57BD7E ADD R0, PC ; "[+]call the method of puts from libc.\n" .text:4C57BD80 LDR R3, [R3] .text:4C57BD82 BLX R3 .text:4C57BD84 MOVS R0, #0 .text:4C57BD86 POP {R3,PC} .text:4C57BD86 ; End of function Java_com_example_ndkplt_PLTUtils_pltTest 局部函数指针和直接调用函数指针均调用的是loc_4C57D2B8,这个函数如下:
.text:4C57D2B8 loc_4C57D2B8 ; CODE XREF: Java_com_example_ndkplt_PLTUtils_pltTest+6j .text:4C57D2B8 ; Java_com_example_ndkplt_PLTUtils_pltTest+Ej .text:4C57D2B8 BX PC .text:4C57D2B8 ; END OF FUNCTION CHUNK FOR Java_com_example_ndkplt_PLTUtils_pltTest .text:4C57D2B8 ; --------------------------------------------------------------------------- .text:4C57D2BA ALIGN 4 .text:4C57D2BC CODE32 .text:4C57D2BC .text:4C57D2BC ; =============== S U B R O U T I N E ======================================= .text:4C57D2BC .text:4C57D2BC ; Attributes: thunk .text:4C57D2BC .text:4C57D2BC ; int j_puts(const char *s) .text:4C57D2BC j_puts ; CODE XREF: Java_com_example_ndkplt_PLTUtils_pltTest:loc_4C57D2B8j .text:4C57D2BC LDR R12, =(puts - 0x4C57D2C8) .text:4C57D2C0 ADD PC, R12, PC ; puts .text:4C57D2C0 ; End of function j_puts 在0x4C47D2C0处,PC已经指向了PLT表:
.plt:4C57BCE0 ; int puts(const char *s) .plt:4C57BCE0 puts ; DATA XREF: j_puts+4o .plt:4C57BCE0 ; .text:off_4C57D2C4o .plt:4C57BCE0 ADR R12, 0x4C57BCE8 .plt:4C57BCE4 ADD R12, R12, #0x3000 .plt:4C57BCE8 LDR PC, [R12,#(puts_ptr - 0x4C57ECE8)]! ; __imp_puts LDR PC, [R12,#(puts_ptr - 0x4C57ECE8)]! 从got表中对应的位置取出puts的地址,并开始执行。而这个对应的位置,就是0x00003fe8:
00003fe8 00000416 R_ARM_JUMP_SLOT 00000000 puts 局部函数指针和直接调用函数指针,它的重定位类型是R_ARM_JUMP_SLOT,并且位于.re.plt节区,其Offset指向最终调用函数地址的地址(也就是函数指针的指针)。整个过程是先到.plt,再到.got,最后才定位到真正的函数地址。
接着说全局调用函数指针,在Java_com_example_ndkplt_PLTUtils_pltTest函数中对应的代码是:
.text:4C57BD76 LDR R3, =(global_fun_ptr - 0x4C57BD7E) .text:4C57BD78 LDR R0, =(aCallTheMethodO - 0x4C57BD82) .text:4C57BD7A ADD R3, PC ; global_fun_ptr .text:4C57BD7C LDR R3, [R3] ; global_fun .text:4C57BD7E ADD R0, PC ; "[+]call the method of puts from libc.\n" .text:4C57BD80 LDR R3, [R3] .text:4C57BD82 BLX R3 .text:4C57BD84 MOVS R0, #0 .text:4C57BD86 POP {R3,PC} .got:4C57EFB4 global_fun_ptr DCD global_fun ; DATA XREF: Java_com_example_ndkplt_PLTUtils_pltTest+16o .data:4C57F004 global_fun DCD puts+1 ; DATA XREF: Java_com_example_ndkplt_PLTUtils_pltTest+18o 通过全局函数指针的方式调用外部函数,它的重定位类型是R_ARM_ABS32,并且位于.rel.dyn节区。
因此R_ARM_ABS32重定位项的Offset指向最终调用函数地址的地址(也就是函数指针的指针),整个重定位过程是先位到.got,再从.got定位到.date。