这是我的示例 C 代码,用于从 user32.dll 中转储
MessageBoxA
:
#include <windows.h>
#include <stdio.h>
void DumpFun(HANDLE process, LPVOID address, SIZE_T dump_size) {
BYTE *buffer = (BYTE *)malloc(dump_size);
if (buffer == NULL) {
printf("Memory allocation failed\n");
return;
}
SIZE_T bytes_read;
if (ReadProcessMemory(process, address, buffer, dump_size, &bytes_read)) {
printf("Dumping function bytes at address 0x%p:\n", address);
for (SIZE_T i = 0; i < bytes_read; i++) {
printf("%02X ", buffer[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
printf("\n");
} else {
printf("ReadProcessMemory failed with error %lu\n", GetLastError());
}
free(buffer);
}
int main() {
HMODULE user32 = LoadLibraryA("user32.dll");
if (!user32) {
printf("Failed to load user32.dll\n");
return 1;
}
FARPROC fun = GetProcAddress(user32, "MessageBoxA");
if (!fun) {
printf("Failed to get address of MessageBoxA\n");
FreeLibrary(user32);
return 1;
}
SIZE_T dump_size = 100;
DumpFun(GetCurrentProcess(), fun, dump_size);
FreeLibrary(user32);
return 0;
}
这是输出:
Dumping function bytes at address 0x75C91600:
8B FF 55 8B EC 83 3D B4 6C CB 75 00 74 22 64 A1
18 00 00 00 BA FC 80 CB 75 8B 48 24 33 C0 F0 0F
B1 0A 85 C0 75 0A C7 05 20 6D CB 75 01 00 00 00
6A FF 6A 00 FF 75 14 FF 75 10 FF 75 0C FF 75 08
...
但是当我尝试使用此 python 代码时:
import ctypes
user32 = ctypes.WinDLL('user32.dll')
message_box_a = user32.MessageBoxA
message_box_a_addr = ctypes.cast(message_box_a, ctypes.c_void_p).value
print(f'Address of MessageBoxA: {hex(message_box_a_addr)}')
num_bytes = 100
buffer = (ctypes.c_ubyte * num_bytes)()
ctypes.memmove(buffer, message_box_a_addr, num_bytes)
byte_array = bytearray(buffer)
hex_bytes = ' '.join(f'{byte:02x}' for byte in byte_array)
print(f'Bytes of MessageBoxA: {hex_bytes}')
这是输出
Address of MessageBoxA: 0x7ffa2749a710
Bytes of MessageBoxA: 48 83 ec 38 45 33 db 44 39 1d 02 8c 03 00 74 2e 65 48 8b 04 25 30 00 00 00 4c 8b 50 48 33 c0 f0 4c 0f b1 15 78 97 03 00 4c 8b 15 79 97 03 00 41 8d 43 01 4c 0f 44 d0 4c 89 15 6a 97 03 00 83 4c 24 28 ff 66 44 89 5c 24 20 e8 e2 02 00 00 48 83 c4 38 c3 cc cc cc cc cc cc cc cc cc cc cc cc cc 48 83 ec 38
当我检查 user32.dll 时:
C 代码和 Python 代码都显示了
MessageBoxA
函数的内存转储,但它们之所以不同,是因为它们正在转储函数的不同方面:
-
C 代码转储的是函数的
开头
,更准确地说,是
GetProcAddress
返回的入口点。这个入口点通常包含一个短序言,后面是函数的实际代码。这就是在 C 代码输出中看到的序言:
8B FF 55 8B EC 83 3D ...
这些指令(
8B FF
、
55
、
8B EC
)是典型的函数序言,用于设置堆栈帧并保存寄存器。
- Python 代码转储的是函数指针的值 ,该值被视为内存地址。这个地址指向包含函数代码的内存位置,但它 不一定是代码的开头 *。它可能是代码中一个稍后的点,尤其是在现代编译器和加载器中,它们出于性能或安全原因,可能会对代码进行重定位和优化。
这就是为什么在 Python 输出中看到的是不同的字节序列,它不以典型的函数序言开头:
48 83 ec 38 45 33 db ...
这些字节是
MessageBoxA
函数机器代码的一部分,但不是最开始的部分。
总结
-
两种代码都显示了
MessageBoxA
函数的有效机器代码,但从不同的偏移量开始。 - C 代码的输出更接近于函数在反汇编视图中的显示方式,因为它从入口点开始。
- Python 代码的输出展示了函数代码在内存中的实际布局,这可能包括由于优化或重定位而导致的偏移。
为了使 Python 代码显示与 C 代码相同的初始字节,需要找到函数的实际入口点。这在一般情况下可能很困难,因为它需要解析 DLL 的结构和重定位表。
希望这能解释清楚!
标签:python,c,windows,winapi,dump From: 78821190