Windows syscall

使用syscall的作用

在安全对抗用syscall直接调用api可以在一定程度上绕过一些EDR或者杀毒软件对一些dll的api hook,可以直接调用设计内核的函数。在此只写一个简单的测试用例。

以NtDelayExecution为例

这个函数就是让程序延迟一段时间执行的一个函数,便于观察syscall成功没有的。

windows syscall的调用号是存在eax这个寄存器里的,要直接设置寄存器的值,所以需要使用简单的汇编代码。x64环境不支持直接内联汇编,所以单独创建一个.asm文件写汇编。

syscall stub结构

一般的syscall stub结构如下:

mov r10, rcx => 4C 8B D1

mov eax, SSN => B8 34 00 00 00 (假设 SSN 是 0x34)

syscall => 0F 05

ret => C3

按照index顺序,第5个字节是调用号ssn,这里假设是0x34,存储大小4个字节,小段写。

实现方法

动态获取ssn

在不同的系统版本了里一个api对应的ssn可能是不一样的,所以动态获取ssn是比较稳妥的。从第5个字节获取到ssn即可:

ULONG GetSSN(HMODULE hNtdll, const char* pName) {
    FARPROC FuncAddr = GetProcAddress(hNtdll, pName);
    ULONG* ssn = (ULONG*)((ULONGLONG)FuncAddr + 4);
    return *ssn;
}

如果要检测当前设备的ntdll有没有被hook,可以检查一下syscall stub的前四个字节是不是常规的值,如果被修改了那可能就是被inline hook过的。

syscall

我们先看NtDelayExecution这个函数:

NTSTATUS NtDelayExecution(
   BOOLEAN Alertable,
   PLARGE_INTEGER DelayInterval
);

两个参数,第一个填False就行,第二个是延迟的时间,+表示绝对时间,-表示相对时间,这里为了实验结果明显,直接延迟了10s执行。

在传参方面,x64传参是前四个参数用RCX, RDX, R8, R9传参,后面的进栈,但是syscall不一样,syscall的第一个参数进R10,后面的都一样。

还有一点是前面讲过的syscall是call eax,调用号放eax。

综上所述汇编代码可以这样写:

	mov eax, ecx;
	mov r10, rdx;
	mov rdx, r8;
	syscall;
	ret 

然后在cpp里的代码是这样的:

extern "C" NTSTATUS MyNtDelayExecution(ULONG ssn, BOOLEAN Alertable, PLARGE_INTEGER DelayInterval);
NTSTATUS status = MyNtDelayExecution(ssn, FALSE, &interval);

调试

运行程序发现程序确实是延迟了很久。

在vs里导入ntdll的符号表可以看到调用号对应的api:

调用号0x34,对应的就是NtDelayExecution()。

代码见BlackIce417/windows-syscall: A easy windows syscall test demo,很简单的一个测试demo。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值