I need to access the WinMain parameters using assembly, but I don't seem to be able to do so despite that I supposedly know where they are in the stack (DWORD offsets 0 to 16, and 0 to 20 when pushing EBP before operations). Below there's an example for showing the lpszCmdline string which contains the command line of the program, but it always seems to contain 0, so nothing is displayed. If I try to use other arguments in the assembly code, no valid string pointer seems to be present and/or the program crashes, as expected.
;[esp+20]==nCmdShow
;[esp+16]==lpszCmdLine
;[esp+12]==0 in win32
;[esp+8]==hInst
;[esp+4]==EIP
;[esp+0]==EBP
push ebp
mov ebp,esp
mov eax,[ebp+16]
push dword 0x00001030 ;UINT uType
push eax ;LPCTSTR lpCaption
push eax ;LPCTSTR lpText
push dword 0 ;HWND hWnd
call dword[MessageBoxA#USER32.DLL]
pop ebp
However, if I use GetCommandLine I can get a valid pointer to the command line string, and it displays.
call dword[GetCommandLineA#KERNEL32.DLL]
push dword 0x00001030 ;UINT uType
push eax ;LPCTSTR lpCaption
push eax ;LPCTSTR lpText
push dword 0 ;HWND hWnd
call dword[MessageBoxA#USER32.DLL]
Where's the error in the first code block? What do I need to get the parameters, and being able to implement my own code to return a valid pointer to lpszCmdLine just like GetCommandLine and as a result, to the other WinMain parameters? If I can't get the command line pointer from the stack, then I presumably won't be able to get the other parameters, like nCmdShow, for other important initializations.
Please let me know if you need more code than the provided above. If it is useful for you to know, I used no linker but fully manual EXE generation (does it make any difference in WinMain, like further stack parameters?), but basically it's just a program for which Windows automatically calls its entry point and the above would be the 2 different options of what program it would contain.
#include <Windows.h>
int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
__asm {
mov eax, [ebp+16]
push 0
push eax
push eax
push 0
call dword ptr ds:[MessageBoxA]
}
return ERROR_SUCCESS;
}
This runs just fine for me within Visual Studio. Oddly running it in a debugger and single stepping causes an access violation when the MessageBox is called. I'm unsure why this is, but running in debug without single stepping as well as running the final binary gives the expected result, ie. a messagebox with caption/message as the argument
Related
I've spend lot of time trying to solve this problem and I don't understand, why it doesn't work. Problem's description is in comments below:
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
.NOLIST
.NOCREF
INCLUDE \masm32\include\windows.inc
.LIST
.CODE
DllEntry PROC hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
mov eax, TRUE
ret
DllEntry ENDP
caesarAsm proc string: DWORD, key: DWORD, stringLength : DWORD
mov esi, 1 ; I cannot use this register, mov esi, (anything) causes Crash:
; Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention
mov eax, string
ret
caesarAsm endp
END DllEntry
I searched "whole" Internet, I found that the problem is connected with stack, but no operation on stacks helped me to solve it.
I'm using Microsoft Visual Studio 2012
I assume the error does not occur in this function, rather, it is triggered elsewhere. The esi register is a callee-saved register. You must make sure its value is the same at function exit as it was at entry. You can use it in your function, but you must save and restore its value. Such as:
push esi
mov esi, 1
mov eax, string
pop esi
ret
This is all well documented. You may only use eax, ecx and edx without saving.
Side note: you are using high-level features of your assembler, you might want to check the actual generated code or refrain from using them until you are confident in what the result is going to be. Incidentally masm has a USES keyword which would do the save/restore for you.
I am newbie in assembler. I need to change text color in loop (5 time - 5 different colors) using Masm32. My code:
Main PROC
LOCAL hStdout:DWORD
call SetConsoleTitleA
push -11
call GetStdHandle
mov hStdout,EAX
mov BX,5
lp:
push hStdout
push 2
call SetConsoleTextAttribute
push 0
push 0
push 24d
push offset sWriteText
push hStdout
call WriteConsoleA
dec BX
jnz lp
push 2000d
call Sleep
push 0
call ExitProcess
Main ENDP
end Main
P.S. Sorry for my Enlish.
Problem 1
As hinted to by Raymond Chen is that the call to SetConsoleTitle is incorrect.
Main PROC
LOCAL hStdout:DWORD
call SetConsoleTitleA
Notice that you don't push any arguments onto the stack for SetConsoleTitle. This means that after this call the stack is corrupted.
Once this is fixed we can move on to problem 2.
Problem #2
According to the __stdcall calling convention arguments are pushed right-to-left. But in the code the arguments are being pushed left-to-right. In the code above this is the call sequence for SetConsoleTextAttribute
push hStdout
push 2
call SetConsoleTextAttribute
Given the function's signature:
BOOL WINAPI SetConsoleTextAttribute(
_In_ HANDLE hConsoleOutput,
_In_ WORD wAttributes
);
The code is calling this function like the following C code,
SetConsoleTextAttribute(2, hStdout);
which is reversed. The call should be:
push 2
push hStdout
call SetConsoleTextAttribute
Problem 3
The code ignores all return values, except for GetStdHandle. For SetConsoleTextAttribute the return value is nonzero if the function was successful. If the function returns zero, then the function call failed, and for this function1 extended error information is available by calling GetLastError. The documentation on MSDN has information about each of the other functions and how they indicate errors.
1Not all functions call SetLastError when they fail. There are a lot of issues caused by thinking otherwise. Also of note that functions that do set the error, only do so when they have an error.
Also worth a read is The History Of Calling Conventions series over at The Old New Thing.
OK, I'm new to PC Assembler. I"m trying to write an program, but it won't stop looping. I'm guessing the ECX register is being modified? How can I fix this? Thanks.
DATA SECTION
;
KEEP DD 0 ;temporary place to keep things
;
CODE SECTION
;
START:
MOV ECX,12
TOPOFLOOP:
PUSH -11 ;STD_OUTPUT_HANDLE
CALL GetStdHandle ;get, in eax, handle to active screen buffer
PUSH 0,ADDR KEEP ;KEEP receives output from API
PUSH 5,'bruce' ;5=length of string
PUSH EAX ;handle to active screen buffer
CALL WriteFile
XOR EAX,EAX ;return eax=0 as preferred by Windows
LOOP TOPOFLOOP
ENDLABEL:
RET
In most x86 calling convention, including the stdcall convention used by Windows API functions, ECX is a caller-save register -- the called function is not required to make sure the value of the register is the same when it returns as when it was called. You have to save it somewhere safe in your own code.
I'm trying to call the following function:
long long RtlLargeIntegerDivide(long long dividend, long long divisor, long long* pRemainder)
in assembly code (NASM). It uses the stdcall calling convention, and it returns the quotient. These are the specifications:
Input: [EDX,EAX] (dividend), [ECX,EBX] (divisor)
Output: [EDX,EAX] (quotient), [ECX,EBX] (remainder)
How do I go about doing this? (My main problem is not exactly understanding EBP and ESP, and how they relate to local variables.)
(And no, this isn't homework; I'm trying to implement a wrapper C run-time library.)
Thank you!
In 32 bit mode you don't have to use EBP to access local variables at all, that is just a convention remnant from 16 bit times and doesn't concern us now anyway.
ESP is your stack pointer, I assume you know that. You can "allocate" space for your local variables by decrementing ESP.
stdcall calling convention uses the stack for argument passing. They are in normal order when on the stack, but if you are using PUSH that means you push them reversed. Integral return values are in EAX (and EDX when necessary). The called function cleans up the arguments from the stack.
So the following code should do what you want:
sub ESP, 8; make room for remainder
push ESP ; pass pointer to remainder as argument
push ECX
push EBX ; pass divisor argument
push EDX
push EAX ; pass dividend argument
call RtlLargeIntegerDivide
; quotient returned in EDX:EAX
; so just load remainder from stack
pop EBX
pop ECX
(For speed, you can use MOV instead of PUSH/POP)
Ive got an annoying problem, I cant append any text to the text file. Every time I open it for writing, I overwrite the data. I tried to move the file pointer to the end of the file, but no result (no writing to the file at all).
Here is the code:
INVOKE CreateFile, offset filePath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0
mov hFile, eax
mov edx, 10
INVOKE SetFilePointer, hFile, 0, 0, FILE_END
INVOKE WriteFile, hFile, offset buffer, edx, ADDR SizeReadWrite, NULL
INVOKE CloseHandle, hFile
Any ideas? Thank you in advance!
You're setting the value of edx before the call to SetFilePointer and using it after the call. However, Windows API functions use the stdcall calling convention which is not guaranteed to preserve the edx register, so the value in it is destroyed, and the call to WriteFile fails.