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)










share|improve this question


















  • 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















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)










share|improve this question


















  • 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













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)










share|improve this question













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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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














  • 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















active

oldest

votes











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















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






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Quarter-circle Tiles

build a pushdown automaton that recognizes the reverse language of a given pushdown automaton?

Mont Emei