我在Ubuntu-Linux 11.10平台上开发了一个cpp小程序。 现在我想对其进行逆向工程。我是初学者。 我使用这样的工具:GDB 7.0、hte editor、hexeditor。
我第一次让它变得如此简单。在符号信息的帮助下,我找到了 main 函数的地址,并制作了我需要的一切。
然后我 strip 化了 (--strip-all
) 可执行的 elf 文件,但我遇到了一些问题。
我知道 main
函数在这个程序中是从 0x8960 开始的。
但是我不知道如果没有这些知识我应该如何找到这一点。
我尝试使用 gdb 逐步调试我的程序,但它进入了 __libc_start_main
然后进入 ld-linux.so.3
(因此,它会找到并加载程序所需的共享库)。我调试了大约10分钟。当然,我可能会在 20 分钟内到达主函数的入口点,但似乎必须存在更简单的方法。
我应该怎么做才能在没有任何符号信息的情况下找到 main
函数的入口点?
您能否在 gdb 的帮助下通过 elf 文件的逆向工程向我推荐一些好书/网站/其他资源?
任何帮助将不胜感激。
最佳答案
在剥离的 Linux ELF 二进制文件中定位 main()
很简单。不需要符号信息。
__libc_start_main
的原型(prototype)是
int __libc_start_main(int (*main) (int, char**, char**),
int argc,
char *__unbounded *__unbounded ubp_av,
void (*init) (void),
void (*fini) (void),
void (*rtld_fini) (void),
void (*__unbounded stack_end));
main()
的运行时内存地址是第一个参数对应的参数,int (*main) (int, char**, char**)
.这意味着在调用 __libc_start_main
之前保存在运行时堆栈上的最后一个内存地址是 main()
的内存地址,因为参数被反向插入运行时堆栈它们对应的参数在函数定义中的顺序。
可以分4步在gdb
中输入main()
:
- 找到程序入口点
- 找到调用
__libc_start_main
的地方 - 在调用
_libc_start_main
之前将断点设置到最后保存在堆栈中的地址 - 让程序执行
继续
,直到main()
的断点被击中
32 位和 64 位 ELF 二进制文件的过程相同。
在名为“test_32”的剥离 32 位 ELF 二进制文件示例中输入 main()
:
$ gdb -q -nh test_32
Reading symbols from test_32...(no debugging symbols found)...done.
(gdb) info file #step 1
Symbols from "/home/c/test_32".
Local exec file:
`/home/c/test_32', file type elf32-i386.
Entry point: 0x8048310
< output snipped >
(gdb) break *0x8048310
Breakpoint 1 at 0x8048310
(gdb) run
Starting program: /home/c/test_32
Breakpoint 1, 0x08048310 in ?? ()
(gdb) x/13i $eip #step 2
=> 0x8048310: xor %ebp,%ebp
0x8048312: pop %esi
0x8048313: mov %esp,%ecx
0x8048315: and $0xfffffff0,%esp
0x8048318: push %eax
0x8048319: push %esp
0x804831a: push %edx
0x804831b: push $0x80484a0
0x8048320: push $0x8048440
0x8048325: push %ecx
0x8048326: push %esi
0x8048327: push $0x804840b # address of main()
0x804832c: call 0x80482f0 <__libc_start_main@plt>
(gdb) break *0x804840b # step 3
Breakpoint 2 at 0x804840b
(gdb) continue # step 4
Continuing.
Breakpoint 2, 0x0804840b in ?? () # now in main()
(gdb) x/x $esp+4
0xffffd110: 0x00000001 # argc = 1
(gdb) x/s **(char ***) ($esp+8)
0xffffd35c: "/home/c/test_32" # argv[0]
(gdb)
在一个名为“test_64”的剥离 64 位 ELF 二进制文件示例中输入 main()
:
$ gdb -q -nh test_64
Reading symbols from test_64...(no debugging symbols found)...done.
(gdb) info file # step 1
Symbols from "/home/c/test_64".
Local exec file:
`/home/c/test_64', file type elf64-x86-64.
Entry point: 0x400430
< output snipped >
(gdb) break *0x400430
Breakpoint 1 at 0x400430
(gdb) run
Starting program: /home/c/test_64
Breakpoint 1, 0x0000000000400430 in ?? ()
(gdb) x/11i $rip # step 2
=> 0x400430: xor %ebp,%ebp
0x400432: mov %rdx,%r9
0x400435: pop %rsi
0x400436: mov %rsp,%rdx
0x400439: and $0xfffffffffffffff0,%rsp
0x40043d: push %rax
0x40043e: push %rsp
0x40043f: mov $0x4005c0,%r8
0x400446: mov $0x400550,%rcx
0x40044d: mov $0x400526,%rdi # address of main()
0x400454: callq 0x400410 <__libc_start_main@plt>
(gdb) break *0x400526 # step 3
Breakpoint 2 at 0x400526
(gdb) continue # step 4
Continuing.
Breakpoint 2, 0x0000000000400526 in ?? () # now in main()
(gdb) print $rdi
$3 = 1 # argc = 1
(gdb) x/s **(char ***) ($rsp+16)
0x7fffffffe35c: "/home/c/test_64" # argv[0]
(gdb)
可以在 Patrick Horgan 的教程 "Linux x86 Program Start Up
or - How the heck do we get to main()?" 中找到有关程序初始化的详细处理和调用 main()
之前发生的事情以及如何到达 main()
关于linux - 如何在没有任何符号信息的elf可执行文件中找到main函数的入口点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9885545/