文章

滴水-day27-导入表注入

导入表注入

1.导入表注入

当Exe被加载时,系统会根据Exe导入表信息来加载需要用到的DLL,导入表注入的原理就是修改exe导入表,将自己的DLI添加到exe的导入表中,这样exe运行时可以将自己的DLL加载到exe的进程空间.


#include "day28.h"

using namespace std;
/**
 * @brief 该方法通过导入表注入DLL
 * @param filePath 注入目标
 * @param InjectionDll 要注入的DLL
 * @param functionName DLL中导出函数名称
 * @return 
*/

unsigned int align_up(unsigned int value, unsigned int alignment) {
	return (value + alignment - 1) & ~(alignment - 1);

}
bool MovImportAndInjectionDll(LPCSTR filePath, LPCSTR InjectionDll, LPCSTR functionName)
{
	
	if (!filePath || !InjectionDll || !functionName)return false;
	
	// 读取数据
	LPVOID fileBuffer = nullptr;
	DWORD ReadFileSize = ReadFile(filePath, &fileBuffer);
	if (!ReadFileSize)return false;
	

	// PE信息
	PEHeaders peheaders;
	if (!GetPeheadersInfo(fileBuffer, peheaders)) return false;

	// 导入表大小
	DWORD importSize = peheaders.optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;

	// 追加0x200字节
	DWORD addByte = importSize + 0x100;
	BYTE* NewFileBuffer = (BYTE*)realloc(fileBuffer, static_cast<size_t>(ReadFileSize) + static_cast<size_t>(addByte));
	memset(ReadFileSize + NewFileBuffer, 0, addByte);

	// 更新PE信息
	PEHeaders newPeheaders;
	if (!GetPeheadersInfo(NewFileBuffer, newPeheaders))
	{
		return false;
	}

	// 导入表信息
	PIMAGE_IMPORT_DESCRIPTOR importAddress = (PIMAGE_IMPORT_DESCRIPTOR)(DWORD*)((BYTE*)NewFileBuffer + RvaToFoa(newPeheaders.optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, NewFileBuffer));

	// 获取程序对齐信息
	DWORD SectionAlign = newPeheaders.optionalHeader->SectionAlignment;
	DWORD FileAlign = newPeheaders.optionalHeader->FileAlignment;

	// 获取上一个节的VirtualAddress和PointerToRawData
	PIMAGE_SECTION_HEADER LastSection = newPeheaders.sectionHeader + (newPeheaders.fileHeader->NumberOfSections - 1);

	// 新增节表
	// 确定位置
	PIMAGE_SECTION_HEADER EndSectionAddress = (PIMAGE_SECTION_HEADER)((BYTE*)newPeheaders.sectionHeader + (newPeheaders.fileHeader->NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER));

	// 节表头
	PIMAGE_SECTION_HEADER StratSectionAddress = IMAGE_FIRST_SECTION(newPeheaders.ntHeaders);

	// 复制节数据到新节表
	memcpy_s((BYTE*)EndSectionAddress, IMAGE_SIZEOF_SECTION_HEADER, (BYTE*)StratSectionAddress, IMAGE_SIZEOF_SECTION_HEADER);
	const char name[] = ".GaGa!!!";
	memcpy_s((BYTE*)EndSectionAddress->Name, IMAGE_SIZEOF_SHORT_NAME, (BYTE*)name, sizeof(name) - 1);

	// 修正PE字段
	newPeheaders.fileHeader->NumberOfSections += 0x1;
	newPeheaders.optionalHeader->SizeOfImage += addByte;

	// 修正节表属性
	EndSectionAddress->Misc.VirtualSize = addByte;
	EndSectionAddress->SizeOfRawData = addByte;
	EndSectionAddress->VirtualAddress = align_up(LastSection->VirtualAddress + LastSection->Misc.VirtualSize, SectionAlign);
	EndSectionAddress->PointerToRawData = align_up(LastSection->PointerToRawData + LastSection->SizeOfRawData, FileAlign);
	EndSectionAddress->Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;

	// 移动导入表到新节
	BYTE* NewSectionAddress = (BYTE*)NewFileBuffer + ReadFileSize;
	memcpy(NewSectionAddress,(BYTE*)importAddress, importSize);

	// 新增导入表
	PIMAGE_IMPORT_DESCRIPTOR NewEndSectionAddress = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD*)((BYTE*)NewFileBuffer + ReadFileSize + importSize - sizeof(_IMAGE_IMPORT_DESCRIPTOR)));
	// 复制头导入表信息到新导入表
	memcpy(NewEndSectionAddress, (BYTE*)importAddress, sizeof(_IMAGE_IMPORT_DESCRIPTOR));

	// 复制DLL名称
	BYTE* DllNameAddress = (BYTE*)NewEndSectionAddress + sizeof(_IMAGE_IMPORT_DESCRIPTOR) * 2;
	DWORD NameSize = strlen(InjectionDll) + 1;
	strcpy_s((char*)DllNameAddress, NameSize, InjectionDll);

	// 名称RVA
	DWORD NameRva = FoaToRva(DllNameAddress - NewFileBuffer, NewFileBuffer);
	NewEndSectionAddress->Name = NameRva;

	// 创建一个BY_NAME
	PIMAGE_IMPORT_BY_NAME By_NameAddress = (PIMAGE_IMPORT_BY_NAME)((DWORD*)((BYTE*)DllNameAddress + NameSize));
	memset(By_NameAddress, 0, 0x2);
	DWORD FuncNameSize = strlen(functionName) + 0x1;
	strcpy_s((char*)By_NameAddress + 0x2, FuncNameSize, functionName);

	DWORD By_Name_RVA = FoaToRva((BYTE*)By_NameAddress - NewFileBuffer, NewFileBuffer);

	// 创建一个长度为8的INT和IAT
	BYTE* IntAndIatAddress = (BYTE*)By_NameAddress + FuncNameSize + 0x2;
	*(DWORD*)IntAndIatAddress = By_Name_RVA;

	// IAT
	// 因为是DWORD*类型,所以加0x2就相等于加了0x8
	BYTE* IatAddress = IntAndIatAddress + 0x8;
	*((DWORD*)IatAddress) = By_Name_RVA;

	// 修复新导入表的INT和IAT
	DWORD INT_RVA = FoaToRva(IntAndIatAddress - NewFileBuffer, NewFileBuffer);
	DWORD IAT_RVA = FoaToRva(IatAddress - NewFileBuffer, NewFileBuffer);
	NewEndSectionAddress->OriginalFirstThunk = INT_RVA;
	NewEndSectionAddress->FirstThunk = IAT_RVA;

	// 修正目录项
	DWORD NewSectionRva = FoaToRva(NewSectionAddress - NewFileBuffer, NewFileBuffer);
	newPeheaders.optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = NewSectionRva;
	newPeheaders.optionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size += sizeof(_IMAGE_IMPORT_DESCRIPTOR);

	// 存盘
	FwritrFile(NewFileBuffer, ReadFileSize + addByte, filePath);

	return false;
}

License:  CC BY 4.0