把exe里面的资源通通取出来<br> <br><br>作者:king_koo<br><br>下载例子源代码<br><br> <br> <br> <br> <br> <br> <br>一、前言 <br> 不知大家用过exescope没有,那是日本鬼子写的一个很有用的东西,它能把exe等pe<br>格式(portable executable)文件的资源(图标、位图、对话框、声音等等)分析出来,并<br>能改写回去。当然vc的ide也有类似功能。大家是不是觉得很神秘?其实只要弄清了pe文件<br>的结构,你也可以写一个类似的工具出来。下面是我近 来对pe文件的分析经验,给大家<br>作参考。同时希望看到有中国人能写出比日本鬼子更牛的分析工具来。 <br> <br> <br>二、重要的数据结构 <br> PE格式简要说明:(更详细的资料见http://vcangle.8u8.com文件格式专页)<br>PE文件总结构如下表: <br> <br> <br> <br>DOS MZ header ;dos头 <br>DOS stub ;dos附加段<br>PE header ;NT头<br>Section table ;节表<br>Section 1 ;第一节<br>Section 2 ;<br>Section ... <br>Section n ;第n节<br> 其中NT头:<br> typedef struct _IMAGE_NT_HEADERS { <br> DWORD Signature;//PE文件头标志 :"PE/0/0"。<br> IMAGE_FILE_HEADER FileHeader; //PE文件物理分布的信息 <br> IMAGE_OPTIONAL_HEADER32 OptionalHeader;//PE文件逻辑分布的信息 <br> } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; <br> 节表数据结构
可参考winnt.h)<br> typedef struct _IMAGE_SECTION_HEADER { <br> BYTE Name[IMAGE_SIZEOF_SHORT_NAME];//节表名称,如“.text” <br> union { DWORD PhysicalAddress; //物理地址 <br> DWORD VirtualSize; //真实长度 <br>} Misc; <br>DWORD VirtualAddress; //RVA <br>DWORD SizeOfRawData; //物理长度 <br>DWORD PointerToRawData; //节基于文件的偏移量 <br>DWORD PointerToRelocations; //重定位的偏移 <br>DWORD PointerToLinenumbers; //行号表的偏移 <br>WORD NumberOfRelocations; //重定位项数目 <br>WORD NumberOfLinenumbers; //行号表的数目 <br>DWORD Characteristics; //节属性 <br> } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; <br><br> 2.2位图文件格式。由文件头,位图信息和数据段组成。<br> typedef struct tagBITMAPFILEHEADER { // bmfh文件头 <br> WORD bfType; //"BM"<br> DWORD bfSize; <br> WORD bfReserved1; <br> WORD bfReserved2; <br> DWORD bfOffBits; <br> } BITMAPFILEHEADER;<br> typedef struct tagBITMAPINFO { // bmi----位图信息 <br> BITMAPINFOHEADER bmiHeader; // ----位图信息头<br> RGBQUAD bmiColors[1];// ----调色板* <br> } BITMAPINFO; <br> typedef struct tagBITMAPINFOHEADER{ // bmih 位图信息头<br> DWORD biSize; //该结构大小<br> LONG biWidth; <br> LONG biHeight; <br> WORD biPlanes; <br> WORD biBitCount; <br> DWORD biCompression; <br> DWORD biSizeImage; //位图数据大小 <br> LONG biXPelsPerMeter; <br> LONG biYPelsPerMeter; <br> DWORD biClrUsed; <br> DWORD biClrImportant; <br> } BITMAPINFOHEADER; //该结构后紧接着就是DATA了。 <br> <br> <br>三、取资源主要思路<br> 先要判断是否PE文件。文件头两byte应为0x4d5a即("MZ"),然后到地址0x3c中读出PE<br>文件头(_IMAGE_NT_HEADERS)。判断文件头结构的Signature是否为17744(即"PE/0/0")。<br><br> 读出节表(_IMAGE_SECTION_HEADER),判断有没有资源节。我采用了一个简单的方法<br>:节表名为".rsrc/0/0"即是资源节。(注:据说该法不定可靠)<br> 如有资源节,则读取资源目录(_IMAGE_RESOURCE_DIRECTORY)和资源入口(_IMAGE_RES<br>OURCE_DIRECTORY_ENTRY)。资源在pe文件中处一树型结构中,可有三层。在资源目录根部<br>,如果资源入口的资源名是一个id,那么它代表一种资源类型。否则,它指向下一层资源<br>入口。(祥见例程)<br> 读出具体资源的数据来。具体资源的入口(_IMAGE_RESOURCE_DATA_ENTRY)在就是资源<br>树的叶子。它的OffsetToData成员指明了具体资源的物理位置。不过特别要注意的是,Of<br>fsetToData并不是具体资源在文件中的实际偏移,具体见我的例程。具体资源的长度则由<br>Size成员指定。<br> 导出bmp资源。pe文件里的bmp资源由BITMAPINFO部分和BITMAPDATA部分组成。我们只<br>要为它构造一个文件头(BITMAPFILEHEADER),就可以写成bmp文件了。这里特别要注意的<br>是BITMAPINFO的bmiColors成员是未定长的。你要为它<br>指明长度,以申请内存。<br>好了,我不说了,有什么不明白就看例程吧。 <br> <br> <br>四、例子程序简介<br> 我的例子程序基本实现了读取pe文件的资源信息,并能把位图显示、导出。其它资源<br>的操作还在研究中。由于作者水平有限,在分析有些文件时可能会不成功。欢迎指正!主<br>页: http://vcangle.8u8.com,邮箱:king_koo@163.net. <br>五、参考资料<br> <br>如何提取并保存图标资源<br><br>作者:Future Studio.徐景周<br><br>下载例子源代码<br><br> <br> <br> <br> <br> <br> <br> 当你想要使用别的应用程序中的漂亮图标时,该怎么办呢?也许就会用到一些图标提<br>取工具吧!那么,你知道它们是怎么实现的,想不想自己动手也做一个适合自己的图标提<br>取工具呢?下面,就让我用我以前做过的一个工具<轻轻松松抓图标>来告诉你吧!它可<br>以提取各种文件中的图标资源,并可将其保存为图标(ICO)、位图(BMP)两种格式。程序运<br>行后界面如下: <br> <br> <br> <br>图一 <br> 在上面的例程中,我整合出一个图标类CIcons和与之相配的一个位图类CDib,其中包<br>括Icons.h、Icons.cpp、Dib.h和Dib.cpp四个文件。在你的工程中直接加入这四个文件后<br>,调用其类涵数,既可做出你自己的图标工具来。<br>下面让我们来看看如何来具体用它们来实现:<br>1、 提取并显示出图标到左侧列表框中。<br>代码实现如下:<br>//读取各种资源内部图标并显示在左侧列表框中 <br> <br> <br>void CIconSnapDlg::OnOK() <br>{ <br> CFileDialog fileDialog(<br>TRUE,"*.ICO",NULL,NULL,"资源文件(*.ICO,*.BMP,*.EXE,*.DLL,*.ICL)|*.ICO;*.BMP;*.<br>EXE;*.DLL;*.ICL||");<br> if (fileDialog.DoModal() == IDOK) <br> { <br> szOpenFileName=fileDialog.GetPathName(); <br> szOpenFileExtName= fileDialog.GetFileExt ();<br> szOpenFileExtName.MakeLower ();<br><br> m_List.ResetContent (); //选清空左侧图标列表框<br><br> //读取并显示ICON文件<br> if(szOpenFileExtName =="ico") <br> {<br> lpIR=pIcons->ReadIconFromICOFile (szOpenFileName); <br> HICON hIcon;<br> hIcon=ExtractIcon(AfxGetInstanceHandle(),szOpenFileName,0);<br> if(hIcon!=NULL)<br> m_List.AddString (szOpenFileName);<br> CStatic* pStatic = (CStatic*) GetDlgItem(IDC_ICONS);<br> pStatic->SetIcon (hIcon);<br> }<br> else if(szOpenFileExtName == "bmp") //读取并显示BMP文件<br> {<br> pIcons->IconImageFromBMPFile<br>(szOpenFileName,&lpIR->IconImages[0],TRUE);<br> HICON hIcon;<br> hIcon=pIcons->MakeIconFromResource (&lpIR->IconImages [0]);<br> if(hIcon!=NULL) <br> m_List.AddString (szOpenFileName);<br> CStatic* pStatic = (CStatic*) GetDlgItem(IDC_ICONS);<br> pStatic->SetIcon (hIcon);<br> }<br> else //读取并显示EXE、DLL等资源文件<br> {<br> HINSTANCE hLibrary;<br><br> // Load the DLL/EXE - NOTE: must be a 32bit EXE/DLL for this to work<br> if( (hLibrary = LoadLibraryEx( szOpenFileName, NULL,<br>LOAD_LIBRARY_AS_DATAFILE )) == NULL )<br> {<br> // Failed to load - abort<br> MessageBox( szOpenFileName+ "文件载入错误,必须是WIN32的文件!", "错误",<br>MB_OK );<br> return;<br> }<br> // Store the info<br> EDII.szFileName =szOpenFileName;<br> EDII.hInstance = hLibrary;<br> <br> // Fill in the listbox with the icons available<br> if( ! EnumResourceNames( EDII.hInstance, RT_GROUP_ICON, (ENUMRESNAMEPROC<br>)MyEnumProcedure, (LPARAM)GetSafeHwnd()) )<br> {<br> MessageBox( "列举图标资源名时出错!", "错误", MB_OK );<br> return;<br> }<br> }<br><br> m_List.SetCurSel (0);<br> if( m_List.GetCount() == 0 )<br> {<br> MessageBox( "此文件中没有图标资源!", "错误", MB_OK );<br> //无图标资源,置保存和复制按钮为无效状态<br> m_Copy.EnableWindow (false);<br> m_SaveAs.EnableWindow (false);<br> return;<br> }<br> //有图标资源,置保存和复制按钮为有效状态????<br> m_Copy.EnableWindow (true);<br> m_SaveAs.EnableWindow (true);<br><br> //刷新调用OnPaint来显示图标<br> InvalidateRect(NULL,TRUE);<br> } <br>} <br> <br> <br>在OnPaint()涵数中加入下面代码用来具体显示提取出的图标或位图资源。<br>//根据左侧图标列表,利用OnPaint()来更新右侧相应图标 <br> <br> <br> <br>LPTSTR lpIconID;<br>HICON hIcon;<br>if((lpIconID=(LPTSTR)m_List.GetItemData(m_List.GetCurSel()))!=(LPTSTR)LB_ERR<br>)<br>{<br><br> if(szOpenFileExtName=="exe"||szOpenFileExtName=="dll"||szOpenFileExtName=="ic<br>l")<br> {<br> hIcon=pIcons->GetIconFromInstance(EDII.hInstance,lpIconID);<br> CStatic* pStatic = (CStatic*) GetDlgItem(IDC_ICONS);<br> pStatic->SetIcon (hIcon);<br> }<br>} <br> <br> <br>2、 如何将提取出的图标资源保存为Ico或Bmp格式。<br>//保存图标资源为ICO或BMP格式文件 <br> <br> <br>void CIconSnapDlg::OnButtonSaveas() <br>{<br> LPTSTR lpIconID;<br><br> CFileDialog fileDialog( FALSE,"*.ICO",NULL,NULL,"图标文件(*.ICO)|*.ICO|位图<br>文件(*.BMP)|*.BMP||");<br> if (fileDialog.DoModal() == IDOK) <br> {<br> szSaveFileName=fileDialog.GetPathName(); <br> szSaveFileExtName= fileDialog.GetFileExt ();<br> szSaveFileExtName.MakeLower ();<br><br> if(szOpenFileExtName=="exe"||szOpenFileExtName=="dll"||szOpenFileExtName=="i<br>cl")<br> if((lpIconID=(LPTSTR)m_List.GetItemData (m_List.GetCurSel()))!=<br>(LPTSTR)LB_ERR)<br> lpIR=pIcons->ReadIconFromEXEFile (szOpenFileName,lpIconID);<br> if(szSaveFileExtName=="bmp")<br> {<br> if(lpIR!=NULL && m_List.GetCount ()>0)<br> {<br> BeginWaitCursor();<br> pIcons->IconImageToBMPFile (szSaveFileName,&lpIR->IconImages [0]);<br> EndWaitCursor();<br> }<br> else<br> MessageBox( "没有可保存的图标资源!", "错误", MB_OK );<br> }<br> else if(szSaveFileExtName=="ico")<br> {<br> if(lpIR!=NULL && m_List.GetCount ()>0)<br> {<br> BeginWaitCursor();<br> pIcons->WriteIconToICOFile (lpIR,szSaveFileName);<br> EndWaitCursor();<br> }<br> else<br> MessageBox( "没有可保存的图标资源!", "错误", MB_OK );<br> }<br> }<br>}<br> <br> <br>以上代码的详细实现,请在下载后源码后,仔细参看既可。 <br> <br>