ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 GDB 反汇编内存范围?

我正在尝试反汇编程序以查看系统调用汇编指令(我相信是 INT 指令)和带有 GDB 的处理程序,并为其编写了一个小程序(见下文)来打开和关闭文件。

我能够使用 GDB 跟踪 fopen 的调用,直到它执行调用。

当我试图告诉 GDB“反汇编 0x....”(调用地址)时,它以“没有函数包含指定地址”作为响应。

是否可以强制 GDB 反汇编(或在汇编程序中尽可能好地显示)该内存地址?如果是这样,怎么做?

#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE* f;
    f = fopen("main.c", "r");
    if (!f) { 
      perror("open");
      return -1;
    }
    fclose(f);
    return 0;
}
fopen() 不是系统调用,它是对 C 标准库的调用。为什么你认为必须通过 INT 指令进行系统调用?
我可能错了,但是我们被告知 fopen 调用最终会导致系统调用内核来打开文件并返回文件描述符?
帕特里克:是的,但不需要直接这样做。通常它调用 libc 函数,然后进入内核。但是调用内核不仅可以使用 int (这很慢),而且可以使用 syscall/sysenter 来完成,具体取决于处理器架构......
kexik - 感谢您提供的信息。我看到 Wikipedia 在其系统调用文章 (en.wikipedia.org/w/…) 中提到了这一点。显然 Linux 开始使用 2.5 内核中的特殊调用。另一件事是了解我的操作系统架构。

M
Michael Snyder

是的,反汇编不是在这里使用的最佳命令。您想要的命令是“x/i”(按说明检查):

(gdb) x/i 0xdeadbeef

谢谢!添加此文本以帮助其他人找到此提示:这是用于反汇编二进制 blob、反汇编 ROM、检查二进制映像文件中的指令等的指令。编写一个小 C 程序以将二进制 blob fread() 放入缓冲区。然后在缓冲区上执行“x /i”。
@user188012 如果要反汇编二进制 blob,更简单的方法是使用独立的反汇编程序,例如 ndisasm 或类似的。
您可以使用: x/i $pc 来获取 pc 的指令,即当前指令的地址
您可以使用:"(gdb) x/i 0xaddress" 打印 个指令 ex "(gdb) x/10i 0xaddress" 打印 10 条指令
地址 0xdeadbeef 在这里有什么意义吗?我的意思是问它有什么特殊的地址吗?
t
timrau

你只想拆卸你的实际主机吗?如果是这样试试这个:

(gdb) info line main 
(gdb) disas STARTADDRESS ENDADDRESS

像这样:

USER@MACHINE /cygdrive/c/prog/dsa
$ gcc-3.exe -g main.c

USER@MACHINE /cygdrive/c/prog/dsa
$ gdb a.exe
GNU gdb 6.8.0.20080328-cvs (cygwin-special)
...
(gdb) info line main
Line 3 of "main.c" starts at address 0x401050 <main> and ends at 0x401075 <main+
(gdb) disas 0x401050 0x401075
Dump of assembler code from 0x401050 to 0x401075:
0x00401050 <main+0>:    push   %ebp
0x00401051 <main+1>:    mov    %esp,%ebp
0x00401053 <main+3>:    sub    $0x18,%esp
0x00401056 <main+6>:    and    $0xfffffff0,%esp
0x00401059 <main+9>:    mov    $0x0,%eax
0x0040105e <main+14>:   add    $0xf,%eax
0x00401061 <main+17>:   add    $0xf,%eax
0x00401064 <main+20>:   shr    $0x4,%eax
0x00401067 <main+23>:   shl    $0x4,%eax
0x0040106a <main+26>:   mov    %eax,-0xc(%ebp)
0x0040106d <main+29>:   mov    -0xc(%ebp),%eax
0x00401070 <main+32>:   call   0x4010c4 <_alloca>
End of assembler dump.

但是,我没有看到您的系统中断调用。 (自从我上次尝试在汇编中进行系统调用以来已经有一段时间了。不过,INT 21h,最后我记得


好的,那我以后会尝试寻找INT 21h。谢谢你的提示。但是我想尝试的是遵循源自 fopen() 的调用序列(在您的代码中看不到它......)“向下”,直到我可以看到 INT 命令。
管理它-要走的路是同时使用您的答案和Falaina的答案。我必须使用 gcc --static main.c 对其进行静态编译,然后使用 gdb/objdump 深入到 C 库中。最终,它导致了对 __open_nocancel 的调用,该调用执行了 INT 0x80。感谢你们俩
注意:至少在 gdb 7.7 版本中的 disas 0x401050 0x401075 语法不起作用。你宁愿把它写成 disas 0x401050,0x401075。您可能还想添加前缀 «/m» 以显示源代码:disas \m 0x401050,0x401075
@Patrick,虽然这是很久以前的事了,但值得注意的是 INT 0x80 正是 Linux 的做法。也就是说,Linux 的 syscall 处理程序在中断 128 处注册。其他操作系统可能会有所不同——它们确实如此。
N
Nubok

这不是您问题的直接答案,但由于您似乎只想反汇编二进制文件,也许您可以使用 objdump

objdump -d program

这应该给你它的反汇编。如果您希望它带有源注释,您可以添加 -S


⁺¹ 对于 -S,我不知道它可以包含源代码。
佚名

您可以通过添加 -S 开关强制 gcc 直接输出到汇编代码

gcc -S hello.c

J
Joel

fopen() 是一个 C 库函数,因此您不会在代码中看到任何系统调用指令,只是一个常规函数调用。在某些时候,它确实调用了 open(2),但它是通过蹦床来实现的。只需跳转到 VDSO 页面,该页面由内核提供给每个进程。 VDSO 然后提供代码来进行系统调用。在现代处理器上,将使用 SYSCALL 或 SYSENTER 指令,但您也可以在 x86 处理器上使用 INT 80h。


A
Al.

如果您只想通过 INTC 调用查看反汇编,请使用 objdump -d 就像有人提到的那样,但在编译时使用 -static 选项。否则 fopen 函数不会编译到 elf 中,而是在运行时链接。


L
Lakshman Kumar

gdb disassemble 有一个 /m 以在说明旁边包含源代码。这等效于 objdump -S,额外的好处是仅限于一个感兴趣的函数(或地址范围)。


M
Milhous

您不必使用 gdb。海合会会这样做。

 gcc -S foo.c

这将创建作为程序集的 foo.s。

gcc -m32 -c -g -Wa,-a,-ad foo.c > foo.lst

上述版本将创建一个包含 C 和由它生成的程序集的列表文件。 GCC FAQ


Y
YU Chen Shih

将内存范围反汇编为 C 的完整示例

/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb

(gdb)file /root/ncs/zephyr/samples/hello_world/build_nrf9160dk_nrf9160ns/zephyr/zephyr.elf
(gdb) directory /root/ncs/zephyr/samples/hello_world/src
#here you want 1
(gdb) info line* 0x000328C0
#here you want 2, -0x04 ~ +0x04 is your range size
(gdb) disassemble /m 0x000328C0-0x04, 0x000328C0+0x04
#here with binary code
(gdb) disassemble /r 0x000328C0-0x04, 0x000328C0+0x04
(gdb) info thread
(gdb) interpreter-exec mi -thread-info