当前位置: 首页 > news >正文

PE文件(十三)资源表

所谓的资源也就是我们之前学的MFC中的对话框,按钮,编辑框之类的东西。不仅MFC有资源,我们平时熟悉的控制台程序也有资源

当我们平时写一些程序或者木马时,我们通常对其定义一个随机的名称或者路径,然后再向外界进行释放(资源的 二进制数据写入文件)。而这些随机的名称或路径被写入PE文件的资源中

资源释放

我们以一个控制台程序为例,添加一个exe文件资源然后再进行资源释放:

首先我们先添加一个资源:资源文件->添加资源->导入->某exe文件->自定义资源类型,此时便会加载该exe文件的二进制数据

代码演示

#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <Windows.h>
#include "resource.h"

//随机资源名称
LPCSTR RandomString() 
{
	srand((int)time(NULL));//设置随机数起始值
	char szStr[] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' };//设置随机名称的字符
	char Temp[9] = { 0 };
	for (size_t i = 0; i < 7; i++)
	{
		int nIndex = rand();//设置随机数
		nIndex = nIndex % 26;//获取对应名称字符的随机数
		Temp[i] = szStr[nIndex];//获取随机数对应字符
	}
	return Temp;
}
//释放
void ReleaseFile(LPCSTR lpFilePath)
{
	HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_INJECTEXE1), "injectexe");//获取添加的资源
	DWORD dwSize = SizeofResource(NULL, hRsrc);//获取资源大小
	HGLOBAL hGlobal = LoadResource(NULL, hRsrc);//加载资源
	LPVOID lpRes = LockResource(hGlobal);//获取资源内存二进制数据
	HANDLE hFile = CreateFile(lpFilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);//创建文件
	DWORD dwWriteLen = 0;
	WriteFile(hFile, lpRes, dwSize, &dwWriteLen, NULL);//将资源的二进制数据写入文件
	CloseHandle(hFile);//关闭文件句柄
}

int main()
{
	char szFilePath[50] = "D:\\";
	char szFileEnd[5] = ".exe";
	LPCSTR szFileName = new char[50];
	strcpy((char *)szFileName, RandomString());
	strcat(szFilePath, szFileName);
	strcat(szFilePath, szFileEnd);//拼接资源名称
	ReleaseFile(szFilePath);
	system("pause");
	return 0;
}

此时我们生成的文件可以正常运行

资源表

资源表是一张描述资源数据在PE中的分布情况的表,其包含了PE文件中所使用到的资源。通过资源表,操作系统和应用程序可以轻松地访问和加载可执行文件中的资源。开发人员可以使用资源编辑器或编程工具来创建、编辑和管理资源表中的资源。

资源表定位

通过数据目录的第3个目录项,我们可以得知资源表所在地址RVA及其数据大小,从而定位到资源表所在地址

从资源表的起始开始为一级子目录的资源目录头,紧接着是各个一级子目录的资源目录项。每个一级子目录都可以指向一个二级子目录,起始为二级子目录的资源目录头,紧接着是各个二级子目录的资源目录项。每个而级子目录都可以指向一个三级子目录,起始为三级子目录的资源目录头,紧接着是各个三级子目录的资源目录项。每个三级子目录都可以指向一个资源或者代码页

三级目录结构

PE文件组织资源的方式类似于操作系统的文件管理方式。从根目录开始向下分为三级管理:一级子目录、二级子目录和三级子目录,三级子目录下为具体资源。如图所示:

1.一级子目录按照资源类型分类,如光标一级子目录,位图一级子目录等多个资源类型。

2.二级子目录按照资源的ID分类。例如:在菜单一级子目录下可以有: IDM_OPEN的ID为2001,IDM_EXIT的ID为2002,IDM1的ID为4000等多个菜单项。

3.三级子目录是按照资源的代码页分类,即不同的语言代码页对应不同的数据。其中,根据语言可以分为简体中文、英文、繁体中文等多个代码页。一般来说这个目录没啥用,这样用该目录下的文件

4.三级子目录后即为文件(资源),三级子目录和文件一一对应。文件是包含了资源数据的指针和大小等信息的一个数据结构。对所有资源数据块的访问均可从这里开始。

资源表结构

资源表的结构分为如下四个部分:

资源目录表(根目录):资源目录表是资源表的顶层结构,它包含了指向各个资源类型的目录项的指针。

资源类型目录表(一级子目录):资源类型目录表包含了每个资源类型的目录项,例如位图、图标、对话框等。

资源名称/标识符目录表(二级子目录):资源名称/标识符目录表包含了每个资源类型下的资源名称或标识符的目录项。

资源数据目录表(资源):资源数据目录表包含了每个资源的实际数据的位置和大小。

资源目录头

资源目录头,它标识了当前级别目录整体信息,如:属性,创建日期,版本目录项的数量等等描述信息。

资源目录头结构如下:

typedef struct _IMAGE_RESOURCE_DIRECTORY {
	DWORD   Characteristics;				//资源特性
    DWORD   TimeDateStamp;					//时间戳
    WORD    MajorVersion;					//资源的大版本号
    WORD    MinorVersion;					//资源的小版本号
    WORD    NumberOfNamedEntries;			//以字符串命名的入口数量
    WORD    NumberOfIdEntries;				//以ID命名的入口数量
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;

资源目录项

紧接着资源目录头的是资源目录项。一个资源目录可以有多个资源目录项(以名称定义的资源目录项或以ID定义的资源目录项,或者两者组合)。目录项和目录项之间按照线性排列:首先按照字母升序(不分大小写)排列名称资源目录项, 然后再按ID升序排列ID资源目录项。

资源目录项分为两种表示类型,分别为名称和ID。名称为以字符串形式命名的资源,一般为用户自定义的。ID条目为以整数形式命名的资源,一般为操作系统为我们预定义

 如下的操作系统为我们预定义的一级子目录的ID类型的类型数据,ID = 0到ID = 0x11

const char * g_ResType[0x11] = 
{
    "NULL",
	"鼠标指针",
	"位图",
	"图标",
	"菜单",
	"对话框",
	"字符串列表",
	"字体目录",
	"字体",
	"快捷键",
	"非格式化资源",
	"消息列表",
	"鼠标指针组",
	"NULL",
	"图标组",
	"NULL",
	"版本信息",
};

资源目录项结构如下:

typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
    union {
        struct {
            DWORD NameOffset:31;//低位:当高位为1时,该值为一个包含名称的结构体相对于一级子目录的资源目录头的偏移。当高位为0时,该值为一个编号
            DWORD NameIsString:1;//高位:当为1时,资源类型为名称。当为0时,资源类型为ID
        } DUMMYSTRUCTNAME;
        DWORD   Name;    //当NameIsString为1时,该值为ID,当NameIsString为0时,该值为一个包含名称的结构体相对于一级子目录的资源目录头的偏移。一般不用该成员
        WORD    Id;      //资源ID
    } DUMMYUNIONNAME;
    union {
        DWORD   OffsetToData;
        struct {
            DWORD   OffsetToDirectory:31;//低位:高位为1时,该值为下一级目录或资源相对于一级子目录的资源目录头的偏移。
            DWORD   DataIsDirectory:1;//高位:当为1时,该值表示下一级目录或资源
        } DUMMYSTRUCTNAME2;
    } DUMMYUNIONNAME2;
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

由于一级子目录下的DataIsDirectory为1指向二级子目录。而二级子目录下的DataIsDirectory为1指向资源

包含union字符串的结构体如下:

typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
    WORD    Length;
    WCHAR   NameString[ 1 ];
} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;

注意:NameString并不是以0结尾的字符串数组,因此我们在使用时,需要把它复制到一个新的数组中,以添加结尾的0

资源数据项

资源数据项即三级目录结构中的文件,它是通过三次目录定位后找到的一个数据结构,其结构如下:

typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
    DWORD   OffsetToData; //文件偏移
    DWORD   Size;         //资源大小
    DWORD   CodePage;     //代码页
    DWORD   Reserved;     //保留字段
} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;

通过资源目录项的OffsetToData,我们可以找到具体的资源。

资源表图示

 我们通过LoadPE观察一个PE文件的资源表:

如上图所示:

AFX_DIALOG_LAYOUT为一级子目录的资源目录项的类型信息

102为二级子目录的资源目录项的类型信息

图中并没有显示三级子目录,一般来说三级子目录的作用就是指向资源,因此常常把它忽略

Root Rirectory为根目录的资源目录头的相关信息

Selected Rirectory为一级子目录的资源目录头的相关信息

Selected Item为三级子目录下资源的相关信息

遍历资源表

代码实现:

static const char* szResName[0x11]
{
    0,
    "Corsor",
    "Bitmap",
    "Icon",
    "Menu",
    "Dialog",
    "StringTable",
    "FontDir",
    "Font",
    "Accelerator",
    "RCDATA",
    "MessageTable",
    "GroupCursor",
    "zz",
    "GroupIcon",
    "xx",
    "Version"
};

void PrintResourceTable()
{
    PIMAGE_DOS_HEADER pDosHeader = nullptr;
    PIMAGE_NT_HEADERS pNTHeader = nullptr;
    PIMAGE_FILE_HEADER pFileHeader = nullptr;
    PIMAGE_OPTIONAL_HEADER pOptionalHeader = nullptr;

    PIMAGE_DATA_DIRECTORY pDataDirectory = nullptr;
    PIMAGE_RESOURCE_DIRECTORY pResourceTable = nullptr;
    PIMAGE_RESOURCE_DIRECTORY_ENTRY pResourceEntry = nullptr;

    LPVOID pFileBuffer = nullptr;
    DWORD dwSize = 0;
    
    dwSize = ReadFile(&pFileBuffer, FILE_PATH_IN);
    if (dwSize == 0 || pFileBuffer == nullptr)
    {
        printf("读取文件失败");
    }

    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + sizeof(pNTHeader->Signature));
    pOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pFileHeader + IMAGE_SIZEOF_FILE_HEADER);

    //定位资源表
    pDataDirectory = (PIMAGE_DATA_DIRECTORY)(&pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]);
    pResourceTable = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pFileBuffer + RVA2FOA(pDataDirectory->VirtualAddress, pFileBuffer));
    pResourceEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResourceTable + 1);

    //解析第一层
    DWORD dwTypeCount = pResourceTable->NumberOfIdEntries + pResourceTable->NumberOfNamedEntries;
    for (DWORD i = 0; i < dwTypeCount; i++)
    {
        //最高位为0
        if (pResourceEntry[i].NameIsString == 0)
        {
            if (pResourceEntry[i].Id < 0x11)
            {
                printf("资源类型ID:%d %s\n", pResourceEntry[i].Id, szResName[pResourceEntry[i].Id]);
            }
            else
            {
                printf("资源类型ID:%d\n", pResourceEntry[i].Id);
            }
        }
        //最高位为1
        else if (pResourceEntry[i].NameIsString == 1)
        {
            PIMAGE_RESOURCE_DIR_STRING_U pStr = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)pResourceTable + pResourceEntry[i].NameOffset);
            WCHAR szStr[MAX_PATH] = { 0 };
            memcpy(szStr, pStr->NameString, pStr->Length * sizeof(WCHAR));
            printf("资源类型名称:%ls\n", szStr);
        }

        //解析第二层
        if (pResourceEntry[i].DataIsDirectory == 1)
        {
            printf("第二层目录偏移:%x\n", pResourceEntry[i].OffsetToDirectory);
            PIMAGE_RESOURCE_DIRECTORY pRes2 = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pResourceTable + pResourceEntry[i].OffsetToDirectory);
            PIMAGE_RESOURCE_DIRECTORY_ENTRY pResEntry2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes2 + 1);
            DWORD dwCount = pRes2->NumberOfIdEntries + pRes2->NumberOfNamedEntries;

            for (DWORD i = 0; i < dwCount; i++)
            {
                //最高位为0
                if (pResEntry2[i].NameIsString == 0)
                {
                    printf("  ->资源标识ID:%d\n", pResEntry2[i].Id);
                }
                else
                {
                    PIMAGE_RESOURCE_DIR_STRING_U pStr = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)pResourceTable + pResEntry2[i].NameOffset);
                    WCHAR szStr[MAX_PATH] = { 0 };
                    memcpy(szStr, pStr->NameString, pStr->Length * sizeof(WCHAR));
                    printf("  ->资源名称:%ls\n", szStr);
                }

                //解析第三层
                if (pResEntry2[i].DataIsDirectory == 1)
                {

                    PIMAGE_RESOURCE_DIRECTORY pRes3 = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pResourceTable + pResEntry2[i].OffsetToDirectory);
                    PIMAGE_RESOURCE_DIRECTORY_ENTRY pResEntry3 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pRes3 + 1);
                    printf("    -->代码页标号为:%x\n", pResEntry3->Id);
                    if (pResEntry3->DataIsDirectory == 0)
                    {
                        PIMAGE_RESOURCE_DATA_ENTRY pResDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((DWORD)pResourceTable+pResEntry3->OffsetToData);
                        printf("    --数据RVA:%x\n", pResDataEntry->OffsetToData);
                        printf("    --数据大小:%x\n", pResDataEntry->Size);
                    }
                }
            }
            
        }
    }
}

作业

利用MFC遍历资源表,用树进行显示记录



// ResTreeDlg.h: 头文件
//

#pragma once
#include<iostream>
#include<Windows.h>

// CResTreeDlg 对话框
class CResTreeDlg : public CDialogEx
{
// 构造
public:
	CResTreeDlg(CWnd* pParent = nullptr);	// 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_RESTREE_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	CTreeCtrl m_ResTree;
	CString RootNameEntries;
	CString FirstNameEntries;
	CString RootIDEntries;
	CString FirstIDEntries;
	CString ResRVA;
	CString ResFOA;
	CString ResSize;
	afx_msg void OnOpenFile();
	char* LoadFile(const WCHAR* szFilePath);
	char* szFileBuffer;
	DWORD RvaToFoa(DWORD dwRva, char* szBuffer);
	void OnInitResTree();
	DWORD dwFirstNameEntrys = 0;
	DWORD dwFirstIDEntrys = 0;
};


// ResTreeDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "ResTree.h"
#include "ResTreeDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnTvnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult);
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
	ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, &CAboutDlg::OnTvnSelchangedTree1)
END_MESSAGE_MAP()


// CResTreeDlg 对话框



CResTreeDlg::CResTreeDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_RESTREE_DIALOG, pParent)
	, RootNameEntries(_T(""))
	, FirstNameEntries(_T(""))
	, RootIDEntries(_T(""))
	, FirstIDEntries(_T(""))
	, ResRVA(_T(""))
	, ResFOA(_T(""))
	, ResSize(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CResTreeDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TREE1, m_ResTree);
	DDX_Text(pDX, IDC_EDIT1, RootNameEntries);
	DDX_Text(pDX, IDC_EDIT3, FirstNameEntries);
	DDX_Text(pDX, IDC_EDIT2, RootIDEntries);
	DDX_Text(pDX, IDC_EDIT4, FirstIDEntries);
	DDX_Text(pDX, IDC_EDIT5, ResRVA);
	DDX_Text(pDX, IDC_EDIT6, ResFOA);
	DDX_Text(pDX, IDC_EDIT7, ResSize);
}

BEGIN_MESSAGE_MAP(CResTreeDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_COMMAND(ID_32771, &CResTreeDlg::OnOpenFile)
END_MESSAGE_MAP()


// CResTreeDlg 消息处理程序

BOOL CResTreeDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CResTreeDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CResTreeDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CResTreeDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CResTreeDlg::OnOpenFile()
{
	// TODO: 在此添加命令处理程序代码
	CFileDialog file(TRUE, L"exe", L"*.exe", OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY, L"可执行文件|.exe|所有文件|.*", NULL);
	if (file.DoModal() == IDOK)
	{
		CString FilePath = file.GetPathName();
		szFileBuffer = LoadFile(FilePath.GetBuffer());
		AfxMessageBox(L"打开文件成功");
		OnInitResTree();
	}
	else
	{
		AfxMessageBox(L"打开文件失败");
	}
	
}

char* CResTreeDlg::LoadFile(const WCHAR* szFilePath)
{
	HANDLE hFile = CreateFileW(szFilePath, GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		return FALSE;
	}
	DWORD dwFileSize = GetFileSize(hFile, NULL);
	char* szBuffer = new char[dwFileSize];
	memset(szBuffer, 0, dwFileSize);
	if (ReadFile(hFile, szBuffer, dwFileSize, &dwFileSize, NULL))
	{
		return szBuffer;
	}
	else
	{
		return FALSE;
	}
}

DWORD CResTreeDlg::RvaToFoa(DWORD dwRva, char* szBuffer)
{
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szBuffer;
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szBuffer + pDos->e_lfanew);
	PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNt);
	if (dwRva < pSectionHeader[0].VirtualAddress)
	{
		return dwRva;
	}
	else
	{
		for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++)
		{
			if (dwRva >= pSectionHeader[i].VirtualAddress && dwRva < pSectionHeader[i].VirtualAddress + pSectionHeader[i].Misc.VirtualSize)
			{
				return dwRva - pSectionHeader[i].VirtualAddress + pSectionHeader[i].PointerToRawData;
			}
		}
	}
	return 0;
}

void CResTreeDlg::OnInitResTree()
{ 
	const WCHAR* g_ResType[0x11] = {
		L"NULL",
		L"鼠标指针",
		L"位图",
		L"图标",
		L"菜单",
		L"对话框",
		L"字符串列表",
		L"字体目录",
		L"字体",
		L"快捷键",
		L"非格式化资源",
		L"消息列表",
		L"鼠标指针组",
		L"NULL",
		L"图标组",
		L"NULL",
		L"版本信息",
	};
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)szFileBuffer;
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(szFileBuffer + pDos->e_lfanew);
	PIMAGE_OPTIONAL_HEADER pOptionHeader = &pNt->OptionalHeader;
	PIMAGE_DATA_DIRECTORY pResDir = pOptionHeader->DataDirectory + IMAGE_DIRECTORY_ENTRY_RESOURCE;

	PIMAGE_RESOURCE_DIRECTORY pFirst = (PIMAGE_RESOURCE_DIRECTORY)(RvaToFoa(pResDir->VirtualAddress, szFileBuffer) + szFileBuffer);
	DWORD dwFirstNum = pFirst->NumberOfIdEntries + pFirst->NumberOfNamedEntries;
	CHAR cRootNameEntries[MAX_PATH];
	sprintf(cRootNameEntries, "%04x", pFirst->NumberOfNamedEntries);
	RootNameEntries = cRootNameEntries;

	CHAR cRootIDEntries[MAX_PATH];
	sprintf(cRootIDEntries, "%04x", pFirst->NumberOfIdEntries);
	RootIDEntries = cRootIDEntries;
	UpdateData(FALSE);

	PIMAGE_RESOURCE_DIRECTORY_ENTRY pFirstEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pFirst + 1);
	HTREEITEM tFirstEntry;
	HTREEITEM tSecondEntry;
	HTREEITEM tResEntry;
	for (DWORD i = 0; i < dwFirstNum; i++)
	{
		if (pFirstEntry[i].NameIsString != 1)
		{
			if (pFirstEntry[i].Id < 0x11)
			{
				tFirstEntry = m_ResTree.InsertItem(g_ResType[pFirstEntry[i].Id], TVI_ROOT, TVI_LAST);
			}
			else
			{				
				WCHAR wcFirstEntryID[MAX_PATH];
				wsprintf(wcFirstEntryID, L"%d", pFirstEntry[i].Id);
				tFirstEntry = m_ResTree.InsertItem(wcFirstEntryID, TVI_ROOT, TVI_LAST);
			}			
		}
		else
		{
			PIMAGE_RESOURCE_DIR_STRING_U pFirstEntryName = (PIMAGE_RESOURCE_DIR_STRING_U)(pFirstEntry[i].NameOffset + (DWORD)pFirst);
			WCHAR wcFirstEntryName[MAX_PATH];
			memset(wcFirstEntryName, 0, MAX_PATH);
			memcpy(wcFirstEntryName, pFirstEntryName->NameString, pFirstEntryName->Length * 2);
			tFirstEntry = m_ResTree.InsertItem(wcFirstEntryName, TVI_ROOT, TVI_LAST);
		}
		if (pFirstEntry[i].DataIsDirectory == 1)
		{
			PIMAGE_RESOURCE_DIRECTORY pSecond = (PIMAGE_RESOURCE_DIRECTORY)(pFirstEntry[i].OffsetToDirectory + (DWORD)pFirst);
			DWORD dwSecondNum = pSecond->NumberOfIdEntries + pSecond->NumberOfNamedEntries;
			for (DWORD i = 0; i < dwSecondNum; i++)
			{
				PIMAGE_RESOURCE_DIRECTORY_ENTRY pSecondEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pSecond + 1);
				if (pSecondEntry[i].NameIsString != 1)
				{
					WCHAR wcSecondEntryID[MAX_PATH];
					wsprintf(wcSecondEntryID, L"%d", pSecondEntry[i].Id);
					tSecondEntry = m_ResTree.InsertItem(wcSecondEntryID, tFirstEntry, TVI_LAST);
				}
				else
				{
					PIMAGE_RESOURCE_DIR_STRING_U pSecondEntryName = (PIMAGE_RESOURCE_DIR_STRING_U)(pSecondEntry[i].NameOffset + (DWORD)pFirst);
					WCHAR wcFirstEntryName[MAX_PATH];
					memset(wcFirstEntryName, 0, MAX_PATH);
					memcpy(wcFirstEntryName, pSecondEntryName->NameString, pSecondEntryName->Length * 2);
					tSecondEntry = m_ResTree.InsertItem(wcFirstEntryName, tFirstEntry, TVI_LAST);
				}
				if (pSecondEntry[i].DataIsDirectory == 1)
				{
					PIMAGE_RESOURCE_DIRECTORY pThird = (PIMAGE_RESOURCE_DIRECTORY)(pSecondEntry[i].OffsetToDirectory + (DWORD)pFirst);
					PIMAGE_RESOURCE_DIRECTORY_ENTRY pThirdEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pThird + 1);
					if (pThirdEntry->DataIsDirectory == 1)
					{
						PIMAGE_RESOURCE_DATA_ENTRY pResDateEntry = (PIMAGE_RESOURCE_DATA_ENTRY)((DWORD)pFirst + pThirdEntry->OffsetToDirectory);
						
					}
				}
			}
		}
	}
}

由于本人能力有限,并不能全部实现功能,望诸位基于本人相关意见
 

http://www.dtcms.com/a/99240.html

相关文章:

  • 瑞芯微 RKrga接口 wrapbuffer_virtualaddr 使用笔记
  • SQL REGEXP 正则表达式
  • 圆球法线图,图生法线图 图片生成法线图
  • Git Reset 命令详解与实用示例
  • LangChain 结构化输出:用 Pydantic + PydanticOutputParser 驯服 LLM 的“自由发挥”
  • 【VP开发如此简单】Vision pro 实现图片跟踪
  • 异步转同步,实现一个消息队列
  • leetcode刷题日记——H 指数
  • 【Qt】数据库管理
  • Unity编辑器功能及拓展(3) —[Attribute]特性
  • 导航到渲染:浏览器加载页面的关键路径分析
  • 链表的创建:头插法与尾插法详解(数据结构)
  • 指纹识别之whois的作用:WHOIS数据在渗透测试中深度利用
  • vmware 创建win10 系统,虚拟机NAT网络设置
  • OJ题:移动零
  • Day 5
  • FPGA实现4K MIPI视频解码转HDMI2.0输出,基于IMX317摄像头,支持4K@60Hz,提供2套工程源码和技术支持
  • Logback 全面指南:从基础配置到高级应用
  • 76个复古黑白科幻几何抽象灵感运动元素纹理DJ舞台背景MV视频/PSD/PNG/JPG素材 Pixflow - Tour Visual Elements
  • 深入实践:基于WebSocket的全球化金融数据实时对接方案。 马来西亚、印度、美国金融数据API
  • 【Python桌面应用】PySide6 界面开发完全指南
  • javascript实现一个函数,将字符串中的指定子串全部替换为另一个字符串的原理,以及多种方法实现。
  • 1014 Waiting in Line
  • C++中shared_ptr 是线程安全的吗?
  • 使用 Avada 主题实现高级表单功能的技术指南
  • Day2 蓝桥杯省赛冲刺精炼刷题 —— 递归与递推
  • 浙江大学公开课|第二季|从大模型、智能体到复杂AI应用系统的构建——以产业大脑为例
  • final+模版设计模式的理解
  • [操作系统,学习记录]3.进程(2)
  • -PHP 应用文件上传函数缺陷条件竞争二次渲染黑白名单JS 绕过