本文为看雪论坛精华文章
看雪论坛作者ID:cslime
1
前言
2
思路
3
实现过程
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
pushf
lea rcx,[rsp+0x80] ;参数1是堆栈指针
movabs rax,0x10000000000 ;回调函数地址
xor rax,0x7fffffff
xchg rbx,rax
call WinAPI_EnterStack ;强制对齐堆栈
call rbx
call WinAPI_ExitStack
popf
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
push rax ;这是一个不修改寄存器的jump
mov DWORD PTR [rsp],0x10000000 ;跳转地址高4字节
mov DWORD PTR [rsp+0x4],0x10000000 ;跳转地址低4字节
ret
WinAPI_EnterStack:
lea r11,[rsp+0x8]
and rsp,0xfffffffffffffff0
push r11
push r11
sub rsp,0x30
jmp QWORD PTR [r11-0x8]
WinAPI_ExitStack:
pop r11
add rsp,0x38
pop rsp
jmp r11
PUCHAR pcode = (PUCHAR)ExAllocatePool(NonPagedPool, 0x500);
memcpy(pcode, shellcode, sizeof(shellcode));
*(ULONG64 *)(pcode + 0x22) = ((ULONG64)DispatchCallback) ^ 0x7fffffff; //回调函数
//ViPacketLookaside.Region=0
//防止RtlpInterlockedPopEntrySList返回非0值
*(ULONG64*)(ViPacketLookaside + 0x8) = 0;
//修改ViPacketLookaside.AllocateEx
ULONG64 pfn = *(ULONG64*)(ViPacketLookaside + 0x30);
LARGE_INTEGER Addr;
Addr.QuadPart = (ULONG64)MyAllocEx; //使ViPacketLookaside.L. AllocateEx最终返回0
*(ULONG *)(pcode + 0x5A) = Addr.LowPart;
*(ULONG *)(pcode + 0x62) = Addr.HighPart;
InterlockedExchange64((volatile LONG64*)(ViPacketLookaside + 0x30), (LONG64)pcode);
__kernel_entry NTSTATUS NtDeviceIoControlFile(
[in] HANDLE FileHandle,
[in] HANDLE Event,
[in] PIO_APC_ROUTINE ApcRoutine,
[in] PVOID ApcContext,
[out] PIO_STATUS_BLOCK IoStatusBlock,
[in] ULONG IoControlCode,
[in] PVOID InputBuffer,
[in] ULONG InputBufferLength,
[out] PVOID OutputBuffer,
[in] ULONG OutputBufferLength
);
VOID TestDeviceIoControl() {
HANDLE FileHandle = 0;
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\??\\C:");
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, 0, 0);
IO_STATUS_BLOCK iosb;
RtlZeroMemory(&iosb, sizeof(IO_STATUS_BLOCK));
NTSTATUS stats = ZwCreateFile(&FileHandle, FILE_GENERIC_READ, &oa, &iosb, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, 0, 0);
RtlZeroMemory(&iosb, sizeof(IO_STATUS_BLOCK));
PFILE_OBJECT obj = 0;
OBJECT_HANDLE_INFORMATION objhandle = { 0 };
RtlZeroMemory(&objhandle, sizeof(objhandle));
stats = ObReferenceObjectByHandle(FileHandle, 0, *IoFileObjectType, KernelMode, (PVOID *)&obj, &objhandle);
if (!NT_SUCCESS(stats)) {
ZwClose(FileHandle);
KeBugCheck(0x56009);
}
ObDereferenceObject(obj);
Search_Object = (ULONG64)obj;
typedef NTSTATUS
(*NTAPI fnNtDeviceIoControlFile)(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ ULONG IoControlCode,
_In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer,
_In_ ULONG InputBufferLength,
_Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer,
_In_ ULONG OutputBufferLength
);
fnNtDeviceIoControlFile pNtDeviceIoControlFile = (fnNtDeviceIoControlFile)KGetProcAddress(KGetNtoskrnl(), "NtDeviceIoControlFile");
UCHAR Input[4] = { 0 };
UCHAR Output[4] = { 0 };
ULONG64 Magic[2];
Magic[0] = 0x1122334455667788; //Magic1
Magic[1] = 0x8877665544772299; //Magic2
pNtDeviceIoControlFile(FileHandle, 0, 0, 0, &iosb, IOCTL_NDIS_QUERY_GLOBAL_STATS, Input, 4, Output, 4);
ZwClose(FileHandle);
}
for (int i = 0; (ULONG64)Rsp < StackHighLimit - 8; Rsp++, i++) {
if (RspOffset == 0) {
if (Rsp[0] == 0x1122334455667788) {
if (Rsp[1] == 0x8877665544772299) {
//搜索栈上Object偏移
ULONG64 OLRSP = (ULONG64)Rsp;
for (int j = 0; OLRSP > pRsp && j < 0x1000; OLRSP -= 8, j += 8) {
if (*(ULONG64*)OLRSP == NtDeviceIoControlFileRet) {
RspOffset = OLRSP - pRsp;
ULONG64 OOLRSP = OLRSP;
for (int p = 0; OOLRSP > pRsp && p < 0x1000; OOLRSP -= 8, p += 8) {
if (NtDevice_Offset_Object)
break;
if (NtDevice_Offset_Object == 0) {
if (*(ULONG64*)OOLRSP == Search_Object) {
NtDevice_Offset_Object = OOLRSP - pRsp;
continue;
}
}
}
break;
}
}
}
}
if (RspOffset)break;
}
}
movabs rcx,0x100000000000 ;原先返回地址
push rcx
movabs rcx,0x100000000000 ;参数
push rax ;jump到shellcode模板2
mov DWORD PTR [rsp],0x10000000
mov DWORD PTR [rsp+0x4],0x10000000
ret
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
pushf
movabs rax,0x10000000000 ;填入DICHook.cpp ! DICPreCallback函数地址
xor rax,0x7fffffff
xchg rbx,rax
call WinAPI_EnterStack ;强制对齐堆栈
call rbx ;调用函数
call WinAPI_ExitStack
popf
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
ret
WinAPI_EnterStack:
lea r11,[rsp+0x8]
and rsp,0xfffffffffffffff0
push r11
push r11
sub rsp,0x30
jmp QWORD PTR [r11-0x8]
WinAPI_ExitStack:
pop r11
add rsp,0x38
pop rsp
jmp r11
if (*(ULONG64 *)(pRsp + RspOffset) == NtDeviceIoControlFileRet) {
ULONG64 LRSP = (ULONG64)(pRsp + RspOffset);
ULONG64 Object = *(ULONG64 *)(pRsp + NtDevice_Offset_Object);
ULONG64 iosb = *(ULONG64*)(LRSP + 8 + 0x90);
ULONG ControlCode = *(ULONG *)(LRSP + 8 + 0x98);
ULONG64 InputBuffer = *(ULONG64 *)(LRSP + 8 + 0xA0);
ULONG InputBufferLength = *(ULONG *)(LRSP + 8 + 0xA8);
ULONG64 OutputBuffer = *(ULONG64 *)(LRSP + 8 + 0xB0);
ULONG OutputBufferLength = *(ULONG *)(LRSP + 8 + 0xB8);
HOOK_DEVICE_IO_CONTEXT lContext;
RtlZeroMemory(&lContext, sizeof(lContext));
lContext.iosb = iosb;
lContext.InputBuffer = InputBuffer;
lContext.InputBufferLength = InputBufferLength;
lContext.OutputBuffer = OutputBuffer;
lContext.OutputBufferLength = OutputBufferLength;
lContext.IoControlCode = ControlCode;
lContext.Object = (PVOID)Object;
HOOK_DEVICE_IO_CONTEXT *Context = (HOOK_DEVICE_IO_CONTEXT *)ExAllocatePool(NonPagedPoolNx, sizeof(lContext));
RtlZeroMemory(Context, sizeof(HOOK_DEVICE_IO_CONTEXT));
memcpy(Context, &lContext, sizeof(lContext));
PUCHAR JmpPage = (PUCHAR)ExAllocatePool(NonPagedPool, sizeof(shellcode)+1);
memcpy(JmpPage, shellcode, sizeof(shellcode));//shellcode模板1
*(ULONG64 *)(JmpPage + 0x2) = *(ULONG64 *)(LRSP + 0x70);
*(ULONG64 *)(JmpPage + 0xd) = (ULONG64)Context;
LARGE_INTEGER Addr;
Addr.QuadPart = pRetCodePage;//这是填充后的shellcode模板2,调用DICHook.cpp ! DICPreCallback
*(ULONG *)(JmpPage + 0x19) = Addr.LowPart;
*(ULONG *)(JmpPage + 0x21) = Addr.HighPart;
Context->JmpPage = JmpPage;
//修改返回地址
*(ULONG64 *)(LRSP + 0x70) = (ULONG64)JmpPage;
return;
}
看雪ID:cslime
https://bbs.pediy.com/user-home-844784.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!