我正在玩Win32程序集。
我一直在努力处理汇编中的WinMain入口点一段时间了。对我而言,有一个奇怪的 - NASM和...之间的区别。 link.exe是由我手写的asm和MSVC提出的。
1)C(++)代码 - 只是另一个MessageBox hello world
#include <Windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MessageBoxA(NULL, "Hello world", "Window title", MB_OK | MB_ICONEXCLAMATION);
}
2)装配等效
global _main
extern _MessageBoxA@16
extern _ExitProcess@4
section .text
_main:
push 0x30
push wintitle
push message
push 0
call _MessageBoxA@16
push 0
call _ExitProcess@4
section .data
message:
db 'Hello, World', 0
wintitle:
db 'Window title', 0
技术“规范”:
- 操作系统是32位Win7
- C ++程序已使用MS VC ++ 2013编译
- 汇编程序已使用nasm -fwin32 msgbox.asm
编译,然后与link /nodefaultlib /subsystem:windows msgbox.obj kernel32.lib user32.lib -entry:main
现在来了实际问题。
当我用OllyDbg 2.01拆解它们时,这就是我所看到的:
1)C ++版本
2)ASM版本:
现在,如果我们看一下堆栈窗口,看起来好像Windows实际上没有将正确的参数传递给我的汇编入口点。返回到ntdll之前只有两个垃圾整数,而不是C ++版本,其中存在所有四个参数。
这对我来说是一个问题,因为我想在(在另一个汇编程序中)获取入口点内的hInstance变量。使用[EBP+8]
给了我上面提到的垃圾而不是正确的hInstance值。
非常感谢任何帮助。
答案 0 :(得分:6)
C ++代码中的WinMain
入口点由C运行时库调用,而不是由Windows调用。
实际的Win32入口点签名是
void __stdcall NoCRTMain(void);
您可以使用GetCommandLine
获取命令行,如果需要将其转换为argc / argv格式,可以使用CommandLineToArgvW
。
您可以通过将参数设置为hInstance
来调用GetModuleHandle
来获取NULL
。 (请注意,在Win32中,与16位Windows不同,HINSTANCE
和HMODULE
是相同的。)
答案 1 :(得分:4)
这四个参数由运行时提供,而不是由操作系统提供。如果您将查看入口点上的[esp]
值,则程序集版本将返回到kernel32
,即操作系统,而C ++版本将返回到模块的运行时代码。
在真正的入口点打开带有OllyDbg的C ++版本,你会看到许多初始化代码,比如参数解析,TLS变量等。另外,比较二进制文件的大小,你会看到4 kb vs大约30-90 kb。