这两天看了精华8的“向导入表中注入代码“这篇文章,对阅读PEMaker6源代码进行了部分注释,要不总是忘了哪一部分是什么功能,为了增加点发帖量,将注释过的几个类逐一整理后发布,老鸟就无需看了,也是为了自己加强学习。
这篇介绍CPELibrary类的功能:找回并重建PE文件(具体可参照加壳技术->加壳软件的编写->向PE中注入代码)
类定义:
class CPELibrary
{
private:
//-----------------------------------------
PCHAR pMem;
DWORD dwFileSize;
//-----------------------------------------
protected:
//-----------------------------------------
PIMAGE_DOS_HEADER image_dos_header;
PCHAR pDosStub;
DWORD dwDosStubSize, dwDosStubOffset;
PIMAGE_NT_HEADERS image_nt_headers; //指针
PIMAGE_SECTION_HEADER image_section_header[MAX_SECTION_NUM];
PCHAR image_section[MAX_SECTION_NUM];
/*typedef struct _IMAGE_TLS_DIRECTORY32 {
DWORD StartAddressOfRawData;
DWORD EndAddressOfRawData;
PDWORD AddressOfIndex;
PIMAGE_TLS_CALLBACK *AddressOfCallBacks;
DWORD SizeOfZeroFill;
DWORD Characteristics;
} IMAGE_TLS_DIRECTORY32*/
PIMAGE_TLS_DIRECTORY32 image_tls_directory;
//-----------------------------------------
protected:
//-----------------------------------------
DWORD PEAlign(DWORD dwTarNum,DWORD dwAlignTo);
void AlignmentSections();
//-----------------------------------------
DWORD Offset2RVA(DWORD dwRO);
DWORD RVA2Offset(DWORD dwRVA);
//-----------------------------------------
PIMAGE_SECTION_HEADER ImageRVA2Section(DWORD dwRVA);
PIMAGE_SECTION_HEADER ImageOffset2Section(DWORD dwRO);
//-----------------------------------------
DWORD ImageOffset2SectionNum(DWORD dwRVA);
PIMAGE_SECTION_HEADER AddNewSection(char* szName,DWORD dwSize);
//-----------------------------------------
public:
//-----------------------------------------
CPELibrary();
~CPELibrary();
//-----------------------------------------
void OpenFile(char* FileName);
void SaveFile(char* FileName);
//-----------------------------------------
};
CPP文件:
CPELibrary::CPELibrary()
{ //构造DOS文件头
image_dos_header=new (IMAGE_DOS_HEADER);
dwDosStubSize=0;
//构造NT文件头
image_nt_headers=new (IMAGE_NT_HEADERS);
//构造20个节表
for(int i=0;i<MAX_SECTION_NUM;i++) image_section_header[i]=new (IMAGE_SECTION_HEADER);
image_tls_directory=NULL;
}
//----------------------------------------------------------------
CPELibrary::~CPELibrary()
{
delete []image_dos_header;
dwDosStubSize=0;
delete []image_nt_headers;
for(int i=0;i<MAX_SECTION_NUM;i++) delete []image_section_header[i];
if(image_tls_directory!=NULL) delete image_tls_directory;
}
//================================================================
//----------------------------------------------------------------
// returns aligned value
//对齐
DWORD CPELibrary::PEAlign(DWORD dwTarNum,DWORD dwAlignTo)
{
return(((dwTarNum+dwAlignTo-1)/dwAlignTo)*dwAlignTo);
}
//----------------------------------------------------------------
void CPELibrary::AlignmentSections()
{ //根据节的数量循环
for(int i=0;i<image_nt_headers->FileHeader.NumberOfSections;i++)
{
//节中数据的RVA。
image_section_header[i]->VirtualAddress=
PEAlign(image_section_header[i]->VirtualAddress,
image_nt_headers->OptionalHeader.SectionAlignment);
//对齐Misc.VirtualSize
image_section_header[i]->Misc.VirtualSize=
PEAlign(image_section_header[i]->Misc.VirtualSize,
image_nt_headers->OptionalHeader.SectionAlignment);
//对齐PointerToRawData
image_section_header[i]->PointerToRawData=
PEAlign(image_section_header[i]->PointerToRawData,
image_nt_headers->OptionalHeader.FileAlignment);
//对齐SizeOfRawData
image_section_header[i]->SizeOfRawData=
PEAlign(image_section_header[i]->SizeOfRawData,
image_nt_headers->OptionalHeader.FileAlignment);
}
//是个RVA,重建映象文件基址
image_nt_headers->OptionalHeader.SizeOfImage=image_section_header[i-1]->VirtualAddress+
image_section_header[i-1]->Misc.VirtualSize;
image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress=0;
image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size=0;
image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0;
image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0;
image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress=0;
image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size=0;
}
//================================================================
//----------------------------------------------------------------
// 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 CPELibrary::RVA2Offset(DWORD dwRVA)
{
DWORD _offset;
PIMAGE_SECTION_HEADER section;
section=ImageRVA2Section(dwRVA);//ImageRvaToSection(pimage_nt_headers,Base,dwRVA);
if(section==NULL)
{
return(0);
}
//文件偏移
_offset=(dwRVA-section->VirtualAddress)+section->PointerToRawData;
return(_offset);
}
//----------------------------------------------------------------
// calulates the RVA from a Offset
// Base - base of the MMF
// dwRO - the Offset to calculate
// returns 0 if an error occurred else the calculated Offset will be returned
DWORD CPELibrary::Offset2RVA(DWORD dwRO)
{
PIMAGE_SECTION_HEADER section;
section=ImageOffset2Section(dwRO);
if(section==NULL)
{
return(0);
}
//返回RVA
return((dwRO-section->PointerToRawData)+section->VirtualAddress);
}
//================================================================
//----------------------------------------------------------------
PIMAGE_SECTION_HEADER CPELibrary::ImageRVA2Section(DWORD dwRVA)
{
int i;
for(i=0;i<image_nt_headers->FileHeader.NumberOfSections;i++)
{ //确定包含在哪一个节中
if((dwRVA>=image_section_header[i]->VirtualAddress) && (dwRVA<=(image_section_header[i]->VirtualAddress+image_section_header[i]->SizeOfRawData)))
{ //返回该节
return ((PIMAGE_SECTION_HEADER)image_section_header[i]);
}
}
return(NULL);
}
//----------------------------------------------------------------
//The ImageOffset2Section function locates a Off Set address (RO)
//within the image header of a file that is mapped as a file and
//returns a pointer to the section table entry for that virtual
//address.
PIMAGE_SECTION_HEADER CPELibrary::ImageOffset2Section(DWORD dwRO)
{
for(int i=0;i<image_nt_headers->FileHeader.NumberOfSections;i++)
{
//确定包含在哪一个节中
if((dwRO>=image_section_header[i]->PointerToRawData) && (dwRO<(image_section_header[i]->PointerToRawData+image_section_header[i]->SizeOfRawData)))
{ //返回该节
return ((PIMAGE_SECTION_HEADER)image_section_header[i]);
}
}
return(NULL);
}
//================================================================
//----------------------------------------------------------------
// retrieve Enrty Point Section Number
// Base - base of the MMF
// dwRVA - the RVA to calculate
// returns -1 if an error occurred else the calculated Offset will be returned
//由文件偏移到节号
DWORD CPELibrary::ImageOffset2SectionNum(DWORD dwRO)
{
for(int i=0;i<image_nt_headers->FileHeader.NumberOfSections;i++)
{
if((dwRO>=image_section_header[i]->PointerToRawData) && (dwRO<(image_section_header[i]->PointerToRawData+image_section_header[i]->SizeOfRawData)))
{
return (i);
}
}
return(-1);
}
//增加新节----------------------------------------------------------------
PIMAGE_SECTION_HEADER CPELibrary::AddNewSection(char* szName,DWORD dwSize)
{
DWORD roffset,rsize,voffset,vsize;
//最后一节
int i=image_nt_headers->FileHeader.NumberOfSections;
rsize=PEAlign(dwSize,
image_nt_headers->OptionalHeader.FileAlignment);
vsize=PEAlign(rsize,
image_nt_headers->OptionalHeader.SectionAlignment);
roffset=PEAlign(image_section_header[i-1]->PointerToRawData+image_section_header[i-1]->SizeOfRawData,
image_nt_headers->OptionalHeader.FileAlignment);
voffset=PEAlign(image_section_header[i-1]->VirtualAddress+image_section_header[i-1]->Misc.VirtualSize,
image_nt_headers->OptionalHeader.SectionAlignment);
//初始化新节表
memset(image_section_header[i],0,(size_t)sizeof(IMAGE_SECTION_HEADER));
//通过计算上一节得到
image_section_header[i]->PointerToRawData=roffset;
image_section_header[i]->VirtualAddress=voffset;
//通过传递的参数得到
image_section_header[i]->SizeOfRawData=rsize;
image_section_header[i]->Misc.VirtualSize=vsize;
//属性
image_section_header[i]->Characteristics=0xC0000040;
//新节名称
memcpy(image_section_header[i]->Name,szName,(size_t)strlen(szName));
//申请一个节的空间
image_section[i]=(char*)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,rsize);
//更新文件头
image_nt_headers->FileHeader.NumberOfSections++;
//返回新节
return (PIMAGE_SECTION_HEADER)image_section_header[i];
}
//================================================================
//----------------------------------------------------------------
void CPELibrary::OpenFile(char* FileName)
{
DWORD dwBytesRead = 0;
HANDLE hFile= NULL;
DWORD SectionNum;
DWORD i;
DWORD dwRO_first_section;
//基类成员
pMem=NULL;
//----------------------------------------
hFile=CreateFile(FileName,
GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
ShowErr(FileErr);
return;
}
dwFileSize=GetFileSize(hFile,0);
if(dwFileSize == 0)
{
CloseHandle(hFile);
ShowErr(FsizeErr);
return;
}
//不用内存映射文件,奇怪?
pMem=(char*)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,dwFileSize);
if(pMem == NULL)
{
CloseHandle(hFile);
ShowErr(MemErr);
return;
}
//读入文件
ReadFile(hFile,pMem,dwFileSize,&dwBytesRead,NULL);
//关闭句柄
CloseHandle(hFile);
//----------------------------------------
//读出DOS文件头
memcpy(image_dos_header,pMem,sizeof(IMAGE_DOS_HEADER));
//MS-DOS Stub Program(位于e_lfanew和Signature之间)
dwDosStubSize=image_dos_header->e_lfanew-sizeof(IMAGE_DOS_HEADER);
dwDosStubOffset=sizeof(IMAGE_DOS_HEADER);
pDosStub=new CHAR[dwDosStubSize];
if((dwDosStubSize&0x80000000)==0x00000000)
{
CopyMemory(pDosStub,pMem+dwDosStubOffset,dwDosStubSize);
}
//读出NT文件头
memcpy(image_nt_headers,
pMem+image_dos_header->e_lfanew,
sizeof(IMAGE_NT_HEADERS));
//DOS头大小+NT头大小
dwRO_first_section=image_dos_header->e_lfanew+sizeof(IMAGE_NT_HEADERS);
if(image_dos_header->e_magic!=IMAGE_DOS_SIGNATURE)// MZ
{
ShowErr(PEErr);
GlobalFree(pMem);
return;
}
if(image_nt_headers->Signature!=IMAGE_NT_SIGNATURE)// PE00
{
ShowErr(PEErr);
GlobalFree(pMem);
return;
}
//----------------------------------------
//节的数量
SectionNum=image_nt_headers->FileHeader.NumberOfSections;
//----------------------------------------
for( i=0;i<SectionNum;i++)
{
//读取节表,储存节表的空间已经初始化了。
CopyMemory(image_section_header[i],pMem+dwRO_first_section+i*sizeof(IMAGE_SECTION_HEADER),
sizeof(IMAGE_SECTION_HEADER));
}
//----------------------------------------
for(i=0;i<SectionNum;i++)
{
//为每个节数据分配空间,大小为每个节在文件中的大小
image_section[i]=(char*)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
PEAlign(image_section_header[i]->SizeOfRawData,
image_nt_headers->OptionalHeader.FileAlignment));
//循环读出每个节,按照文件对齐
CopyMemory(image_section[i],
pMem+image_section_header[i]->PointerToRawData,
image_section_header[i]->SizeOfRawData);
}
//是否存在TLS节----------------------------------------
if(image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress!=0)
{
//分配空间
image_tls_directory = new (IMAGE_TLS_DIRECTORY32);
//文件偏移
DWORD dwOffset=RVA2Offset(image_nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
//复制
memcpy(image_tls_directory,
pMem+dwOffset,
sizeof(IMAGE_TLS_DIRECTORY32));
}
//----------------------------------------
GlobalFree(pMem);
}
//----------------------------------------------------------------
void CPELibrary::SaveFile(char* FileName)
{
DWORD dwBytesWritten = 0;
DWORD i;
DWORD dwRO_first_section;
DWORD SectionNum;
HANDLE hFile= NULL;
pMem=NULL;
//----------------------------------------
hFile=CreateFile(FileName,
GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
hFile=CreateFile(FileName,
GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
ShowErr(FileErr);
return;
}
}
//对齐----------------------------------------
AlignmentSections();
//----------------------------------------
i=image_nt_headers->FileHeader.NumberOfSections;
//得到新文件的大小
dwFileSize=image_section_header[i-1]->PointerToRawData+
image_section_header[i-1]->SizeOfRawData;
//申请内存
pMem=(char*)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,dwFileSize);
if(pMem == NULL)
{
CloseHandle(hFile);
ShowErr(MemErr);
return;
}
//复制DOS头----------------------------------------
memcpy(pMem,image_dos_header,sizeof(IMAGE_DOS_HEADER));
//MS-DOS Stub Program
if((dwDosStubSize&0x80000000)==0x00000000)
{
memcpy(pMem+dwDosStubOffset,pDosStub,dwDosStubSize);
}
//复制NT头
memcpy(pMem+image_dos_header->e_lfanew,
image_nt_headers,
sizeof(IMAGE_NT_HEADERS));
//节表的偏移
dwRO_first_section=image_dos_header->e_lfanew+sizeof(IMAGE_NT_HEADERS);
//节的数量
SectionNum=image_nt_headers->FileHeader.NumberOfSections;
//复制节表----------------------------------------
for( i=0;i<SectionNum;i++)
{
CopyMemory(pMem+dwRO_first_section+i*sizeof(IMAGE_SECTION_HEADER),
image_section_header[i],
sizeof(IMAGE_SECTION_HEADER));
}
//复制节数据----------------------------------------
for(i=0;i<SectionNum;i++)
{
CopyMemory(pMem+image_section_header[i]->PointerToRawData,
image_section[i],
image_section_header[i]->SizeOfRawData);
}
// ----- WRITE FILE MEMORY TO DISK -----
//设置文件指针
SetFilePointer(hFile,0,NULL,FILE_BEGIN);
//写内存到磁盘
WriteFile(hFile,pMem,dwFileSize,&dwBytesWritten,NULL);
// ------ FORCE CALCULATED FILE SIZE ------
//强制计算文件大小
SetFilePointer(hFile,dwFileSize,NULL,FILE_BEGIN);
SetEndOfFile(hFile);
CloseHandle(hFile);
//----------------------------------------
GlobalFree(pMem);
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课