Projects STRLCPY syscall_api Commits 0f0ef8a4
🤬
  • .github/img/example.png
  • ■ ■ ■ ■ ■ ■
    LICENSE
     1 +MIT License
     2 + 
     3 +Copyright (c) 2023 Ege Balcı
     4 + 
     5 +Permission is hereby granted, free of charge, to any person obtaining a copy
     6 +of this software and associated documentation files (the "Software"), to deal
     7 +in the Software without restriction, including without limitation the rights
     8 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9 +copies of the Software, and to permit persons to whom the Software is
     10 +furnished to do so, subject to the following conditions:
     11 + 
     12 +The above copyright notice and this permission notice shall be included in all
     13 +copies or substantial portions of the Software.
     14 + 
     15 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     18 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21 +SOFTWARE.
     22 + 
     23 + 
  • ■ ■ ■ ■ ■ ■
    README.md
     1 +# SYSCALL_API
     2 + 
     3 +`syscall_api.asm` block is used for dynamically finding the syscall number (SN) inside a function body and performing a manual syscall with the found SN. If SN could not be found inside the given function body, `R10` register will be equal to `-1`. Check [here](./example/) for example code.
     4 + 
     5 +Block searches for the following common instruction sequence during syscalls.
     6 +```nasm
     7 + mov r10, rcx
     8 + mov eax, ??? ; <-- two byte SN here
     9 + ; ...
     10 + syscall
     11 + ret
     12 +```
     13 + 
     14 +![example](.github/img/example.png)
     15 + 
     16 + 
     17 +## Prior Work & References
     18 +* https://conference.hitb.org/hitbsecconf2023ams/session/windows-syscalls-in-shellcode-advanced-techniques-for-malicious-functionality/
     19 +* https://github.com/klezVirus/SysWhispers3
     20 +* https://github.com/jthuraisamy/SysWhispers2
     21 +* https://github.com/jthuraisamy/SysWhispers
     22 +* https://klezvirus.github.io/RedTeaming/AV_Evasion/NoSysWhisper/
     23 +* https://outflank.nl/blog/2019/06/19/red-team-tactics-combining-direct-system-calls-and-srdi-to-bypass-av-edr/
  • ■ ■ ■ ■ ■ ■
    example/build.sh
     1 +#!/bin/bash
     2 +## ANSI Colors (FG & BG)
     3 +RED="$(printf '\033[31m')" GREEN="$(printf '\033[32m')" YELLOW="$(printf '\033[33m')" BLUE="$(printf '\033[34m')"
     4 +MAGENTA="$(printf '\033[35m')" CYAN="$(printf '\033[36m')" WHITE="$(printf '\033[37m')" BLACK="$(printf '\033[30m')"
     5 +REDBG="$(printf '\033[41m')" GREENBG="$(printf '\033[42m')" YELLOWBG="$(printf '\033[43m')" BLUEBG="$(printf '\033[44m')"
     6 +MAGENTABG="$(printf '\033[45m')" CYANBG="$(printf '\033[46m')" WHITEBG="$(printf '\033[47m')" BLACKBG="$(printf '\033[40m')"
     7 +RESET="$(printf '\e[0m')"
     8 + 
     9 +print_warning() {
     10 + echo ${YELLOW}"[!] ${RESET}${1}"
     11 +}
     12 +print_error() {
     13 + echo "${RED}[-] ${RESET}${1}"
     14 +}
     15 +print_fatal() {
     16 + echo -e ${RED}"[!] $1\n${RESET}"
     17 + kill -10 $$
     18 +}
     19 +print_good() {
     20 + echo "${GREEN}[+] ${RESET}${1}"
     21 +}
     22 +print_status() {
     23 + echo "${YELLOW}[*] ${RESET}${1}"
     24 +}
     25 +must_exist() {
     26 + for i in "$@"; do
     27 + command -v $i >/dev/null || print_fatal "$i not installed! Exiting..."
     28 + done
     29 +}
     30 + 
     31 +must_exist "nasm" "wget" "x86_64-w64-mingw32-gcc" "xxd"
     32 +[[ ! -f crc32_api_x64.asm ]] && wget https://raw.githubusercontent.com/EgeBalci/crc32_api/master/crc32_api_x64.asm &>/dev/null
     33 +nasm -f bin shellcode.asm -o shellcode || print_fatal "nasm assembly failed!"
     34 +[[ -f shellcode ]] && xxd -i shellcode shellcode.h
     35 +x86_64-w64-mingw32-gcc stub.c -o example.exe || print_fatal "Compilation failed!"
     36 +rm shellcode shellcode.h
     37 +print_warning "Do NOT!! use wine for running the example. It won't work cuz raw syscalls ¯\_(ツ)_/¯"
     38 +print_good "Example built! -> example.exe"
     39 + 
  • ■ ■ ■ ■ ■ ■
    example/shellcode.asm
     1 +[BITS 64]
     2 + 
     3 + 
     4 +_start:
     5 + push rbp
     6 + mov rbp, rsp ; New stack frame
     7 + 
     8 + mov r10d, 0xF03F2E65 ; Move the CRC32 hash into R10 = crc32("NTDLL.DLL", "NtDelayExecution")
     9 + call api_call ; Get the address of NtDelayExecution into RAX
     10 +
     11 + add rsp, 40 ; Allocate some space for fastcall conv.
     12 + mov rdx, 0xFFDFC7C9FFFFFFFF ; Move the LARGE_INTEGER delayTime value into RDX
     13 + push rdx ; Push delayTime
     14 + mov rdx, rsp ; RDX = &delayTime
     15 + mov rcx, 0 ; bAlertable = FALSE
     16 + 
     17 + mov r10, rax ; Move the address of NtDelayExecution function into R10
     18 + call syscall_api ; NtDelayExecution(RCX, RDX)
     19 + 
     20 + mov rsp, rbp ; Restore the stack frame
     21 + pop rbp ; Restore RBP
     22 + ret ; Return to caller
     23 + %include "../syscall_api.asm"
     24 + %include "crc32_api_x64.asm"
  • ■ ■ ■ ■ ■ ■
    example/stub.c
     1 +#include "shellcode.h"
     2 +#include <windows.h>
     3 + 
     4 +int main(int argc, char const *argv[]) {
     5 + char *BUFFER = (char *)VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT,
     6 + PAGE_EXECUTE_READWRITE);
     7 + memcpy(BUFFER, shellcode, sizeof(shellcode));
     8 + (*(void (*)())BUFFER)();
     9 + return 0;
     10 +}
     11 + 
  • ■ ■ ■ ■ ■ ■
    syscall_api.asm
     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
Please wait...
Page is in error, reload to recover