我想写一个类似于以下C ++程序的MASM程序:
#include <Windows.h>
#include <iostream>
typedef UINT (_stdcall *FuncPtr)(LPCSTR lpCmdLine, UINT uCmdShow);
int main(void)
{
HMODULE hDll = LoadLibrary(TEXT("Kernel32.dll"));
FuncPtr func_addr = reinterpret_cast<FuncPtr>(GetProcAddress(hDll, "WinExec"));
(*func_addr)("C:\\WINDOWS\\system32\\calc.exe", SW_SHOWDEFAULT);
FreeLibrary(hDll);
return (0);
}
如您所见,此代码执行microsoft计算器。我只是想使用MASM做同样的事情,但执行失败。
这是MASM源代码:
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\msvcrt.lib
.data
LpFileName db "kernel32.dll", 0
procName db "WinExec", 0
display db "addr_func = 0x%x", 0
.data?
hModule HMODULE ?
procAddr FARPROC ?
.code
start:
invoke LoadLibrary, offset LpFileName
mov hModule, eax
invoke GetProcAddress, hModule, ADDR procName
mov procAddr, eax
INVOKE crt_printf, ADDR display, procAddr
mov esi, procAddr
call esi
db "C:\WINDOWS\system32\calc.exe"
invoke FreeLibrary, hModule
invoke ExitProcess, NULL
end start
crt_printf
输出正确无误。与C ++程序一样打印相同的地址。因此传递给call
的地址是相同的。然而,执行失败。
这是一个有效的MASM32代码,但这次WinExec函数的地址硬编码如下:
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
.code
start:
jmp _Debut
_Final:
TCHAR 233
dword 42424242h
_Suite:
mov esi, 779e304eh
call esi
jmp _Final
_Debut:
xor eax, eax
push eax
call _Suite
db "C:\WINDOWS\system32\calc.exe"
end start
请参阅第mov esi, 779e304eh
行。但动态地,存在问题。如果我在上面反汇编代码,我们可以看到字节的顺序是相反的。
8EEH047E379
也许动态并非如此,也许我需要在以下行中使用关键字(在逗号和procAddr
之间):
mov esi, procAddr
我找不到解决方案。我迷路了。任何人都可以帮助我吗?
非常感谢您的帮助。
答案 0 :(得分:1)
执行失败,因为您没有传递它的参数。
这里你只需要调用没有任何参数的函数,或者使用无效的参数(因为当前堆栈中的任何内容都将被占用,并且堆栈在此过程中被破坏)。
mov esi, procAddr
call esi
你应该做
push SW_SHOWDEFAULT
push offset YourPathToCalc
mov esi, procAddr
call esi
在您的示例代码中,这是隐式执行的操作
xor eax, eax
push eax ; uCmdShow
call _Suite ; Returnadress is the address of the commandline so this is bascially the "push path"
您遗失的另一件事是,当WinExec
返回时,它将开始执行您的案例中的路径,因此您需要在调用后jmp somewhere
。
正如Gunner指出的那样,路径必须0终止。
答案 1 :(得分:1)
要添加Devolus发布的正确答案,您的calc路径不会以NULL结尾。 这个
"C:\WINDOWS\system32\calc.exe"
不正确!
相反它应该是:
"C:\WINDOWS\system32\calc.exe", 0
另外,如果你要在代码部分中使用字符串,你需要给它们一个标签以便使用它们,你需要跳过它们,否则CPU会尝试执行字节。
INVOKE crt_printf, ADDR display, procAddr
mov esi, procAddr
push SW_SHOWDEFAULT
push offset Calc
call esi
jmp @F
Calc db "C:\WINDOWS\system32\calc.exe", 0
@@:
invoke FreeLibrary, hModule
invoke ExitProcess, NULL
*编辑* 要使用MASM将该代码转换为Assembly,只需要:
.data
LpFileName db "kernel32", 0
procName db "WinExec", 0
Calc db "calc", 0
.code
start:
invoke LoadLibrary, offset LpFileName
push eax
invoke GetProcAddress, eax, ADDR procName
push SW_SHOWDEFAULT
push offset Calc
call eax
call FreeLibrary
invoke ExitProcess, NULL
end start