【问题标题】:Use ptrace to obtain machine instructions使用 ptrace 获取机器指令
【发布时间】:2012-03-05 13:14:32
【问题描述】:

我编写了一个简单的程序来使用 ptrace 获取进程的指令。你可以在这里找到代码

http://pastebin.com/yHbkc0Je

我在 Ubuntu 64 位下编译并运行它。

我得到的是这样的:

EIP: 7f7e5edf5c75 Instruction executed: 8824848948f0394c
EIP: 7f7e5edf5c78 Instruction executed: 8824848948
EIP: 7f7e5edf5c80 Instruction executed: 84f6000000da840f
EIP: 7f7e5edf5c86 Instruction executed: 2000000b42484f6
...
...
EIP: 400dab Instruction executed: e8c78948ef458d48
EIP: 400daf Instruction executed: fffffe29e8c78948
EIP: 400db2 Instruction executed: 458d48fffffe29e8
EIP: 400be0 Instruction executed: d680020148225ff
...
...
EIP: 7f7e5ee012f0 Instruction executed: 2404894838ec8348
EIP: 7f7e5ee012f4 Instruction executed: 244c894824048948
...
...

我用gdb的时候只能看到EIP下的那些指令:400dab... 7f下的找不到...所以我猜是错...

(gdb) x/20xg 0x0000000000400dab
0x400dab <main+135>:    0xe8c78948ef458d48  0xee458d48fffffe29
0x400dbb <main+151>:    0xfffffe4de8c78948  0x10c0834880458b48
0x400dcb <main+167>:    0x48ee558d48088b48  0x8948ce8948c0458d

谁能解释为什么我的代码是错误的以及如何只打印正确的 EIP 和指令?

【问题讨论】:

    标签: c linux ubuntu 64-bit ptrace


    【解决方案1】:

    抱歉,我懒得实际测试您的代码,但您的实验对我来说似乎很有趣。

    在我的 Debian x86_64 上,我执行了cat /proc/self/maps 以获得以下结果:

    $ cat /proc/self/maps
    00400000-0040c000 r-xp 00000000 08:06 786437                             /bin/cat
    0060c000-0060d000 rw-p 0000c000 08:06 786437                             /bin/cat
    0121a000-0123b000 rw-p 00000000 00:00 0                                  [heap]
    7f3fb1886000-7f3fb1aeb000 r--p 00000000 08:06 274045                     /usr/lib/locale/locale-archive
    7f3fb1aeb000-7f3fb1c68000 r-xp 00000000 08:06 136221                     /lib/x86_64-linux-gnu/libc-2.13.so
    7f3fb1c68000-7f3fb1e68000 ---p 0017d000 08:06 136221                     /lib/x86_64-linux-gnu/libc-2.13.so
    7f3fb1e68000-7f3fb1e6c000 r--p 0017d000 08:06 136221                     /lib/x86_64-linux-gnu/libc-2.13.so
    7f3fb1e6c000-7f3fb1e6d000 rw-p 00181000 08:06 136221                     /lib/x86_64-linux-gnu/libc-2.13.so
    7f3fb1e6d000-7f3fb1e72000 rw-p 00000000 00:00 0
    7f3fb1e72000-7f3fb1e91000 r-xp 00000000 08:06 141623                     /lib/x86_64-linux-gnu/ld-2.13.so
    7f3fb206c000-7f3fb206f000 rw-p 00000000 00:00 0
    7f3fb208f000-7f3fb2091000 rw-p 00000000 00:00 0
    7f3fb2091000-7f3fb2092000 r--p 0001f000 08:06 141623                     /lib/x86_64-linux-gnu/ld-2.13.so
    7f3fb2092000-7f3fb2093000 rw-p 00020000 08:06 141623                     /lib/x86_64-linux-gnu/ld-2.13.so
    7f3fb2093000-7f3fb2094000 rw-p 00000000 00:00 0
    7ffff2e77000-7ffff2e98000 rw-p 00000000 00:00 0                          [stack]
    7ffff2fff000-7ffff3000000 r-xp 00000000 00:00 0                          [vdso]
    ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
    

    所以我想7f... 用于 libc 或 ld-linux.so,您的输出完全有效。也试试

    $ gdb ./a.out -ex start
    (gdb) disp/4i $pc
    (gdb) nexti
    (gdb) (hit enter to repeat nexti ...)
    

    【讨论】:

    • 哦,我明白了,谢谢 nodakai,有没有办法忽略其他库中的所有这些指令,只获取程序本身的指令?像...跨过而不是踏入..
    • 不幸的是,我想不出简单的解决方案...在程序的开头,您可以解析 /proc/self/maps 以获取程序的 .text 段的地址范围(包含 argv 的行[0] 和 "r-xp" == "只读和可执行")
    【解决方案2】:

    您获得的以 7f 开头的地址的输出是针对 libc 和其他系统库的。 你可以做的是运行以下命令 -

    objdump -d -j.text <your program> | less
    

    这将为您提供整个 objdump。从这里您会看到,在您的代码开始或结束之前,会出现很多序言。因此,您会看到所有这些 7f 指令。

    要回答您的第二个问题,如果您只想从代码中获取指令,您可以解析 /proc//maps 文件并获取代码所在的范围。这可以通过检查 x 标志来获得 -

    08048000-08049000 **r-xp** 00000000 fd:5f 33931270                           /fs_user/samirba/myPer/test2
    08049000-0804a000 rw-p 00000000 fd:5f 33931270                           /fs_user/samirba/myPer/test2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-10
      • 2019-10-02
      • 1970-01-01
      • 1970-01-01
      • 2012-05-07
      • 2011-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多