| 1 | + | ;-----------------------------------------------------------------------------; |
| 2 | + | ; Author: Ege Balcı (egebalci[at]pm[dot]me) |
| 3 | + | ; Compatible: Windows 11, 10, 8.1, 8, 7, 2008, Vista |
| 4 | + | ; Version: 1.0 (22 April 2023) |
| 5 | + | ; Architecture: x64 |
| 6 | + | ; Size: 99 bytes |
| 7 | + | ;-----------------------------------------------------------------------------; |
| 8 | + | |
| 9 | + | [BITS 64] |
| 10 | + | |
| 11 | + | ; Windows x64 calling convention: |
| 12 | + | ; http://msdn.microsoft.com/en-us/library/9b372w95.aspx |
| 13 | + | |
| 14 | + | ; Input: Normal function parameters in [RCX,RDX,R8,R9]+[STACK] and the function address in R10 |
| 15 | + | ; Output: If SN found, expected return value will be in RAX. If fails R10 will be -1 |
| 16 | + | ; Clobbers: RCX, RDX, R8, R9, R10, R11 |
| 17 | + | ; Un-Clobbered: RBX, RSI, RDI, RBP , R12, R13, R14, R15. |
| 18 | + | |
| 19 | + | %define _SearchRange 100 ; Search range for syscall+ret instructions in bytes |
| 20 | + | |
| 21 | + | |
| 22 | + | syscall_api: |
| 23 | + | pop r11 ; Pop out the return address to R11 |
| 24 | + | call _syscall_api ; Search for the SN |
| 25 | + | test rax, rax ; Check if we found the SN |
| 26 | + | jz syscall_failed ; SN could not be found |
| 27 | + | mov r10, rcx ; Move the first parameter into R10 |
| 28 | + | syscall ; Perform the syscamm |
| 29 | + | push r11 ; Push back the return address |
| 30 | + | ret ; Return to caller |
| 31 | + | syscall_failed: |
| 32 | + | xor r10, r10 ; Zero out R10 |
| 33 | + | dec r10 ; R10 = -1 |
| 34 | + | push r11 ; Push back the return address |
| 35 | + | ret ; Return to caller with R10 = -1 |
| 36 | + | _syscall_api: |
| 37 | + | push rcx ; Save RCX |
| 38 | + | push rbp ; Save RBP |
| 39 | + | mov rbp, rsp ; Create a new stack frame |
| 40 | + | mov rcx, r10 ; Save the function address to RCX for range checking |
| 41 | + | push r10 ; Save one more copy to the stack for the second search |
| 42 | + | add r10, _SearchRange ; Add max address threshold |
| 43 | + | find_syscall: |
| 44 | + | cmp rcx, r10 ; Check if we are out of the search range |
| 45 | + | jg sn_zero ; If yes, bail out for preventing crash! |
| 46 | + | mov eax, dword [rcx] ; Read the first QWORD from function |
| 47 | + | shl eax, 8 ; Discard the first byte |
| 48 | + | cmp eax, 0xc3050f00 ; Check if syscall+ret |
| 49 | + | jz found_syscall ; Move to second part... |
| 50 | + | inc rcx ; If not keep looking |
| 51 | + | jmp find_syscall ; Loopt until found... |
| 52 | + | found_syscall: |
| 53 | + | pop r10 ; Restore the saved function address to RDX |
| 54 | + | find_sn: |
| 55 | + | ; Now we're looking for the "mov eax, ??" for extracting the syscall number |
| 56 | + | cmp rcx, r10 ; Check if we are above the function address |
| 57 | + | jl sn_zero ; If yes, bail out for preventing crash! |
| 58 | + | mov rax, qword [rcx] ; Read 8 bytes into RAX |
| 59 | + | cmp eax, 0xb8d18b4c ; Check if "mov r10, rcx + mov eax, ??" |
| 60 | + | jz found_sn ; If yes, we found the syscall number !! |
| 61 | + | loop find_sn ; Loop until found... |
| 62 | + | found_sn: |
| 63 | + | shr rax, 32 ; Discard EAX and what you have left is 2 byte SN |
| 64 | + | jmp not_found ; Proudly exit... |
| 65 | + | sn_zero: |
| 66 | + | xor rax,rax ; Could not found the syscall number (SN=0) |
| 67 | + | not_found: |
| 68 | + | mov rsp, rbp ; Restore stack frame |
| 69 | + | pop rbp ; Restore RBP |
| 70 | + | pop rcx ; Restore RCX |
| 71 | + | ret ; Return to caller |