I've been trying to program in assembly for the windows OS for a few days now. I'm trying to store a string in the global atom table and getting it back afterwards.
The problem is: When I call the function GlobalGetAtomNameA, the program crashes with code 5, access violation! Here's the code I wrote:
GLOBAL _main ; Entrypoint
EXTERN printf ; msvcrt.dll
EXTERN GlobalAddAtomA
EXTERN GlobalDeleteAtom
EXTERN GlobalFindAtomA
EXTERN GlobalGetAtomNameA ; kernel32.dll (and umengx86.dll?)
EXTERN SetLastError
EXTERN GetLastError ; Errhandlingapi.h
EXTERN LoadLibraryA ; libloaderapi.h
EXTERN ExitProcess
SEGMENT .data
LoadLib DB "User32", 0x00
AtomString DB "This is a string I want to store in the Global Atom Table!", 0x00
AtomFailed DB "Oops! Something went wrong:", 0x0A, 0x00
AtomSucceed DB "Data stored successfully!", 0x00
String1 DB "Here is the string:", 0x0A, 0x00
ErrCode5 DB "Error: Access denied!", 0x00
SEGMENT .bss
AtomPTR: resb 2 ; Atom will be 2 bytes long
AtomBuffer: resb 100 ; Where the received message gets stored
SEGMENT .text
_main:
PUSH LoadLib
CALL LoadLibraryA ; explicitly load this library into memory
ADD esp, 4 ; if this isn't done, GlobalAddAtomA will return NULL
CMP eax, 0x00 ; if function returns 0, something went wrong
JE Fail
PUSH AtomString
CALL GlobalAddAtomA ; Call function
ADD esp, 4 ; Data stored as atom can have a maximum size of 255 bytes
CMP ax, 0x00
JE Fail
MOV WORD[AtomPTR], ax ; Copy Atom into memory (16 bits)
PUSH AtomSucceed
CALL printf
ADD esp, 4
PUSH AtomString
CALL GlobalFindAtomA ; Search for our string
ADD esp, 4
MOV bx, WORD[AtomPTR]
CMP ax, bx ; CMP these two atoms
JNE Fail ; If they don't match, something went wrong
PUSH 0x64 ; 3rd arg: Buffer size
PUSH AtomBuffer ; 2nd arg: Buffer for the retrieved value
PUSH ax ; 1st arg: Atom
CALL GlobalGetAtomNameA ; Get String back
; Program crashes inside this function
ADD esp, 10 ; 3rd & 2nd arg: 4 bytes | ax: 2 bytes
PUSH AtomBuffer
CALL printf
ADD esp, 4 ; Print out the retrieved string
XOR eax, eax
PUSH eax
CALL SetLastError ; Set last error to 0x00
ADD esp, 4
MOV ax, WORD[AtomPTR]
PUSH ax
CALL GlobalDeleteAtom ; Delete Atom from Table
ADD esp, 2 ; ax is only 2 bytes
CALL GetLastError ; If last error has changed from 0x00,
CMP ax, 0x00 ; something went wrong
JNE Fail
ExitProc:
XOR eax, eax
PUSH eax
CALL ExitProcess
; ----------------------------------------------------- ;
Fail:
PUSH AtomFailed
CALL printf
ADD esp, 4
CALL GetLastError ; No arguments
CMP ax, 0x05
JNE ExitProc ; If not error code 5, exit
PUSH ErrCode5 ; If error code 5, printf
CALL printf
ADD esp, 4
JMP ExitProc ; Exit
I use nasm to make an .obj file:
nasm -fwin32 Atoms.asm
And I link it with GoLink:
GoLink.exe /mix /console /entry _main Atoms.obj kernel32.dll user32.dll msvcrt.dll libloaderapi.h Errhandlingapi.h
When I ran the program in the debugger, I saw that the program crashed in the address space of umengx86.dll. What is this file?
I tried to link umengx86.dll with my .obj file, but that didn't work either.
Can you tell me what the problem is?
Thanks for your help!
PUSH ax
only pushes 16 bits but the calling convention passes narrow integers in a full 4-byte stack slot.
Use movzx eax, word [...]
loads of narrow data so you don't have to mess around with 16-bit operand-size.
Then you can use push eax
to push without garbage in the upper 2 bytes, in case your callee wants an int
instead of a short
. If it only looks at the low 2 bytes, it doesn't matter what was in the top half, but you definitely need push eax
.