读书笔记_windows下的混合钩子(HOOK)_part 3_HookImportsOfImage函数解析

HookImportsOfImage函数解析

以下是_IMAGE_DOS_HEADER的结构,是在winnt.h头文件下的,指的是DOS.exe文件的头

typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header

WORD e_magic; // Magic number

WORD e_cblp; // Bytes on last page of file

WORD e_cp; // Pages in file

WORD e_crlc; // Relocations

WORD e_cparhdr; // Size of header in paragraphs

WORD e_minalloc; // Minimum extra paragraphs needed

WORD e_maxalloc; // Maximum extra paragraphs needed

WORD e_ss; // Initial (relative) SS value

WORD e_sp; // Initial SP value

WORD e_csum; // Checksum

WORD e_ip; // Initial IP value

WORD e_cs; // Initial (relative) CS value

WORD e_lfarlc; // File address of relocation table

WORD e_ovno; // Overlay number

WORD e_res[4]; // Reserved words

WORD e_oemid; // OEM identifier (for e_oeminfo)

WORD e_oeminfo; // OEM information; e_oemid specific

WORD e_res2[10]; // Reserved words

LONG e_lfanew; // File address of new exe header

} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

PIMAGE_NT_HEADERS结构如下所示,作为PE文件的头,包含了三部分内容。

typedef struct _IMAGE_NT_HEADERS {

DWORD Signature;

IMAGE_FILE_HEADER FileHeader;

IMAGE_OPTIONAL_HEADER OptionalHeader;

} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;

PIMAGE_IMPORT_DESCRIPTOR之前介绍过,在winnt.h头文件中的定义如下:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {

union {

DWORD Characteristics; // 0 for terminating null import descriptor

DWORD OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)

};

DWORD TimeDateStamp; // 0 if not bound,

// -1 if bound, and real date\time stamp

// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)

// O.W. date/time stamp of DLL bound to (Old BIND)

DWORD ForwarderChain; // -1 if no forwarders

DWORD Name;

DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)

} IMAGE_IMPORT_DESCRIPTOR;

typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

PIMAGE_IMPORT_BY_NAME的结构如下所示:

typedef struct _IMAGE_IMPORT_BY_NAME {

WORD Hint;

BYTE Name[1];

} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

以上四个定义的结构已经完成,注意变量pc_dlltar要hook的模块名称,pc_fnctar为要hook的目标函数。

PMDL的结构如下:

//MDLreferences defined in ntddk.h
typedef struct _MDL{
struct _MDL*Next;
CSHORT Size;
CSHORT MdlFlags;
struct _EPROCESS *Process;
PVOID MappedSystemVa;
PVOID StartVa;
ULONG ByteCount;
ULONG ByteOffset;
}MDL, *PMDL;
//MDLFlags

MDL(Memory Descriptor List)内存描述表,用来描述一块内存区域,其中包含了该内存区域的起始地址、拥有者进程、字节数据以及标志。

具体函数的执行如下,每个关键语句都有中文注释

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;

// 导入的是IMAGE_INFO结构中的 PVOID ImageBase变量

dosHeader = (PIMAGE_DOS_HEADER) image_addr;

// 宏,对指针的操作

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

// 通过PE文件的Signature字段来判断该文件是否是标准的PE文件

if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE)

return STATUS_INVALID_IMAGE_FORMAT;

// 导入段的RVA

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

if ( !importsStartRVA )

return STATUS_INVALID_IMAGE_FORMAT;

// 导入段的RVA与模块在内存中的起始地址(dosHeader)相加,得到

// 指向第一个IMAGE_IMPORT_DESCRIPTOR的指针

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

// 过滤每个IMAGE_IMPORT_DESCRIPTOR

for(count = 0; importDesc[count].Characteristics != 0; count++)

{

// 得到导入模块的dll的名称

dll_name = (char*)(importDesc[count].Name + (DWORD)dosHeader);

// 得到IAT

pd_IAT = (PDWORD)(((DWORD)dosHeader) + (DWORD)importDesc[count].FirstThunk);

// 得到指向IMAGE_IMPORT_BY_NAME结构的指针数组

pd_INTO = (PDWORD)(((DWORD)dosHeader) + (DWORD)importDesc[count].OriginalFirstThunk);

// IAT中的过滤,找到特定的dll与要hook的函数

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));

// 对比dll名与函数名,找到所需要的

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

// 改变内存属性,以便修改IAT属性

// 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"

// 将“GetProcAddress”指向自己定义的函数

*MappedImTable = d_shareM;

// Free MDL

MmUnmapLoackedPages(MappedImTable, p_mdl);

IoFreeMdl(p_mdl);

}

}

}

return STATUS_SUCCESS;

}

你可能感兴趣的:(windows)