https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture
https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
fastcall ⇒ first 4 args are passed into rcx, rdx, R8, R9 then right to left onto the stack
Register | Volatile | Purpose |
---|---|---|
rax | yes | hold an integer/pointer return value |
rbx | no | |
rcx | yes | hold first integer/pointer arg |
rdx | yes | hold second integer/pointer arg |
rsi | no | |
rdi | no | |
rbp | no | |
rsp | no | |
r8 | yes | hold third integer/pointer arg |
r9 | yes | hold fourth integer/pointer arg |
r10 | yes | |
r11 | yes | |
r12 | no | |
r13 | no | |
r14 | no | |
r15 | no |
volatile ⇒ to be destroyed across a call
nonvolatile ⇒ retain values after a call. callee must save them somehow
MOV ⇒ Move a value; the source register will no longer hold said value
MOV rax, m
moves contents at m
to the rax
PUSH ⇒ Move a value or register
PUSH rcx
moves the rcx
value onto the stack
POP ⇒ retrieve the last value pushed onto the stack
;<https://stackoverflow.com/questions/4584089/what-is-the-function-of-the-push-pop-instructions-used-on-registers-in-x86-ass>
push 0xdeadbeef ; push a value to the stack
pop eax ; eax is now 0xdeadbeef
;swap contents of registers
push eax
mov eax, ebx
pop ebx
; holding return values
push eax ; preserve the value of eax
call some_method ; some method is called which will put return value in eax
mov edx, eax ; move the return value to edx
pop eax ; restore original eax
CALL ⇒ store location of where it will return to, JMP to address, then when we hit a RET, JMP back to stored location. https://stackoverflow.com/questions/32793117/assembly-call-vs-jmp
func1(int a, int b, int c, int d, int e, int f);
// a in RCX, b in RDX, c in R8, d in R9, f then e pushed on stack
https://github.com/crummie5/FreshyCalls/blob/master/syscall.cpp
masked_syscall_stub
func(id, instruct, args...)
/* Initial setup when called
id in RCX
instruct in RDX
ARG1 in R8
ARG2 in R9
*/
//Assembly code
//Move 2 registers into the stack. These will hold the 2 of the initial 4 that overflow
push R13 onto the stack to store its value
Push R14 onto the stack to store its value
//Assign the registers, offset 2 because we added ID and instruct
move the value of the RDX into R14 (which is in the stack)
move the value of the RCX into R13 (which is in the stack)
move the value of R8 into RCX
move the value of R9 into RDX
/*
R14, in stack, holds instruct right now
R13, in stack, holds id right now
RCX holds ARG1 right now
RDX holds ARG2 right now
R8 is empty
R9 is empty
*/
//These two are the missing two args within the stack. They are integer args
move the value of RSP+0x38 into R8
move the value of RSP+0x40 into R9
/*
R8 holds ARG3 right now
R9 holds ARG4 right now
*/
add 0x28 to the stack pointer
load the address of RIP + 0x0C into R11
call address at R11
//RIP+0x0C contains the following instructions
move the value of r13 into rax
move the value of rcx into r10
/*
R14, in stack, holds instruct right now
R13, in stack, holds id right now
RCX holds ARG1 right now
RDX holds ARG2 right now
RAX holds r13
R10 holds RCX
*/
jump to r14
subtract 28h from the stack pointer
pop the last item pushed onto stack (r14) into r14
pop the last item pushed onto stack (r13) into r13
return