注入(5)---导入表注入(HookINT)

导入表是WindowsPE文件中的一组数据结构,可执行程序(即EXE文件)被加载到地址空间后,每个导入的DLL模块都有一个对应的导入表,PE加载器会根据导入表来加载进程需要的其他DLL模块。
导入表的数据结构如下:

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date	ime 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;


OriginalFirstThunk/Characteristics:指向导入表(INT)的RVA(相对虚拟地址)。INT是一个IMAGE_THUNK_DATA结构的数组,数组中的每个元素指向一个IMAGE_IMPORT_BY_NAME结构,INT以元素0结束。
TimeDateStamp:时间戳,可以忽略。
ForwarderChain:如果没有前向引用(forwarders)的话就是-1.
Name:被导入DLL的名字指针,是一个RVA。
FirstThunk:指向导入表(IAT)的RVA。IAT是一个IMAGE_THUNK_DATA结构的数组。

导入表逻辑结构如下:

下面贴出源码:


// INTHook.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<Windows.h>
#include <exception>
#include <iostream>
using namespace std;

BOOL AddImportTable(const WCHAR * wzPEFilePath, char * szInjectDllName, char *szFunctionName);
BOOL AddNewImportDescriptor(const WCHAR * wzPEFilePath, char * szInjectDllName, char *szImportFunctionName);
BOOL AddNewSection(LPCTSTR lpModulePath, DWORD dwNewSectionSize);
DWORD PEAlign(DWORD dwTarNumber, DWORD dwAlignTo);
DWORD RVAToOffset(PIMAGE_NT_HEADERS pImageNTHeader, DWORD dwRVA);
PIMAGE_SECTION_HEADER ImageRVAToSection(PIMAGE_NT_HEADERS pImageNTHeader, DWORD dwRVA);
int main()
{
	WCHAR TargetPath[0x20] = {0};
	char DllPath[0x20] = "InjectDll.dll";

	printf("Please Input Target Full Path:
");
	//scanf_s(TargetPath, "%s");
	wcin >> TargetPath;
	AddImportTable(TargetPath,DllPath, "InjectFunction");

    return 0;
}

BOOL AddImportTable(const WCHAR * wzPEFilePath, char * szInjectDllName, char *szFunctionName)
{
	BOOL bOk = FALSE;
	try
	{
		//增加一个叫"WINSUN"的节
		bOk = AddNewSection(wzPEFilePath, 256);
		if (!bOk)
		{
			MessageBox(NULL, L"Add New Section Fail", L"Error", MB_OK);
			return bOk;
		}
		//增加一个导入表
		AddNewImportDescriptor(wzPEFilePath, szInjectDllName, szFunctionName);
	}
	catch (exception* e)
	{
		return bOk;
	}
	return bOk;
}


//
//增加导入表项
//
BOOL AddNewSection(LPCTSTR lpModulePath, DWORD dwNewSectionSize)
{
	BOOL   bOk = FALSE;
	LPVOID lpMemoryModule = NULL;
	LPBYTE lpData = NULL;
	DWORD  dwNewSectionFileSize, dwNewSectionMemorySize;
	HANDLE FileHandle = INVALID_HANDLE_VALUE, MappingHandle = INVALID_HANDLE_VALUE;
	PIMAGE_NT_HEADERS NtHeader = NULL;
	PIMAGE_SECTION_HEADER NewSection = NULL, LastSection = NULL;

	printf("[!] AddNewSection Enter!
");

	//TODO:可能还涉及关闭windows文件保护
	__try
	{
		//pe文件映射到内存
		FileHandle = CreateFile(
			lpModulePath,
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ | FILE_SHARE_WRITE,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL
		);
		if (INVALID_HANDLE_VALUE == FileHandle)
		{
			printf("[-] AddNewSection CreateFile Fail!
");
			goto _EXIT_;
		}

		DWORD dwFileLength = GetFileSize(FileHandle, NULL);
		//映射PE文件
		MappingHandle = CreateFileMapping(FileHandle, NULL, PAGE_READWRITE/* | SEC_IMAGE*/, 0, dwFileLength,L"WINSUN_MAPPING_FILE");
		if (NULL == MappingHandle)
		{

			printf("[-] AddNewSection CreateFileMapping Fail!
");
			goto _EXIT_;

		}

		lpMemoryModule = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, dwFileLength);
		if (NULL == lpMemoryModule)
		{
			printf("[-] AddNewSection MapViewOfFile Fail!
");
			goto _EXIT_;
		}

		lpData = (LPBYTE)lpMemoryModule;
		//判断是否是PE文件
		if (((PIMAGE_DOS_HEADER)lpData)->e_magic != IMAGE_DOS_SIGNATURE)
		{
			printf("[-] AddNewSection PE Header MZ error!
");
			goto _EXIT_;
		}

		NtHeader = (PIMAGE_NT_HEADERS)(lpData + ((PIMAGE_DOS_HEADER)(lpData))->e_lfanew);
		if (NtHeader->Signature != IMAGE_NT_SIGNATURE)
		{
			printf("[-] AddNewSection PE Header PE Error!
");
			goto _EXIT_;
		}

		//判断是否可以增加一个新节
		if (((NtHeader->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER)) > (NtHeader->OptionalHeader.SizeOfHeaders))
		{
			printf("[-] AddNewSection Cannot Add A New Section!
");
			goto _EXIT_;
		}

		NewSection = (PIMAGE_SECTION_HEADER)(NtHeader + 1) + NtHeader->FileHeader.NumberOfSections;
		LastSection = NewSection - 1;


		DWORD rSize, vSize, rOffset, vOffset;
		//对齐偏移和RVA
		rSize = PEAlign(dwNewSectionSize,
			NtHeader->OptionalHeader.FileAlignment);

		rOffset = PEAlign(LastSection->PointerToRawData + LastSection->SizeOfRawData,
			NtHeader->OptionalHeader.FileAlignment);

		vSize = PEAlign(dwNewSectionSize,
			NtHeader->OptionalHeader.SectionAlignment);

		vOffset = PEAlign(LastSection->VirtualAddress + LastSection->Misc.VirtualSize,
			NtHeader->OptionalHeader.SectionAlignment);

		//填充新节表
		memcpy(NewSection->Name, "WINSUN", strlen("WINSUN"));
		NewSection->VirtualAddress = vOffset;
		NewSection->PointerToRawData = rOffset;
		NewSection->Misc.VirtualSize = vSize;
		NewSection->SizeOfRawData = rSize;
		NewSection->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;

		//修改IMAGE_NT_HEADERS,增加新节表
		NtHeader->FileHeader.NumberOfSections++;
		NtHeader->OptionalHeader.SizeOfImage += vSize;
		NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
		NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;

		//增加新节到文件尾部
		DWORD dwWriteBytes;
		SetFilePointer(FileHandle, 0, 0, FILE_END);
		PBYTE pbNewSectionContent = new BYTE[rSize];
		ZeroMemory(pbNewSectionContent, rSize);
		bOk = WriteFile(FileHandle, pbNewSectionContent, rSize, &dwWriteBytes, NULL);
		if (!bOk)
		{
			MessageBox(NULL, L"新增节失败", L"Error", MB_OK);
			goto _EXIT_;
		}

	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		printf("[-] AddImportTableItem  Exception!
");
		return false;
	}
	printf("[!] AddNewSection Exit!
");
	bOk = true;
_EXIT_:

	if (FileHandle)
	{
		CloseHandle(FileHandle);
	}

	if (lpMemoryModule)
	{
		UnmapViewOfFile(lpMemoryModule);
	}

	if (MappingHandle)
	{
		CloseHandle(MappingHandle);
	}
	return true;
}
//内存对齐
DWORD PEAlign(DWORD dwTarNumber, DWORD dwAlignTo)
{
	return(((dwTarNumber + dwAlignTo - 1) / dwAlignTo)*dwAlignTo);
}

//增加一个导入表
BOOL AddNewImportDescriptor(const WCHAR * wzPEFilePath, char * szInjectDllName, char *szImportFunctionName)
{
	BOOL bOk = FALSE;
	LPVOID lpMemoryModule = NULL;
	LPBYTE lpData = NULL;
	DWORD  dwNewSecFileSize, dwNewSecMemSize;
	HANDLE FileHandle = INVALID_HANDLE_VALUE, MappingHandle = INVALID_HANDLE_VALUE;
	PIMAGE_NT_HEADERS NtHeader = NULL;
	PIMAGE_IMPORT_DESCRIPTOR ImportTable = NULL;
	PIMAGE_SECTION_HEADER    SectionHeader = NULL;
	__try
	{
		//pe文件映射到内存
		FileHandle = CreateFile(
			wzPEFilePath,
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_READ | FILE_SHARE_WRITE,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL
		);
		if (INVALID_HANDLE_VALUE == FileHandle)
		{
			printf("[-] AddNewImportDescriptor CreateFile fail!
");
			goto _EXIT_;
		}

		DWORD dwFileLength = GetFileSize(FileHandle, NULL);
		MappingHandle = CreateFileMapping(FileHandle, NULL, PAGE_READWRITE/* | SEC_IMAGE*/, 0, dwFileLength,L"WINSUN_MAPPING_FILE");
		if (NULL == MappingHandle)
		{

			printf("[-] AddNewImportDescriptor CreateFileMapping fail!
");
			goto _EXIT_;

		}

		lpMemoryModule = MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, dwFileLength);
		if (NULL == lpMemoryModule)
		{
			printf("[-] AddNewImportDescriptor MapViewOfFile fail!
");
			goto _EXIT_;
		}

		lpData = (LPBYTE)lpMemoryModule;
		//判断是否是PE
		if (((PIMAGE_DOS_HEADER)lpData)->e_magic != IMAGE_DOS_SIGNATURE)
		{
			printf("[-] AddNewImportDescriptor PE Header MZ error!
");
			goto _EXIT_;
		}

		NtHeader = (PIMAGE_NT_HEADERS)(lpData + ((PIMAGE_DOS_HEADER)(lpData))->e_lfanew);
		if (NtHeader->Signature != IMAGE_NT_SIGNATURE)
		{
			printf("[-] AddNewImportDescriptor PE Header PE error!
");
			goto _EXIT_;
		}
		ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)(lpData + RVAToOffset(NtHeader, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
		BOOL bBoundImport = FALSE;
		if (ImportTable->Characteristics == 0 && ImportTable->FirstThunk != 0)
		{
			bBoundImport = TRUE;
			NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
			NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
		}

		SectionHeader = (PIMAGE_SECTION_HEADER)(NtHeader + 1) + NtHeader->FileHeader.NumberOfSections - 1;
		PBYTE pbNewSection = SectionHeader->PointerToRawData + lpData;
		int i = 0;
		while (ImportTable->FirstThunk != 0)
		{
			memcpy(pbNewSection, ImportTable, sizeof(IMAGE_IMPORT_DESCRIPTOR));
			ImportTable++;
			pbNewSection += sizeof(IMAGE_IMPORT_DESCRIPTOR);
			i++;
		}
		memcpy(pbNewSection, (pbNewSection - sizeof(IMAGE_IMPORT_DESCRIPTOR)), sizeof(IMAGE_IMPORT_DESCRIPTOR));



		DWORD dwDelt = SectionHeader->VirtualAddress - SectionHeader->PointerToRawData;

		//avoid import not need table
		PIMAGE_THUNK_DATA pImgThunkData = (PIMAGE_THUNK_DATA)(pbNewSection + sizeof(IMAGE_IMPORT_DESCRIPTOR) * 2);



		//import dll name
		PBYTE pszDllNamePosition = (PBYTE)(pImgThunkData + 2);
		memcpy(pszDllNamePosition, szInjectDllName, strlen(szInjectDllName));
		pszDllNamePosition[strlen(szInjectDllName)] = 0;

		//确定IMAGE_IMPORT_BY_NAM的位置
		PIMAGE_IMPORT_BY_NAME pImgImportByName = (PIMAGE_IMPORT_BY_NAME)(pszDllNamePosition + strlen(szInjectDllName) + 1);


		//init IMAGE_THUNK_DATA
		pImgThunkData->u1.Ordinal = dwDelt + (DWORD)pImgImportByName - (DWORD)lpData;


		//init IMAGE_IMPORT_BY_NAME
		pImgImportByName->Hint = 1;
		memcpy(pImgImportByName->Name, szImportFunctionName, strlen(szImportFunctionName)); //== dwDelt + (DWORD)pszFuncNamePosition - (DWORD)lpData ;
		pImgImportByName->Name[strlen(szImportFunctionName)] = 0;
		//init OriginalFirstThunk
		if (bBoundImport)
		{
			((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->OriginalFirstThunk = 0;
		}
		else
			((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->OriginalFirstThunk = dwDelt + (DWORD)pImgThunkData - (DWORD)lpData;
		//init FirstThunk
		((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->FirstThunk = dwDelt + (DWORD)pImgThunkData - (DWORD)lpData;
		//init Name
		((PIMAGE_IMPORT_DESCRIPTOR)pbNewSection)->Name = dwDelt + (DWORD)pszDllNamePosition - (DWORD)lpData;

		//改变导入表
		NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = SectionHeader->VirtualAddress;
		NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (i + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);


	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		printf("[-] AddNewImportDescriptor  Exception!
");
		return false;
	}

_EXIT_:

	if (FileHandle)
	{
		CloseHandle(FileHandle);
	}

	if (lpMemoryModule)
	{
		UnmapViewOfFile(lpMemoryModule);
	}

	if (MappingHandle)
	{
		CloseHandle(MappingHandle);
	}
	return true;
}

//
// calulates the Offset from a RVA
// Base    - base of the MMF
// dwRVA - the RVA to calculate
// returns 0 if an error occurred else the calculated Offset will be returned
DWORD RVAToOffset(PIMAGE_NT_HEADERS pImageNTHeader, DWORD dwRVA)
{
	DWORD _offset;
	PIMAGE_SECTION_HEADER section;
	section = ImageRVAToSection(pImageNTHeader, dwRVA);//ImageRvaToSection(pimage_nt_headers,Base,dwRVA);
	if (section == NULL)
	{
		return(0);
	}
	_offset = dwRVA + section->PointerToRawData - section->VirtualAddress;
	return(_offset);
}

PIMAGE_SECTION_HEADER ImageRVAToSection(PIMAGE_NT_HEADERS pImageNTHeader, DWORD dwRVA)
{
	int i;
	PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pImageNTHeader + 1);
	for (i = 0; i<pImageNTHeader->FileHeader.NumberOfSections; i++)
	{
		if ((dwRVA >= (pSectionHeader + i)->VirtualAddress) && (dwRVA <= ((pSectionHeader + i)->VirtualAddress + (pSectionHeader + i)->SizeOfRawData)))
		{
			return ((PIMAGE_SECTION_HEADER)(pSectionHeader + i));
		}
	}
	return(NULL);
}



原文地址:https://www.cnblogs.com/Toring/p/6628280.html