zoukankan      html  css  js  c++  java
  • Windows PE资源表编程(枚举资源树)

    资源枚举

        写一个例子,枚举一个PE文件的资源表。首先说下资源相关的作为铺垫。

    1.资源类型也是PE可选头中数据目录的一种。位于第三个类型。


    2.资源目录分为三层。第四层是描述文件相关的。这些结构是按照二叉排序树的结构存的。每一个节点都可以看成是一段连续的数据块(1个资源目录头+n个资源目录项)。


    3.整体基本结构:


    OK,基础知识就简单说这些。如果还是不清楚,看下这里http://blog.csdn.net/u013761036/article/details/54562473这里我单独针对资源表写的一个博客。


    说下写这个枚举资源表结构的程序思路:

    理解了PE里面怎么存资源的剩下的就很简单了。

    1.把PE加载到内存里。拿出来PE头,找到扩展头里面的第三个数据项。找到资源表RVA和大小。

    2.根据RVA用函数换算出FOA的地址,这个地址指向的就是第一层目录的目录头结构,根据这个目录头开始,紧跟在后面的就是n个以名称命名的和m个以id命名的资源目录项。

    3.上面2可以把目录头看成节点,把目录项看成连接到下一条节点的边,这样DFS或者BFS跑三层。依次枚举经过的信息。在第三层的时候直接把文件相关的也都输出来就可以了。

    [:DFS-深度优先搜索,就是平时说的递归 BFS-广度优先搜索,用队列模拟的一个扩散感觉的遍历]

    刚刚写了个例子,简单跑了一遍没发现啥问题:代码如下:

    注意两个地方(这个我被坑了好一会):

    1

      结构里面涉及的下一个目录项和指向资源块的地址都是相对于资源表的起始位置而不是文件起始位置。

    2

     指针加法问题

     XXXX * y;

     DWORD z;

     Y地址后偏移z长度得到x地址

     XXXX * x = (XXXX *)((DWORD) y + DWORD(z))

    // GET_RES.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <windows.h>  
    #include <winbase.h>  
    #include <stdio.h>  
    #include <tchar.h>  
    #include <imagehlp.h>  
    #include <vector>  
    #include <string>
    #include <iostream>  
    #include <string>  
    
    using namespace std; 
    
    //CP_ACP
    string ws2s(const wstring& wide, UINT CodePage){
    
    	int wide_length = static_cast<int>(wide.length());
    	if (wide_length == 0)
    		return string();
    
    	int charcount = WideCharToMultiByte(CodePage, 0, wide.data(), wide_length,
    		NULL, 0, NULL, NULL);
    	if (charcount == 0)
    		return string();
    
    	string mb;
    	mb.resize(charcount);
    	WideCharToMultiByte(CodePage, 0, wide.data(), wide_length,
    		&mb[0], charcount, NULL, NULL);
    
    	return mb;
    }
    
    
    VOID ShowRes_DFS(DWORD dwDeep ,IMAGE_RESOURCE_DIRECTORY* pNowResourceDesc ,IMAGE_RESOURCE_DIRECTORY* pBaseResourceDesc){
        /*
    	一级子目录按照资源类型分类。
    	二级子目录按照资源ID分类。
    	三级子目录按照资源代码页分类。
    	三级子目录后即为节点,也就是所说的文件。这里的文件其实就是包含了资源数据的指针和大小等信息的一个数据结构而已。
    	对于所有资源数据块的访问均可以从这里开始。
    	*/
    	dwDeep ++;
    	IMAGE_RESOURCE_DIRECTORY_ENTRY  *pResourceBaseAddress = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)((PBYTE) 
    		pNowResourceDesc + sizeof(IMAGE_RESOURCE_DIRECTORY));  
    	for(int i = 0 ;i < pNowResourceDesc->NumberOfIdEntries + pNowResourceDesc->NumberOfNamedEntries ;i ++){
    		IMAGE_RESOURCE_DIRECTORY_ENTRY  *pNowResourceAddress = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)((DWORD)pResourceBaseAddress + i * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
    
    		for(int j = 1 ;j < (dwDeep-1) * 3 ;j ++){
    			cout<<" ";
    		}
    		cout<<"Value: ";
    		if(pNowResourceAddress->NameIsString){
    			IMAGE_RESOURCE_DIR_STRING_U *wsName = (IMAGE_RESOURCE_DIR_STRING_U*)
    				((DWORD)pNowResourceAddress->NameOffset + (DWORD)pBaseResourceDesc);
    			wstring wsV = wstring(wsName->NameString ,wsName->Length);
    			cout<<ws2s(wsV ,CP_ACP);
    		}else{
    			cout<<pNowResourceAddress->Id;
    		}
    		cout<<endl;
    		if(pNowResourceAddress->DataIsDirectory){
    		    ShowRes_DFS(dwDeep ,(IMAGE_RESOURCE_DIRECTORY*)((DWORD)pNowResourceAddress->OffsetToDirectory + (DWORD)pBaseResourceDesc),pBaseResourceDesc);
    		}else{
    			for(int j = 1 ;j < (dwDeep) * 3 ;j ++){
    			cout<<" ";
    		}
    		IMAGE_RESOURCE_DATA_ENTRY * pFileRes = (IMAGE_RESOURCE_DATA_ENTRY*)((DWORD)pNowResourceAddress->OffsetToDirectory + (DWORD)pBaseResourceDesc);
    		cout<<"File: RVA-"<<pFileRes->OffsetToData;
    		cout<<",Size-"<<pFileRes->Size;
    		cout<<",Page-"<<pFileRes->CodePage;
    		cout<<endl;
    		}
    	}
    	return ;
    }
    
    typedef PVOID (CALLBACK* PFNEXPORTFUNC)(PIMAGE_NT_HEADERS,PVOID,ULONG,PIMAGE_SECTION_HEADER*);
    
    BOOL FindReso(const wstring &wsPeFilePath){
    	HANDLE hFileHandle,hFileMapHandle;
    	DWORD dwFileAttrib=0;
    	void * pBaseAddress; 
    	hFileHandle=CreateFile(wsPeFilePath.c_str(),GENERIC_READ,0,0,OPEN_EXISTING,dwFileAttrib,0);  
    	if(hFileHandle == INVALID_HANDLE_VALUE){
    		return FALSE;
    	}
    	hFileMapHandle=CreateFileMapping(hFileHandle,0,PAGE_READONLY,0,0,0);  
    	if(hFileMapHandle==NULL){  
    		CloseHandle(hFileHandle);  
    		return FALSE;  
    	}  
    	pBaseAddress=MapViewOfFile(hFileMapHandle,FILE_MAP_READ,0,0,0);  
    	if (pBaseAddress==NULL) {  
    		CloseHandle(hFileMapHandle);  
    		CloseHandle(hFileHandle);  
    		return FALSE;  
    	}  
    
    	HMODULE hModule = ::LoadLibrary(L"DbgHelp.dll");
    	if(!hModule){
    		return FALSE;
    	}
    	PFNEXPORTFUNC ImageRvaToVax=(PFNEXPORTFUNC)GetProcAddress(hModule,"ImageRvaToVa");
    	if(!ImageRvaToVax){
    		FreeLibrary(hModule);
    		return FALSE;
    	}
    
    	IMAGE_DOS_HEADER * pDosHeader = (IMAGE_DOS_HEADER*)pBaseAddress;  
    	IMAGE_NT_HEADERS * pNtHeader = (IMAGE_NT_HEADERS *)((BYTE*)pBaseAddress+ pDosHeader->e_lfanew);
    	IMAGE_OPTIONAL_HEADER * pOptHeader =  (IMAGE_OPTIONAL_HEADER *)((BYTE*)pBaseAddress + pDosHeader->e_lfanew + 24);
    	IMAGE_RESOURCE_DIRECTORY* pResourceDesc = (IMAGE_RESOURCE_DIRECTORY*)ImageRvaToVax(pNtHeader,pBaseAddress,pOptHeader->DataDirectory[2].VirtualAddress,0);  
    
    	if(pResourceDesc->NumberOfIdEntries + pResourceDesc->NumberOfNamedEntries == 0){
    		return TRUE;
    	}
    	ShowRes_DFS(0 ,pResourceDesc ,pResourceDesc);
    	FreeLibrary(hModule);
    	CloseHandle(hFileMapHandle);  
    	CloseHandle(hFileHandle);  
    	return TRUE;  
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    	WCHAR wcLocalFilePath[MAX_PATH] = {0};
    	GetModuleFileName(0 ,wcLocalFilePath ,MAX_PATH);
    	FindReso(wcLocalFilePath);
    	return 0;
    }


  • 相关阅读:
    Live Writer配置
    protobufnet 学习手记
    好的Sql语句也能提高效率(二)
    关于CodeSmith的输出问题
    [Scrum]12.29
    [scrum] 1.4
    分享 关于c#注释的规范
    [Scrum] 1.3
    分享:将XML(VS提取注释时生成)转换为Chm的一个方法
    【Scrum】2010.12.27
  • 原文地址:https://www.cnblogs.com/csnd/p/12062076.html
Copyright © 2011-2022 走看看