此程式用來仿真PE加載器,可以直接運作記憶體中的程式。
bool PELoader(char *lpStaticPEBuff, long lStaticPELen)
{
long lPESignOffset = *(long *)(lpStaticPEBuff + 0x3c);
IMAGE_NT_HEADERS *pINH = (IMAGE_NT_HEADERS *)(lpStaticPEBuff + lPESignOffset);
//取加載到記憶體中大小
long lImageSize = pINH->OptionalHeader.SizeOfImage;
char *lpDynPEBuff = new char[lImageSize];
if(lpDynPEBuff == NULL)
{
return false;
}
memset(lpDynPEBuff, 0, lImageSize);
//取PE檔案的節數量
long lSectionNum = pINH->FileHeader.NumberOfSections;
//計算PE頭資訊及節表資訊占用記憶體大小
long lPEHeadSize = lPESignOffset + sizeof(IMAGE_NT_HEADERS) + lSectionNum * sizeof(IMAGE_SECTION_HEADER);
//加載PE頭部資訊及其各個節表
memcpy(lpDynPEBuff, lpStaticPEBuff, lPEHeadSize);
//加載各個節
long lFileAlignMask = pINH->OptionalHeader.FileAlignment - 1; //各節在磁盤中的對齊掩碼
long lSectionAlignMask = pINH->OptionalHeader.SectionAlignment - 1; //各節在load後記憶體中的對齊掩碼
IMAGE_SECTION_HEADER *pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + sizeof(IMAGE_NT_HEADERS));
for(int nIndex = 0; nIndex < lSectionNum; nIndex++, pISH++)
{
//判定各節的對齊屬性,合法不
if((pISH->VirtualAddress & lSectionAlignMask) || (pISH->SizeOfRawData & lFileAlignMask))
{
//出現非法節
delete lpDynPEBuff;
return false;
}
//加載改節
memcpy(lpDynPEBuff + pISH->VirtualAddress, lpStaticPEBuff + pISH->PointerToRawData, pISH->SizeOfRawData);
}
//修改導入表,導入程式執行過程中要用到的API函數位址
if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0) //大于0說明有導入表
{
IMAGE_IMPORT_DESCRIPTOR *pIID = (IMAGE_IMPORT_DESCRIPTOR *)(lpDynPEBuff + /
pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
//循環掃描每個将有函數導入的dll
for(; pIID->Name != NULL; pIID++)
{
IMAGE_THUNK_DATA *pITD = (IMAGE_THUNK_DATA *)(lpDynPEBuff + pIID->FirstThunk);
HINSTANCE hInstance = LoadLibrary(lpDynPEBuff + pIID->Name);
if(hInstance == NULL)
{
//導入這個dll失敗
delete lpDynPEBuff;
return false;
}
//循環掃描dll内每個被導入函數
for(; pITD->u1.Ordinal != 0; pITD++)
{
FARPROC fpFun;
if(pITD->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
{
//函數是以序号的方式導入的
fpFun = GetProcAddress(hInstance, (LPCSTR)(pITD->u1.Ordinal & 0x0000ffff));
}
else
{
//函數是以名稱方式導入的
IMAGE_IMPORT_BY_NAME * pIIBN = (IMAGE_IMPORT_BY_NAME *)(lpDynPEBuff + pITD->u1.Ordinal);
fpFun = GetProcAddress(hInstance, (LPCSTR)pIIBN->Name);
}
if(fpFun == NULL)
{
//導出這個函數失敗
delete lpDynPEBuff;
return false;
}
pITD->u1.Ordinal = (long)fpFun;
}
FreeLibrary(hInstance);
}
}
//重定位處理
if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
{
//取第一個重定位塊
IMAGE_BASE_RELOCATION *pIBR = (IMAGE_BASE_RELOCATION *)(lpDynPEBuff + /
pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
long lDifference = (long)lpDynPEBuff - pINH->OptionalHeader.ImageBase;
//循環每個重定位塊
for(; pIBR->VirtualAddress != 0; )
{
char *lpMemPage = lpDynPEBuff + pIBR->VirtualAddress;
long lCount = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1;
//對這個頁面中的每個需重定位的項進行處理
short int *pRelocationItem = (short int *)((char *)pIBR + sizeof(IMAGE_BASE_RELOCATION));
for(int nIndex = 0; nIndex < lCount; nIndex++)
{
int nOffset = pRelocationItem[nIndex] &0x0fff;
int nType = pRelocationItem[nIndex] >> 12;
//雖然windows定義了很多重定位類型,但是在PE檔案中隻能見到0和3兩種
if(nType == 3)
{
*(long *)(lpDynPEBuff + nOffset) += lDifference;
}
else if(nType == 0)
{
//什麼也不做
}
}
//pIBR指向下一個重定位塊
pIBR = (IMAGE_BASE_RELOCATION *)(pRelocationItem + lCount);
}
}
delete lpDynPEBuff;
return true;
}