注入技術--修改pe文件導入表進行注入


1.修改導入表,即添加一個新的導入表描述符及其iat,int. 這樣系統加載該pe文件時將自動加載添加的dll,從而實現dll注入

2.思路:

可以手工修改,但是復雜程度一點也不比寫代碼低,而且低效. 通過代碼實現可以一勞永逸.

新增一個節來存儲新的導入表. 其實也可以在原來的pe文件找空隙插入進去,但是又很難實現通用,因為不同的pe文件空隙位置大小不同.容易出錯

新增的導入表描述符通過序號導入,這樣更簡單一些

基本步驟: 修改節區數量,在原來的節區頭中添加一個節,如果空間不夠就不行了,但絕大多數pe文件的節區空間都是足夠的 ->

填好新節頭的字段->申請節內存->復制原來的導入表到新節中->增加新的導入表描述符並填寫相應字段->增加該導入表描述符的iat和int->將新增數據

寫入到文件尾部-> 修改pe文件中重要字段

以上步驟並不是嚴格順序的,因為涉及到rva, 文件偏移,各種大小的計算.

 

3.代碼:

//導入表注入

DWORD rva2offset(LPVOID base, DWORD rva)
{
	IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)base;
	IMAGE_NT_HEADERS32* ntHeader = (IMAGE_NT_HEADERS32*)(dosHeader->e_lfanew + (DWORD)base);
	IMAGE_SECTION_HEADER* sectionHeader = (IMAGE_SECTION_HEADER*)((DWORD)ntHeader + sizeof(IMAGE_NT_HEADERS32));
	if (rva<ntHeader->OptionalHeader.SizeOfHeaders)
	{
		return rva;
	}
	for (DWORD i = 1; i <= ntHeader->FileHeader.NumberOfSections; i++)
	{
		//如果到了最后一個節時,就可以直接計算了,否則可以通過前后節頭的VirtualAddress確定在哪個節中
		if (i == ntHeader->FileHeader.NumberOfSections)
		{
			return rva - sectionHeader->VirtualAddress + sectionHeader->PointerToRawData;
		}
		else if (rva >= sectionHeader->VirtualAddress && rva < (sectionHeader + 1)->VirtualAddress)
		{
			return rva - sectionHeader->VirtualAddress + sectionHeader->PointerToRawData;
		}
		sectionHeader++;
	}
	return 0;
}
//文件或者內存對齊
DWORD PEAlign(DWORD size, DWORD dwAlignTo)
{
	return(((size + dwAlignTo - 1) / dwAlignTo)*dwAlignTo);
}

DWORD importTableInject(WCHAR* modulepath,char* dllpath)//dllpath傳入dll的名字,而不是路徑
{
	//先備份源文件
	WCHAR newFile[MAX_PATH];

	wsprintf(newFile, L"%s.bak", modulepath);
	CopyFileW(modulepath, newFile, 0);
	HANDLE hFile = CreateFileW(modulepath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile==0||hFile==INVALID_HANDLE_VALUE)
	{
		return 0;
	}
	DWORD fileSize = GetFileSize(hFile, 0);
	HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READWRITE, 0, 0 , 0);
	if (hMap<=0)
	{
		CloseHandle(hFile);
		return 0;
	}
	LPVOID imagebase = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
	if (imagebase==0)
	{
		CloseHandle(hFile);
		CloseHandle(hMap);
		return 0;
	}
	PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS32)((DWORD)imagebase + ((PIMAGE_DOS_HEADER)(imagebase))->e_lfanew);
	if ((ntHeader->FileHeader.NumberOfSections+1)*sizeof(IMAGE_SECTION_HEADER)>ntHeader->OptionalHeader.SizeOfHeaders)
	{
		CloseHandle(hFile);
		CloseHandle(hMap);
		return 0;
	}
	//定位到最后一個節區的最外面地址,就是nt頭最后的尾部
	PIMAGE_SECTION_HEADER newSection = (PIMAGE_SECTION_HEADER)(ntHeader + 1) + ntHeader->FileHeader.NumberOfSections;

	//添加節區頭
	memcpy(newSection->Name, "freesec", 8); //節區頭名字最多為8個字節,包括結尾的\0
	newSection->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
	newSection->Misc.VirtualSize =  //添加一個dll信息,所以在原來大小的基礎上加一個導入表描述符大小加dll名字字符串大小+4個IMAGE_THUNK_DATA32大小
		ntHeader->OptionalHeader.DataDirectory[1].Size + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(dllpath) + 1  + sizeof(IMAGE_THUNK_DATA32) * 4;
	newSection->NumberOfLinenumbers = 0;
	newSection->NumberOfRelocations = 0;
	newSection->PointerToLinenumbers = 0;
	newSection->PointerToRawData = (newSection-1)->PointerToRawData+(newSection-1)->SizeOfRawData;
	newSection->PointerToRelocations = 0;
	newSection->VirtualAddress = (newSection - 1)->VirtualAddress + PEAlign((newSection - 1)->SizeOfRawData, ntHeader->OptionalHeader.SectionAlignment);
	newSection->SizeOfRawData = PEAlign(newSection->Misc.VirtualSize, ntHeader->OptionalHeader.FileAlignment);
	DWORD sectionSize = newSection->SizeOfRawData;
	//添加節表
	SetFilePointer(hFile, 0, 0, FILE_END); //文件指針向文件尾部
	LPVOID content = malloc(newSection->SizeOfRawData);
	memset(content, 0, newSection->SizeOfRawData);
	char* p = (char*)content;
	memcpy(content, (LPVOID)((DWORD)imagebase+rva2offset(imagebase, ntHeader->OptionalHeader.DataDirectory[1].VirtualAddress)), ntHeader->OptionalHeader.DataDirectory[1].Size-sizeof(IMAGE_IMPORT_DESCRIPTOR));
	
	p =(char*)((DWORD)p + ntHeader->OptionalHeader.DataDirectory[1].Size - sizeof(IMAGE_IMPORT_DESCRIPTOR));
	((PIMAGE_IMPORT_DESCRIPTOR)p)->OriginalFirstThunk = newSection->VirtualAddress + ntHeader->OptionalHeader.DataDirectory[1].Size + sizeof(IMAGE_IMPORT_DESCRIPTOR) + strlen(dllpath) + 1;
	((PIMAGE_IMPORT_DESCRIPTOR)p)->FirstThunk = ((PIMAGE_IMPORT_DESCRIPTOR)p)->OriginalFirstThunk + sizeof(IMAGE_THUNK_DATA32)*2;
	((PIMAGE_IMPORT_DESCRIPTOR)p)->ForwarderChain = 0;
	((PIMAGE_IMPORT_DESCRIPTOR)p)->Name = newSection->VirtualAddress + ntHeader->OptionalHeader.DataDirectory[1].Size + sizeof(IMAGE_IMPORT_DESCRIPTOR);
	((PIMAGE_IMPORT_DESCRIPTOR)p)->TimeDateStamp = 0;
	p += sizeof(IMAGE_IMPORT_DESCRIPTOR)*2; //越過新增節和空節尾
	
	//導入表描述符中的name字段,注意2者之間rva的關聯
	memcpy(p, dllpath, strlen(dllpath)+1);
	p += strlen(dllpath) + 1;
	//添加注入的dll的iat和int.4個元素,前2個是給iat的,后2個給int的均以
	IMAGE_THUNK_DATA32 ixt[4] = { 0 };
	ixt[0].u1.AddressOfData |= 0x80000000; //將最高位置1,表示是以序號導入
	ixt[0].u1.AddressOfData += 1;
	ixt[2].u1.AddressOfData |= 0x80000000; //將最高位置1,表示是以序號導入
	ixt[2].u1.AddressOfData += 1;
	memcpy(p, ixt, 4 * sizeof(IMAGE_THUNK_DATA32));

	//修改必要字段
	ntHeader->FileHeader.NumberOfSections++;
	ntHeader->OptionalHeader.SizeOfImage += newSection->SizeOfRawData;
	//綁定導入表改為0,保險一些
	ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
	ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
	ntHeader->OptionalHeader.DataDirectory[1].VirtualAddress = newSection->VirtualAddress;
	ntHeader->OptionalHeader.DataDirectory[1].Size = newSection->Misc.VirtualSize;
	UnmapViewOfFile(imagebase); //這個操作需要在writefile之前調用
	if (!WriteFile(hFile, content, sectionSize, 0, 0))
	{
		
		CloseHandle(hMap);
		CloseHandle(hFile);
		free(content);
		return 0;
	}
	CloseHandle(hMap);
	CloseHandle(hFile);
	free(content);
	return 1;
}
//end 導入表注入

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM