《Windows PE》7.3 遍历资源表

本节我们将通过一个示例程序实现对资源表的遍历。

本节必须掌握的知识点:

        资源表遍历

7.3.1 资源表遍历

实验四十九:遍历资源表

●模块1:resource.h

//{{NO_DEPENDENCIES}}

// Microsoft Visual C++ 生成的包含文件。

// 供 peinfo.rc 使用

//

#define ICO_MAIN                 111

#define DLG_MAIN                 1000

#define IDC_INFO                 001

#define IDM_MAIN                 2000

#define IDM_OPEN                 2001

#define IDM_EXIT                 2002

#define IDM_1                    4000

#define IDM_2                    4001

#define IDM_3                    4002



// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        113

#define _APS_NEXT_COMMAND_VALUE         4003

#define _APS_NEXT_CONTROL_VALUE         1002

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif

●模块2:peinfo.rc

// Microsoft Visual C++ generated resource script.

//

#include "resource.h"



#define APSTUDIO_READONLY_SYMBOLS

/

//

// Generated from the TEXTINCLUDE 2 resource.

//

#include "winres.h"



/

#undef APSTUDIO_READONLY_SYMBOLS



/

// 中文(简体,中国) resources



#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)

LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED



#ifdef APSTUDIO_INVOKED

/

//

// TEXTINCLUDE

//



1 TEXTINCLUDE

BEGIN

    "resource.h\0"

END



2 TEXTINCLUDE

BEGIN

    "#include ""winres.h""\r\n"

    "\0"

END



3 TEXTINCLUDE

BEGIN

    "\r\n"

    "\0"

END



#endif    // APSTUDIO_INVOKED



/

//

// Dialog

//



DLG_MAIN DIALOGEX 50, 50, 427, 300

STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "PE文件头中几个关键地址的定位:"

MENU IDM_MAIN

FONT 9, "宋体", 0, 0, 0x0

BEGIN

    CONTROL         "",IDC_INFO,"RichEdit20W",ES_MULTILINE | ES_NOHIDESEL | ES_READONLY | ES_WANTRETURN | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP,7,7,411,280,WS_EX_ACCEPTFILES

END



/

//

// DESIGNINFO

//



#ifdef APSTUDIO_INVOKED

GUIDELINES DESIGNINFO

BEGIN

    DLG_MAIN, DIALOG

    BEGIN

        LEFTMARGIN, 7

        TOPMARGIN, 7

    END

END

#endif    // APSTUDIO_INVOKED



/

//

// AFX_DIALOG_LAYOUT

//



DLG_MAIN AFX_DIALOG_LAYOUT

BEGIN

    0

END



RESULT_MODULE AFX_DIALOG_LAYOUT

BEGIN

    0

END



/

//

// Menu

//



IDM_MAIN MENU

BEGIN

    POPUP "文件(&F)"

    BEGIN

        MENUITEM "打开文件(&O)...",            IDM_OPEN

        MENUITEM SEPARATOR

        MENUITEM "退出(&x)",                   IDM_EXIT

    END

    POPUP "编辑(&E)"

    BEGIN

        MENUITEM SEPARATOR

    END

    POPUP "格式(&O)"

    BEGIN

        MENUITEM SEPARATOR

    END

    POPUP "查看(&V)"

    BEGIN

        MENUITEM "源文件",                  IDM_1

        MENUITEM "窗口透明度",              IDM_2

        MENUITEM SEPARATOR

        MENUITEM "大小",                    IDM_3

    END

    POPUP "帮助(&H)"

    BEGIN

        MENUITEM SEPARATOR

    END

END



/

//

// Icon

//



// Icon with lowest ID value placed first to ensure application icon

// remains consistent on all systems.

ICO_MAIN                ICON                    "main.ico"



#endif    // 中文(简体,中国) resources

/



#ifndef APSTUDIO_INVOKED

/

//

// Generated from the TEXTINCLUDE 3 resource.

//



/

#endif    // not APSTUDIO_INVOKED

●模块三:info.h

#pragma once

#ifndef INFO_H_

#define INFO_H_



#include <windows.h>

#include <richedit.h>   //CHARFORMAT富文本结构定义

#include <commctrl.h>       //通用控件

#pragma comment(lib,"comctl32.lib")

#include <strsafe.h>    //StringCchCopy

#include <stdlib.h>



//函数声明

BOOL CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void Exception(void);

void init(); //初始化

void  _OpenFile();//打开PE文件并处理

DWORD RVAToOffset(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);// 将内存偏移量RVA转换为文件偏移

DWORD GetRVASection(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);//查找 RVA 所在的节区

int  CALLBACK _Handler(EXCEPTION_POINTERS * lpExceptionPoint);

void ShowErrMsg();

void _AppendInfo(const TCHAR * _lpsz);//往文本框中追加文本

//PE文件处理模块

void _getMainInfo(PBYTE, IMAGE_NT_HEADERS *, int);//从内存中获取PE文件的主要信息

void _getResourceInfo(PBYTE, IMAGE_NT_HEADERS *, int);//获取PE文件的资源信息

//将PEInfo.txt文本信息读入RichEdit控件

void _readToRichEdit();



#endif

●模块四:pemain.c(略)

●模块五:RvaToFileOffset.c(略)

●模块六:Getpeinfo.c(略)

●模块七:GetResourceInfo.c 

/*

获取PE资源信息

*/

#include <windows.h>

#include "info.h"



extern TCHAR szFileName[MAX_PATH];  //pemian.c模块中定义

extern HANDLE hWinEdit,hFileDump;

extern HWND hWinMain;



void _AppendInfo(const TCHAR * _lpsz);

DWORD RVAToOffset(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);

DWORD GetRVASection(IMAGE_DOS_HEADER * lpFileHead, DWORD dwRVA);



//参数1:PE文件地址;参数2:资源块起始地址;参数3:目录项地址:参数4:层级

void ProcessRes(PBYTE lpFile, PBYTE lpRes, IMAGE_RESOURCE_DIRECTORY * lpResDir, DWORD dwLevel)

{

    const TCHAR szLevel1[] = TEXT("\r\n---------------------------------------------------------\r\n")

        TEXT("资源类型:%s\r\n")

        TEXT("---------------------------------------------------------\r\n");

    const TCHAR szResData[] = TEXT("     文件偏移:%08X (代码页=%04X, 长度%d字节)\r\n");

    const TCHAR szLevel1byID[] = TEXT("%d (自定义编号)");

    const TCHAR szLevel2byID[] = TEXT("  ID: %d\r\n");

    const TCHAR szLevel2byName[] = TEXT("  Name: %s\r\n");

    const TCHAR szType[][16] = {

                            TEXT("光标        "),//1

                            TEXT("位图        "),//2

                            TEXT("图标        "),//3

                            TEXT("菜单        "),//4

                            TEXT("对话框      "),//5

                            TEXT("字符串      "),//6

                            TEXT("字体目录    "),//7

                            TEXT("字体        "),//8

                            TEXT("加速键      "),//9

                            TEXT("未格式化资源 "),//10

                            TEXT("消息表      "),//11

                            TEXT("光标组      "),//12

                            TEXT("未知类型    "),//13

                            TEXT("图标组      "),//14

                            TEXT("未知类型    "),//15

                            TEXT("版本信息    ") //16

    };



    DWORD dwNextLevel;

    static TCHAR szBuffer[256];

    static TCHAR szResName[256];

    IMAGE_RESOURCE_DIRECTORY * lpstRES_DIR;//资源目录

    IMAGE_RESOURCE_DIRECTORY_ENTRY * lpstRES_DIR_ENT;

    IMAGE_RESOURCE_DATA_ENTRY * lpstRES_DATA_ENT;

    int number; //资源数量

    DWORD lpAddr, address;

    DWORD IDname, dwBytesWrite;



    dwNextLevel = dwLevel + 1;

    //检查资源目录表,得到资源目录项的数量

    lpstRES_DIR = lpResDir;

    number = lpstRES_DIR->NumberOfIdEntries + lpstRES_DIR->NumberOfNamedEntries;

//IMAGE_RESOURCE_DIRECTORY结构后面紧跟着是IMAGE_RESOURCE_DIRECTORY_ENTRY结构

    lpstRES_DIR_ENT = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)((PBYTE)lpstRES_DIR + sizeof(IMAGE_RESOURCE_DIRECTORY));



    //循环处理每个资源目录项

    while (number--)

    {

        RtlZeroMemory(szBuffer, sizeof(szBuffer));

//OffsetToData字段最高位为1,后七位指向下层目录块的起始地址IMAGE_RESOURCE_DIRECTORY结构

        lpAddr = lpstRES_DIR_ENT->OffsetToData;

        if (lpAddr & 0x80000000)

        {

            lpAddr &= 0x7fffffff;

            lpAddr += (DWORD)lpRes;

            //第一层:资源类型

            if (dwLevel == 1)

            {

                IDname = lpstRES_DIR_ENT->Name;//目录项名称字符串或ID

//最高位为1时,低7位值作为指向UNICODE编码的资源名IAMGE_RESOURCE_STRING_U结构

                if (IDname & 0x80000000)

                {

                    IDname &= 0x7fffffff;

                    IDname += (DWORD)lpRes;

                    //复制UNICODE资源名

                    lstrcpy(szResName, (LPCWSTR)(IDname + 2));

                    address = (DWORD)szResName;

                }

                //高位为0时,表示字段的值作为ID使用

                else

                {

                    if (IDname <= 16)   //为预定义资源

                    {

                        address = (DWORD)&szType[IDname - 1];

                    }

                    else //大于16,自定义资源

                    {

                        wsprintf(szResName, szLevel1byID, IDname);

                        address = (DWORD)szResName;

                    }

                }

                wsprintf(szBuffer, szLevel1, (PBYTE)address);

            }

            //第二层:资源(ID或名称)

            else if (dwLevel == 2)

            {

                IDname = lpstRES_DIR_ENT->Name;//目录项名称字符串或ID

                //资源以字符串方式命名

                if (IDname & 0x80000000)

                {

                    IDname &= 0x7fffffff;

                    IDname += (DWORD)lpRes;

                    //复制UNICODE资源名

                    lstrcpy(szResName, (LPCWSTR)(IDname + 2));

                    wsprintf(szBuffer, szLevel2byName, szResName);

                }

                //资源以 ID 命名

                else

                {

                    wsprintf(szBuffer, szLevel2byID, IDname);

                }

            }

            else

                break;

            //_AppendInfo(szBuffer);

            //写入Dump文件

            dwBytesWrite = 0;

            WriteFile(hFileDump, szBuffer,

sizeof(szBuffer), &dwBytesWrite, NULL);

            ProcessRes(lpFile, lpRes,

(IMAGE_RESOURCE_DIRECTORY *)lpAddr, dwNextLevel); //递归调用

        }

        //OffsetToData字段最高位为0,不是资源目录则显示资源详细信息,

        //后七位指向用来描述资源数据块的IMAGE_RESOURCE_DATA_ENTRY结构

        else

        {

            lpAddr += (DWORD)lpRes;

            lpstRES_DATA_ENT = (IMAGE_RESOURCE_DATA_ENTRY *)lpAddr;

            address = RVAToOffset((IMAGE_DOS_HEADER *)lpFile,

lpstRES_DATA_ENT->OffsetToData);

            if (!address)

                return;



            wsprintf(szBuffer, szResData, address,

                lpstRES_DIR_ENT->Name, lpstRES_DATA_ENT->Size);

            //_AppendInfo(szBuffer);

            //写入Dump文件

            dwBytesWrite = 0;

            WriteFile(hFileDump, szBuffer, sizeof(szBuffer),

 &dwBytesWrite, NULL);

        }

        lpstRES_DIR_ENT++;

    }

}



void _getResourceInfo(PBYTE lpFile, IMAGE_NT_HEADERS * _lpPeHead, int _dwSize)

{

    const TCHAR szMsg5[] = TEXT("\r\n\r\n文件名:%s\r\n")

        TEXT("---------------------------------------------------------\r\n")

        TEXT("资源所处的节:%s\r\n");

    const TCHAR szErrNoRes[] = TEXT("\r\n这个文件中没有包含资源!");



    static TCHAR szBuffer[256];

    static TCHAR szSectionName[16];

    static TCHAR szNameB[256];

    static TCHAR szNameW[256];

    IMAGE_NT_HEADERS32 * lpstNT32;      //PE32文件头

    IMAGE_NT_HEADERS64 * lpstNT64;      //PE64文件头

    IMAGE_RESOURCE_DIRECTORY * lpstRES_DIR;资源目录

    DWORD rva, address, dwBytesWrite;



    lpstNT32 = _lpPeHead;

    lpstNT64 = (IMAGE_NT_HEADERS64 *)_lpPeHead;

    //检测是否存在资源--数据目录第2项

    if (lpstNT64->OptionalHeader.Magic == 0x020B) //64位PE文件

    {//数据目录项的第3项

        rva = lpstNT64->OptionalHeader.DataDirectory[2].VirtualAddress;

    }

    else

        rva = lpstNT32->OptionalHeader.DataDirectory[2].VirtualAddress;

    if (!rva)

    {

        MessageBox(hWinMain, szErrNoRes, NULL, MB_OK);

        //写入Dump文件

        dwBytesWrite = 0;

        WriteFile(hFileDump, szErrNoRes,

sizeof(szErrNoRes), &dwBytesWrite, NULL);

        return;

    }

    //将 RVA 转换成实际的数据位置

    address = RVAToOffset((IMAGE_DOS_HEADER *)lpFile, rva);

    if (!address)

        return;

    //资源目录的实际地址

lpstRES_DIR = (IMAGE_RESOURCE_DIRECTORY *)(address + (DWORD)lpFile);



    //获取资源目录所在的节区名

    address = GetRVASection((IMAGE_DOS_HEADER *)lpFile, rva);

    if (!address)

        return;

    RtlCopyMemory(szNameB, (LPCWSTR)address, 8);//改用内存拷贝

    //需要将节区名称ASCII码字符转为Unicode字符

    MultiByteToWideChar(CP_ACP, 0, (LPCCH)szNameB, 8, szSectionName, 16);

    //显示一些常用的信息

    RtlZeroMemory(szBuffer, sizeof(szBuffer));

    wsprintf(szBuffer, szMsg5, szFileName, szSectionName);

    //SetWindowText(hWinEdit, szBuffer);

    //写入Dump文件

    dwBytesWrite = 0;

    WriteFile(hFileDump, szBuffer, sizeof(szBuffer), &dwBytesWrite, NULL);



    //显示所有资源目录块的信息

    ProcessRes(lpFile, (PBYTE)lpstRES_DIR, lpstRES_DIR, 1);

}

       运行:

      

图7-6 遍历资源表

提示

1.对于命名的资源类型,输出字符串名称。

资源类型:AFX_DIALOG_LAYOUT

RESULT_MODULE

---------------------------------------------------------

  Name: RESULT_MODULE

    文件偏移:00003AC0 (代码页=0804, 长度2字节)

  ID: 1000

     文件偏移:00003AB8 (代码页=0804, 长度2字节)

2.示例程序对于非资源内容(例如应用程序清单)归类于自定义资源类型。

资源类型:24 (自定义编号)

---------------------------------------------------------

 ID: 1

文件偏移:00007DD0 (代码页=0409, 长度381字节)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值