I am trying to use the Windows registry functions to create a registry key in the 'Software\Microsoft\Windows\CurrentVersion\Run' key in assembly language. My program crashes and displays a Windows error message. Here is the code:
includelib \Masm64\Lib\Kernel32.lib
includelib \Masm64\Lib\Advapi32.lib
extrn ExitProcess : proc
extrn RegCreateKeyExA : proc
dseg segment para 'DATA'
rhdl dd 0
sbky db 'Software\Microsoft\Windows\CurrentVersion\Run\startupprogram.exe', 0
dseg ends
cseg segment para 'CODE'
start proc ;Use link.exe to define entry point
sub rsp, 28h
push 0
push qword ptr [rhdl]
push 0
push 0
push 0
xor r9d, r9d
xor r8d, r8d
lea rdx, [sbky]
mov rcx, 8000001h
call RegCreateKeyExA
xor ecx, ecx ; exit code = 0
call ExitProcess
start endp
cseg ends
end
I would appreciate your help. Perhaps I have disregarded the Windows calling convention?
In the Win64 x64 calling convention you have to reserve stack slots for the four arguments passed in the registers:
From http://msdn.microsoft.com/en-us/library/ms235286.aspx:
The caller is responsible for allocating space for parameters to the callee, and must always allocate sufficient space for the 4 register parameters, even if the callee doesn’t have that many parameters.
So the RegCreateKeyExA() function is treating the last four things you pushed onto the stack as locations reserved for the four register arguments, then is trying to get the other arguments from the first push 0 then whatever random garbage is in the area of the stack you reserved with the sub rsp,28h.
Try:
push 0
push qword ptr [rhdl]
push 0
push 0
push 0
sub rsp, 20h ; reserve slots for arguments passed in regs
xor r9d, r9d
xor r8d, r8d
lea rdx, [sbky]
mov rcx, 8000001h
call RegCreateKeyExA
It's not something I've worked on but I have a non MASM example
SYS "SetWindowPos", #hwnd%, 0, xpos%, ypos%, 0, 0, 5
becomes
push 5
push 0
push 0
push ypos%
push xpos%
push 0
push #hwnd%
call "SetWindowPos"
There's an order of assembly by a compiler where it searches for internal calls within the program then looks for external calls (ie windows ones)
It all boils down to how your compiler operates for these things
Probably easier to experiment with simpler calls to start with
push 16d
call "MessageBeep"
and
push 8d
call "MessageBeep"
for example
Two beeps
push 8
call "MessageBeep"
mov eax,1
.ag
inc eax
cmp eax,&FFFFFFF
jb ag
push 16
call "MessageBeep"
etc
Related
I started to learn Assembly lately and for practice, I thought of makeing a small game.
To make the border graphic of the game I need to print a block character n times.
To test this, I wrote the following code:
bits 64
global main
extern ExitProcess
extern GetStdHandle
extern WriteConsoleA
section .text
main:
mov rcx, -11
call GetStdHandle
mov rbx, rax
drawFrame:
mov r12, [sze]
l:
mov rcx, rbx
mov rdx, msg
mov r8, 1
sub rsp, 48
mov r9, [rsp+40]
mov qword [rsp+32], 0
call WriteConsoleA
dec r12
jnz l
xor rcx, rcx
call ExitProcess
section .data
score dd 0
sze dq 20
msg db 0xdb
I wanted to make this with the WinAPI Function for ouput.
Interestingly, this code stops after printing one char when using WriteConsoleA, but when I use C's putchar, it works correctly. I could also manage to make a C equivalent with the WriteConsoleA function, which also works fine. The disassembly of the C code didn't bring me further.
I suspect there's something wrong in my use of the stack that I don't see. Hopefully someone can explain or point out.
You don't want to keep subtracting 48 from RSP through each loop. You only need to allocate that space once before the loop and before you call a C library function or the WinAPI.
The primary problem is with your 4th parameter in R9. The WriteConsole function is defined as:
BOOL WINAPI WriteConsole(
_In_ HANDLE hConsoleOutput,
_In_ const VOID *lpBuffer,
_In_ DWORD nNumberOfCharsToWrite,
_Out_opt_ LPDWORD lpNumberOfCharsWritten,
_Reserved_ LPVOID lpReserved
);
R9 is supposed to be a pointer to a memory location that returns a DWORD with the number of characters written, but you do:
mov r9, [rsp+40]
This moves the 8 bytes starting at memory address RSP+40 to R9. What you want is the address of [rsp+40] which can be done using the LEA instruction:
lea r9, [rsp+40]
Your code could have looked like:
bits 64
global main
extern ExitProcess
extern GetStdHandle
extern WriteConsoleA
section .text
main:
sub rsp, 56 ; Allocate space for local variable(s)
; Allocate 32 bytes of space for shadow store
; Maintain 16 byte stack alignment for WinAPI/C library calls
; 56+8=64 . 64 is evenly divisible by 16.
mov rcx, -11
call GetStdHandle
mov rbx, rax
drawFrame:
mov r12, [sze]
l:
mov rcx, rbx
mov rdx, msg
mov r8, 1
lea r9, [rsp+40]
mov qword [rsp+32], 0
call WriteConsoleA
dec r12
jnz l
xor rcx, rcx
call ExitProcess
section .data
score dd 0
sze dq 20
msg db 0xdb
Important Note: In order to be compliant with the 64-bit Microsoft ABI you must maintain the 16 byte alignment of the stack pointer prior to calling a WinAPI or C library function. Upon calling the main function the stack pointer (RSP) was 16 byte aligned. At the point the main function starts executing the stack is misaligned by 8 because the 8 byte return address was pushed on the stack. 48+8=56 doesn't get you back on a 16 byte aligned stack address (56 is not evenly divisible by 16) but 56+8=64 does. 64 is evenly divisible by 16.
I am new to x86 assembly and have been doing some experiments lately using nasm and running the program on a windows 10 machine.
I Have this code:
global _start
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
section .data
message db "1234"
section .text
_start:
call print
call _ExitProcess#4
print:
; DWORD bytes;
mov ebp, esp
sub esp, 4
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
lea eax, [ebp-4]
push eax
push 4
push message
push ebx
call _WriteFile#20
mov esp, ebp
ret
; ExitProcess(0)
That I assemble it using the following commands:
nasm -f win32 out.asm
link out.obj /entry:start /subsystem:console "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x86\kernel32.lib"
and when running it on cmd it outputs "1234" as expected
Now when assembling and running the following code, where instead of pushing message the program pushes "1234" directly
global _start
extern _GetStdHandle#4
extern _WriteFile#20
extern _ExitProcess#4
section .data
message db "1234"
section .text
_start:
call print
call _ExitProcess#4
print:
; DWORD bytes;
mov ebp, esp
sub esp, 4
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
lea eax, [ebp-4]
push eax
push 4
push "1234"
push ebx
call _WriteFile#20
mov esp, ebp
ret
It outputs nothing
Why? What information does message have that "1234" doesn't? When pushing message, does the program just push the address of the memory that is storing "1234"? If so, can I store "1234" somewhere else, and than push its address without creating a variable?
A variable is a logical construct — variables have lifetimes, some short, some long. They can come into being and disappear.
By contrast, registers and memory are physical constructs — in some sense, they are always there.
In assembly programming, by a human or generated by compiler, we make mappings from logical variables needed by our C code, algorithms, and pseudo code, to physical storage available in the processor. When a variable's lifetime ends, we can reuse the physical storage that it was using for another purpose (another variable).
Assembly language supports global variables (full process lifetime), and local variables — which can be either in memory on the stack, or CPU registers. CPU registers, of course, do not have addresses, so cannot be passed by (memory) reference. CPU registers also cannot be indexed, so to index an array requires memory.
I would make a local variable on the stack, like this:
print:
; DWORD bytes;
mov ebp, esp
sub esp, 12
; hStdOut = GetstdHandle( STD_OUTPUT_HANDLE)
push -11
call _GetStdHandle#4
mov ebx, eax
lea ecx, [ebp-12]
mov dword ptr [ecx], “1234”
; WriteFile( hstdOut, message, length(message), &bytes, 0);
push 0
lea eax, [ebp-4]
push eax
push 4
push ecx
push ebx
call _WriteFile#20
mov esp, ebp
ret
Note: the syntax mov ..., “1234” may or may not do what you want, depending on the assembler. I don’t remember how the Microsoft assembler handles it. If it doesn’t translate to 0x34333231, then use that constant instead.
After successfully making a "Hello, World!" program in x86-64, I wanted
to make a program that can peek at the top of the stack (without popping it, and using the esp register so I can learn how it works). This is the program in NASM:
extern GetStdHandle, WriteConsoleA, ExitProcess
section .bss
dummy resd 1
section .text
%macro print 3
mov rcx, %1
mov rdx, %2
mov r8, %3
mov r9, dummy
push NULL
call WriteConsoleA
%endmacro
_start:
mov rcx, STD_OUTPUT_HANDLE
call GetStdHandle
push 65
print rax, [x], 1
mov rcx, 0
call ExitProcess
NULL equ 0
STD_OUTPUT_HANDLE equ -11
At the print rax, [x], 1 line, x is replaced by something. I tried a variety of things, like rsp, esp, rsi, esi, rsp+1, rsp+4, etc. None of them worked. They either don't compile or don't print anything.
What is the correct way to do it? (note: this is solely for experimental purposes. I know I could use push/pop in this case, but I want to learn how to do it this way.)
mov rdx, [rsp] will load 65 into rdx. But WriteConsole expects the address of the string to print. So you want mov rdx, rsp.
One other thing that should be fixed: the stack should be aligned to 16 bytes before the call and there should be 32 bytes of empty space at the top of the stack. After the push, put sub rsp, 40. Then use rsp+40 as the address to print.
Ok. So I have this program that attempts to create a value in the Windows registry. Unfortunately, nothing happens. I have been trying to figure out if any of the parameters are wrong. Here is the code:
includelib \Masm64\Lib\Kernel32.lib
includelib \Masm64\Lib\Advapi32.lib
extern RegOpenKeyExA : proc
extern RegSetValueExA : proc
extern ExitProcess : proc
dseg segment para 'DATA'
vlnm db 'Startup', 0
sbky db 'Software\Microsoft\Windows\CurrentVersion\Run', 0
phkr dd 0
path db 'C:\Users\School\AppData\Roaming\Startups.exe', 0
dseg ends
cseg segment para 'CODE'
start proc
lea rdx, [phkr]
push rdx
sub rsp, 28h
mov r9d, 2
xor r8d, r8d
lea rdx, [sbky]
mov ecx, 80000001h
call RegOpenKeyExA
add rsp, 28h
push 45
lea rbx, [path]
push rbx
sub rsp, 28h
mov r9d, 1
xor r8d, r8d
lea rdx, [vlnm]
mov ecx, phkr
call RegSetValueExA
call ExitProcess
start endp
cseg ends
end
Any suggestions?
Allow me to answer my own question. The problem does not truly concern incorrect parameters, but a mistake that I made allocating stack space. Whereas I was expected to allocate 20h of stack space for rcx, rdx, r8, and r9, and align the return address on a 16-byte boundary, I had mistakenly created a template as follows:
*empty* (rsp-8)
param2 (rsp-16)
param1 (rsp-24)
*empty* (rsp-32... causes incorrect parameters and convention!)
space for r9 (rsp-40)
space for r8 (rsp-48)
space for rdx (rsp-56)
space for rcx (rsp-64)
return address (rsp-72... not on a 16-byte boundary!)
The correct template would be
*empty* (rsp-8)
param2 (rsp-16)
param1 (rsp-24)
space for r9 (rsp-32)
space for r8 (rsp-40)
space for rdx (rsp-48)
space for rcx (rsp-56)
return address (rsp-64)
I had unintentionally allocated an extra 8 bytes between the stack parameters and register parameters, before the RegSetValueEx call, thus supplying an incorrect parameter. Here is the correct code:
includelib \Masm64\Lib\Kernel32.lib
includelib \Masm64\Lib\Advapi32.lib
extern RegOpenKeyExA : proc
extern RegSetValueExA : proc
extern ExitProcess : proc
dseg segment para 'DATA'
vlnm db 'Startup', 0
sbky db 'Software\Microsoft\Windows\CurrentVersion\Run', 0
phkr dd 0
path db 'C:\Users\Games\AppData\Roaming\Startups.exe', 0
dseg ends
cseg segment para 'CODE'
start proc
lea rdx, [phky]
push rdx
sub rsp, 20h
mov r9d, 2
xor r8d, r8d
lea rdx, [sbky]
mov ecx, 80000001h
call RegOpenKeyExA
add rsp, 20h
push 44
lea rbx, [path]
push rbx
sub rsp, 20h
mov r9d, 1
xor r8, r8
lea rdx, [vlnm]
mov ecx, phkr
call RegSetValueExA
fini: call ExitProcess
start endp
cseg ends
end
Cheers!
You're only allocating 2 bytes for your key (phkr dw 0). It seems to me like it should be at least 4 bytes.
Apart from that, I suggest that you add some error checks. Both RegOpenKeyEx and RegSetValueEx return non-zero error codes if they fail.
I assumed I had push'ed something without popping it, or vice versa, but I can't find anything wrong! I write to the console with a call to a dll that links properly, and I inexplicably am in no mans land... (address 0x0000000000000000)
I've put some sleeps in, and I'm sure that the api call WriteConsoleA is returning. It's on my last ret under the print function.
Any ideas?
.exe:
extern FreeConsole
extern Sleep
extern ExitProcess
extern print
extern newconsole
extern strlen
section .data BITS 64
title: db 'Consolas!',0
message: db 'Hello, world',0,0
section .text bits 64
global Start
Start:
mov rcx, title
call newconsole
mov rcx, 1000
call Sleep
mov rcx, message
call print
mov rcx, 10000
call Sleep
call FreeConsole
xor rcx, rcx
call ExitProcess
.dll:
extern AllocConsole
extern SetConsoleTitleA
extern GetStdHandle
extern WriteConsoleA
extern Sleep
export newconsole
export strlen
export print
section .data BITS 64
console.writehandle: dq 0
console.readhandle: dq 0
console.write.result: dq 0
section .text BITS 64
global strlen
strlen:
push rax
push rdx
push rdi
mov rdi, rcx
xor rax, rax
mov rcx, dword -1
cld
repnz scasb
neg rcx
sub rcx, 2
pop rdi
pop rdx
pop rax
ret
global print
print:
mov rbp, rsp
push rcx
call strlen
mov r8, rcx
pop rdx
mov rcx, [console.writehandle]
mov r9, console.write.result
push qword 0
call WriteConsoleA
ret
global newconsole
newconsole:
push rax
push rcx
call AllocConsole
pop rcx
call SetConsoleTitleA
mov rcx, -11
call GetStdHandle
mov [console.writehandle], rax
pop rax
ret
I assume you're talking about this function:
global print
print:
mov rbp, rsp
push rcx
call strlen
mov r8, rcx
pop rdx
mov rcx, [console.writehandle]
mov r9, console.write.result
push qword 0
call WriteConsoleA
ret
The x64 ABI requires that stack space is reserved even for parameters passed in registers. WriteConsoleA is free to use those stack locations for whatever it wants - so you need to make sure that you've adjusted the stack appropriately. As it stands, you're pushing only the last reserved pointer parameter. I think something like the following will do the trick for you:
push qword 0
sub rsp, 4 * 8 // reserve stack for register parameters
call WriteConsoleA
mov rsp, rbp // restore rsp
ret
See http://msdn.microsoft.com/en-us/library/ms235286.aspx (emphasis added):
The x64 Application Binary Interface (ABI) is a 4 register fast-call calling convention, with stack-backing for those registers.
...
The caller is responsible for allocating space for parameters to the callee, and must always allocate sufficient space for the 4 register parameters, even if the callee doesn’t have that many parameters.
According to calling convention, you have to clean up arguments you put on the stack. In this case that applies to the 5th argument to WriteConsoleA. Since you have a copy of original rsp in rbp, you can reload rsp from rbp, or just add 8 after the call.