系统调用总结(1)

admin 2024年1月3日13:19:35评论21 views字数 8614阅读28分42秒阅读模式

系统调用简介

什么是系统调用

Windows系统调用使它们能够请求特定服务,例如读取或者写入文件,创建新的进程以及分配内存等等,我们之前使用的一些API都是R3层也就是用户层的API,比如VirtualAlloc,VirtualAllocEx等等,当我们去调用这些API函数的时候会触发NtAllocateVirtualMemory的系统调用,然后系统调用会将用户在上一个函数调用中提供的参数给到Windows内核中,执行请求的操作也会返回给程序。

所有的系统调用都会返回一个NTSTATUS值。

大多数的系统调用都是从NTDLL.DLL中进行导出的。

为什么要使用系统调用

使用系统调用可以对操作系统的底层进行访问,这对于执行R3层的Windows API来说一些无法执行的操作和复杂的操作都是很有利的,比如说NtCreateUserProcess系统调用在创建CreateProcess Win API无法提供的进程时提供了其他的选项。

还有就是系统调用可以用于规避EDR相关的设备,比如说如果EDR在用户层挂的钩子,那么我们直接使用系统调用就可以绕过。

Zw与Nt系统调用

系统调用有两种类型需要了解,一种是Nt开头的,一种是zW开头的,其实无论是Nt开头还是zW开头功能都是一样的,不同的是Nt开头的系统调用是用户模式程序的主要接口,就比如说VirtualAlloc申请内存等操作,而zW开头的系统调用是操作系统的低级内核模式接口,一般的话需要直接访问操作系统的设备驱动或其他内核模式代码使用。

简单来说zW系统调用用于设备驱动开发中的内核模块,而Nt系统调用用于用户模式程序执行,如下图可以看到同一系统调用的zW和Nt版本共享相同的函数地址。


系统调用总结(1)

系统调用总结(1)

系统调用号

这里系统调用号我们可以在x32dbg中看到。

系统调用总结(1)

跟进这个call,这里将18给了eax寄存器,这里的18就是系统调用号,后续我们会用到这个。

系统调用总结(1)

不同的系统调用号

需要注意的是系统调用号会根据操作系统的不同而有所不同的,比如NtAllocateVirtualMemory在win10上调用号是18,到了win11就变成了19了。

Syscall

在系统中,调用号不是随意的,而是每次都加1的表示方式。

就比如说NtAllocateVirtualMemory的系统调用号是18,ZwQueryInformationProcess就是19。

系统调用总结(1)

Syscall结构

上面的图我们会发现它们的结构其实是一样的,只是系统调用号不同罢了。

mov r10,rcxmov eax,系统调用号syscall

比如NtAllocateVirtualMemory的调用号就是18。

系统调用总结(1)

汇编指令解释

首先将保存在RCE中的第一个参数移动到R10寄存器中,然后将系统调用号放到eax寄存器中,最后执行syscall指令。

64位系统上的系统调用指令或32位系统上的系统调指令是启动系统调用的指令。执行系统共享指令将导致程序将控制从用户模式转移到内核模式。然后,内核将执行所请求的操作,并将控制返回到用户模式程序

并不是所有的NT API都是系统调用

这里需要注意的是虽然某些NtAPI返回NTSTATUS,但是它们不一定都是系统调用,这些NtAPI可能是Win API或系统调用使用的较低级别的函数,某些NtAPI不被归类为系统调用的原因是他们不符号系统调用的结构,比如说没有调用调用号或开头缺少mov r10,rcx等指令。

如下API非系统调用的NtAPI示例:

LdrLoadDll - LoadLibrary WinAPI使用它来将DLL加载到调用进程SystemFunction032和SystemFunction033这些NTAPI是用于RC4加密和解密的操作。

LdrLoadDll

可以看到它并没有遵循我们上面说到的系统调用的结构,比如mov r10,rcx。

系统调用总结(1)

系统调用-用户态挂钩

简介

目前大部分安全厂商都会在系统调用上执行API挂钩,以便运行时分析和监控程序的行为,比如可以挂钩NtProtectVirtualMemory系统调用,这样的话就可以检测到更高级别的Win API调用,比如说VirtualProtect,即使他在导入地址表中隐藏了名称,也是可以检测到的,一般的话用户态钩子通常安装在syscall指令之前,这是用户模式下系统调用的最后一步。

绕过用户态挂钩

直接使用系统调用是绕过用户态挂钩的一种方法,比如说在分配内存的时候使用NtAllocateVirtualMemory而不是直接使用VirtualAlloc/Ex 这些Win API函数,还有几种可以绕过用户态挂钩的方法。

使用直接系统调用使用间接系统调用脱钩

直接系统调用

直接系统调用可以绕过对用户态系统调用挂钩EDR等设备,现在的问题是我们如何去确定系统调用编号,因为操作系统的不同所以编号也就不同,调用编号可以在硬编码在二进制文件中,也可以在运行时动态计算。

如下汇编代码可以用于相同的结果,这样的话就不需要从安装了挂钩的NTDLL地址空间内调用,从而避免了挂钩。

NtAllocateVirtualMemory PROC  mov r10,rcx  mov eax,系统调用号  syscall  retNtAllocateVirtualMemory ENDP
NtProtectVirtualMemory PROC mov r10,rcx mov eax,系统调用号 syscall retNtProtectVirtualMemory ENDP

间接系统调用

间接系统调用的实现方式和直接系统调用是相差不多的,唯一的区别就是汇编代码中缺少了syscall指令,因为一些EDR会检测我们二进制文件中是否有syscall,这样的话间接系统调用就避免了这个问题。

如下图描述了间接系统调用:


系统调用总结(1)

汇编如下:

NtAllocateVirtualMemory PROC  mov r10,rcx  mov eax,系统调用号  jmp (Address) syscall的地址  retNtAllocateVirtualMemory ENDP
NtProtectVirtualMemory PROC mov r10,rcx mov eax,系统调用号 jmp (Address) syscall的地址 retNtProtectVirtualMemory ENDP

间接系统调用的好处

间接系统调用与直接系统调用的好处在于AV/EDR查找如果NTDLL地址空间外部调用的系统调用,它们会认为是可疑的,对于间接系统调用来说,系统调用指令从NTDLL的地址空间执行,就像正常的系统调用一样,所以间接系统调用比直接系统调用更容易绕过EDR。

脱钩

取消挂钩是另一种逃避挂钩的方法,也就是说加载到内存的挂钩NTDLL库被未挂钩的版本进行了替换,比如说NTDLL这个DLL模块的内存,被我们通过硬盘上的NTDLL.DLL进行了替换,这样的话就可以删除NTDLL库中放置的所有挂钩。

系统调用-SysWhispers

简介

SysWhispers是一种方便于我们通过直接系统调用来逃避系统调用挂钩的一个工具,他有多个版本。

SysWhispers下载地址:

https://github.com/jthuraisamy/SysWhispers

这里生成一个NtAllocateVirtualMemory函数的syscall。

python .syswhispers.py -f NtAllocateVirtualMemory -o syscalls

这里他会生成两个文件一个是头文件一个是asm文件。

系统调用总结(1)

我们打开asm文件如下:

这边它首先会去判断操作系统的版本来决定使用内置的函数调用号,最后直接系统调用。

.code
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_UnknownNtAllocateVirtualMemory_Check_6_X_XXXX: ; Check minor version for Windows Vista/7/8. cmp dword ptr [rax+11ch], 0 je NtAllocateVirtualMemory_Check_6_0_XXXX cmp dword ptr [rax+11ch], 1 je NtAllocateVirtualMemory_Check_6_1_XXXX cmp dword ptr [rax+11ch], 2 je NtAllocateVirtualMemory_SystemCall_6_2_XXXX cmp dword ptr [rax+11ch], 3 je NtAllocateVirtualMemory_SystemCall_6_3_XXXX jmp NtAllocateVirtualMemory_SystemCall_UnknownNtAllocateVirtualMemory_Check_6_0_XXXX: ; Check build number for Windows Vista. cmp word ptr [rax+120h], 6000 je NtAllocateVirtualMemory_SystemCall_6_0_6000 cmp word ptr [rax+120h], 6001 je NtAllocateVirtualMemory_SystemCall_6_0_6001 cmp word ptr [rax+120h], 6002 je NtAllocateVirtualMemory_SystemCall_6_0_6002 jmp NtAllocateVirtualMemory_SystemCall_UnknownNtAllocateVirtualMemory_Check_6_1_XXXX: ; Check build number for Windows 7. cmp word ptr [rax+120h], 7600 je NtAllocateVirtualMemory_SystemCall_6_1_7600 cmp word ptr [rax+120h], 7601 je NtAllocateVirtualMemory_SystemCall_6_1_7601 jmp NtAllocateVirtualMemory_SystemCall_UnknownNtAllocateVirtualMemory_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 je NtAllocateVirtualMemory_SystemCall_10_0_15063 cmp word ptr [rax+120h], 16299 je NtAllocateVirtualMemory_SystemCall_10_0_16299 cmp word ptr [rax+120h], 17134 je NtAllocateVirtualMemory_SystemCall_10_0_17134 cmp word ptr [rax+120h], 17763 je NtAllocateVirtualMemory_SystemCall_10_0_17763 cmp word ptr [rax+120h], 18362 je NtAllocateVirtualMemory_SystemCall_10_0_18362 cmp word ptr [rax+120h], 18363 je NtAllocateVirtualMemory_SystemCall_10_0_18363 cmp word ptr [rax+120h], 19041 je NtAllocateVirtualMemory_SystemCall_10_0_19041 cmp word ptr [rax+120h], 19042 je NtAllocateVirtualMemory_SystemCall_10_0_19042 cmp word ptr [rax+120h], 19043 je NtAllocateVirtualMemory_SystemCall_10_0_19043 jmp NtAllocateVirtualMemory_SystemCall_UnknownNtAllocateVirtualMemory_SystemCall_5_X_XXXX: ; Windows XP and Server 2003 mov eax, 0015h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_6_0_6000: ; Windows Vista SP0 mov eax, 0015h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_6_0_6001: ; Windows Vista SP1 and Server 2008 SP0 mov eax, 0015h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_6_0_6002: ; Windows Vista SP2 and Server 2008 SP2 mov eax, 0015h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_6_1_7600: ; Windows 7 SP0 mov eax, 0015h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_6_1_7601: ; Windows 7 SP1 and Server 2008 R2 SP0 mov eax, 0015h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_6_2_XXXX: ; Windows 8 and Server 2012 mov eax, 0016h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_6_3_XXXX: ; Windows 8.1 and Server 2012 R2 mov eax, 0017h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_10240: ; Windows 10.0.10240 (1507) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_10586: ; Windows 10.0.10586 (1511) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_14393: ; Windows 10.0.14393 (1607) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_15063: ; Windows 10.0.15063 (1703) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_16299: ; Windows 10.0.16299 (1709) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_17134: ; Windows 10.0.17134 (1803) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_17763: ; Windows 10.0.17763 (1809) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_18362: ; Windows 10.0.18362 (1903) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_18363: ; Windows 10.0.18363 (1909) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_19041: ; Windows 10.0.19041 (2004) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_19042: ; Windows 10.0.19042 (20H2) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_10_0_19043: ; Windows 10.0.19043 (21H1) mov eax, 0018h jmp NtAllocateVirtualMemory_EpilogueNtAllocateVirtualMemory_SystemCall_Unknown: ; Unknown/unsupported version. retNtAllocateVirtualMemory_Epilogue: mov r10, rcx syscall retNtAllocateVirtualMemory ENDP
end

.h文件中声明了函数原型。

#pragma once
#include <Windows.h>
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);

SysWhispers2

SysWhispers2是比较好用的,下载地址:

https://github.com/jthuraisamy/SysWhispers2

下载之后执行:

python .syswhispers.py --functions NtAllocateVirtualMemory,NtWriteVirtualMemory -o syscall_enm

系统调用总结(1)

生成之后将syscall_enm_stubs.std.x64.asm复制到项目中。

然后将头文件syscall_enm.h复制到项目中以及syscall_enm.c文件。

这三个复制到项目中之后,我们就可以正常使用函数进行调用了。

可以看到我上面没有定义任何导出。

系统调用总结(1)

正常上线:

系统调用总结(1)

SysWhispers3

SysWhispers3和SysWhispers2是差不多的。

python syswhispers.py --functions NtWriteVirtualMemory,NtAllocateVirtualMemory -o syscalls_mem -m jumper_randomized

系统调用总结(1)

还是一样会生成3个文件一个是头文件,一个是asm文件,还有一个就是.c文件了。

系统调用总结(1)

原文始发于微信公众号(Relay学安全):系统调用总结(1)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年1月3日13:19:35
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   系统调用总结(1)https://cn-sec.com/archives/2355177.html

发表评论

匿名网友 填写信息