使用简单的MASM32程序的奇怪行为

时间:2013-11-28 17:09:03

标签: windows assembly x86 masm masm32

我想写一个类似于以下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

我找不到解决方案。我迷路了。任何人都可以帮助我吗?

非常感谢您的帮助。

2 个答案:

答案 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