基于Android arm64 Linux got 调试

gdb调试一下got实现,加深理解。涉及一些gdb常用命令,记录一下。

环境:Ubuntu 15.10
代码: Android-6.0.1_r9
直接编译的arm 64位eng版本。
启动模拟器:emulator -system system.img -data userdata.img -ramdisk ramdisk.img
这里写图片描述

这里写图片描述
adb shell直接可用,Good!

示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>


int flag = 1;
int count = 0;

int main()
{
    pid_t pid;
    pid = getpid();

    printf("sizeof(int)  = %ld\n", sizeof(int));
    printf("sizeof(long) = %ld\n", sizeof(long));

    printf("Target pid = %d\n", pid);

    while(flag) {
        printf("Target is running:%d\n", count);
        count++;
        sleep(10);
    }
    return 0;
}

反编译命令,加上-S反编译带上源码:

/opt/android-6.0.1_r9/out/target/product/generic_arm64/obj/EXECUTABLES/hello_intermediates/LINKED$ aarch64-linux-android-objdump -S hello > hello.dis

    hello:     file format elf64-littleaarch64  


    Disassembly of section .plt:  

    00000000000006d0 <__libc_init@plt-0x20>:  
     6d0:   a9bf7bf0    stp x16, x30, [sp,#-16]!  
     6d4:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>  
     6d8:   f947d211    ldr x17, [x16,#4000]  
     6dc:   913e8210    add x16, x16, #0xfa0  
     6e0:   d61f0220    br  x17  
     6e4:   d503201f    nop  
     6e8:   d503201f    nop  
     6ec:   d503201f    nop  

    00000000000006f0 <__libc_init@plt>:  
     6f0:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>  
     6f4:   f947d611    ldr x17, [x16,#4008]  
     6f8:   913ea210    add x16, x16, #0xfa8  
     6fc:   d61f0220    br  x17  

    0000000000000700 <getpid@plt>:  
     700:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>  
     704:   f947da11    ldr x17, [x16,#4016]  
     708:   913ec210    add x16, x16, #0xfb0  
     70c:   d61f0220    br  x17  

    0000000000000710 <sleep@plt>:  
     710:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>  
     714:   f947de11    ldr x17, [x16,#4024]  
     718:   913ee210    add x16, x16, #0xfb8  
     71c:   d61f0220    br  x17  

    0000000000000720 <__cxa_atexit@plt>:  
     720:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>  
     724:   f947e211    ldr x17, [x16,#4032]  
     728:   913f0210    add x16, x16, #0xfc0  
     72c:   d61f0220    br  x17  

    0000000000000730 <printf@plt>:  
     730:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>  
     734:   f947e611    ldr x17, [x16,#4040]  
     738:   913f2210    add x16, x16, #0xfc8  
     73c:   d61f0220    br  x17  

    0000000000000740 <__register_atfork@plt>:  
     740:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>  
     744:   f947ea11    ldr x17, [x16,#4048]  
     748:   913f4210    add x16, x16, #0xfd0  
     74c:   d61f0220    br  x17  

    Disassembly of section .text:  

    0000000000000750 <main>:  

    int flag = 1;  
    int count = 0;  

    int main()  
    {  
     750:   a9bd7bfd    stp x29, x30, [sp,#-48]!  
     754:   910003fd    mov x29, sp  
     758:   a90153f3    stp x19, x20, [sp,#16]  
     75c:   f90013f5    str x21, [sp,#32]  
        pid_t pid;  
        pid = getpid();  
     760:   97ffffe8    bl  700 <getpid@plt>  
     764:   2a0003f3    mov w19, w0  

        printf("sizeof(int)  = %ld\n", sizeof(int));  
     768:   90000000    adrp    x0, 0 <abitag-0x250>  
     76c:   d2800081    mov x1, #0x4                    // #4  
     770:   9123a000    add x0, x0, #0x8e8  
        printf("sizeof(long) = %ld\n", sizeof(long));  

        printf("Target pid = %d\n", pid);  

        while(flag) {  
     774:   b0000094    adrp    x20, 11000 <__dso_handle>  
    int main()  
    {  
        pid_t pid;  
        pid = getpid();  

        printf("sizeof(int)  = %ld\n", sizeof(int));  
     778:   97ffffee    bl  730 <printf@plt>  
        printf("sizeof(long) = %ld\n", sizeof(long));  
     77c:   90000002    adrp    x2, 0 <abitag-0x250>  
     780:   d2800101    mov x1, #0x8                    // #8  
     784:   91240040    add x0, x2, #0x900  
     788:   97ffffea    bl  730 <printf@plt>  

        printf("Target pid = %d\n", pid);  
     78c:   90000001    adrp    x1, 0 <abitag-0x250>  
     790:   91246020    add x0, x1, #0x918  
     794:   2a1303e1    mov w1, w19  
     798:   97ffffe6    bl  730 <printf@plt>  

        while(flag) {  
     79c:   b9400a83    ldr w3, [x20,#8]  
     7a0:   34000203    cbz w3, 7e0 <main+0x90>  
            printf("Target is running:%d\n", count);  
     7a4:   90000015    adrp    x21, 0 <abitag-0x250>  
     7a8:   b0000084    adrp    x4, 11000 <__dso_handle>  
     7ac:   9124c2b5    add x21, x21, #0x930  
     7b0:   91003093    add x19, x4, #0xc  
        printf("sizeof(int)  = %ld\n", sizeof(int));  
        printf("sizeof(long) = %ld\n", sizeof(long));  

        printf("Target pid = %d\n", pid);  

        while(flag) {  
     7b4:   91002294    add x20, x20, #0x8  
            printf("Target is running:%d\n", count);  
     7b8:   b9400261    ldr w1, [x19]  
     7bc:   aa1503e0    mov x0, x21  
     7c0:   97ffffdc    bl  730 <printf@plt>  
            count++;  
     7c4:   b9400265    ldr w5, [x19]  
            sleep(10);  
     7c8:   52800140    mov w0, #0xa                    // #10  

        printf("Target pid = %d\n", pid);  

        while(flag) {  
            printf("Target is running:%d\n", count);  
            count++;  
     7cc:   110004a6    add w6, w5, #0x1  
     7d0:   b9000266    str w6, [x19]  
            sleep(10);  
     7d4:   97ffffcf    bl  710 <sleep@plt>  
        printf("sizeof(int)  = %ld\n", sizeof(int));  
        printf("sizeof(long) = %ld\n", sizeof(long));  

        printf("Target pid = %d\n", pid);  

        while(flag) {  
     7d8:   b9400287    ldr w7, [x20]  
     7dc:   35fffee7    cbnz    w7, 7b8 <main+0x68>  
            printf("Target is running:%d\n", count);  
            count++;  
            sleep(10);  
        }  
        return 0;  
    }  
     7e0:   52800000    mov w0, #0x0                    // #0  
     7e4:   f94013f5    ldr x21, [sp,#32]  
     7e8:   a94153f3    ldp x19, x20, [sp,#16]  
     7ec:   a8c37bfd    ldp x29, x30, [sp],#48  
     7f0:   d65f03c0    ret  

模拟器上输入:gdbserver :1234 hello
这里写图片描述

adb forward tcp:1234 tcp:1234
主机端执行:aarch64-linux-android-gdb
这里写图片描述

gdb命令:target remote :1234
这里写图片描述

list命令查看源码,提示file命令加载symbol.
这里写图片描述

android上编译的动态链接的应用程序类似有位置无关特性,每次加载的地址可能都会变动。静态编译的不受此影响。
这里写图片描述

这里写图片描述

hello代码段加载至0x5586738000(每次运行都会变动).
aarch64-linux-android-readelf -S hello查看代码段偏移0x750
这里写图片描述

使用如下命令加载symbol,之后可以使用list命令查看代码:
add-symbol-file hello (0x5586738000+0x750)
对应的remove-symbol-file -a addr 可以删除加载过的符号信息,加错了可以重新来过!
这里写图片描述

使用如下命令可以设置加载库文件信息:
set solib-absolute-prefix /opt/android-6.0.1_r9/out/target/product/generic_arm64/symbols
这里写图片描述
暂时只有linker64加载了。

设置几个调试断点。

0000000000000700 <getpid@plt>:
700:    90000090    adrp    x16, 10000 <pthread_atfork+0xf754>
 704:   f947da11    ldr x17, [x16,#4016]
 708:   913ec210    add x16, x16, #0xfb0
 70c:   d61f0220    br  x17

0000000000000710 <sleep@plt>:
 710:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>
 714:   f947de11    ldr x17, [x16,#4024]
 718:   913ee210    add x16, x16, #0xfb8
 71c:   d61f0220    br  x17

0000000000000720 <__cxa_atexit@plt>:
 720:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>
 724:   f947e211    ldr x17, [x16,#4032]
 728:   913f0210    add x16, x16, #0xfc0
 72c:   d61f0220    br  x17

0000000000000730 <printf@plt>:
 730:   90000090    adrp    x16, 10000 <pthread_atfork+0xf754>
 734:   f947e611    ldr x17, [x16,#4040]
 738:   913f2210    add x16, x16, #0xfc8
 73c:   d61f0220    br  x17

这几个库函数跳转首地址刚好0x700 0x710 0x720 0x730, 当然不能忘了我们的偏移:0x5586738000
就以sleep为例,x17第一次拿到的地址应该不是正确sleep地址,got修复之后才是正确的。
watch *(0x5586738000+0x10000+0xfb8),来跟踪查看。

(gdb) p/x 0x5586738000+0x10000+0xfb8
$1 = 0x5586748fb8

如下打印代码也可以得到其地址

(gdb) x/8i 0x5586738710
   0x5586738710:    adrp    x16, 0x5586748000
   0x5586738714:    ldr    x17, [x16,#4024]
   0x5586738718:    add    x16, x16, #0xfb8
   0x558673871c:    br    x17
   0x5586738720:    adrp    x16, 0x5586748000
   0x5586738724:    ldr    x17, [x16,#4032]
   0x5586738728:    add    x16, x16, #0xfc0
   0x558673872c:    br    x17
(gdb) p/x 0x5586748000+4024
$2 = 0x5586748fb8
(gdb) x/8i 0x5586748fb8
   0x5586748fb8:    .inst    0x000006d0 ; undefined
   0x5586748fbc:    .inst    0x00000000 ; undefined
   0x5586748fc0:    .inst    0x000006d0 ; undefined
   0x5586748fc4:    .inst    0x00000000 ; undefined
   0x5586748fc8:    .inst    0x000006d0 ; undefined
   0x5586748fcc:    .inst    0x00000000 ; undefined
   0x5586748fd0:    .inst    0x000006d0 ; undefined
   0x5586748fd4:    .inst    0x00000000 ; undefined
(gdb)

这里写图片描述

b main
再设置一个观察count值变化的量,方便后续主动暂停。
这里写图片描述
helllo symbol偏移信息都白加了?或者只加了代码段?管它呢,有了偏移一样干活。

(gdb) p/x 0x5586738000+0x1100c
$5 = 0x558674900c
(gdb) watch *0x558674900c
Hardware watchpoint 3: *0x558674900c
(gdb) 

就整这三个断点试试。
这里写图片描述

这里写图片描述
第二个断点先到。

这里写图片描述
此时还是未显示其他库加载。

注意一个细节,查看下进程的加载库信息。
这里写图片描述
从进程的信息看到,其实库已经加载完毕,这些信息直接从内核呈现出来。gdb加载比这个慢,正常。

执行bt命令:
这里写图片描述
深入加载细节不是今天重点,有兴趣的自行研究。

这里写图片描述
查看信息,确实更新,而且更新后的地址确实有代码存在,虽然暂时不能证明就是sleep地址,待库symbol完整加入之后(从上面可见,此时库文件内核已经加载完成)。

继续全速运行。
这里写图片描述
这回才停在main首地址的地方,由此可见got段修复在main运行前就成功完成了。

info r 可以显示常规寄存器的值,记录一下(x86上不能简写, info registers)。
这里写图片描述

display/8i ($pc-16),这个可以每次停住显示PC前后的几条命令,很喜欢用。
这里写图片描述

此时再看看库文件加载信息,基本都有了。
这里写图片描述

再查看刚才sleep修改的地址,现在有信息显示了。
这里写图片描述

再看看其他几个got是不是也修改了:
这里写图片描述

大部分都有值了,就看看__register_atfork 以及printf是不是已经设置。
这里写图片描述

单步执行几次
这里写图片描述

这里写图片描述
此时当然直接就是正确的地址了。

再c两次,第三个断点设了,还不知能不能干活。
这里写图片描述

这里写图片描述
还不错,如预期工作。

其实大家看我很简单的设置了这三个断点,这是事后总结此文的时候整的,前期调试还是走了很多弯路。
主要是记录下gdb玩法。

0000000000000710 <sleep@plt>:
 710:   90000090        adrp    x16, 10000 <pthread_atfork+0xf754>
 714:   f947de11        ldr     x17, [x16,#4024]
 718:   913ee210        add     x16, x16, #0xfb8
 71c:   d61f0220        br      x17

got段的理解,以上面这个代码简单总结下:
main函数调用 sleep 不直接跳转执行库函数sleep(就是为了能做到动态加载),而是跳到如上代码,如上代码很加单,x17放的就是执行代码地址,只不过第一次不是正确的地址,需要修复下,后续每次跳到这,就是正确的地址,跳转执行。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值