前言
来论坛很长时间了,这是第一次发主题帖。最近学习了pe文件结构,所以就写了一个peedit,算是一个深入理解pe文件的过程吧,嘿嘿,写的一般,望大家多多指教。
Pe文件结构相对来说比较复杂。但是学习它也是有规律可循的。由于网上学习pe的文章如过江之鲫,而且有很多都是很不错的,为了避免重复造轮子,所以在这里不再赘述,只在关键的地方说明下。下面这是pe文件格式和相关的资料查询链接。
1. http://bbs.pediy.com/showthread.php?t=98202
2.http://bbs.pediy.com/showthread.php?threadid=22892
3.PE文件格式,qduwg翻译http://bbs.pediy.com/showthread.php? threadid=19618
4.《黑客免杀攻防》第七章
5.《Windows Pe权威指南》相关章节
这是pe文件结构图,相对于其他的pe文件结构图来说,本人觉得这图很不错。这样会对pe文件结构有一个感性的认识。
![http://bbs.pediy.com/attachment.php?attachmentid=84796&stc=1&d=1385996350]()
==========================================
正如前面所说,pe文件结构的资料资料很多,所以写这个的目的主要是为了加深自己对pe文件结构的理解与认识和用MFC开发编写peedit的能力。需要说明的是,写pe文件相关的程序不难,那么其区别就在于能不能将程序写像一件艺术品,或者有自己独到的之处。比如用了巧妙的方法,而不是看前人怎么写,自己拿过来用用就了事,所以写程序并不是说只要有功能在就o了。这是我们程序员应该遵守的准则我觉得(呵呵,我知道我也有很多不足的地方,我会慢慢的改正的)。
不费话了,下面就介绍下我的项目吧;
主要功能类的安排
因为pe文件结构有许许多多的表,使用父类与子类配合来解析各个表;
![http://bbs.pediy.com/attachment.php?attachmentid=84797&stc=1&d=1385996405]()
这是结构体,通过成员函数返回给各个需要此结构体的子类
![http://bbs.pediy.com/attachment.php?attachmentida=84762&stc=1&d=1385988139]()
一些关键的函数
1. rva转化为映射到内存的绝对地址
//rva就是内存相对偏移地址这里直接转化为加载进内存中的·绝对地址
2.pe映像文件的载入
具体的代码(展示一下关键的代码,工程源码见附件)
1.获取导出表信息
2.导出表信息
3.资源表信息
这是插入时的一个细节问题大家结合图与代码看看就明白了
![http://bbs.pediy.com/attachment.php?attachmentid=84788&stc=1&d=1385993310]()
导入表信息
获取模块信息
然后是通过点击模块,获取具体模块的api信息
===============
代码就贴这些了,
================
这写是软件界面的截图
主界面
![http://bbs.pediy.com/attachment.php?attachmentid=84789&stc=1&d=1385995081]()
导入表
![http://bbs.pediy.com/attachment.php?attachmentid=84790&stc=1&d=1385995081]()
导出表
![http://bbs.pediy.com/attachment.php?attachmentid=84791&stc=1&d=1385995081]()
资源表
![http://bbs.pediy.com/attachment.php?attachmentid=84794&stc=1&d=1385995313]()
16Edit
这个是调用的16edit的库,本人表示再次被yoda大牛所折服。。。。;):
![http://bbs.pediy.com/attachment.php?attachmentid=84792&stc=1&d=1385995081]()
总结
通过学习pe文件,给我的感觉就是微软那帮人真是厉害,那数据结构搞的如此复杂,当然复杂不是他们的目的,而是更好的更加稳定的让程序在windows上运行。另一个就是绝知此事要躬行,pe文件虽然不是很复杂,但是能掌握到何种程度是另一回事,而且学完之后,你能思考为什么会这样安排某一数据层次,就是另一个层次。思考问题外的问题往往我们会收获更多,这也许就是大牛与菜鸟的区别吧,呵呵。源码见附件,稍后会补上文档,大家先看看源码吧。这样会有更多的思考的机会,也希望大家能指出其中的错误,愿与大家共同成长。
附件密码是:kanxue123:p:
附件 84795
来论坛很长时间了,这是第一次发主题帖。最近学习了pe文件结构,所以就写了一个peedit,算是一个深入理解pe文件的过程吧,嘿嘿,写的一般,望大家多多指教。
Pe文件结构相对来说比较复杂。但是学习它也是有规律可循的。由于网上学习pe的文章如过江之鲫,而且有很多都是很不错的,为了避免重复造轮子,所以在这里不再赘述,只在关键的地方说明下。下面这是pe文件格式和相关的资料查询链接。
1. http://bbs.pediy.com/showthread.php?t=98202
2.http://bbs.pediy.com/showthread.php?threadid=22892
3.PE文件格式,qduwg翻译http://bbs.pediy.com/showthread.php? threadid=19618
4.《黑客免杀攻防》第七章
5.《Windows Pe权威指南》相关章节
这是pe文件结构图,相对于其他的pe文件结构图来说,本人觉得这图很不错。这样会对pe文件结构有一个感性的认识。
==========================================
正如前面所说,pe文件结构的资料资料很多,所以写这个的目的主要是为了加深自己对pe文件结构的理解与认识和用MFC开发编写peedit的能力。需要说明的是,写pe文件相关的程序不难,那么其区别就在于能不能将程序写像一件艺术品,或者有自己独到的之处。比如用了巧妙的方法,而不是看前人怎么写,自己拿过来用用就了事,所以写程序并不是说只要有功能在就o了。这是我们程序员应该遵守的准则我觉得(呵呵,我知道我也有很多不足的地方,我会慢慢的改正的)。
不费话了,下面就介绍下我的项目吧;
主要功能类的安排
因为pe文件结构有许许多多的表,使用父类与子类配合来解析各个表;
这是结构体,通过成员函数返回给各个需要此结构体的子类
一些关键的函数
1. rva转化为映射到内存的绝对地址
//rva就是内存相对偏移地址这里直接转化为加载进内存中的·绝对地址
代码:
DWORD RVA2Memaddr( DWORD dwVA,DWORD lpiamge,PIMAGE_NT_HEADERS32 pNT32 )
{
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNT32);
for ( DWORD i=0; i<=pNT32->FileHeader.NumberOfSections; i++ )
{
DWORD dwFileAddr=0;
if ( dwVA < pSection[i].VirtualAddress )
{
DWORD dwAddr= dwVA - pSection[i-1].VirtualAddress-lpiamge;
dwMemAddr=dwAddr+ pSection[i-1].PointerToRawData;
return dwMemAddr;
}
else if(dwVA>= pSection[pNT32->FileHeader.NumberOfSections-1].VirtualAddress)
{
DWORD dwAddr= dwVA - pSection[pNT32->FileHeader.NumberOfSections-1].VirtualAddress-lpiamge;
dwMemAddr= dwAddr+ pSection[pNT32->FileHeader.NumberOfSections-1].PointerToRawData;
return dwMemAddr;
}
}
return 0;
}
代码:
//载入pe文件
PeMisicInfo CPELoad::LoadPEFile(LPCTSTR lpszPath)
{
DWORD PeFileSize=0;
LPVOID DumpAddr=nullptr;
BOOL CanBeRead;
PIMAGE_NT_HEADERS32 Nt_headers;
//创建文件映射
HANDLE hFile=CreateFile(lpszPath,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,OPEN_EXISTING,SECURITY_IMPERSONATION,NULL);
if(!hFile) goto EndProcess;
PeFileSize=GetFileSize(hFile,NULL);
if(PeFileSize==0)goto EndProcess;
DumpAddr=VirtualAlloc(NULL,PeFileSize,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
if(!DumpAddr)goto EndProcess;
DWORD dwRet;
CanBeRead=ReadFile(hFile,DumpAddr,PeFileSize,&dwRet,NULL);
int a=GetLastError();
if(!CanBeRead)goto EndProcess;//判断是不是pe文件
// 判断是不是pe文件
BOOL isPeFile=IsPeFile(DumpAddr,PeFileSize,Nt_headers);
if(!isPeFile) goto EndProcess;
mypemisc.Dumpaddr=DumpAddr;
mypemisc.nt_headeras=Nt_headers;
mypemisc.hFile=hFile;
mypemisc.lpPath=lpszPath;
return mypemisc;
EndProcess:
if(hFile)CloseHandle(hFile);
ExitProcess(0);
}
1.获取导出表信息
代码:
void CImportDir::ShowModuleInfo(vector<PIMAGE_SECTION_HEADER> Section)
{
//删除掉模块栏的所有条目
m_modulelist.DeleteAllItems();
//删除所有vector中模块
mymodulename.clear();
PeMisicInfo miscinfo=ReturnMiscInfo();
PIMAGE_NT_HEADERS32 LocalHeaders=miscinfo.nt_headeras;
DWORD dumpaddr=(DWORD)miscinfo.Dumpaddr;
m_dumpaddr=dumpaddr;
WORD optional_header_size=LocalHeaders->FileHeader.SizeOfOptionalHeader;
PIMAGE_OPTIONAL_HEADER32 Optional_header=&LocalHeaders->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDir = (PIMAGE_DATA_DIRECTORY)Optional_header->DataDirectory;
//导入表的地址
DWORD my_export_rva=pDataDir[1].VirtualAddress;
DWORD Import_Table_Section_ShiftAddr;
DWORD OA;
//数据段的RVA
for(int a=0;a<Section.size();a++)
{
if(Section[a]->VirtualAddress>my_export_rva)
{
m_OA=OA=Section[a-1]->VirtualAddress-Section[a-1]->PointerToRawData;
Import_Table_Section_ShiftAddr=my_export_rva-OA;
break;
}
}
if(Import_Table_Section_ShiftAddr==0xcccccccc)
{
MessageBox(L"未初始化",L"错误",MB_OK);
return;
}
//获取输入表信息
IMAGE_IMPORT_DESCRIPTOR *my_Import_Data=(PIMAGE_IMPORT_DESCRIPTOR)(Import_Table_Section_ShiftAddr+(DWORD)dumpaddr);
PIMAGE_THUNK_DATA32 pInt;
//判断的条件是因为大多数情况IMAGE_THUNK_DATA 会指向一个IMPORT_BY_NAME 结束的时候会以一个
//全零的IMAGE_THUNK_DATA结束
if(pInt=(PIMAGE_THUNK_DATA32)my_Import_Data->OriginalFirstThunk)
{
while(my_Import_Data->Name)
{
MYIMAGE_IMPORT_DESCRIPTOR my_image_des={0};
DWORD pszDllName_Addr=my_Import_Data->Name-OA+dumpaddr;
my_image_des.dllname=pszDllName_Addr;
my_image_des.my_image_descriptor.FirstThunk=my_Import_Data->FirstThunk;
my_image_des.my_image_descriptor.OriginalFirstThunk=my_Import_Data->OriginalFirstThunk;
my_image_des.my_image_descriptor.ForwarderChain=my_Import_Data->ForwarderChain;
my_image_des.my_image_descriptor.Name=my_Import_Data->Name;
mymodulename.push_back(my_image_des);
my_Import_Data++;
}
for(int a=0;a<mymodulename.size();a++)
{
CString myid;
myid.Format(L"%d",a);
char* mychar;
m_modulelist.InsertItem(LVIF_TEXT | LVIF_STATE,a, myid,(a % 2) == 0 ? LVIS_SELECTED : 0, LVIS_SELECTED,0,0);
for(int i=1;i<6;i++)
{
LPCWCH OutputChar[4]={0};
CString mymoduleinfo;
switch (i)
{
case 1:
MyUtil.ConvertUtf8ToUnicode((char*)mymodulename[a].dllname,*OutputChar);
mymoduleinfo.Format(L"%s",*OutputChar);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 2:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.OriginalFirstThunk);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 3:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.ForwarderChain);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 4:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.Name);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 5:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.FirstThunk);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
default:
break;
}
}
}
}
}
代码:
void CExportDir::GetExportInfo()
{
LPCWCH outputchar={0};
LPCWCH outputchar1={0};
m_exportlistcrl.DeleteAllItems();
m_vec_myexportinfo.clear();
PeMisicInfo miscinfo=ReturnMiscInfo();//获取pe基本信息
PIMAGE_NT_HEADERS32 pNT32 = miscinfo.nt_headeras;
PIMAGE_DATA_DIRECTORY pDataDir = (PIMAGE_DATA_DIRECTORY)pNT32->OptionalHeader.DataDirectory;
PIMAGE_DATA_DIRECTORY pExportDir = &pDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT];
if(pExportDir->Size!=0)
{
DWORD dwExportOfffset = Rva2FileA(pExportDir->VirtualAddress, pNT32);//输出表地文件偏移
PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)miscinfo.Dumpaddr+dwExportOfffset);
PDWORD pEAT = (PDWORD)((DWORD)miscinfo.Dumpaddr + Rva2FileA(pExport->AddressOfFunctions, pNT32));
PDWORD pENT = (PDWORD)((DWORD)miscinfo.Dumpaddr + Rva2FileA(pExport->AddressOfNames, pNT32));
PWORD pEIT = (PWORD)((DWORD)miscinfo.Dumpaddr + Rva2FileA(pExport->AddressOfNameOrdinals, pNT32));
PCHAR exenameaddr=(PCHAR)((DWORD)miscinfo.Dumpaddr + Rva2FileA(pExport->Name, pNT32));
mysttring.ConvertUtf8ToUnicode((char*)exenameaddr,outputchar1);
/////////////////////////////////////////////
//格式化输出
m_ExpDirFa.Format(L"0x%X",dwExportOfffset);
m_funaddr.Format(L"0x%X",pExport->AddressOfFunctions);
m_funnameaddr.Format(L"0x%X",pExport->AddressOfNames);
m_funnamenums.Format(L"%d",pExport->NumberOfNames);
m_char.Format(L"%d",pExport->Characteristics);
m_exename.Format(L"%s",outputchar1);
m_funordaddr.Format(L"0x%X",pExport->AddressOfNameOrdinals);
m_funnums.Format(L"0x%X",pExport->NumberOfFunctions);
m_baseaddr.Format(L"0x%X",pExport->Base);
m_namerva.Format(L"0x%X",pExport->Name);
for ( DWORD dwOrdinal=0; dwOrdinal<pExport->NumberOfFunctions; dwOrdinal++ )
{
if ( !pEAT[dwOrdinal] )
continue;
for ( DWORD dwIndex=0; dwIndex<pExport->NumberOfFunctions; dwIndex++ )
{
EXPORTINFO myexportinfo={0};
if ( pEIT[dwIndex] == dwOrdinal )
{
PCHAR pszFunName = (PCHAR)((DWORD)miscinfo.Dumpaddr+Rva2FileA(pENT[dwIndex], pNT32));
myexportinfo.Ordinal=pExport->Base+dwOrdinal;
myexportinfo.FuncRva=pEAT[dwOrdinal];
mysttring.ConvertUtf8ToUnicode(pszFunName,outputchar);
myexportinfo.funcname=outputchar;
m_vec_myexportinfo.push_back(myexportinfo);
break;
}
else if ( dwIndex == pExport->NumberOfFunctions-1 )
{
myexportinfo.Ordinal=pExport->Base+dwOrdinal;
myexportinfo.FuncRva=pEAT[dwOrdinal];
myexportinfo.funcname=(LPCWCH) L"(Null)" ;
m_vec_myexportinfo.push_back(myexportinfo);
break;
}
/// free(myexportinfo);
}
}
///////////////////////////////////./////
//显示信息
////////////////////////////////////////
UpdateData(FALSE);
Showinfo();
}
else
{
MessageBox(L"没有导出表!",L"错误",MB_OK|MB_ICONSTOP);
}
}
这是插入时的一个细节问题大家结合图与代码看看就明白了
代码:
void CSrc::ShowInfo()
{
//这里用ID关联资源之间的关系,来显示层与层之间的关系
int ID1=0;
m_srcTreecrl.ModifyStyle(NULL,TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT);
PeMisicInfo miscinfo=ReturnMiscInfo();
PIMAGE_NT_HEADERS32 pNT32 = (PIMAGE_NT_HEADERS32)miscinfo.nt_headeras;
// 1.2 获取数据目录表
PIMAGE_DATA_DIRECTORY pDir = (PIMAGE_DATA_DIRECTORY)pNT32->OptionalHeader.DataDirectory;
// 1.3 获取资源表的数据目录
PIMAGE_DATA_DIRECTORY pDataDir = pDir+IMAGE_DIRECTORY_ENTRY_RESOURCE;
// 1.4 获取资源表
PIMAGE_RESOURCE_DIRECTORY pResource1 = (PIMAGE_RESOURCE_DIRECTORY)RVA2Memaddr(pDataDir->VirtualAddress, miscinfo.Dumpaddr, pNT32);
// 2. 循环遍历资源表
// 2.1 第一层目录遍历
DWORD dwCount1 = pResource1->NumberOfIdEntries+pResource1->NumberOfNamedEntries;
for ( DWORD i=0; i<dwCount1; i++ )
{
SRCSTRUCT mystc={0};
ID1++;
mystc.ID=ID1;
LPCWCH* outputchar=new LPCWCH;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pDirEntry1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pResource1+sizeof(IMAGE_RESOURCE_DIRECTORY));
if ( pDirEntry1[i].NameIsString )
{
PIMAGE_RESOURCE_DIR_STRING_U pString = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)pResource1+pDirEntry1[i].NameOffset);
mystc.str.Format(L"Type:%ls",pString->NameString);
Level1.push_back(mystc);
}
else
{
if ( pDirEntry1[i].Name>0x10 )
{
mystc.str.Format(L"%04X",pDirEntry1[i].Name);
Level1.push_back(mystc);
}
else
{
mystc.str.Format(L"%ls",szResourceType[pDirEntry1[i].Name] );
Level1.push_back(mystc);
}
}
if ( pDirEntry1[i].DataIsDirectory )
{
int secid=0;
// 2.2 第二层目录的遍历
PIMAGE_RESOURCE_DIRECTORY pResource2 = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pResource1+pDirEntry1[i].OffsetToDirectory);
DWORD dwCount2 = pResource2->NumberOfIdEntries+pResource2->NumberOfNamedEntries;
for ( DWORD j=0; j<dwCount2; j++ )
{
SRCSTRUCT mystc2={0};
mystc2.ID=ID1;
//第二级的id
secid++;
mystc2.secid=secid;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pDirEntry2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pResource2+sizeof(IMAGE_RESOURCE_DIRECTORY));
if ( pDirEntry2[j].NameIsString )
{
LPWSTR szBuffer[30];
PIMAGE_RESOURCE_DIR_STRING_U pString = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)pResource2+pDirEntry2[j].NameOffset);
mystc2.str.Format(L"ID:%ls",pString->NameString);
Level2.push_back(mystc2);
}
else
{
mystc2.str.Format(L"ID:%X",pDirEntry2[j].Name);
Level2.push_back(mystc2);
}
if ( pDirEntry2[j].DataIsDirectory )
{
DWORD subId=0;
// 2.3 第三层目录的遍历
PIMAGE_RESOURCE_DIRECTORY pResource3 = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pResource1+pDirEntry2[j].OffsetToDirectory);
DWORD dwCount3 = pResource3->NumberOfIdEntries+pResource3->NumberOfNamedEntries;
for ( DWORD k=0; k< dwCount3; k++ )
{
SRCSTRUCT mystc3={0};
mystc3.secid=secid;
mystc3.ID=ID1;
subId++;
mystc3.subID=subId;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pDirEntry3 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pResource3+sizeof(IMAGE_RESOURCE_DIRECTORY));
PIMAGE_RESOURCE_DATA_ENTRY pData = (PIMAGE_RESOURCE_DATA_ENTRY)((DWORD)pResource1+pDirEntry3[k].OffsetToData);
mystc3.str.Format(L"Lng:%04X,RVA:0x%p Size:%04X Page:0x%p",pDirEntry3[k].Name,pData->OffsetToData, pData->Size, pData->CodePage);
Level3.push_back(mystc3);
}
}
else
{
// ....
}
}
}
else
{
// ......
}
}
RealShowInfo();
}
获取模块信息
代码:
void CImportDir::ShowModuleInfo(vector<PIMAGE_SECTION_HEADER> Section)
{
//删除掉模块栏的所有条目
m_modulelist.DeleteAllItems();
//删除所有vector中模块
mymodulename.clear();
PeMisicInfo miscinfo=ReturnMiscInfo();
PIMAGE_NT_HEADERS32 LocalHeaders=miscinfo.nt_headeras;
DWORD dumpaddr=(DWORD)miscinfo.Dumpaddr;
m_dumpaddr=dumpaddr;
WORD optional_header_size=LocalHeaders->FileHeader.SizeOfOptionalHeader;
PIMAGE_OPTIONAL_HEADER32 Optional_header=&LocalHeaders->OptionalHeader;
PIMAGE_DATA_DIRECTORY pDataDir = (PIMAGE_DATA_DIRECTORY)Optional_header->DataDirectory;
//导入表的地址
DWORD my_export_rva=pDataDir[1].VirtualAddress;
DWORD Import_Table_Section_ShiftAddr;
DWORD OA;
//数据段的RVA
for(int a=0;a<Section.size();a++)
{
if(Section[a]->VirtualAddress>my_export_rva)
{
m_OA=OA=Section[a-1]->VirtualAddress-Section[a-1]->PointerToRawData;
Import_Table_Section_ShiftAddr=my_export_rva-OA;
break;
}
}
if(Import_Table_Section_ShiftAddr==0xcccccccc)
{
MessageBox(L"未初始化",L"错误",MB_OK);
return;
}
//获取输入表信息
IMAGE_IMPORT_DESCRIPTOR *my_Import_Data=(PIMAGE_IMPORT_DESCRIPTOR)(Import_Table_Section_ShiftAddr+(DWORD)dumpaddr);
PIMAGE_THUNK_DATA32 pInt;
//判断的条件是因为大多数情况IMAGE_THUNK_DATA 会指向一个IMPORT_BY_NAME 结束的时候会以一个
//全零的IMAGE_THUNK_DATA结束
if(pInt=(PIMAGE_THUNK_DATA32)my_Import_Data->OriginalFirstThunk)
{
while(my_Import_Data->Name)
{
MYIMAGE_IMPORT_DESCRIPTOR my_image_des={0};
DWORD pszDllName_Addr=my_Import_Data->Name-OA+dumpaddr;
my_image_des.dllname=pszDllName_Addr;
my_image_des.my_image_descriptor.FirstThunk=my_Import_Data->FirstThunk;
my_image_des.my_image_descriptor.OriginalFirstThunk=my_Import_Data->OriginalFirstThunk;
my_image_des.my_image_descriptor.ForwarderChain=my_Import_Data->ForwarderChain;
my_image_des.my_image_descriptor.Name=my_Import_Data->Name;
mymodulename.push_back(my_image_des);
my_Import_Data++;
}
for(int a=0;a<mymodulename.size();a++)
{
CString myid;
myid.Format(L"%d",a);
char* mychar;
m_modulelist.InsertItem(LVIF_TEXT | LVIF_STATE,a, myid,(a % 2) == 0 ? LVIS_SELECTED : 0, LVIS_SELECTED,0,0);
for(int i=1;i<6;i++)
{
LPCWCH OutputChar[4]={0};
CString mymoduleinfo;
switch (i)
{
case 1:
MyUtil.ConvertUtf8ToUnicode((char*)mymodulename[a].dllname,*OutputChar);
mymoduleinfo.Format(L"%s",*OutputChar);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 2:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.OriginalFirstThunk);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 3:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.ForwarderChain);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 4:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.Name);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
case 5:
mymoduleinfo.Format(L"0x%X",mymodulename[a].my_image_descriptor.FirstThunk);
m_modulelist.SetItemText(a,i,mymoduleinfo);
break;
default:
break;
}
}
}
}
}
代码:
void CImportDir::ShowImportFuncInfo(PIMAGE_IMPORT_DESCRIPTOR my_Import_Data,DWORD OA,DWORD dumpaddr)
{
m_funlist.DeleteAllItems();
//先清空Func vector
myfunlist.clear();
//指向输入名称地址表(INT) 绝对地址
DWORD pInt=my_Import_Data->OriginalFirstThunk-OA;
DWORD pInt_addr=pInt+dumpaddr;
PIMAGE_THUNK_DATA32 Pint=(PIMAGE_THUNK_DATA32)pInt_addr;
//循环打印INT的内容
if (Pint->u1.Ordinal)
{
while (Pint->u1.Ordinal)
{
DWORD i=0;
if(!IMAGE_SNAP_BY_ORDINAL32(Pint->u1.Ordinal))
{
MYFUNCINFO myfun={0};
DWORD my_import_rva_data=(DWORD)Pint->u1.AddressOfData;
DWORD My_importFunciton_name_addr=my_import_rva_data-OA+dumpaddr;
PIMAGE_IMPORT_BY_NAME My_importFunciton_name_struct=(PIMAGE_IMPORT_BY_NAME)(My_importFunciton_name_addr);
myfun.FunName=(LPCTSTR)My_importFunciton_name_struct->Name;
myfun.ThunkRVA=my_Import_Data->OriginalFirstThunk+i*4;
myfun.Hint=My_importFunciton_name_struct->Hint;
myfun.ThunkValue=my_import_rva_data;
myfunlist.push_back(myfun);
Pint++;
i++;
continue;
}
Pint++;
}
for(int a=0;a<myfunlist.size();a++)
{
CString myid;
myid.Format(L"%d",a+1);
m_funlist.InsertItem(LVIF_TEXT | LVIF_STATE,a, myid,(a % 2) == 0 ? LVIS_SELECTED : 0, LVIS_SELECTED,0,0);
for(int i=1;i<6;i++)
{
LPCWCH outputfun[8]={0};
CString mymoduleinfo;
switch (i)
{
case 1:
MyUtil.ConvertUtf8ToUnicode((char*)myfunlist[a].FunName,*outputfun);
mymoduleinfo.Format(L"%s",*outputfun);
m_funlist.SetItemText(a,i,mymoduleinfo);
break;
case 2:
mymoduleinfo.Format(L"0x%X",myfunlist[a].ThunkRVA+4*a);
m_funlist.SetItemText(a,i,mymoduleinfo);
break;
case 3:
mymoduleinfo.Format(L"0x%X",myfunlist[a].ThunkRVA-OA+4*a);
m_funlist.SetItemText(a,i,mymoduleinfo);
break;
case 4:
mymoduleinfo.Format(L"0x%X",myfunlist[a].ThunkValue);
m_funlist.SetItemText(a,i,mymoduleinfo);
break;
case 5:
mymoduleinfo.Format(L"0X%X",myfunlist[a].Hint);
m_funlist.SetItemText(a,i,mymoduleinfo);
break;
default:
break;
}
}
}
}
}
代码就贴这些了,
================
这写是软件界面的截图
主界面
导入表
导出表
资源表
16Edit
这个是调用的16edit的库,本人表示再次被yoda大牛所折服。。。。;):
总结
通过学习pe文件,给我的感觉就是微软那帮人真是厉害,那数据结构搞的如此复杂,当然复杂不是他们的目的,而是更好的更加稳定的让程序在windows上运行。另一个就是绝知此事要躬行,pe文件虽然不是很复杂,但是能掌握到何种程度是另一回事,而且学完之后,你能思考为什么会这样安排某一数据层次,就是另一个层次。思考问题外的问题往往我们会收获更多,这也许就是大牛与菜鸟的区别吧,呵呵。源码见附件,稍后会补上文档,大家先看看源码吧。这样会有更多的思考的机会,也希望大家能指出其中的错误,愿与大家共同成长。
附件密码是:kanxue123:p:
附件 84795