主要目的 熟悉PE文件
創建句柄 映射pe文件到地址空間 創建文件視圖 得到文件的首地址 PIMAGE
然後對各個結構進行初始化
主要代碼
導入表
void GETIMPORT(PVOID PIMAGE)
{
PBYTE PBIMAGE = (PBYTE)PIMAGE;
DWORD IMPORTRAW = 0;
DWORD CNTDLL=0;
DWORD IMPORTRVA = pe.DATA[1].VirtualAddress;
PIMAGE_SECTION_HEADER PIMPORTSEC;
for (int i=0; i<pe.FILE->NumberOfSections; i++)
{
if (IMPORTRVA>=a[i] && IMPORTRVA<=b[i])
{
IMPORTRAW = IMPORTRVA - pe.SECTION[i].VirtualAddress + pe.SECTION[i].PointerToRawData; //RVA->RAW計算文件偏移
PIMPORTSEC = &pe.SECTION[i]; //記錄輸入表所在節
}
}
if(!IMPORTRVA)
{
MessageBox(NULL,"IMPORT IS EMOPTY","ERROR",NULL);
return;
}
PIMAGE_IMPORT_DESCRIPTOR IMPORT = PIMAGE_IMPORT_DESCRIPTOR(IMPORTRAW+PBIMAGE); //使用輸入表的文件地址
//因爲一般OriginalFirstThunk不爲0 所以採用這個判斷條件 其實是不嚴謹的
//有的程序OriginalFirstThunk是爲0的 這樣的話 就採用FIRSTTHUNK來循環遍歷 在此未考慮爲0的情況
//不過也用了FIRSTTHUNK 目的是利用它得到每個函數的 RVA
while (0 != IMPORT->OriginalFirstThunk) //判斷dll是否結束
{
LPDWORD THUNK =(LPDWORD) (IMPORT->OriginalFirstThunk - PIMPORTSEC->VirtualAddress
+ PIMPORTSEC- >PointerToRawData+PBIMAGE);
LPDWORD FIRSTTHUNK = (LPDWORD)IMPORT->FirstThunk;
//THUNK 使用OriginalFirstThunk 來遍歷每一個 PIMAGE_THUNK_DATA (四個字節大小) 的結構
//FIRSTTHUNK 使用FirstThunk 來遍歷每一個 PIMAGE_THUNK_DATA (四個字節大小) 的結構
//在這裏使用它找到每個函數的RVA
/*****************************************************************************************************/
//要想得到dll 或者 函數的名字 都要計算出其在磁盤上的位置 方可取出
LPDWORD DLLNAME = (LPDWORD)(IMPORT->Name - PIMPORTSEC->VirtualAddress +
PIMPORTSEC->PointerToRawData + PBIMAGE);
CHAR NAMEBUF[20];
sprintf(NAMEBUF,"%s",DLLNAME);
DWORD NAMEBUFFER = strlen(NAMEBUF);
DWORD STYLE;
WriteFile(IMPORTHANDLE,"\r\n",2,&STYLE,NULL);
WriteFile(IMPORTHANDLE,NAMEBUF,NAMEBUFFER,&NAMEBUFFER,NULL);
WriteFile(IMPORTHANDLE,"\r\n",2,&NAMEBUFFER,NULL);
WriteFile(IMPORTHANDLE,"\r\n",2,&NAMEBUFFER,NULL);
/* 這段代碼是 得到每個引入的dll的名字 並且在循環輸出函數索引和名字之前 輸出此函數所在的這個dll名字*/
/*****************************************************************************************************/
//THUNK指針保存的值是OriginalFirstThunk指向的PIMAGE_THUNK_DATA結構 即這是判斷函數是否結束
// *THUNK就是 PIMAGE_THUNK_DATA (四個字節大小) 結構的內容
// 此內容是一個RVA 指向PIMAGE_IMPORT_BY_NAME 轉換成 RAW後 所保存的內容就是函數名字和索引
while(*THUNK)
{
if (*THUNK & IMAGE_ORDINAL_FLAG32) //最高位是1 是序號引入
{
DWORD index = (*THUNK & 0x7fffffff);
CHAR BUFFER[20];
DWORD REALBUFFER;
sprintf(BUFFER,"0x%x",index);
WriteFile(IMPORTHANDLE,BUFFER,4,&REALBUFFER,NULL);
WriteFile(IMPORTHANDLE,"\r",2,&REALBUFFER,NULL);
CHAR FRISTTHUNK[20];
sprintf(FRISTTHUNK,"0x%x",FIRSTTHUNK);
WriteFile(IMPORTHANDLE,FRISTTHUNK,8,&REALBUFFER,NULL);
WriteFile(IMPORTHANDLE,"\r\n",2,&REALBUFFER,NULL);
}
else
{
/*
計算得到 PIMAGE_IMPORT_BY_NAME 結構的磁盤位置
*THUNK就是 PIMAGE_THUNK_DATA (四個字節大小) 結構的內容
此內容是一個RVA 指向PIMAGE_IMPORT_BY_NAME 結構 將其轉換成 RAW後 所保存的內容就是索引和函數名字
FIRSTTHUNK 此時也是PIMAGE_THUNK_DATA的內容
當加載到內存後 纔會 被換成 函數的真實地址 所以在這裏只是取出 FIRSTTHUNK 的值 即一個RVA
因爲此時 *FIRSTTHUNK 的內容跟 *THUNK 是一模一樣的
*/
PIMAGE_IMPORT_BY_NAME NAME = PIMAGE_IMPORT_BY_NAME(*THUNK - PIMPORTSEC->VirtualAddress
+ PIMPORTSEC->PointerToRawData + PBIMAGE);
/*********************************************************************************************************************/
// 輸出 PIMAGE_IMPORT_BY_NAME 結構中的HINT
CHAR BUFFER[10];
DWORD REALBUFFER;
sprintf(BUFFER,"0x%x",NAME->Hint);
WriteFile(IMPORTHANDLE,BUFFER,5,&REALBUFFER,NULL);
WriteFile(IMPORTHANDLE,"\r",2,&REALBUFFER,NULL);
/*********************************************************************************************************************/
//輸出 PIMAGE_IMPORT_BY_NAME 結構中的NAME
CHAR BUF[30];
DWORD LEN ;
sprintf(BUF,"%s",NAME->Name);
LEN=strlen(BUF)+1;
WriteFile(IMPORTHANDLE,NAME->Name,LEN,&REALBUFFER,NULL);
/*********************************************************************************************************************/
//輸出 PIMAGE_THUNK_DATA 結構的內容 即 指向 PIMAGE_IMPORT_BY_NAME 結構的RVA
CHAR THUNKBUF[20];
sprintf(THUNKBUF,"0x%x",*THUNK);
WriteFile(IMPORTHANDLE,THUNKBUF,8,&REALBUFFER,NULL);
WriteFile(IMPORTHANDLE,"\r",2,&REALBUFFER,NULL);
/*********************************************************************************************************************/
//輸出 FRISTTHUNK 的值 即一個當pe加載時指向引入函數真實地址的 RVA 初始值爲 IMPORT->FirstThunk; 指針加1即可
CHAR FRISTTHUNK[20];
sprintf(FRISTTHUNK,"0x%x",FIRSTTHUNK);
WriteFile(IMPORTHANDLE,FRISTTHUNK,6,&REALBUFFER,NULL);
WriteFile(IMPORTHANDLE,"\r\n",2,&REALBUFFER,NULL);
/*********************************************************************************************************************/
}
THUNK++; // 指針加1 也就是跳過一個 PIMAGE_THUNK_DATA 結構 掃描下一個函數
FIRSTTHUNK++; //獲得每個引入函數的RVA
}
IMPORT++;//掃描下一個dll
CNTDLL++; //記錄dll個數
}
}
導出表
void GETEXPORT(PVOID PIMAGE)
{
PBYTE PBIMAGE = (PBYTE)PIMAGE;
DWORD EXPORTRVA = pe.DATA[0].VirtualAddress;
PIMAGE_SECTION_HEADER EXPORTSECT;
PIMAGE_EXPORT_DIRECTORY EXPORT;
DWORD EXPORTRAW;
for(int i=0; i<pe.FILE->NumberOfSections; i++)
{
if (EXPORTRVA>=a[i] && EXPORTRVA<=b[i])
{
EXPORTRAW = EXPORTRVA - pe.SECTION[i].VirtualAddress + pe.SECTION[i].PointerToRawData; //RVA->RAW
EXPORTSECT = &pe.SECTION[i];
}
}
EXPORT = PIMAGE_EXPORT_DIRECTORY(EXPORTRAW+PBIMAGE); //使用輸出表的文件地址
if(!EXPORTRVA)
{
MessageBox(NULL,"EXPORT IS EMOPTY","ERROR",NULL);
return;
}
printf("Base = 0x%x\n",EXPORT->Base);
printf("NumberOfFunctions = 0x%x\n",EXPORT->NumberOfFunctions);
printf("NumberOfNames = 0x%x\n",EXPORT->NumberOfNames);
printf("AddressOfFunctions = 0x%x\n",EXPORT->AddressOfFunctions);
printf("AddressOfNameOrdinals = 0x%x\n",EXPORT->AddressOfNameOrdinals);
printf("AddressOfNames = 0x%x\n",EXPORT->AddressOfNames);
DWORD DLLNAME = (DWORD)(EXPORT->Name - EXPORTSECT->VirtualAddress + EXPORTSECT->PointerToRawData + PBIMAGE);
//輸出名字之前 必須得到名字RVA 的RAW 並加上 文件首地址 得到文件地址
printf("Name = %s\n",DLLNAME);
LPDWORD NAMEADDRESS = (LPDWORD)(EXPORT->AddressOfNames - EXPORTSECT->VirtualAddress + EXPORTSECT->PointerToRawData + PBIMAGE);
LPWORD ADDNAMEORD = (LPWORD)(EXPORT->AddressOfNameOrdinals - EXPORTSECT->VirtualAddress + EXPORTSECT->PointerToRawData + PBIMAGE);
LPDWORD FUNCTIONADDRESS = (LPDWORD)(EXPORT->AddressOfFunctions - EXPORTSECT->VirtualAddress + EXPORTSECT->PointerToRawData + PBIMAGE);
for(DWORD j=0; j<EXPORT->NumberOfNames; j++)
{
// 計算名字所在的文件地址 通過兩步找到的 RVA -> RAW(名字的RVA2) RVA2->RAW2(名字)
PDWORD NAME = (PDWORD)(*NAMEADDRESS - EXPORTSECT->VirtualAddress + EXPORTSECT->PointerToRawData + PBIMAGE);
/*********************************************************************************************************************/
/**********************函數的名字 得到其文件地址很重要********************************************************/
DWORD BUF;
CHAR NAMEBUF[50];
DWORD LEN;
sprintf(NAMEBUF,"%s",NAME);
LEN=strlen(NAMEBUF);
WriteFile(EXPORTHANDLE,NAME,LEN,&BUF,NULL);
WriteFile(EXPORTHANDLE,"\r",2,&BUF,NULL);
WriteFile(EXPORTHANDLE,"\r",2,&BUF,NULL);
/*********************************************************************************************************************/
/**********************索引號 一步可以得到其內容**************************************************************/
sprintf(NAMEBUF,"0x%04x",*ADDNAMEORD+1);
WriteFile(EXPORTHANDLE,NAMEBUF,6,&BUF,NULL);
WriteFile(EXPORTHANDLE,"\r",2,&BUF,NULL);
WriteFile(EXPORTHANDLE,"\r",2,&BUF,NULL);
/*********************************************************************************************************************/
/**********************函數的RVA 類似於索引號的求法**********************************************************************/
sprintf(NAMEBUF,"0x%08x",*FUNCTIONADDRESS);
WriteFile(EXPORTHANDLE,NAMEBUF,10,&BUF,NULL);
WriteFile(EXPORTHANDLE,"\r\n",2,&BUF,NULL);
/*********************************************************************************************************************/
NAMEADDRESS++;
ADDNAMEORD++;
FUNCTIONADDRESS++;
}
}
結束。