首页
社区
课程
招聘
[求助]About "Hybrid Hooking "
发表于: 2007-10-22 16:25 7176

[求助]About "Hybrid Hooking "

2007-10-22 16:25
7176
议题作者:sudami

驱动刚入门, 虽然HOOK ZwQuerySystemInformation被用烂了, 但下面这个更烂了吧

Rootkits: Subverting the Windows Kernel 一书中关于"A Hybrid Hooking Approach"
这种方式之所以hybrid, 其实是在RING0下更改IAT而已.
有点像RING3中的IAT HOOK,又有点像Inline HOOK;

但书上说的毕竟是科普性的, 只提供了一个模版,
于是偶在这个模版的基础上实验了下,结果没有成功.5555~

完整代码如下:
/*********************************************************************************
 * Mender      :    sudami
 * Time          :     07/10/22
 * Comment :    实验一下书中的关于Hybrid Hooking 的方法,掌握基本原理
 *
 ********************************************************************************/

#include "ntddk.h"
#include "ntimage.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

typedef unsigned long DWORD;
typedef unsigned long *PDWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned int UINT;
typedef BYTE BOOLEAN;
typedef BOOLEAN BOOL;

#define WINAPI __stdcall
// 定义一个宏,可有可无
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))

BOOLEAN gb_Hooked;

VOID MyImageLoadNotify(IN PUNICODE_STRING,
                       IN HANDLE,
                       IN PIMAGE_INFO);

NTSTATUS HookImportsOfImage(PIMAGE_DOS_HEADER, HANDLE);

//-------------------------------------------------------------------------------------------------------------------------
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, 
                     IN PUNICODE_STRING theRegistryPath)
{
    NTSTATUS ntStatus;
    gb_Hooked = FALSE; // We have not hooked yet

    ntStatus = PsSetLoadImageNotifyRoutine(MyImageLoadNotify);

    return ntStatus;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

VOID MyImageLoadNotify(IN PUNICODE_STRING  FullImageName,
                       IN HANDLE  ProcessId, // Process where image is mapped
                       IN PIMAGE_INFO  ImageInfo)
{
    UNICODE_STRING u_targetDLL;
    // Setup the name of the DLL to target
    RtlInitUnicodeString(&u_targetDLL, L"\\WINDOWS\\system32\\kernel32.dll");

    if (RtlCompareUnicodeString(FullImageName, &u_targetDLL, TRUE) == 0)
    {
        HookImportsOfImage(ImageInfo->ImageBase, ProcessId);
    }

}

//-----------------------------------------------------------------------------------------------------------
// 这个函数是偶加的,替换掉IAT指定函数入口(TerminateProcess)的前8字节
// 结果并没有见效
//-----------------------------------------------------------------------------------------------------------
BOOL WINAPI MyTerminateProcess(HANDLE hProcess, UINT nExitCode)
{
    return TRUE;
}


NTSTATUS HookImportsOfImage(PIMAGE_DOS_HEADER image_addr, HANDLE h_proc)
{
    PIMAGE_DOS_HEADER dosHeader;
    PIMAGE_NT_HEADERS pNTHeader;
    PIMAGE_IMPORT_DESCRIPTOR importDesc;
    PIMAGE_IMPORT_BY_NAME p_ibn;
    DWORD importsStartRVA;
    PDWORD pd_IAT, pd_INTO;
    int count, index;
    char *dll_name = NULL;
    char *pc_dlltar = "kernel32.dll";
    char *pc_fnctar = "TerminateProcess";
    PMDL  p_mdl;
    PDWORD MappedImTable;
    DWORD d_sharedM = 0x7ffe0800;
    DWORD d_sharedK = 0xffdf0800; 

    // Little detour
    unsigned char new_code[] = { 
        0x90,                          // NOP make INT 3 to see
        0xb8, 0xff, 0xff, 0xff, 0xff,  // mov eax, 0xffffffff
        0xff, 0xe0                     // jmp eax
    };
    
    dosHeader = (PIMAGE_DOS_HEADER) image_addr;

    pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader,
                                dosHeader->e_lfanew );
    
    if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
        return STATUS_INVALID_IMAGE_FORMAT;

    importsStartRVA = pNTHeader->OptionalHeader.DataDirectory
                            [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

    if (!importsStartRVA)
        return STATUS_INVALID_IMAGE_FORMAT;

    importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (importsStartRVA + (DWORD) dosHeader);

    for (count = 0; importDesc[count].Characteristics != 0; count++)
    {
        dll_name = (char*) (importDesc[count].Name + (DWORD) dosHeader);
                
        pd_IAT = (PDWORD)(((DWORD) dosHeader) + (DWORD)importDesc[count].FirstThunk);
        pd_INTO = (PDWORD)(((DWORD) dosHeader) + (DWORD)importDesc[count].OriginalFirstThunk);

        for (index = 0; pd_IAT[index] != 0; index++)
        {
            // If this is an import by ordinal the high
            // bit is set
            if ((pd_INTO[index] & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
            {
                p_ibn = (PIMAGE_IMPORT_BY_NAME)(pd_INTO[index]+((DWORD) dosHeader));
                if ((_stricmp(dll_name, pc_dlltar) == 0) && \
                    (strcmp(p_ibn->Name, pc_fnctar) == 0))
                {
                                        p_mdl = MmCreateMdl(NULL, &pd_IAT[index], 4);
                    if(!p_mdl)
                        return STATUS_UNSUCCESSFUL;

                    MmBuildMdlForNonPagedPool(p_mdl);

                    // Change the flags of the MDL
                    p_mdl->MdlFlags = p_mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

                    MappedImTable = MmMapLockedPages(p_mdl, KernelMode);
                    
                    if (!gb_Hooked)
                    {
                      
                        RtlCopyMemory((PVOID)d_sharedK, new_code, 8);
                        RtlCopyMemory((PVOID)(d_sharedK+2),(PVOID)MyTerminateProcess, 4);
                        gb_Hooked = TRUE;
                    }

                    // Offset to the "new function"
                    *MappedImTable = d_sharedM;

                    // Free MDL
                    MmUnmapLockedPages(MappedImTable, p_mdl);
                    IoFreeMdl(p_mdl);

                }
            }
        }
    }
    return STATUS_SUCCESS;
}



关键地方是,找到要替换的函数后--

p_mdl = MmCreateMdl(NULL, &pd_IAT[index], 4);
                    if(!p_mdl)
                        return STATUS_UNSUCCESSFUL;

                    MmBuildMdlForNonPagedPool(p_mdl);

                    // Change the flags of the MDL
                    p_mdl->MdlFlags = p_mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

                    MappedImTable = MmMapLockedPages(p_mdl, KernelMode);
                    
                    if (!gb_Hooked)
                    {
                        // Writing the raw opcodes to memory
                        // used a kernel address that gets mapped
                        // into the address space of all processes
                        // thanks to Barnaby Jack
                        RtlCopyMemory((PVOID)d_sharedK, new_code, 8);
                        RtlCopyMemory((PVOID)(d_sharedK+2),(PVOID)MyTerminateProcess, 4);                        
      gb_Hooked = TRUE;
                    }

                    // Offset to the "new function"
                    *MappedImTable = d_sharedM;

映射到自己的区域里面,然后替换掉就差不多了

理论上新加载一个PE文件到内存后,比如打开了任务管理器, 再用任务管理器去结束进程,应该结束不掉的吧?
可偶在虚拟机上加载驱动后, 并没有任何效果, 请问是什么原因啊?

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 116
活跃值: (220)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
2
两个错误:
1. 你在Kernel32.dll中通过IAT HOOK TerminateProcess
2. 在Detoured Code中直接Jmp到MyTerminateProcess去
2007-10-22 16:57
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
3
思路就是这样的啊
那应该如何更正呢?
2007-10-22 17:24
0
雪    币: 116
活跃值: (220)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
4
1. TerminateProcess是kernel32.dll导出的,你在IAT中去哪里找?
2. 用户层不能直接JMP到内核地址去

应该HOOK EAT
2007-10-22 17:41
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
5
1. 偶HOOK的就是IAT,不需要HOOK EAT.
PE装载器在装载一个程序时, 会把它相关的DLL装入进程的地址空间中, 再根据程序的引入函数信息,在相关DLL中查找其真实函数地址.  所以要HOOK kernel32.dll中的 TerminateProcess
(而且此书上就是HOOK 的IAT)

2. 看来大叔没有明白偶描述的意思;

RtlCopyMemory((PVOID)d_sharedK, new_code, 8);
RtlCopyMemory((PVOID)(d_sharedK+2),
(PVOID)MyTerminateProcess,4);

   
The kernel address, 0xFFDF0000, and the user address, 0x7FFE0000, both point to the same physical page. The kernel address is writable, but the user address is not. Your rootkit can write code to the kernel address and reference it as the user address in the IAT hook.        

所以其实是在RING0下修改IAT, 同一物理内存被映射到2个区域, 内核模式下修改后,在用户模式下直接调用. 区别只是前者可写,后者只读;

所以不是JMP到内核里去,而是本来就是在用户模式下执行JMP的啊
2007-10-22 18:27
0
雪    币: 116
活跃值: (220)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
6
晕倒。。。
你的MyTerminateProcess不是内核中的地址吗?

你在MyImageLoadNotify调用HookImportsOfImage(ImageInfo->ImageBase, ProcessId);
ImageInfo->ImageBase是kernel32的,你在kernel32的iat找TerminateProcess?
2007-10-22 20:23
0
雪    币: 494
活跃值: (629)
能力值: ( LV9,RANK:1210 )
在线值:
发帖
回帖
粉丝
7
MyTerminateProcess也要copy到KUSER_SHARED_DATA去,还不如直接分析EAT,
覆盖原来的API,犯不着到7FFE0000转一圈
2007-10-22 20:49
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
8
哦,

还不如直接分析EAT,
覆盖原来的API,犯不着到7FFE0000转一圈

汗, 那差不多都是RING3的东西了, RING0的程序随便检测一下就咔嚓掉了...
不过也就是了解下这种方法的原理了,嘿嘿~
-----------------------------------------------------------------------------------

不过 <Rootkits: Subverting the Windows Kernel > 一书上就是这么写的,而且代码里面也是这样的,
难道是书上错了啊?
2007-10-22 21:32
0
雪    币: 116
活跃值: (220)
能力值: ( LV12,RANK:370 )
在线值:
发帖
回帖
粉丝
9
你再仔细看看书
2007-10-23 08:16
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
10
哦,好的.
谢谢西裤大叔.
2007-10-23 12:17
0
游客
登录 | 注册 方可回帖
返回
//