Search code examples
windowsassemblyx86masmmasm32

Strange behaviour with a simple MASM32 program


I want to write a MASM program similar to the following C++ program :

#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);
}

As you can see, this code execute the microsoft calculator. I just want to do the same thing using MASM but the execution fails.

Here's the MASM source code :

.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

The crt_printf output is correct. The same address is printed like withe the C++ program. So the address passed to call is the same one. However the execution fails.

Here's a MASM32 code which works but this time the address of the function WinExec is hardcoded like this :

.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

See the line mov esi, 779e304eh. But dynamically, there is a problem. If I disassemble the code just above we can see that the order of bytes is reversed.

8EEH047E379

Maybe it's not the case dynamically and maybe I need a keyword in the following line (between the comma and procAddr):

mov esi, procAddr

I cannot find the solution. I'm lost. Can anyone help me?

Thanks a lot in advance for your help.


Solution

  • The execution fails because you are not passing it's parameters.

    Here you just call the function without any arguments or rather with invalid arguments (because whatever is currently on the stack will be taken and the stack is corrupted in the process).

    mov esi, procAddr
    call esi
    

    You should do

    push SW_SHOWDEFAULT
    push offset YourPathToCalc
    mov esi, procAddr
    call esi
    

    In your samplecode this is what is done here implicitly

    xor eax, eax
    push eax      ; uCmdShow
    call _Suite   ; Returnadress is the address of the commandline so this is bascially the "push path"
    

    Another thing you are missing is, that when WinExec returns, it will start executing the path in your case so you need a jmp somewhere after the call.

    And as Gunner pointed out, the path must be 0 terminated.