Assebmly. Best practice to track the stack
up vote
0
down vote
favorite
I wrote simple trainer for some game using assmebler. One question I have is how to track the stack to find out what it has before each call (WinAPI call in my case)? Sometime for optimizations yoy don't want to remove something from the stack and just treat it as anything else. Also under Windows x64 we have shadow space which we need to remember about. Do you know any existing best practices for such cases? I just used comments in the code to specify what stack has now.
They look like
; Stack .....
Here is the main piece of code I used:
global WinMain
WinMain:
and rsp, 0xfffffffffffffff0 ; Align stack by 16 byte.
; Allocate on the stack the place for:
; stdin handle;
; stdout handle;
; stderr handle
; money dword
; and save the stack ptr in rbp for easy access.
; We need these variables during program lifetime.
sub rsp, 3 * ptrSize + dwordSize
mov rbp, rsp
; Stack: rbp =>| user money 4 | stdout handle 8 |
; | stdin handle 8 | stderr handle 8 |
%define stderr [rbp + 20]
%define stdin [rbp + 12]
%define stdout [rbp + 4]
%define requiredMoney [rbp]
%define alignment 4
sub rsp, shadowSpaceSize + alignment ; Allocate shadow space and align the stack.
; Stack: | shadow space 32 | alignment 4 | <= rbp => | 28 b |
; Get all the handles for console io.
getStdHandle STD_OUTPUT_HANDLE, stdout
getStdHandle STD_INPUT_HANDLE, stdin
getStdHandle STD_ERROR_HANDLE, stderr
%define alignment 12 ; New alignment.
sub rsp, 4 + alignment ; Add to old 4b alignment another 4b to store ptr.
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | <= rbp => | 28 b |
enterMoney:
writeConsole stdout, enterMoneyStr ; Out money enter message.
; Save 5th arg for next ReadConsoleA call.
; Take 9 bytes from the alignment for:
; Read chars count dword.
; Read chars buf n bytes.
charBufSize equ 5
%define alignment 12 - charBufSize - dwordSize
; Stack: | shadow space 32 | 5th arg 8 | alignment 3 | char count 4 | char buf 5 | rbp |
charBufOffset equ 5
charCountReadOffset equ 9
%define charBuf [rbp - charBufOffset]
%define charCountRead [rbp - charCountReadOffset]
; Read user input.
mov rcx, stdin ; Handle.
lea rdx, charBuf ; Ptr to buffer.
mov r8, charBufSize ; Chars to read.
lea r9, charCountRead ; Ptr to chars read.
mov qword arg5, 0 ; Reserved ptr.
call ReadConsoleA
; If user didn't enter anything then ask again.
cmp dword charCountRead, 2 ; 2 is the size of rn when user presses 'Enter'.
jle enterMoney
; Check in the loop that every character is number (has code 48-57).
%define counter rcx
mov rcx, charBufSize ; Counter
neg rcx
startForEveryChar:
%define currentChar byte [rbp + counter]
; Exit loop if we has null byte.
cmp currentChar, 0
je endForEveryChar
; If it is CR or LF then decrement the numbers of chars read.
cmp currentChar, `n`
je decrementNumOfCharsRead
cmp currentChar, `r`
je decrementNumOfCharsRead
; Check if it's number.
cmp currentChar, '0'
jl enterMoney
cmp currentChar, '9'
jg enterMoney
sub currentChar, '0' ; Subtract '0' char code, to convert char code to int8
jmp nextIteration
decrementNumOfCharsRead:
dec dword charCountRead ; Subtract the number of chars read. Need for ignoring CR and LF.
; Go for a next iteration or exit loop.
nextIteration:
inc rcx
test rcx, rcx
jl startForEveryChar
%undef counter
%undef currentChar
endForEveryChar:
jmp convertStrToNum
convertStrToNum:
; Loop through all the bytes and form a number in a r12.
; Setting up rcx as counter.
xor rcx, rcx
mov ecx, dword charCountRead
xor r12, r12
startForBytes0ToN:
mov r10, 10
mov r11, rcx
dec r11 ; Pow should be the less by 1.
call pow
xor rdx, rdx
mov edx, dword charCountRead
sub rdx, rcx
; Moving memory to make 'mul' use 8b multiplication instead of 1b.
movzx r14, byte [rbp + rdx - charBufOffset]
mul r14
add r12, rax ; Add temp to total.
dec rcx
test rcx, rcx
jg startForBytes0ToN
endForBytes0ToN:
writeConsole stdout, waitingForGameLaunchStr
%undef charBuf
%undef charCountRead
; Remove 16b from the stack:
; - 5th arg 8b;
; - char buffer 5b;
; - alignment 3b;
; use charCount as PId.
add rsp, ptrSize + alignment + charBufSize
; Stack: | shadow space 32 | pId 4 | rbp | 28b |
%define pid [rbp - 4]
mov dword requiredMoney, r12d
; Now we have money as bytes, not as string.
; Wait for game running if it's not yet.
findWin:
findWindow winClassName, winCaption
test rax, rax
jne windowFound
timeOutMs equ 500
mov rcx, timeOutMs
call Sleep
jmp findWin
%define winHandle r12
windowFound:
mov winHandle, rax ; Save handle.
%define alignment 8
sub rsp, ptrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment | pId 4 | rbp | 28b |
writeConsole stdout, okStr
; Get PId by window.
mov rcx, winHandle ; Win handle.
lea rdx, pid ; Address of pId.
call GetWindowThreadProcessId
%undef winHandle
; Open process by PId.
PROCESS_GRANTS equ PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
mov rcx, PROCESS_GRANTS
mov dh, byte FALSE
mov r8d, dword pid
call OpenProcess
; If we've got NULL handle then exit with error message.
test rax, rax
je cantOpenProc
%undef pid
; Stack operations:
; Add ptr for process handle.
; Add x86ptr for ptr to money ptr address.
; Add x86ptr for money ptr address.
; Treat pId place as the place for actualMoney.
; 5th arg still need for next WinAPI calls.
%define alignment 12
sub rsp, ptrSize + 2 * x86PtrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | moneyPtrAddress 4 |
; | ptrToMoneyPtrAddress 4 | procHandle 8 | actualMoney 4 | rbp |
%define actualMoney [rbp - 4]
%define procHandle [rbp - 12]
%define ptrToMoneyPtrAddress [rbp - 16]
%define moneyPtrAddress [rbp - 20]
mov procHandle, rax ; Copy proc handle to the stack.
startReadAndWrite:
readMemory gameBaseAddress, ptrToMoneyPtrAddress ; Read ptr to ptr to money.
; Add offset to received address.
add dword ptrToMoneyPtrAddress, moneyPtrAddressOffsetInGame
readMemory ptrToMoneyPtrAddress, moneyPtrAddress
; Add offset to received address.
add dword moneyPtrAddress, moneyAddressOffsetInGame
readMemory moneyPtrAddress, actualMoney ; Read actual money.
; Compare, if actual money isn't equal to required.
mov eax, actualMoney ; Copy actual money to eax.
cmp eax, dword requiredMoney
je startReadAndWrite
; Now write user's money to the target address.
mov rcx, procHandle
mov edx, dword moneyPtrAddress
lea r8, requiredMoney
mov r9, dwordSize ; Size of user money type.
mov qword arg5, 0
call WriteProcessMemory
findWindow winClassName, winCaption
test rax, rax
jne startReadAndWrite
; Close all the console handles and the process one.
closeHandle procHandle
closeHandle stdin
closeHandle stdout
closeHandle stderr
jmp exitApp
cantOpenProc:
writeConsole stderr, cantOpenProcStr
jmp exitApp
cantReadMemory:
writeConsole stderr, cantReadMemoryStr
jmp exitApp
exitApp:
...
Any other notes on the code are welcome.
OS: Win7 x64
Asm: NASM
Compiler: gcc (MinGW w64)
stack assembly
add a comment |
up vote
0
down vote
favorite
I wrote simple trainer for some game using assmebler. One question I have is how to track the stack to find out what it has before each call (WinAPI call in my case)? Sometime for optimizations yoy don't want to remove something from the stack and just treat it as anything else. Also under Windows x64 we have shadow space which we need to remember about. Do you know any existing best practices for such cases? I just used comments in the code to specify what stack has now.
They look like
; Stack .....
Here is the main piece of code I used:
global WinMain
WinMain:
and rsp, 0xfffffffffffffff0 ; Align stack by 16 byte.
; Allocate on the stack the place for:
; stdin handle;
; stdout handle;
; stderr handle
; money dword
; and save the stack ptr in rbp for easy access.
; We need these variables during program lifetime.
sub rsp, 3 * ptrSize + dwordSize
mov rbp, rsp
; Stack: rbp =>| user money 4 | stdout handle 8 |
; | stdin handle 8 | stderr handle 8 |
%define stderr [rbp + 20]
%define stdin [rbp + 12]
%define stdout [rbp + 4]
%define requiredMoney [rbp]
%define alignment 4
sub rsp, shadowSpaceSize + alignment ; Allocate shadow space and align the stack.
; Stack: | shadow space 32 | alignment 4 | <= rbp => | 28 b |
; Get all the handles for console io.
getStdHandle STD_OUTPUT_HANDLE, stdout
getStdHandle STD_INPUT_HANDLE, stdin
getStdHandle STD_ERROR_HANDLE, stderr
%define alignment 12 ; New alignment.
sub rsp, 4 + alignment ; Add to old 4b alignment another 4b to store ptr.
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | <= rbp => | 28 b |
enterMoney:
writeConsole stdout, enterMoneyStr ; Out money enter message.
; Save 5th arg for next ReadConsoleA call.
; Take 9 bytes from the alignment for:
; Read chars count dword.
; Read chars buf n bytes.
charBufSize equ 5
%define alignment 12 - charBufSize - dwordSize
; Stack: | shadow space 32 | 5th arg 8 | alignment 3 | char count 4 | char buf 5 | rbp |
charBufOffset equ 5
charCountReadOffset equ 9
%define charBuf [rbp - charBufOffset]
%define charCountRead [rbp - charCountReadOffset]
; Read user input.
mov rcx, stdin ; Handle.
lea rdx, charBuf ; Ptr to buffer.
mov r8, charBufSize ; Chars to read.
lea r9, charCountRead ; Ptr to chars read.
mov qword arg5, 0 ; Reserved ptr.
call ReadConsoleA
; If user didn't enter anything then ask again.
cmp dword charCountRead, 2 ; 2 is the size of rn when user presses 'Enter'.
jle enterMoney
; Check in the loop that every character is number (has code 48-57).
%define counter rcx
mov rcx, charBufSize ; Counter
neg rcx
startForEveryChar:
%define currentChar byte [rbp + counter]
; Exit loop if we has null byte.
cmp currentChar, 0
je endForEveryChar
; If it is CR or LF then decrement the numbers of chars read.
cmp currentChar, `n`
je decrementNumOfCharsRead
cmp currentChar, `r`
je decrementNumOfCharsRead
; Check if it's number.
cmp currentChar, '0'
jl enterMoney
cmp currentChar, '9'
jg enterMoney
sub currentChar, '0' ; Subtract '0' char code, to convert char code to int8
jmp nextIteration
decrementNumOfCharsRead:
dec dword charCountRead ; Subtract the number of chars read. Need for ignoring CR and LF.
; Go for a next iteration or exit loop.
nextIteration:
inc rcx
test rcx, rcx
jl startForEveryChar
%undef counter
%undef currentChar
endForEveryChar:
jmp convertStrToNum
convertStrToNum:
; Loop through all the bytes and form a number in a r12.
; Setting up rcx as counter.
xor rcx, rcx
mov ecx, dword charCountRead
xor r12, r12
startForBytes0ToN:
mov r10, 10
mov r11, rcx
dec r11 ; Pow should be the less by 1.
call pow
xor rdx, rdx
mov edx, dword charCountRead
sub rdx, rcx
; Moving memory to make 'mul' use 8b multiplication instead of 1b.
movzx r14, byte [rbp + rdx - charBufOffset]
mul r14
add r12, rax ; Add temp to total.
dec rcx
test rcx, rcx
jg startForBytes0ToN
endForBytes0ToN:
writeConsole stdout, waitingForGameLaunchStr
%undef charBuf
%undef charCountRead
; Remove 16b from the stack:
; - 5th arg 8b;
; - char buffer 5b;
; - alignment 3b;
; use charCount as PId.
add rsp, ptrSize + alignment + charBufSize
; Stack: | shadow space 32 | pId 4 | rbp | 28b |
%define pid [rbp - 4]
mov dword requiredMoney, r12d
; Now we have money as bytes, not as string.
; Wait for game running if it's not yet.
findWin:
findWindow winClassName, winCaption
test rax, rax
jne windowFound
timeOutMs equ 500
mov rcx, timeOutMs
call Sleep
jmp findWin
%define winHandle r12
windowFound:
mov winHandle, rax ; Save handle.
%define alignment 8
sub rsp, ptrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment | pId 4 | rbp | 28b |
writeConsole stdout, okStr
; Get PId by window.
mov rcx, winHandle ; Win handle.
lea rdx, pid ; Address of pId.
call GetWindowThreadProcessId
%undef winHandle
; Open process by PId.
PROCESS_GRANTS equ PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
mov rcx, PROCESS_GRANTS
mov dh, byte FALSE
mov r8d, dword pid
call OpenProcess
; If we've got NULL handle then exit with error message.
test rax, rax
je cantOpenProc
%undef pid
; Stack operations:
; Add ptr for process handle.
; Add x86ptr for ptr to money ptr address.
; Add x86ptr for money ptr address.
; Treat pId place as the place for actualMoney.
; 5th arg still need for next WinAPI calls.
%define alignment 12
sub rsp, ptrSize + 2 * x86PtrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | moneyPtrAddress 4 |
; | ptrToMoneyPtrAddress 4 | procHandle 8 | actualMoney 4 | rbp |
%define actualMoney [rbp - 4]
%define procHandle [rbp - 12]
%define ptrToMoneyPtrAddress [rbp - 16]
%define moneyPtrAddress [rbp - 20]
mov procHandle, rax ; Copy proc handle to the stack.
startReadAndWrite:
readMemory gameBaseAddress, ptrToMoneyPtrAddress ; Read ptr to ptr to money.
; Add offset to received address.
add dword ptrToMoneyPtrAddress, moneyPtrAddressOffsetInGame
readMemory ptrToMoneyPtrAddress, moneyPtrAddress
; Add offset to received address.
add dword moneyPtrAddress, moneyAddressOffsetInGame
readMemory moneyPtrAddress, actualMoney ; Read actual money.
; Compare, if actual money isn't equal to required.
mov eax, actualMoney ; Copy actual money to eax.
cmp eax, dword requiredMoney
je startReadAndWrite
; Now write user's money to the target address.
mov rcx, procHandle
mov edx, dword moneyPtrAddress
lea r8, requiredMoney
mov r9, dwordSize ; Size of user money type.
mov qword arg5, 0
call WriteProcessMemory
findWindow winClassName, winCaption
test rax, rax
jne startReadAndWrite
; Close all the console handles and the process one.
closeHandle procHandle
closeHandle stdin
closeHandle stdout
closeHandle stderr
jmp exitApp
cantOpenProc:
writeConsole stderr, cantOpenProcStr
jmp exitApp
cantReadMemory:
writeConsole stderr, cantReadMemoryStr
jmp exitApp
exitApp:
...
Any other notes on the code are welcome.
OS: Win7 x64
Asm: NASM
Compiler: gcc (MinGW w64)
stack assembly
1
What task does this code accomplish? Please tell us, and also make that the title of the question. See How to Ask.
– 200_success
14 hours ago
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I wrote simple trainer for some game using assmebler. One question I have is how to track the stack to find out what it has before each call (WinAPI call in my case)? Sometime for optimizations yoy don't want to remove something from the stack and just treat it as anything else. Also under Windows x64 we have shadow space which we need to remember about. Do you know any existing best practices for such cases? I just used comments in the code to specify what stack has now.
They look like
; Stack .....
Here is the main piece of code I used:
global WinMain
WinMain:
and rsp, 0xfffffffffffffff0 ; Align stack by 16 byte.
; Allocate on the stack the place for:
; stdin handle;
; stdout handle;
; stderr handle
; money dword
; and save the stack ptr in rbp for easy access.
; We need these variables during program lifetime.
sub rsp, 3 * ptrSize + dwordSize
mov rbp, rsp
; Stack: rbp =>| user money 4 | stdout handle 8 |
; | stdin handle 8 | stderr handle 8 |
%define stderr [rbp + 20]
%define stdin [rbp + 12]
%define stdout [rbp + 4]
%define requiredMoney [rbp]
%define alignment 4
sub rsp, shadowSpaceSize + alignment ; Allocate shadow space and align the stack.
; Stack: | shadow space 32 | alignment 4 | <= rbp => | 28 b |
; Get all the handles for console io.
getStdHandle STD_OUTPUT_HANDLE, stdout
getStdHandle STD_INPUT_HANDLE, stdin
getStdHandle STD_ERROR_HANDLE, stderr
%define alignment 12 ; New alignment.
sub rsp, 4 + alignment ; Add to old 4b alignment another 4b to store ptr.
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | <= rbp => | 28 b |
enterMoney:
writeConsole stdout, enterMoneyStr ; Out money enter message.
; Save 5th arg for next ReadConsoleA call.
; Take 9 bytes from the alignment for:
; Read chars count dword.
; Read chars buf n bytes.
charBufSize equ 5
%define alignment 12 - charBufSize - dwordSize
; Stack: | shadow space 32 | 5th arg 8 | alignment 3 | char count 4 | char buf 5 | rbp |
charBufOffset equ 5
charCountReadOffset equ 9
%define charBuf [rbp - charBufOffset]
%define charCountRead [rbp - charCountReadOffset]
; Read user input.
mov rcx, stdin ; Handle.
lea rdx, charBuf ; Ptr to buffer.
mov r8, charBufSize ; Chars to read.
lea r9, charCountRead ; Ptr to chars read.
mov qword arg5, 0 ; Reserved ptr.
call ReadConsoleA
; If user didn't enter anything then ask again.
cmp dword charCountRead, 2 ; 2 is the size of rn when user presses 'Enter'.
jle enterMoney
; Check in the loop that every character is number (has code 48-57).
%define counter rcx
mov rcx, charBufSize ; Counter
neg rcx
startForEveryChar:
%define currentChar byte [rbp + counter]
; Exit loop if we has null byte.
cmp currentChar, 0
je endForEveryChar
; If it is CR or LF then decrement the numbers of chars read.
cmp currentChar, `n`
je decrementNumOfCharsRead
cmp currentChar, `r`
je decrementNumOfCharsRead
; Check if it's number.
cmp currentChar, '0'
jl enterMoney
cmp currentChar, '9'
jg enterMoney
sub currentChar, '0' ; Subtract '0' char code, to convert char code to int8
jmp nextIteration
decrementNumOfCharsRead:
dec dword charCountRead ; Subtract the number of chars read. Need for ignoring CR and LF.
; Go for a next iteration or exit loop.
nextIteration:
inc rcx
test rcx, rcx
jl startForEveryChar
%undef counter
%undef currentChar
endForEveryChar:
jmp convertStrToNum
convertStrToNum:
; Loop through all the bytes and form a number in a r12.
; Setting up rcx as counter.
xor rcx, rcx
mov ecx, dword charCountRead
xor r12, r12
startForBytes0ToN:
mov r10, 10
mov r11, rcx
dec r11 ; Pow should be the less by 1.
call pow
xor rdx, rdx
mov edx, dword charCountRead
sub rdx, rcx
; Moving memory to make 'mul' use 8b multiplication instead of 1b.
movzx r14, byte [rbp + rdx - charBufOffset]
mul r14
add r12, rax ; Add temp to total.
dec rcx
test rcx, rcx
jg startForBytes0ToN
endForBytes0ToN:
writeConsole stdout, waitingForGameLaunchStr
%undef charBuf
%undef charCountRead
; Remove 16b from the stack:
; - 5th arg 8b;
; - char buffer 5b;
; - alignment 3b;
; use charCount as PId.
add rsp, ptrSize + alignment + charBufSize
; Stack: | shadow space 32 | pId 4 | rbp | 28b |
%define pid [rbp - 4]
mov dword requiredMoney, r12d
; Now we have money as bytes, not as string.
; Wait for game running if it's not yet.
findWin:
findWindow winClassName, winCaption
test rax, rax
jne windowFound
timeOutMs equ 500
mov rcx, timeOutMs
call Sleep
jmp findWin
%define winHandle r12
windowFound:
mov winHandle, rax ; Save handle.
%define alignment 8
sub rsp, ptrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment | pId 4 | rbp | 28b |
writeConsole stdout, okStr
; Get PId by window.
mov rcx, winHandle ; Win handle.
lea rdx, pid ; Address of pId.
call GetWindowThreadProcessId
%undef winHandle
; Open process by PId.
PROCESS_GRANTS equ PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
mov rcx, PROCESS_GRANTS
mov dh, byte FALSE
mov r8d, dword pid
call OpenProcess
; If we've got NULL handle then exit with error message.
test rax, rax
je cantOpenProc
%undef pid
; Stack operations:
; Add ptr for process handle.
; Add x86ptr for ptr to money ptr address.
; Add x86ptr for money ptr address.
; Treat pId place as the place for actualMoney.
; 5th arg still need for next WinAPI calls.
%define alignment 12
sub rsp, ptrSize + 2 * x86PtrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | moneyPtrAddress 4 |
; | ptrToMoneyPtrAddress 4 | procHandle 8 | actualMoney 4 | rbp |
%define actualMoney [rbp - 4]
%define procHandle [rbp - 12]
%define ptrToMoneyPtrAddress [rbp - 16]
%define moneyPtrAddress [rbp - 20]
mov procHandle, rax ; Copy proc handle to the stack.
startReadAndWrite:
readMemory gameBaseAddress, ptrToMoneyPtrAddress ; Read ptr to ptr to money.
; Add offset to received address.
add dword ptrToMoneyPtrAddress, moneyPtrAddressOffsetInGame
readMemory ptrToMoneyPtrAddress, moneyPtrAddress
; Add offset to received address.
add dword moneyPtrAddress, moneyAddressOffsetInGame
readMemory moneyPtrAddress, actualMoney ; Read actual money.
; Compare, if actual money isn't equal to required.
mov eax, actualMoney ; Copy actual money to eax.
cmp eax, dword requiredMoney
je startReadAndWrite
; Now write user's money to the target address.
mov rcx, procHandle
mov edx, dword moneyPtrAddress
lea r8, requiredMoney
mov r9, dwordSize ; Size of user money type.
mov qword arg5, 0
call WriteProcessMemory
findWindow winClassName, winCaption
test rax, rax
jne startReadAndWrite
; Close all the console handles and the process one.
closeHandle procHandle
closeHandle stdin
closeHandle stdout
closeHandle stderr
jmp exitApp
cantOpenProc:
writeConsole stderr, cantOpenProcStr
jmp exitApp
cantReadMemory:
writeConsole stderr, cantReadMemoryStr
jmp exitApp
exitApp:
...
Any other notes on the code are welcome.
OS: Win7 x64
Asm: NASM
Compiler: gcc (MinGW w64)
stack assembly
I wrote simple trainer for some game using assmebler. One question I have is how to track the stack to find out what it has before each call (WinAPI call in my case)? Sometime for optimizations yoy don't want to remove something from the stack and just treat it as anything else. Also under Windows x64 we have shadow space which we need to remember about. Do you know any existing best practices for such cases? I just used comments in the code to specify what stack has now.
They look like
; Stack .....
Here is the main piece of code I used:
global WinMain
WinMain:
and rsp, 0xfffffffffffffff0 ; Align stack by 16 byte.
; Allocate on the stack the place for:
; stdin handle;
; stdout handle;
; stderr handle
; money dword
; and save the stack ptr in rbp for easy access.
; We need these variables during program lifetime.
sub rsp, 3 * ptrSize + dwordSize
mov rbp, rsp
; Stack: rbp =>| user money 4 | stdout handle 8 |
; | stdin handle 8 | stderr handle 8 |
%define stderr [rbp + 20]
%define stdin [rbp + 12]
%define stdout [rbp + 4]
%define requiredMoney [rbp]
%define alignment 4
sub rsp, shadowSpaceSize + alignment ; Allocate shadow space and align the stack.
; Stack: | shadow space 32 | alignment 4 | <= rbp => | 28 b |
; Get all the handles for console io.
getStdHandle STD_OUTPUT_HANDLE, stdout
getStdHandle STD_INPUT_HANDLE, stdin
getStdHandle STD_ERROR_HANDLE, stderr
%define alignment 12 ; New alignment.
sub rsp, 4 + alignment ; Add to old 4b alignment another 4b to store ptr.
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | <= rbp => | 28 b |
enterMoney:
writeConsole stdout, enterMoneyStr ; Out money enter message.
; Save 5th arg for next ReadConsoleA call.
; Take 9 bytes from the alignment for:
; Read chars count dword.
; Read chars buf n bytes.
charBufSize equ 5
%define alignment 12 - charBufSize - dwordSize
; Stack: | shadow space 32 | 5th arg 8 | alignment 3 | char count 4 | char buf 5 | rbp |
charBufOffset equ 5
charCountReadOffset equ 9
%define charBuf [rbp - charBufOffset]
%define charCountRead [rbp - charCountReadOffset]
; Read user input.
mov rcx, stdin ; Handle.
lea rdx, charBuf ; Ptr to buffer.
mov r8, charBufSize ; Chars to read.
lea r9, charCountRead ; Ptr to chars read.
mov qword arg5, 0 ; Reserved ptr.
call ReadConsoleA
; If user didn't enter anything then ask again.
cmp dword charCountRead, 2 ; 2 is the size of rn when user presses 'Enter'.
jle enterMoney
; Check in the loop that every character is number (has code 48-57).
%define counter rcx
mov rcx, charBufSize ; Counter
neg rcx
startForEveryChar:
%define currentChar byte [rbp + counter]
; Exit loop if we has null byte.
cmp currentChar, 0
je endForEveryChar
; If it is CR or LF then decrement the numbers of chars read.
cmp currentChar, `n`
je decrementNumOfCharsRead
cmp currentChar, `r`
je decrementNumOfCharsRead
; Check if it's number.
cmp currentChar, '0'
jl enterMoney
cmp currentChar, '9'
jg enterMoney
sub currentChar, '0' ; Subtract '0' char code, to convert char code to int8
jmp nextIteration
decrementNumOfCharsRead:
dec dword charCountRead ; Subtract the number of chars read. Need for ignoring CR and LF.
; Go for a next iteration or exit loop.
nextIteration:
inc rcx
test rcx, rcx
jl startForEveryChar
%undef counter
%undef currentChar
endForEveryChar:
jmp convertStrToNum
convertStrToNum:
; Loop through all the bytes and form a number in a r12.
; Setting up rcx as counter.
xor rcx, rcx
mov ecx, dword charCountRead
xor r12, r12
startForBytes0ToN:
mov r10, 10
mov r11, rcx
dec r11 ; Pow should be the less by 1.
call pow
xor rdx, rdx
mov edx, dword charCountRead
sub rdx, rcx
; Moving memory to make 'mul' use 8b multiplication instead of 1b.
movzx r14, byte [rbp + rdx - charBufOffset]
mul r14
add r12, rax ; Add temp to total.
dec rcx
test rcx, rcx
jg startForBytes0ToN
endForBytes0ToN:
writeConsole stdout, waitingForGameLaunchStr
%undef charBuf
%undef charCountRead
; Remove 16b from the stack:
; - 5th arg 8b;
; - char buffer 5b;
; - alignment 3b;
; use charCount as PId.
add rsp, ptrSize + alignment + charBufSize
; Stack: | shadow space 32 | pId 4 | rbp | 28b |
%define pid [rbp - 4]
mov dword requiredMoney, r12d
; Now we have money as bytes, not as string.
; Wait for game running if it's not yet.
findWin:
findWindow winClassName, winCaption
test rax, rax
jne windowFound
timeOutMs equ 500
mov rcx, timeOutMs
call Sleep
jmp findWin
%define winHandle r12
windowFound:
mov winHandle, rax ; Save handle.
%define alignment 8
sub rsp, ptrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment | pId 4 | rbp | 28b |
writeConsole stdout, okStr
; Get PId by window.
mov rcx, winHandle ; Win handle.
lea rdx, pid ; Address of pId.
call GetWindowThreadProcessId
%undef winHandle
; Open process by PId.
PROCESS_GRANTS equ PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
mov rcx, PROCESS_GRANTS
mov dh, byte FALSE
mov r8d, dword pid
call OpenProcess
; If we've got NULL handle then exit with error message.
test rax, rax
je cantOpenProc
%undef pid
; Stack operations:
; Add ptr for process handle.
; Add x86ptr for ptr to money ptr address.
; Add x86ptr for money ptr address.
; Treat pId place as the place for actualMoney.
; 5th arg still need for next WinAPI calls.
%define alignment 12
sub rsp, ptrSize + 2 * x86PtrSize + alignment
; Stack: | shadow space 32 | 5th arg 8 | alignment 12 | moneyPtrAddress 4 |
; | ptrToMoneyPtrAddress 4 | procHandle 8 | actualMoney 4 | rbp |
%define actualMoney [rbp - 4]
%define procHandle [rbp - 12]
%define ptrToMoneyPtrAddress [rbp - 16]
%define moneyPtrAddress [rbp - 20]
mov procHandle, rax ; Copy proc handle to the stack.
startReadAndWrite:
readMemory gameBaseAddress, ptrToMoneyPtrAddress ; Read ptr to ptr to money.
; Add offset to received address.
add dword ptrToMoneyPtrAddress, moneyPtrAddressOffsetInGame
readMemory ptrToMoneyPtrAddress, moneyPtrAddress
; Add offset to received address.
add dword moneyPtrAddress, moneyAddressOffsetInGame
readMemory moneyPtrAddress, actualMoney ; Read actual money.
; Compare, if actual money isn't equal to required.
mov eax, actualMoney ; Copy actual money to eax.
cmp eax, dword requiredMoney
je startReadAndWrite
; Now write user's money to the target address.
mov rcx, procHandle
mov edx, dword moneyPtrAddress
lea r8, requiredMoney
mov r9, dwordSize ; Size of user money type.
mov qword arg5, 0
call WriteProcessMemory
findWindow winClassName, winCaption
test rax, rax
jne startReadAndWrite
; Close all the console handles and the process one.
closeHandle procHandle
closeHandle stdin
closeHandle stdout
closeHandle stderr
jmp exitApp
cantOpenProc:
writeConsole stderr, cantOpenProcStr
jmp exitApp
cantReadMemory:
writeConsole stderr, cantReadMemoryStr
jmp exitApp
exitApp:
...
Any other notes on the code are welcome.
OS: Win7 x64
Asm: NASM
Compiler: gcc (MinGW w64)
stack assembly
stack assembly
asked 17 hours ago
user1225207
392
392
1
What task does this code accomplish? Please tell us, and also make that the title of the question. See How to Ask.
– 200_success
14 hours ago
add a comment |
1
What task does this code accomplish? Please tell us, and also make that the title of the question. See How to Ask.
– 200_success
14 hours ago
1
1
What task does this code accomplish? Please tell us, and also make that the title of the question. See How to Ask.
– 200_success
14 hours ago
What task does this code accomplish? Please tell us, and also make that the title of the question. See How to Ask.
– 200_success
14 hours ago
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209304%2fassebmly-best-practice-to-track-the-stack%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
What task does this code accomplish? Please tell us, and also make that the title of the question. See How to Ask.
– 200_success
14 hours ago