记录
最近阅读到zoemurmure大佬的文章:红队战术:在C#中使用syscall之背景知识介绍,最初的想法是想使用powershell实现syscall的功能,后来需要在powershell里嵌入c#语言,然后着手开始编写调试一个调用syscall的C#程序,不经常使用这些语言,查阅了一些资料搭出了一个半成品,最终程序能执行出一点效果,没达到预期效果,在这里记录一下翻车的经过。
首先从文章中指示的Windows X86-64系统调用表,查找一个目标函数进行测试,于是就找到一个比较简单的函数NtQuerySystemTime,用windbg查看该函数的汇编代码。
0:000> x ntdll!NtQuerySystemTime
00007ffc`370fcba0 ntdll!NtQuerySystemTime (NtQuerySystemTime)
0:000> u 00007ffc`370fcba0
ntdll!NtQuerySystemTime:
00007ffc`370fcba0 e93b88fdff jmp ntdll!RtlQuerySystemTime (00007ffc`370d53e0)
00007ffc`370fcba5 6666660f1f840000000000 nop word ptr [rax+rax]
ntdll!NtWaitForMultipleObjects:
00007ffc`370fcbb0 4c8bd1 mov r10,rcx
00007ffc`370fcbb3 b85b000000 mov eax,5Bh
00007ffc`370fcbb8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
00007ffc`370fcbc0 7503 jne ntdll!NtWaitForMultipleObjects+0x15 (00007ffc`370fcbc5)
00007ffc`370fcbc2 0f05 syscall
00007ffc`370fcbc4 c3 ret
摘录下来得到
public static byte[] bNtQuerySystemTime = {
0x4c,0x8b,0xd1, //mov r10,rcx
0xb8,0x5b,0x00,0x00,0x00, //mov eax,5Bh
0x0f,0x05, //syscall
0xc3 //ret
函数原型
__kernel_entry NTSTATUS NtQuerySystemTime(
OUT PLARGE_INTEGER SystemTime
);
传入long(64位) 通过C#的调用后返回值
|
名称 |
值 |
类型 |
|
status |
0xc00000ef |
int |
STATUS_INVALID_PARAMETER_1 无效参数作为第一个参数传递给服务或函数。
调了很多次后,后来想着写入CC开调试器看堆栈,还没开始做,看了后续的文章红队战术:在C#中使用syscall之编写代码确认代码没有明显错误后研究是不是函数调用出问题了,于是搜索RtlQuerySystemTime查找相关信息想知道这个函数的返回值是什么,然后传给syscall,结果从https://github.com/hfiref0x/SyscallTables/issues/1上找到相关信息,说的是NtQuerySystemTime 不在syscall的队列里,因为它在用户模式执行RtlQuerySystemTime,NtAccessCheckByTypeAndAuditAlarm 服务号为89(0x59),NtWaitForMultipleObjects 服务号为91(0x5B),这里丢失了90(0x5a),微软资料说明NtQuerySystemTime在未来版本的 Windows 中,可能会更改或不可用。
函数名称/服务号 |
win10-1507 |
1511 |
1607 |
1703 |
1709 |
1803 |
1809 |
1903 |
1909 |
2004 |
NtQuerySystemTime |
0x005a |
0x005a |
0x005a |
0x005a |
0x005a |
0x005a |
0x005a |
0x005a |
0x005a |
0x005a |
然后到此我知道我错在哪里了。
0:000> x ntdll!NtWaitForMultipleObjects
00007ffc`370fcbb0 ntdll!NtWaitForMultipleObjects (NtWaitForMultipleObjects)
0:000> u 00007ffc`370fcbb0
ntdll!NtWaitForMultipleObjects:
00007ffc`370fcbb0 4c8bd1 mov r10,rcx
00007ffc`370fcbb3 b85b000000 mov eax,5Bh
00007ffc`370fcbb8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1
00007ffc`370fcbc0 7503 jne ntdll!NtWaitForMultipleObjects+0x15 (00007ffc`370fcbc5)
00007ffc`370fcbc2 0f05 syscall
00007ffc`370fcbc4 c3 ret
00007ffc`370fcbc5 cd2e int 2Eh
00007ffc`370fcbc7 c3 ret
正确示范代码请到zoemurmure的Github:SharpCall。
贴一下我的部分核心代码,最终想完成powershell的实现,半成品错误示范:
delegate int NtQuerySystemTimeProc(out long SystemTime);
public class BasicTest2
{
public static byte[] bNtQuerySystemTime = {
0x4c,0x8b,0xd1, //mov r10,rcx
0xb8,0x5b,0x00,0x00,0x00, //mov eax,5Bh
0x0f,0x05, //syscall
0xc3 //ret
};
public static LARGE_INTEGER li = new LARGE_INTEGER();
public static long li2 = 0;
[DllImport("Kernel32")] private static extern bool VirtualProtect(IntPtr lpAddress, int dwSize, int flNewProtect,out int lpflOldProtect);
public static NTSTATUS NtQuerySystemTime()
{
IntPtr memoryAddress = IntPtr.Zero;
IntPtr memoryAddress2 = IntPtr.Zero;
byte[] syscall = bNtQuerySystemTime;
NTSTATUS status = 0;
unsafe
{
fixed (byte* ptr = syscall)
{
memoryAddress = (IntPtr)ptr;
}
fixed (long* ptr2 = &li2) {
memoryAddress2 = (IntPtr)ptr2;
}
}
if (IntPtr.Zero != memoryAddress)
{
if (Marshal.GetDelegateForFunctionPointer(memoryAddress, typeof(NtQuerySystemTimeProc)) is NtQuerySystemTimeProc QuerySystemTimeProc
&& memoryAddress2 != IntPtr.Zero
)
{
int outMemProtect = 0;
VirtualProtect(memoryAddress,bNtQuerySystemTime.Length,64, out outMemProtect);
status = QuerySystemTimeProc(out li2);
}
}
return status;
}
}
【公告】 讲师招募 | 全新“预付费”模式,不想来试试吗?