我已经开始学习NASM汇编程序&回覆。我得到的第一个问题是下一个问题(简称):
我无法使用 objconv
实用程序恢复已反编译的程序。
我的简单应用:
#include <stdio.h>
char* msg = "Hello World!";
int main(void) {
printf("%s\r\n", msg);
return 0;
}
1)。我做的第一步是:
gcc -fno-asynchronous-unwind-tables -s -c -o 1.o 1.c
标志:fno-asynchronous-unwind-tables
用于在输出对象文件中生成不必要的部分。
2)。然后,我以这种方式使用了objconv
实用程序:
objconv -fnasm 1.o
为NASM
汇编程序生成汇编代码,我得到了下一个:
; Disassembly of file: 1.o
; Sun Aug 27 23:56:53 2017
; Mode: 64 bits
; Syntax: YASM/NASM
; Instruction set: 8086, x64
default rel
global main: function
global msg
extern printf ; near
SECTION .text align=1 execute ; section number 1, code
main: ; Function begin
push rbp ; 0000 _ 55
mov rbp, rsp ; 0001 _ 48: 89. E5
mov rax, qword [rel msg] ; 0004 _ 48: 8B. 05, 00000000(rel)
mov rsi, rax ; 000B _ 48: 89. C6
mov edi, ?_001 ; 000E _ BF, 00000000(d)
mov eax, 0 ; 0013 _ B8, 00000000
call printf ; 0018 _ E8, 00000000(rel)
mov eax, 0 ; 001D _ B8, 00000000
pop rbp ; 0022 _ 5D
ret ; 0023 _ C3
; main End of function
SECTION .data align=8 noexecute ; section number 2, data
msg: ; qword
dq Unnamed_4_0 ; 0000 _ 0000000000000000 (d)
SECTION .bss align=1 noexecute ; section number 3, bss
SECTION .rodata align=1 noexecute ; section number 4, const
db 48H, 65H, 6CH, 6CH, 6FH, 20H, 57H, 6FH ; 0000 _ Hello Wo
db 72H, 6CH, 64H, 21H, 00H ; 0008 _ rld!.
?_001: ; byte
db 25H, 73H, 0DH, 0AH, 00H ; 000D _ %s...
3)。下一步是:
删除不必要的部分,例如:
.SECTION
行的 align = N 和执行/不执行字样: function
default rel
行修复msg: dq Unnamed_4_0
。我曾经想过,使用objconv
之后,这部分会受到损害/破坏。
所以,我改变了:
dq Unnamed_4_0
致:
db "Hello World",10
尽管有这个部分:.rodata
(我正在思考,我的问题恰恰与输出字符串的错误使用有关...)。
4)。然后我在shell中使用了下一个命令:
nasm -f elf64 1.asm
gcc 1.o
当我在gcc之后启动a.out
文件时,我收到了下一个错误:
user@:~/Desktop/tmp$ ./a.out
Segmentation fault (core dumped)
这是我无法从反汇编程序中恢复原始行为的方法。原始程序是通过以下方式编制的:
gcc -std=c99 -o 1 1.c
它的源代码发布在我的问题的开头。我想要实现的目标很简单:使用objconv -> nasm
方法构建可执行文件,该方法充当原始可执行文件。
答案 0 :(得分:1)
您编写了char* msg = "Hello World!";
,因此您有一个指向存储在读/写.data
部分中的字符串文字的指针。这是dq Unnamed_4_0
。
如果您已撰写char msg[] = "Hello World!";
,则msg
处的字节将为文字字符串,而main
会将printf
的指针传递给mov edi, msg
(即mov r32,imm32
)。
您更改了asm,因此msg:
处的字节是字符串数据而不是指针。但是您的main
仍将msg
中存储的前8个字节作为指针(作为printf
arg)传递给const char *fmt
。
当printf
尝试取消引用这些ASCII字节作为指向格式字符串的指针时,会发生段错误。 (请记住,在C中,字符串是通过引用传递的。)
顺便说一下,我建议至少使用gcc -Og
或-O1
进行编译。在每个C语句之后没有将所有内容存储/重新加载到堆栈中时(通过调试器更改任何变量),读取asm将会容易得多。有关更多提示,另请参阅How to remove "noise" from GCC/clang assembly output?。