2013年9月6日星期五

x64 inline hook ZwCreateSection

#include <ntddk.h>

/*
x64 inline hook ZwCreateSection.
为啥不x64 ssdt hook?,原因有:
1.ssdt 里面的函数少.
2.微软官方声明,这样会patchguard检测到并蓝屏.
3.ssdt 没有导出,需要自己获得.

made by correy
made at 2013.09.06
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com
*/

/*
本代码测试环境为:windows server 2008 R2 X64
测试对象为:ZwCreateSection

0: kd> vertarget
Windows 7 Kernel Version 7601 (Service Pack 1) MP (2 procs) Free x64
Product: Server, suite: Enterprise TerminalServer SingleUserTS
Built by: 7601.18205.amd64fre.win7sp1_gdr.130708-1532
Machine Name:
Kernel base = 0xfffff800`01617000 PsLoadedModuleList = 0xfffff800`0185a6d0
Debug session time: Thu Sep  5 20:21:57.396 2013 (UTC + 8:00)
System Uptime: 0 days 0:11:39.021
0: kd> u nt!ZwCreateSection
nt!ZwCreateSection:
fffff800`016c3a60 488bc4          mov     rax,rsp
fffff800`016c3a63 fa              cli
fffff800`016c3a64 4883ec10        sub     rsp,10h
fffff800`016c3a68 50              push    rax
fffff800`016c3a69 9c              pushfq
fffff800`016c3a6a 6a10            push    10h
fffff800`016c3a6c 488d055d290000  lea     rax,[nt!KiServiceLinkage (fffff800`016c63d0)]
fffff800`016c3a73 50              push    rax
*/

/*
经过编译,搜索,发现如下机器码.提示,用push 0x9999999999 是不行的.只能一个字节.
48b89999999909000000 mov rax,999999999h
50                   push    rax
c3                   retn
retn 应该没啥影响,实验吧!

这个12字节,正好对应ZwCreateSection的前几个指令.
如果不对应,后面可以加NOP.
*/
#pragma pack(1) //这一行必不可少.
typedef struct _opcode {
    unsigned short int mov_rax;
    unsigned __int64 my_fn;
    unsigned char push_rax;
    unsigned char retn;
} opcode, *popcode;

opcode g_op;

unsigned char g_original[sizeof(opcode)];//保存函数的前几个字节.

PVOID g_pfn = 0;

NTSTATUS SuperRtlCopyMemory(IN VOID UNALIGNED  *Destination, IN CONST VOID UNALIGNED  *Source, IN SIZE_T  Length)
{
    NTSTATUS status = STATUS_SUCCESS;//STATUS_UNSUCCESSFUL
    PMDL  g_pmdl;
    unsigned int * Mapped;
    KIRQL kirql;

    //改变内存属性。
    g_pmdl = IoAllocateMdl(Destination, sizeof(opcode), 0, 0, NULL);
    if(!g_pmdl)  {
        return status;
    }
    MmBuildMdlForNonPagedPool(g_pmdl);
    Mapped = (unsigned int *)MmMapLockedPages(g_pmdl, KernelMode); //建议使用MmMapLockedPagesSpecifyCache。
    if (Mapped == NULL) {
        return status;
    }

    kirql = KeRaiseIrqlToDpcLevel();

    RtlCopyMemory(Mapped,/*&*/Source,Length);//运行此行前后可以用u nt!ZwOpenProcess看看达到效果没有.  

    KeLowerIrql(kirql);

    //恢复内存属性.
    if(g_pmdl) {
        MmUnmapLockedPages((PVOID)Mapped, g_pmdl);
        IoFreeMdl(g_pmdl);
    }

    return status;
}

NTSTATUS
    MyZwCreateSection(
    OUT PHANDLE  SectionHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes  OPTIONAL,
    IN PLARGE_INTEGER  MaximumSize  OPTIONAL,
    IN ULONG  SectionPageProtection,
    IN ULONG  AllocationAttributes,
    IN HANDLE  FileHandle  OPTIONAL
    )
{
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    //也可以通过bu nt!ZwOpenProcess,看看在那里是否跳转到这里.
    KdBreakPoint();//DbgBreakPoint()

    //这是一个示例:打印一个消息,然后原路返回,没有过滤.

    KdPrint(("i am in MyZwCreateSection!\n"));

    SuperRtlCopyMemory(g_pfn,g_original,sizeof(opcode));

    //疑问是在两个SuperRtlCopyMemory函数的调用之间,再发生ZwCreateSection调用,估计是拦截不到的.
    status = ZwCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle);

    SuperRtlCopyMemory(g_pfn,&g_op,sizeof(opcode));

    //if (0) //如果拒绝
    //{
    //    //直接返回即可,不必进行下一行的复杂操作.注意,这没有测试.
    //    //设置ZwOpenProcess的sizeof(opcode)+1 = 0xc3,让主函数返回.
    //}
    //else
    //{
    //    //恢复设置,(加DPC及内存读写),包括:ZwOpenProcess的sizeof(opcode)+1 = 0xc3的恢复.
    //    //调用原来的函数.//不准别的在调用.这时功能已经完成了.
    //    //设置hook.(加DPC及内存读写)
    //}

    return status;
}

NTSTATUS hook(wchar_t * pfn,unsigned __int64 p_my_fn)
{
    NTSTATUS status = STATUS_SUCCESS;//STATUS_UNSUCCESSFUL
    UNICODE_STRING usfn;
 
    RtlInitUnicodeString( &usfn, pfn);
    g_pfn = MmGetSystemRoutineAddress(&usfn);
    if (g_pfn == NULL) {
        return status;
    }

    g_op.mov_rax = 0xb848;
    g_op.my_fn = MyZwCreateSection;
    g_op.push_rax = 0x50;
    g_op.retn = 0xc3;//此时可以用 u g_op看看效果.

    RtlCopyMemory(g_original,g_pfn,sizeof(opcode));

    return SuperRtlCopyMemory(g_pfn,&g_op,sizeof(opcode));
}

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
    SuperRtlCopyMemory(g_pfn,g_original,sizeof(opcode));
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();//DbgBreakPoint()

    DriverObject->DriverUnload = DriverUnload;

    return hook(L"ZwCreateSection",MyZwCreateSection);
}

/*一下是验证效果.
0: kd> u nt!ZwCreateSection
nt!ZwCreateSection:
fffff800`016c3a60 488bc4          mov     rax,rsp
fffff800`016c3a63 fa              cli
fffff800`016c3a64 4883ec10        sub     rsp,10h
fffff800`016c3a68 50              push    rax
fffff800`016c3a69 9c              pushfq
fffff800`016c3a6a 6a10            push    10h
fffff800`016c3a6c 488d055d290000  lea     rax,[nt!KiServiceLinkage (fffff800`016c63d0)]
fffff800`016c3a73 50              push    rax
0: kd> p
test!write_memory+0x8d:
fffff880`049a029d 0fb64c2430      movzx   ecx,byte ptr [rsp+30h]
0: kd> u nt!ZwCreateSection
nt!ZwCreateSection:
fffff800`016c3a60 48b840019a0480f8ffff mov rax,offset test!MyZwCreateSection (fffff880`049a0140)
fffff800`016c3a6a 50              push    rax
fffff800`016c3a6b c3              ret
fffff800`016c3a6c 488d055d290000  lea     rax,[nt!KiServiceLinkage (fffff800`016c63d0)]
fffff800`016c3a73 50              push    rax
fffff800`016c3a74 b847000000      mov     eax,47h
fffff800`016c3a79 e982600000      jmp     nt!KiServiceInternal (fffff800`016c9b00)
fffff800`016c3a7e 6690            xchg    ax,ax

依旧出现:
BugCheck 109
Fatal System Error: 0x00000109
nt!FsRtlPrivateInsertSharedLock
*/

没有评论:

发表评论