从 GCC 获取函数十六进制代码
Get function hex-codes from GCC
现在遇到问题了。我的项目在汇编级别工作。
所以我需要汇编级编程,但项目规模太大,无法仅在汇编级进行工作。由于这个问题,我决定从 gcc 制作的 c 源文件中获取十六进制代码。但是怎么办? 如何使用 gcc 获取某些函数的 HEXCODES?
我有个想法,
int function_name(){
int a=1;
return a;
}
write(fd, (char *)function_name, sizeof(function_name))
这样做之后我会得到 function_name 的十六进制代码。
但这不是解决这个问题的好方法,当我需要很多功能作为目标时,它会让我需要处理很多文件。
请问还有其他好的方法可以解决这个问题吗?我认为理想的解决方案只需要函数名(和输出文件名,如果需要)并在命令行上工作。我认为不可能的理想解决方案?
我还假设编译器的优化选项已关闭
所以我会从 function_name 得到 hexcodes 是 '\x55\x8B\xEC\x83\xEC\x04\xC7\x45\xFC\x01\x00\x00\x00\x8B\x45\xFC\x8B\xE5\x5D\xC3'
function_name的汇编代码如下
PUSH EBP
MOV EBP, ESP
SUB ESP, 4
MOV DWORD PTR[EBP-4], 1
MOV EAX, DWORD PTR[EBP-4]
MOV ESP, EBP
POP EBP
RETN
gcc 从每个源文件生成一个汇编文件作为编译工具链的一部分。该文件通常是临时的,因此会立即删除。如果要保存为myfile.s
,可以使用这个命令:
gcc -S -o myfile.s myfile.c
我猜你在 Linux,因为你正在使用 gcc
你可能 运行
gcc -Wall -O -c myfile.c
从源 C 文件 myfile.c
获取目标文件 myfile.o
;该目标文件在 ELF so contains notably binary code and relocation orders. You could parse that ELF object file (e.g. with commands like objdump(1) 或 readelf
中或通过某些库,如 libelf
或 libbfd
)
或者仅在具有 position independent code and use dlopen(3). See program library howto
的 ELF 共享对象上工作
请注意,并非每个源代码级 C 函数都对应于目标文件中的某个函数(例如 ELF 符号)(例如,由于 static
函数 - 它们的名称可能会被遗忘或 stripped, or because of inline
functions - they don't have their own machine code, it has been inlined in the caller). Assume an optimizing compiler (例如 gcc -O2
).
记住 decompilation is an impossible task in general. Be aware of the halting problem which is undecidable.
另请参阅 this question 以及有关 libopcode
的答案
顺便说一句,
write(fd, (char *)function_name, sizeof(function_name))
不会编译(你不能使用 sizeof
some 函数)。也许你会做
write(fd, (char*)function_name, sizeof(char*))
这将写入一些地址,这可能意义不大(请注意 ASLR)。
也许你想要dladdr(3)?您可能需要使用链接时传递的 -rdynamic
选项编译您的程序。
尝试
objdump -D -Mintel yourfile.o
转储看起来像(.O 由 free pascal 编译器生成,但 gcc 大致相同)
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 8d 64 24 ec lea esp,[esp-0x14]
7: 53 push ebx
8: 89 45 fc mov DWORD PTR [ebp-0x4],eax
b: c7 45 f4 00 00 00 00 mov DWORD PTR [ebp-0xc],0x0
12: 31 c0 xor eax,eax
14: 68 00 00 00 00 push 0x0
19: 55 push ebp
1a: 68 00 00 00 00 push 0x0
1f: 64 ff 30 push DWORD PTR fs:[eax]
22: 64 89 20 mov DWORD PTR fs:[eax],esp
25: c7 45 f8 00 00 00 00 mov DWORD PTR [ebp-0x8],0x0
2c: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
2f: 8b 50 04 mov edx,DWORD PTR [eax+0x4]
代码仍可重定位,因此引用将为零字节。
要解决这个问题,您需要 objdump 二进制文件 (.exe) 而不是 .o,但这样的输出通常很大,并且会使查找特定位置变得更加困难。
现在遇到问题了。我的项目在汇编级别工作。 所以我需要汇编级编程,但项目规模太大,无法仅在汇编级进行工作。由于这个问题,我决定从 gcc 制作的 c 源文件中获取十六进制代码。但是怎么办? 如何使用 gcc 获取某些函数的 HEXCODES?
我有个想法,
int function_name(){
int a=1;
return a;
}
write(fd, (char *)function_name, sizeof(function_name))
这样做之后我会得到 function_name 的十六进制代码。 但这不是解决这个问题的好方法,当我需要很多功能作为目标时,它会让我需要处理很多文件。
请问还有其他好的方法可以解决这个问题吗?我认为理想的解决方案只需要函数名(和输出文件名,如果需要)并在命令行上工作。我认为不可能的理想解决方案?
我还假设编译器的优化选项已关闭 所以我会从 function_name 得到 hexcodes 是 '\x55\x8B\xEC\x83\xEC\x04\xC7\x45\xFC\x01\x00\x00\x00\x8B\x45\xFC\x8B\xE5\x5D\xC3' function_name的汇编代码如下
PUSH EBP
MOV EBP, ESP
SUB ESP, 4
MOV DWORD PTR[EBP-4], 1
MOV EAX, DWORD PTR[EBP-4]
MOV ESP, EBP
POP EBP
RETN
gcc 从每个源文件生成一个汇编文件作为编译工具链的一部分。该文件通常是临时的,因此会立即删除。如果要保存为myfile.s
,可以使用这个命令:
gcc -S -o myfile.s myfile.c
我猜你在 Linux,因为你正在使用 gcc
你可能 运行
gcc -Wall -O -c myfile.c
从源 C 文件 myfile.c
获取目标文件 myfile.o
;该目标文件在 ELF so contains notably binary code and relocation orders. You could parse that ELF object file (e.g. with commands like objdump(1) 或 readelf
中或通过某些库,如 libelf
或 libbfd
)
或者仅在具有 position independent code and use dlopen(3). See program library howto
的 ELF 共享对象上工作请注意,并非每个源代码级 C 函数都对应于目标文件中的某个函数(例如 ELF 符号)(例如,由于 static
函数 - 它们的名称可能会被遗忘或 stripped, or because of inline
functions - they don't have their own machine code, it has been inlined in the caller). Assume an optimizing compiler (例如 gcc -O2
).
记住 decompilation is an impossible task in general. Be aware of the halting problem which is undecidable.
另请参阅 this question 以及有关 libopcode
顺便说一句,
write(fd, (char *)function_name, sizeof(function_name))
不会编译(你不能使用 sizeof
some 函数)。也许你会做
write(fd, (char*)function_name, sizeof(char*))
这将写入一些地址,这可能意义不大(请注意 ASLR)。
也许你想要dladdr(3)?您可能需要使用链接时传递的 -rdynamic
选项编译您的程序。
尝试
objdump -D -Mintel yourfile.o
转储看起来像(.O 由 free pascal 编译器生成,但 gcc 大致相同)
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 8d 64 24 ec lea esp,[esp-0x14]
7: 53 push ebx
8: 89 45 fc mov DWORD PTR [ebp-0x4],eax
b: c7 45 f4 00 00 00 00 mov DWORD PTR [ebp-0xc],0x0
12: 31 c0 xor eax,eax
14: 68 00 00 00 00 push 0x0
19: 55 push ebp
1a: 68 00 00 00 00 push 0x0
1f: 64 ff 30 push DWORD PTR fs:[eax]
22: 64 89 20 mov DWORD PTR fs:[eax],esp
25: c7 45 f8 00 00 00 00 mov DWORD PTR [ebp-0x8],0x0
2c: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
2f: 8b 50 04 mov edx,DWORD PTR [eax+0x4]
代码仍可重定位,因此引用将为零字节。
要解决这个问题,您需要 objdump 二进制文件 (.exe) 而不是 .o,但这样的输出通常很大,并且会使查找特定位置变得更加困难。