基于Android arm64 Linux got 调试(续)
有些地方没整理清楚,再调试下。
由于hello这个格式(类似动态加载库格式)的原因,每次调试加载地址都会有变,不能接着上面的调试,方法是一致的。
顺便看下x86的格式,对比。
准备工作先做好。
有兴趣可以从link64源头玩起,这里跳过。
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
根据plt段信息,这回多设置几个断点。
前文第二点断点应该设置以下格式更为合适。
watch *(long *) <addr>
(gdb) x/16x 0x55855cafa0
0x55855cafa0: 0x00000000 0x00000000 0x000006d0 0x00000000
0x55855cafb0: 0x000006d0 0x00000000 0x000006d0 0x00000000
0x55855cafc0: 0x000006d0 0x00000000 0x000006d0 0x00000000
0x55855cafd0: 0x000006d0 0x00000000 0x00010d50 0x00000000
(gdb)
前文没有描述,0xfa0除外,0xfa8,0xfb0——0xfd0,这里存储的地址其实就是__libc_init的地址。当然是没偏移前的地址,由于应用程序本身是动态加载的,这个地址就是无用的了。额外的活当然交给linker64来干。
类比与x86编译的程序,虽然动态加载库,自身应用程序里的地址就是运行地址,里面的值就是有效的,所以可以在第一次运行函数的时候跳转到__libc_init(x86并不一定这么叫,但一定有个相同功能的函数)修正地址就可以工作。
这么说来,arm及x86区别的源头就是可执行的程序的格式以及对应的linker,不知道理解对不对。
全速运行,第一个停住的是修改__libc_init的地址,可以理解!
接下来修改sleep的加载地址,因为getpid我们没设断点。
随便看下lib加载情况,kernel必然加载了,gdb还未显示。
接下来这个全速运行后比较慢,估计暂停后gdb要搜索库信息加载,最后查了半天,[vdso]没找到,正常。
这回停在__libc_init函数,此时main还未到。先看上图,地址更新应该linker都干完了,意淫一下,这家伙似乎没啥活要干。当然,具体有兴趣看源码,跳过!
接下来,无悬念,就到main了。
0x700, 0x710分别断点停住一次,删除,全速跑两圈,再偷偷看看跳转表,发现一致。
<__libc_init@plt-0x20> 一直都没运行过。