读书笔记_windows下的混合钩子(HOOK)_part 2

来源:互联网 发布:大专网络教育 编辑:程序博客网 时间:2024/06/11 16:55
 

读书笔记_windows下的混合钩子(HOOK)_part 2

1.       分析PE文件

下面接着看如果分析PE文件,从而找到其要导入的DLL。

首先看PE文件的导入数据.idata段。.idata段是导入数据,包括导入库和导入地址名称表。在WINNT.H中所定义的数据目录为:

// 目录入口

// 导出目录

#define IMAGE_DIRECTORY_ENTRY_EXPORT 0

// 导入目录

#define IMAGE_DIRECTORY_ENTRY_IMPORT 1

// 资源目录

#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2

// 异常目录

#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3

// 安全目录

#define IMAGE_DIRECTORY_ENTRY_SECURITY 4

// 重定位基本表

#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5

// 调试目录

#define IMAGE_DIRECTORY_ENTRY_DEBUG 6

// 描述字串

#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7

// 机器值(MIPS GP)

#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8

// TLS目录

#define IMAGE_DIRECTORY_ENTRY_TLS 9

// 载入配置目录

#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10

在分析PE时,首先要得到导入段(即DataDirectory的IMAGE_DIRECTROY_ENTRY_IMPORT)的RVA。将RVA与模块在内存中的起始地址相加(基地址),就会得到虚拟地址,这个地址也就是指向IMAGE_IMPORT_DESCRIPTOR的指针。

关于IMAGE_IMPORT_DESCRIPTOR的描述如下:

   IMAGE_IMPORT_DESCRIPTOR是在导入段中(Imports Section)中,DataDirectory 入口的导入点都是指向IMAGE_IMPORT_DESCRIPTOR结构的,具体的结构如下表所示:

Size

Member

Description

DWORD

OriginalFirstThunk

This field is badly named. It contains the RVA of the Import Name Table (INT). This is an array of IMAGE_THUNK_DATA structures. This field is set to 0 to indicate the end of the array of IMAGE_IMPORT_DESCRIPTORs.

DWORD

TimeDateStamp

This is 0 if this executable is not bound against the imported DLL. When binding in the old style (see the section on Binding), this field contains the time/date stamp (number of seconds since 1/1/1970 GMT) when the binding occurred. When binding in the new style, this field is set to -1.

DWORD

ForwarderChain

This is the Index of the first forwarded API. Set to -1 if no forwarders. Only used for old-style binding, which could not handle forwarded APIs efficiently.

DWORD

Name

The RVA of the ASCII string with the name of the imported DLL.

DWORD

FirstThunk

Contains the RVA of the Import Address Table (IAT). This is array of IMAGE_THUNK_DATA structures.

每个导入执行块都有一个IMAGE_IMPORT_DESCRIPTOR结构。

     通过得到第一个IMAGE_IMPORT_DESCRIPTOR结构后,由于所有的DLL都具有相应的IMAGE_IMPORT_DESCRIPTOR结构,当发现Characteristics域为0的结构时,就已经达到该模块所导入的最后一个DLL。

     每个IMAGE_IMPORT_DESCRIPTOR结构中包含指向两个独立数组的指针。其中一个是该模块从给定的DLL中导入的所有函数的地址数据指针,通过IMAGE_IMPORT_DESCRIPTOR的FirstThunk成员到达该地址表,IMAGE_IMPORT_DESCRIPTOR中的OriginalFirstThunk用于寻找指向IMAGE_IMPORT_BY_NAME结构的指针数组,这些结构包含了被导入函数的名称,除非函数是根据序号导入的。

2. HookImportsOfImage函数

来看HookImportsOfImage函数,它的功能是扫描所有模块,确定它们是否从Kernel32.dll导入了GetProcAddress函数,如果发现了这个IAT,可以首先修改IAT的内存保护机制,改变权限后就使用钩子重写IAT中的地址。来具体看HookImportsOfImage函数,

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;

              PWORD pd_IAT, pd_INTO;

              int count, index;

              char *dll_name = NULL;

              char *pc_dlltar = "kernel32.dll";

              char *pc_fnctar = "GetProcAddress";

              PMDL p_mdl;

              PDWORD MappedImTable;

              dosHeader = (PIMAGE_DOS_HEADER) image_addr;

 

              pNTHeader = MakePtr ( PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew );

 

              // First, verify that the e_lfanew field gave us a reasonable

              // pointer, then verify the PE signature.

              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_INT[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))

                                                        {

                                                                      // Use the trick you already learned to map a different

                                                                      // virtual address to the same physical page so no permission problems

                                                                      //

                                                                      // Map the memory into our domain so we can change the

                                                                      // permissions on the MDL

                                                                      p_mdl = MmCreateMdl(NULL, &pd_IAT[index], 4);

                                                                      if(!p_mdl)

                                                                                    return STATUS_UNSUCCESSFUL;

                                                                      MmBuildMdlForNonPagedPool(p_mdl);

                                                                      // Change the flags of MDL

                                                                      p_mdl->MdlFlags = p_mdl->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;

                                                                      MappedImTable = MmMapLocakedPages(p_mdl, KernelMode);

 

                                                                      // Address of the "new function"

                                                                      *MappedImTable = d_shareM;

                                                                      // Free MDL

                                                                      MmUnmapLoackedPages(MappedImTable, p_mdl);

                                                                      IoFreeMdl(p_mdl);

 

                                                        }

                                          }

                            }

                            return STATUS_SUCCESS;

 

              }

 

HookImportsOfImage是一个回调函数,每当将一个映像(进程,设备驱动程序,DLL等)加载到内存中是,都会调用它。代码已经搜索了每个映像,检查它是否导入了钩子的目标函数,如果找到该目标函数,则替换它在IAT中的地址。

 

原创粉丝点击