windows assembly x86 weird Function Issue [duplicate] - windows

This question already has answers here:
What if there is no return statement in a CALLed block of code in assembly programs
(2 answers)
Why is no value returned if a function does not explicity use 'ret'
(2 answers)
Closed 10 days ago.
I am creating a simple function that prints a character to the screen
STD_OUTPUT_HANDLE equ -11
NULL equ 0
global Start
extern ExitProcess, GetStdHandle, WriteConsoleA
section .bss
msg resb 1
section .text
Start:
push 'b'
call Print
Print:
; Function Start
push ebp
mov ebp,esp
; accepting the argument
mov ebx , [esp + 8]
mov [msg],ebx
; eax = handle
push STD_OUTPUT_HANDLE
call GetStdHandle
; WriteConsoleA System call
push NULL
push 1
push msg
push eax
call WriteConsoleA
; Funcion end
mov esp, ebp
pop ebp
ret
When I remove the ret instruction the output is as expected is b but when I add it back the output changes to b., what's Happening ????
I am using the Nasm Assembler and the golink link

Related

Hello world in NASM with LINK.EXE and WinAPI

I'm trying to get a simple Hello world program in NASM to run.
I want to print to the console without using C-Libraries, interfacing directly with WinAPI.
I am using the Visual Studio provided LINK.EXE for linking.
Here's my code so far:
section .data
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen: db $-message ; Length of the 'Hello world!' string
global _start
extern GetStdHandle
extern WriteConsoleW
extern ExitProcess
section .text
_start:
; DWORD bytes;
mov rbp, rsp
sub rsp, byte 8
; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
mov ecx, -11
call GetStdHandle
; WriteFile(hstdOut, message, length(message), &bytes, 0);
mov rcx, rax
mov rdx, message
mov r8, messageLen
lea r9, [rsp-4]
push 0
call WriteConsoleW
; ExitProcess(0)
mov rcx, 0
call ExitProcess
ret
Which I assemble and link like this:
nasm -f win64 .\ASM.ASM
link /entry:_start /nodefaultlib /subsystem:console .\ASM.obj "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64\kernel32.lib" "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64\user32.lib"
However when I run the resulting .exe file, I get nothing.
Some things I tried so far are
Using the decorated names (like _GetStdHandle#4), which resulted in the linker complaining about unresolved references
Not trying to print anything and calling Sleep, which resulted in the process sleeping indefinitely
Exiting with a different return code, which once again did nothing
What am I doing wrong?
EDIT: Fixed calling convention
There are three problems with your revised code. The first is:
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen: db $-message ; Length of the 'Hello world!' string
You defined messageLen to be a byte containing the length of the message and storing that value at the address of messageLen. You then do this:
mov r8, messageLen
That would move the address of label messageLen to r8. What you really should have done is define messageLen as an assembly time constant like this:
messageLen equ $-message ; Length of the 'Hello world!' string
The second problem is that you define the the string as a sequence of single byte characters:
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
There is nothing wrong with this, but to print them out you need to use the Ansi version of the function WriteConsole which is WriteConsoleA. Using WriteConsoleW printed the string as Unicode (UTF-16 on Windows 2000 and later, UTS-2 on NT4 and earlier versions of Windows).
The third problem is with regards to a mandatory 32 bytes of shadow space before the stack based parameter(s) are placed on the stack before making a function call. You also need to make sure the stack (RSP) is a 16-byte aligned value at the point of making a function call. These requirement can be found in the Microsoft 64-bit calling convention.
Code that would take this into account would look like this:
section .data
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen equ $-message ; Length of the 'Hello world!' string
global _start
extern GetStdHandle
extern WriteConsoleA
extern ExitProcess
section .text
_start:
; At _start the stack is 8 bytes misaligned because there is a return
; address to the MSVCRT runtime library on the stack.
; 8 bytes of temporary storage for `bytes`.
; allocate 32 bytes of stack for shadow space.
; 8 bytes for the 5th parameter of WriteConsole.
; An additional 8 bytes for padding to make RSP 16 byte aligned.
sub rsp, 8+8+8+32
; At this point RSP is aligned on a 16 byte boundary and all necessary
; space has been allocated.
; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
mov ecx, -11
call GetStdHandle
; WriteFile(hstdOut, message, length(message), &bytes, 0);
mov rcx, rax
mov rdx, message
mov r8, messageLen
lea r9, [rsp-16] ; Address for `bytes`
; RSP-17 through RSP-48 are the 32 bytes of shadow space
mov qword [rsp-56], 0 ; First stack parameter of WriteConsoleA function
call WriteConsoleA
; ExitProcess(0)
; mov rcx, 0
; call ExitProcess
; alternatively you can exit by setting RAX to 0
; and doing a ret
add rsp, 8+8+32+8 ; Restore the stack pointer.
xor eax, eax ; RAX = return value = 0
ret

Printing a parameter to the console

I am trying to print a character received as a parameter by a function.
My function is declared as follows:
STD_OUTPUT_HANDLE equ -11
NULL equ 0
global _print
extern _ExitProcess#4, _GetStdHandle#4, _WriteConsoleA#20
section .data
msg db 'a', 13, 10, 0
msg.len equ $ - msg
section .bss
dummy resd 1
section .text
_print:
;Prologue
push ebp
mov ebp, esp
mov edx, [ebp + 4]
push STD_OUTPUT_HANDLE
call _GetStdHandle#4
push NULL
push dummy
push 1
push edx
push eax
call _WriteConsoleA#20
;Epilogue
mov esp, ebp
pop ebp
push NULL
call _ExitProcess#4
And my calling function is declared as follows:
global _main
extern _print
section .data
msg db 'c', 13, 10, 0
msg.len equ $ - msg
section .text
_main:
;Prologue
push ebp
mov ebp, esp
push msg
call _print
;Epilogue
mov esp, ebp
pop ebp
I am expecting 'c' as output in my console, but this is not working. The method printing the message works when I pass the variable msg (the one defined as 'a'), to WriteConsole. So I am guessing the problem is in passing the parameter or reading it from the stack.
I am using Nasm to compile, gcc to link & compiling with intel syntax on a windows platform (32bit).
I use these commands to compile and link
nasm -fwin32 tiny.asm
nasm -fwin32 tiny_print_char.asm
gcc tiny_print_char.obj tiny.obj -m32 --enable-stdcall-fixup -nostdlib c:\windows\system32\kernel32.dll -lkernel32
Can anyone help me?

Creating variables inside main's frame (Linux)

[SOLVED]
I'm trying to do my own assembly code to do what similar C code will do:
main()
{
scanf("%d",&integer_var); // here must be the address of the integer_var
printf("Your Value is:%d",integer_var);
}
Well this is in C, so I'm doing with NASM under linux with extern functions. scanf and printf and compile first with nasm and then with gcc.
Here's my code (is not right :D)
SECTION .text
argstr: db "%d",10,0
str: db "Your value is:%d",10,0
extern printf
extern scanf
SECTION .data
global main
main:
push ebp
mov esp,ebp
sub esp, 0x10 ;ok integer right?
mov [ebp-0x4],0x0 ;just put 0 number on our integer variable
mov eax,(ebp-0x4) ;here i don't know how to push the address of ebp-0x4
push ecx ;first push is last argument so here's our address to scanf
push argstr ;just the string format
call scanf ;call that to input something
;I have no idea how to do this
;but if i don't do this i get an error
;because the scanf won't clear the arguments on stack
;and what scanf can't return
pop edx ;maybe help here? but it works fine
pop edx
push [-0x4(ebp)] ;i want the value of our var :D
push str
call printf
pop edx ;clear the stack to avoid "segment fault" or something similar
pop edx
mov esp,ebp
pop ebp
ret ;the end :(
Compiler error:
a.asm:18: error: invalid operand type
a.asm:28: error: parser: expecting ]
Another thing: Do I need to align the stack on this case, by the way?
thanks guys ! :)
EDIT solved whole program!
well at least, I can print the variable with printf. scanf i will do later and then I will share here the last result:
SECTION .text
str: db "Value is:%d",10,0
extern printf
SECTION .data
global main
main:
push ebp ;the main function starts here.
mov ebp,esp
;
sub esp,4 ;we need 4bytes of space for the integer
and esp,0xfffffff0 ;align the stack
mov [esp-4], dword 0xff ;move the value 0xff to our var
mov eax,[esp-4] ;move our variable value to the eax
push eax ;second argument of printf
push str ;first argument of printf
call printf ;printf
;
add esp,16 ;this add to the stack pointer what we pushed basicly
mov ebp,esp ;if we don't do add 16 to esp it shows us
pop ebp ;a segment fault cuz ret doesnt pop saved ebp
ret ;of who whatever called this program :)
To load the address EBP-4 into EAX, use lea eax, [ebp-4]. (this is NOT the same as pushing the address.)
In order to push the value at memory location EBP-4, push dword [ebp-4] should work.
Then you need to specify operand size for one of your movs, too: mov [ebp-4], dword 0x0.
These will fix your current assembler errors, and make your program compile, but there are a few other errors in there that will probably prevent it from running.
Here's a working attempt that is close to yours:
;note the sections, the string literals are better in .rodata
;all code goes in .text
SECTION .rodata
;no newline after scanf string
argstr: db "%d",0
str: db "Your value is: %d",10,0
SECTION .text
extern printf
extern scanf
global main
main:
push ebp
mov ebp,esp ;move esp to ebp, NOT other way round!
sub esp, 4 ;4 bytes are enough for the local variable
;there are NO alignment requirements for this program
lea eax,[ebp-4]
push eax
push dword argstr
call scanf
add esp, 8 ;since we don't actually need the popped values
;we can increment esp instead of two pop edx
push dword [ebp-4]
push dword str
call printf
add esp, 8
mov esp,ebp
pop ebp
ret

Push an argument into stack?

I know that the first four arguments are in the register (RCX, RDX, R8, R9), and that additional arguments are pushed on the stack.
Question:
How to push an argument onto the stack? I tried with (push 0) but it does not work?
Code (MASM64)
extrn ExitProcess: PROC
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp, 38h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
push 0 ; wLanguageId
call MessageBoxExA
mov ecx, eax
add rsp, 38h
call ExitProcess
Start ENDP
End
I'm know that MessageBox and MessageBoxEx work the same way, but im trying to use MessageBoxEx because its need one parameter to be passed (for learning purpose).
I know I've asked similar question, but it is more related to vb.net while this is not.
My assembly is a little rusty, but I was under the impression that all arguments went onto the stack (in reverse order) - I'd have thought you want to be pushing r8 and rdx in as well as the other arguments. Frankly though you might as well just keep doing lea rax, param and push rax for each of the arguments that are pointers.
The order in which the arguments are passed and whether they are passed in registers or on the stack (along with whether caller or callee is responsible for cleanup) is defined by the 'Calling Convention'.
What you are probably thinking of is STDCALL or CDECL, both are calling conventions used in 32-bit Windows that pass arguments on the stack in reverse order (right to left). x64 has moved to a FastCall calling convention where the arguments are passed in forward order (from left to right) and the first 4 arguments are passed in the registers RCX, RDX, R8 & R9. Any arguments beyond 4 are passed on the stack in the same left-to-right order. The original poster had the correct calling convention setup for x64 assembly with MASM. Also, the above responder who said the shadowspace valued subtracted from RSP should be 20h (32d) is correct. The shadow space is allowing space on the stack for the 4 arguments that are passed in by the registers in FastCall.
Changing the code above to:
extrn ExitProcess: PROC
extrn MessageBoxExA: PROC
.data
caption db '64-bit hello!', 0
message db 'Hello World!', 0
.code
Start PROC
sub rsp, 20h
mov rcx, 0 ; hWnd = HWND_DESKTOP
lea rdx, message ; LPCSTR lpText
lea r8, caption ; LPCSTR lpCaption
mov r9d, 0 ; uType = MB_OK
push 0 ; wLanguageId
call MessageBoxExA
mov ecx, eax
add rsp, 20h
call ExitProcess
Start ENDP
End
Works just fine in Visual Studio on a 64-bit machine

Trouble with CommandLineToArgvW Windows Function in Assembly

I am trying just to print out the value of argc using the CommandLineToArgvW Window's API function in NASM. The following is what I have:
extern _ExitProcess#4
extern _GetCommandLineA#0
extern _CommandLineToArgvW#8
extern printf
global _start
section .code
Format:
db "%d",10,0
FormatS:
db "%s",10,0
_start:
push ebp
mov ebp, esp
sub esp, 4 ; Create empty space for ArgC
call _GetCommandLineA#0
push eax; Push value beneath ArgC
mov ebx, ebp ; Set ebx to ebp
sub ebx, 4
push dword ebx ; pushes ArgC address onto stack
push dword [ebp - 8] ; pushes pointer to Command Line String
call _CommandLineToArgvW#8
push dword [ebp - 4]
push Format
call printf
push dword 0
call _ExitProcess#4
No matter what I do, the value for argc is 1. What am I doing wrong?
I assemble and link with these commands:
nasm -fwin32 FunctionTests.asm
golink FunctionTests.obj kernel32.dll msvcrt.dll shell32.dll /console /entry _start
FunctionTests.exe hi asdf asdf asdf asdf
As you can see, from the last line, argc should be 6.
Change _GetCommandLineA to _GetCommandLine*W* CommandLineToArgv expects a pointer to a UNICODE string.
MASM but just about the same:
start:
push ebp
mov ebp, esp
sub esp, 4
call GetCommandLineW
lea ecx, dword ptr[ebp - 4] ; need the address of local
push ecx ; address of local
push eax ; pointer to unicode string
call CommandLineToArgvW
push dword ptr [ebp - 4] ; value of local
push offset Format
call crt_printf
add esp, 8
; this is all? Then we don't have to restore stack.
push 0
call ExitProcess
end start
and this is the output:
D:\Projects>ConTest.exe boo boo I see you
6
D:\Projects>
Set a breakpoint just before you call CommandLineToArgvW and inspect the parameters you're about to pass. Observe that the first parameter you are passing is not a pointer to a string. It is a pointer to a pointer to a string.
You need to use GetCommandLineW rather than GetCommandLineA.
You are using CommandLineToArgvW with an ANSI string, use GetCommandLineW to get the command line in unicode.
You are also not dereferencing the pointer to the command line:
push ebx ; pushes ArgC address onto stack

Resources