深入理解PE结构_导入表注入实战

PE结构学习,其实最主要的学习节表、重定位表、导入表、IAT表;

1、是学习这些表的结构,理解各个表设计的原理

2、移动、修改、修复这些表中的内容,才能真正理解各个表的意思

注入的本质是什么,注入的本质是把自己编写的dll能够贴到目标程序的4GB(针对x86系统)虚拟内存中(不管哪些注入都是这个目的)。

前边刚学过导入表,本篇就介绍导入表注入:

            通过编写代码,理解导入表各个结构的意思,并深入理解导入表的作用。

    第一步:根据数据目录项得到导入表的VA和SIZE,这2个值最后都需要修正


    第二步:需要新增的空间大小,PE32+:新增一个导入表20字节,6个字节的INT,8个字节IAT,dll字符串长度+1,函数名长度+1+2

                                                                 PE64+:新增一个导入表20字节,16个字节的INT,16个字节IAT,dll字符串长度+1,函数名长度+1+2


    第三步:判断哪个空间的空白区  >  Size(原导入表大小) + 20 + 32 + dll_Length+1 + FunctionNameLength + 3

                              或者新增一个节,新增节的时候注意,节的属性要为NewSectionHeader->Characteristics = 0xC0000040;不然可能最后代码跑不起来,我是遇到这样的问题。


    第四步:在新的导入表后边,追加一个导入表

              第五步:追加8个字节的INT表,8个字节的IAT表;PE64得追加16个字节的INT表和16个字节的IAT表

              第六步 追加一个IMAGE_BY_NAME结构,前2个字节是0,后边是函数名字符串

              第七步:将IMAGE_BY_NAME的RVA赋值给INT和IAT表中的第一项

              第八步:分配空间存储DLL名称字符串,兵将该字符串的RVA赋值给Name属性

              第九步:修正IMAGE_DATA_DIRECTORY结构中的VA和SIZE

 

#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <time.h>
//
#define DiskFileParh   "IATunstand.exe" //"notepad.exe"//"kernel32.dll" // "LearnDll.dll"//
#define SaveDll  "IATunstand_release3.exe"
#define IATInjectDllName "IATInject.dll"
#define IATInjectDllFunctionName  "IATInFun"
#define word unsigned short
#define dword unsigned int
#define ULONGLONG unsigned long long
#define OLDIMAGEBASEADDRESS 0x10000000
#define AddSectionSpec 0x00001000
struct PE_ntHeader{
	unsigned char PEsig[4];
	word	Machine;
	word	NumberOfSections;
	dword	TimeDateStamp;
	dword	PointerToSymbolTable;
	dword	NumberOfSymbols;
	word	SizeofOptionalHeader;
	word	Characteristics;
};
struct IMAGE_DATA_DICECTORY{
	dword	RVA;
	dword	SIZE;
};
struct PE_OptionalHeader32{
	word	Magic	;
	unsigned char	MajorLinkerVersion	;
	unsigned char	MinorLinkerVersion	;
	dword	SizeOfCode	;
	dword	SizeOfIntiaizeData	;
	dword	SizeOfUninitalizedData	;
	dword	AddressOfEntryPoint;	
	dword	BaseOfCode	;
	dword	BaseOfData;	
	dword	ImageBase;	
	dword	SectionAlignment	;
	dword	FileAlignment	;
	word	MajorOperationSystemVersion	;
	word	MinorOperationSystemVersion	;
	word	MajorImageVersion	;
	word	MinorImageVersion;	
	word	MajorSubSystemVersion	;
	word	MinorSubSystemVersion;	
	dword	Win32VersionVaue	;
	dword	SizeOfImage	;
	dword	SizeOfHeaders	;
	dword	CheckSum	;
	word	SubSystem	;
	word	DllCharacteristics	;
	dword	SizeOfStackReverse	;
	dword	SizeOfStackCommit	;
	dword	SIzeOfHeapReverse;	
	dword	SizeOfHeapCommit;	
	dword	LoaderFlags	;
	dword	NumberOfRvaAndSizes	;
	IMAGE_DATA_DICECTORY DataDirectory[16]	;	
};
struct PE_OptionalHeader64{
word 	Magic	;
unsigned char	MajorLinkerVersion	;
unsigned char	MinorLinkerVersion;	
dword	SizeOfCode	;
dword	SizeOfIntiaizeData	;
dword	SizeOfUninitalizedData;	
dword	AddressOfEntryPoint	;
dword	BaseOfCode	;
ULONGLONG	ImageBase	;
dword	SectionAlignment	;
dword	FileAlignment	;
word	MajorOperationSystemVersion	;
word	MinorOperationSystemVersion	;
word	MajorImageVersion	;
word	MinorImageVersion	;
word	MajorSubSystemVersion	;
word	MinorSubSystemVersion	;
dword	Win32VersionValue;	
dword	SizeOfImage	;
dword	SizeOfHeaders	;
dword	CheckSum	;
word	SubSystem	;
word	DllCharacteristics;	
ULONGLONG	SizeOfStackReverse	;
ULONGLONG	SizeOfStackCommit;	
ULONGLONG	SIzeOfHeapReverse	;
ULONGLONG	SizeOfHeapCommit;	
dword	LoaderFlags	;
dword	NumberOfRvaAndSizes	;
IMAGE_DATA_DICECTORY DataDirectory[16];	
};


struct SectionHeader{			
	unsigned char Name[8];		
	union{		
		dword	PhysicalAddress;
		dword	VirtualSize;
	}Misc;		
	dword	VirtualAddress	;
	dword	SizeOfRawData;	
	dword	PointerToRawData	;
	dword	PointerToRelocations;	
	dword	PointerToLinenumbers;	
	word	NumberOfRelocations	;
	word	NumberOfLinenumbers	;
	dword	Characteristics	;
}	;		

struct Image_Ex_Directory{		
	dword 	Characteristics;
	dword 	TimeStamp;

	word 	MajorVersion;
	word 	MinorVersion;

	dword 	Name;
	dword 	Base;
	dword 	NumberOfFunctions;
	dword 	NumberOfNames;
		
	dword 	AddressOfFunctions;
	dword 	AddressOfNames;
	dword 	AddressOfNameOrdinals;
};	
struct Image_Relocation{
	dword VirtualAddress;
	dword SizeOfBlock;
	//word TypeOffset[1];
};
struct Image_ImportTable{
 
	union {
        dword   Characteristics;// 0 for terminating null import descriptor
        dword   OriginalFirstThunk;// RVA 指向(IMAGE_THUNK_DATA)结构体数组 INT
    } INTName;
    dword   TimeDateStamp;      // 时间戳 0 if not bound                              
    dword   ForwarderChain;     // -1 if no forwarders
    dword   Name;				//RVA dll文件名称
	dword   FirstThunk;			//  RVA to IAT 导入地址表 IMAGE_THUNK_DATA数组
};
struct Image_ImportByName{		
    word    Hint;//导入函数索引		
    char   Name[1];		
};	

struct Image_Bound_Import{
    dword TimeDateStamp;                //真正的绑定时间,时间戳
    word OffsetModuleName;				//
    word NumberOfModuleForwarderRefs;  //,一个dll中可能需要导入其他的dll中的函数,这个值就是指依赖的其他dll有几个
};  
struct Module_Forwarder_Ref{
    dword TimeDateStamp;   //时间戳,检查引用的其他dll是否被更新
    dword OffsetModuleName;  //引用的其他dll的名字
    dword Reserved;  //保留(未使用)
};
int ReadDiskFileToFileBuffer(void* path,void** FileBuffer){

	FILE* fp = fopen(DiskFileParh,"rb");
	if(fp == NULL)
	{
		printf("打开磁盘文件失败!\n");
		///
		return 0;
	}

	fseek(fp,0,SEEK_END);

	long pos = ftell(fp);

	printf("磁盘文件大小为%d字节\n",pos);

	fseek(fp,0,SEEK_SET);

	void* MemFileBuffer=malloc(pos);
	if(MemFileBuffer==NULL)
		printf("分配内存失败\n");
	else
	{
		printf("分配内存成功\n");
		memset(MemFileBuffer,0,pos);
	}

	
	//memcpy(FileData,OpenFile,pos);
	fread(MemFileBuffer,pos,1,fp);

	*FileBuffer = MemFileBuffer;
	fclose(fp);
	return 1;
}
void MovFileHeadersToStub(void* lpFileBuffer,void*** lpmemBuffer)
{
		//void* lpFileBuffer=**lpmemBuffer;
		
		unsigned int* NT_offset =(unsigned int* )((unsigned char*)lpFileBuffer +  60);
		PE_ntHeader* lp_NT_header =(PE_ntHeader*)((unsigned char*)lpFileBuffer + *NT_offset);
	
		//Image_OPtional_header* lp_Optional_header =(Image_OPtional_header*)(lpFileBuffer1 + *NT_offset + 24);
		int AllHeadSize=  24  + lp_NT_header->SizeofOptionalHeader +lp_NT_header->NumberOfSections*40;

		void* MoveHead = malloc(AllHeadSize + 80);//预留2个节表的空间
		memset(MoveHead,0,AllHeadSize+80);
		memcpy(MoveHead,(unsigned char*)lpFileBuffer+*NT_offset,AllHeadSize);
		
		memset((unsigned char*)lpFileBuffer+64,0,AllHeadSize+*NT_offset-60);
		memcpy((unsigned char*)lpFileBuffer+64,MoveHead,AllHeadSize+ 80);
		*NT_offset = 0x40;
		free(MoveHead);
		
		PE_ntHeader* lp_Moved_NT_header =(PE_ntHeader*)((unsigned char*)lpFileBuffer+ *NT_offset);
		if(lp_Moved_NT_header->SizeofOptionalHeader == 0xE0)
		{
			PE_OptionalHeader32* lp_Moved_Optional_header = (PE_OptionalHeader32*)((unsigned char*)lpFileBuffer+ *NT_offset +24);
			SectionHeader*  lp_Moved_NewSection_header = (SectionHeader*)((unsigned char*)lpFileBuffer+ *NT_offset +AllHeadSize);
			SectionHeader* lp_Moved_LastSection_header= (SectionHeader*)((unsigned char*)lpFileBuffer+ *NT_offset +AllHeadSize-40);
			//修改新节表中的内容
			memset(lp_Moved_NewSection_header->Name,0,8);
			memcpy(lp_Moved_NewSection_header->Name,".NewSec",8);
			lp_Moved_NewSection_header->Misc.VirtualSize = 0x00001000;
			lp_Moved_NewSection_header->VirtualAddress=lp_Moved_Optional_header->SizeOfImage;//一种是SizeOfImage,另一种是最后一个节的内存偏移+maxsize(Misc,RawOfData)
			lp_Moved_NewSection_header->SizeOfRawData =AddSectionSpec;
			lp_Moved_NewSection_header->PointerToRawData=lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData;
			lp_Moved_NewSection_header->Characteristics=0x20000060;
		
			lp_Moved_NT_header->NumberOfSections = lp_Moved_NT_header->NumberOfSections+1;
			lp_Moved_Optional_header->SizeOfImage =lp_Moved_Optional_header->SizeOfImage + AddSectionSpec;
			//*NT_offset = 0x60;
			//0、先0x1000扩大空间
			void* lpNewFileBuffer = malloc(lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData+AddSectionSpec);
			memset(lpNewFileBuffer,0,lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData+AddSectionSpec);
			printf("lpNewFileBuffer:%x\n",lpNewFileBuffer);

			//1、把原来的内容原封不动的复制到这个大空间中。
			memcpy(lpNewFileBuffer,lpFileBuffer,lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData);
			//lpFileBuffer1 = (char*)lpNewFileBuffer;这句也是指针复制
			**lpmemBuffer = lpNewFileBuffer;
			//free(lpNewFileBuffer);
		}else if(lp_Moved_NT_header->SizeofOptionalHeader == 0xF0)
		{
			PE_OptionalHeader64* lp_Moved_Optional_header = (PE_OptionalHeader64*)((unsigned char*)lpFileBuffer+ *NT_offset +24);
			SectionHeader*  lp_Moved_NewSection_header = (SectionHeader*)((unsigned char*)lpFileBuffer+ *NT_offset +AllHeadSize);
			SectionHeader* lp_Moved_LastSection_header= (SectionHeader*)((unsigned char*)lpFileBuffer+ *NT_offset +AllHeadSize-40);
			//修改新节表中的内容
			memset(lp_Moved_NewSection_header->Name,0,8);
			memcpy(lp_Moved_NewSection_header->Name,".NewSec",8);
			lp_Moved_NewSection_header->Misc.VirtualSize = AddSectionSpec;
			lp_Moved_NewSection_header->VirtualAddress=lp_Moved_Optional_header->SizeOfImage;//一种是SizeOfImage,另一种是最后一个节的内存偏移+maxsize(Misc,RawOfData)
			lp_Moved_NewSection_header->SizeOfRawData =AddSectionSpec;
			lp_Moved_NewSection_header->PointerToRawData=lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData;
			lp_Moved_NewSection_header->Characteristics=0x20000060;
		
			lp_Moved_NT_header->NumberOfSections = lp_Moved_NT_header->NumberOfSections+1;
			lp_Moved_Optional_header->SizeOfImage =lp_Moved_Optional_header->SizeOfImage + AddSectionSpec;
			//*NT_offset = 0x60;
			//0、先0x1000扩大空间
			void* lpNewFileBuffer = malloc(lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData+AddSectionSpec);
			memset(lpNewFileBuffer,0,lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData+AddSectionSpec);
			printf("lpNewFileBuffer:%x\n",lpNewFileBuffer);

			//1、把原来的内容原封不动的复制到这个大空间中。
			memcpy(lpNewFileBuffer,lpFileBuffer,lp_Moved_LastSection_header->PointerToRawData+lp_Moved_LastSection_header->SizeOfRawData);
			//lpFileBuffer1 = (char*)lpNewFileBuffer;这句也是指针复制
			**lpmemBuffer = lpNewFileBuffer;

		}	
}
unsigned  int RvaToFoa(void* FileBuffer, int RvaAddress){

	 unsigned int* NTOffset = (unsigned int*)((char*)FileBuffer + 60);
	 PE_ntHeader* lpNtHeader=(PE_ntHeader*)((char*)FileBuffer + *NTOffset);
	 SectionHeader* SectionFirsteader = (SectionHeader*)((char*)FileBuffer + *NTOffset + 24 + lpNtHeader->SizeofOptionalHeader);
	 if(lpNtHeader->SizeofOptionalHeader == 0xE0)
	 {
		PE_OptionalHeader32* lpOPtionalHeader = (PE_OptionalHeader32*)((char*)FileBuffer + *NTOffset + 24 );
		if(RvaAddress<=lpOPtionalHeader->SizeOfHeaders)
			return RvaAddress;

	 }else if(lpNtHeader->SizeofOptionalHeader == 0xF0)
	 {
		PE_OptionalHeader64* lpOPtionalHeader = (PE_OptionalHeader64*)((char*)FileBuffer + *NTOffset + 24 );
		if(RvaAddress<=lpOPtionalHeader->SizeOfHeaders)
			return RvaAddress;
	 }

	 for(int j=lpNtHeader->NumberOfSections-1;j>=0;j--)
	 {
		 if(RvaAddress >= SectionFirsteader[j].VirtualAddress)
		 {
			 return SectionFirsteader[j].PointerToRawData + RvaAddress - SectionFirsteader[j].VirtualAddress;
			 //x-SectionFirsteader[j].PointerToRawData = RvaAddress - VirtualAddress
		 }else
			 continue;

	 }

	return 0;
}
unsigned  int FoaToRva(void* FileBuffer, int FileOffset){

	 unsigned int* NTOffset = (unsigned int*)((char*)FileBuffer + 60);
	 PE_ntHeader* lpNtHeader=(PE_ntHeader*)((char*)FileBuffer + *NTOffset);
	 SectionHeader* SectionFirsteader = (SectionHeader*)((char*)FileBuffer + *NTOffset + 24 + lpNtHeader->SizeofOptionalHeader);

	 for(int j=lpNtHeader->NumberOfSections-1;j>=0;j--)
	 {
		 if(FileOffset >= SectionFirsteader[j].PointerToRawData)
		 {
			 return FileOffset - SectionFirsteader[j].PointerToRawData +  SectionFirsteader[j].VirtualAddress;
			 //FileOffset-SectionFirsteader[j].PointerToRawData = RvaAddress(x) - VirtualAddress
		 }else
			 continue;

	 }

	return 0;
}
void AddNewSection(void* FileBuffer,void** NewFileBuffer){
	//第一种判断节区最后有80个空字节没
	//第二种移动到Dos Stub
	//第三种合并成一个节
	//第四种扩大最后一个节
	unsigned int* Nt_offset = (unsigned int*)((unsigned char*)FileBuffer+60);
	PE_ntHeader* lpNtHeader = (PE_ntHeader*)((unsigned char*)FileBuffer + *Nt_offset);
	PE_OptionalHeader32* lpOptionHead32	= (PE_OptionalHeader32*)((unsigned char*)FileBuffer + *Nt_offset + 24 );
	unsigned char* SpecNum=((unsigned char*)FileBuffer + *Nt_offset + 24 + lpNtHeader->SizeofOptionalHeader + lpNtHeader->NumberOfSections*40);

	SectionHeader* FrstSectionHeader = (SectionHeader*)((unsigned char*)FileBuffer + *Nt_offset + 24 + lpNtHeader->SizeofOptionalHeader);
	SectionHeader* LastSectionHeader = FrstSectionHeader + lpNtHeader->NumberOfSections-1;
	SectionHeader* NewSectionHeader = FrstSectionHeader + lpNtHeader->NumberOfSections;
	unsigned char i=0;
	while(SpecNum[i] == 0x0 && i<=79)
		i++;
	if(i>=79)
	{
		printf("节后空间够,可以添加新节!\n");
		//计算要添加节的空间
		//把最后一个节的内容复制到新节中
		memcpy(SpecNum,FrstSectionHeader + lpNtHeader->NumberOfSections-1,40);
		//然后修改新节的内容
		char* NewSectionName=".NewSec";
		memcpy(SpecNum,NewSectionName,8);
		NewSectionHeader->VirtualAddress = lpOptionHead32->SizeOfImage;
		NewSectionHeader->Misc.VirtualSize = AddSectionSpec;
		NewSectionHeader->SizeOfRawData = AddSectionSpec;
		NewSectionHeader->PointerToRawData = LastSectionHeader->PointerToRawData + LastSectionHeader->SizeOfRawData;
		NewSectionHeader->Characteristics = 0xC0000040;
		lpNtHeader->NumberOfSections++;
		lpOptionHead32->SizeOfImage = lpOptionHead32->SizeOfImage+AddSectionSpec;
		
		void* NewBuffer = malloc(NewSectionHeader->PointerToRawData+AddSectionSpec);
		memset(NewBuffer,0,NewSectionHeader->PointerToRawData+AddSectionSpec);
		memcpy(NewBuffer,FileBuffer,NewSectionHeader->PointerToRawData);
		*NewFileBuffer = NewBuffer;
		//存盘


	}else{

		printf("节后空间不够,需要移动、合并或者扩大节,现在采取移动头部到Dos Stub的位置!\n");

		MovFileHeadersToStub(FileBuffer,&NewFileBuffer);

		return;
	}

	
}
int _tmain(int argc, _TCHAR* argv[])
{

	void* FileBuffer = NULL;
	void* NewFileBuffer = NULL;

	ReadDiskFileToFileBuffer(DiskFileParh,&FileBuffer);
	
	if(FileBuffer==NULL)
	{
		printf("读取文件失败");
		return 0;
	}
	//PrintfDataTatDirectory(FileBuffer);
	AddNewSection(FileBuffer,&NewFileBuffer);
	
	unsigned int MovLength =0;
	MoveImportToNewSection(NewFileBuffer,MovLength);
	

	getchar();
	return 0;
}

上边是导入表注入代码。

我们还需要一个自己生成一个IATInject.dll,里面含有一个IATInFun()函数。生成动态链接库的方法,前文有介绍,这里简单介绍一下:

 先新建一个IATInject的win32项目

然后再选择DLL 项目,完成

然后在项目右键---->添加一个新的类

 

 完成之后,在我们新建的InjectTest.cpp编写导出函数和普通函数代码

 

 然后再头文件中编写函数声明

 最后再dllMain入口中编写,当exe加载dll或者卸载dll的时候弹框

 

 然后F7生成,要注入的dll

 最后我们用前边的生成的exe,把要注入的程序运行一下,注入之后,把该dll放在注入后的exe同一个目录,运行之后,就会发现已成功注入。

posted @ 2023-08-11 17:24  一日学一日功  阅读(256)  评论(0)    收藏  举报