48、资源逆向:图标、字符串、对话框、菜单资源提取与修改

资源逆向,说白了就是跟 PE 文件里的「素材」打交道。你想想看,一个 Windows 程序除了代码,还有图标、对话框、菜单、字符串表这些东西。它们不像代码那样需要反汇编,直接就能看到结构。我个人觉得,这是逆向工程里最「解压」的环节——因为你能立刻看到成果。

资源在 PE 文件里是怎么存的?

PE 文件里有个叫「资源节」的区域,通常是 .rsrc。它是一棵三层树:类型 → ID → 语言。比如一个对话框资源,类型是 RT_DIALOG,ID 是 101,语言是中文简体。

我刚开始学逆向时,总以为资源是散乱存着的。后来用 CFF Explorer 打开一看,才发现它是个标准的树形结构。嗯,这里要注意:资源数据是 RVA 对齐的,不是直接文件偏移。你手动改的时候,得算清楚这个偏移量。

核心概念: 资源目录表(IMAGE_RESOURCE_DIRECTORY) + 资源目录条目(IMAGE_RESOURCE_DIRECTORY_ENTRY) + 资源数据条目(IMAGE_RESOURCE_DATA_ENTRY)。这三层结构,构成了整个资源树。

图标资源:不只是换张图

图标资源(RT_ICON 和 RT_GROUP_ICON)是成对出现的。RT_GROUP_ICON 是个「目录」,里面记录了图标的分辨率、色深,以及指向具体 RT_ICON 的索引。RT_ICON 才是真正的像素数据。

我记得有一次,客户说某个软件的图标太丑,想换成自己的。我直接用 Resource Hacker 打开,替换了 RT_GROUP_ICON 里的索引,再把新的 RT_ICON 数据写进去。结果程序启动时图标变了,但任务栏缩略图还是旧的——因为 Windows 会缓存图标。清一下图标缓存就好了。

小技巧: 替换图标时,最好保持新图标的分辨率与原图标一致。否则 Windows 可能会缩放失真。我一般用 32×32 和 16×16 两套。

字符串表:藏在代码里的「人话」

字符串表(RT_STRING)是很多逆向新手容易忽略的地方。它不像对话框那样直观,而是以「块」的形式存储。每个块包含 16 个字符串,按 ID 范围分组。比如 ID 1~16 在第一个块,17~32 在第二个块,以此类推。

为什么要这样设计?说白了是为了节省空间。Windows 早期内存金贵,按块加载比逐个加载高效。你想想看,如果一个程序有 1000 个字符串,但只用到前 20 个,按块加载只需要加载两个块。

我曾经在分析一个恶意软件时,发现它的 C2 域名就藏在字符串表里。但 ID 是乱序的,而且有些字符串是空的(占位符)。我写了个小脚本,把每个块里的 16 个字符串全部 dump 出来,才找到真正的域名。

// 解析字符串表的伪代码
for each block in RT_STRING:
    for i in 0..15:
        length = block[i].length
        if length > 0:
            string = block[i].data
            print(string)

对话框资源:布局与控件的「蓝图」

对话框资源(RT_DIALOG)定义了窗口的位置、大小,以及上面所有控件(按钮、文本框、列表等)的属性。它是个二进制结构,但 Resource Hacker 这类工具能把它解析成可读的文本。

我建议你直接看十六进制,因为有些工具会「美化」显示,反而掩盖了细节。比如对话框的 style 字段,决定了窗口是否有标题栏、是否可调整大小。我曾经改过一个对话框的 DS_CENTER 样式,让弹窗居中显示——就改了一个 bit。

注意: 对话框资源的坐标单位是「对话框单位」(DLU),不是像素。1 DLU 约等于 1/4 字符宽度。你直接改像素值,控件会错位。

菜单资源:结构简单,但坑不少

菜单资源(RT_MENU)定义了菜单栏和弹出菜单。它的结构比对话框简单:一个头,后面跟一串菜单项。每个菜单项有 flagsIDtext 三个关键字段。

我遇到过最坑的事:改了一个菜单项的 ID,结果点击后程序崩溃。后来发现,那个菜单项关联的 WM_COMMAND 消息处理函数里,用了一个 switch-case 表。ID 变了,case 匹配不上,直接跳到 default 分支,而 default 分支里有个空指针解引用。

所以改菜单 ID 时,一定要同步检查代码里的消息处理逻辑。或者,你干脆只改文本,不改 ID——这样最安全。

实战:用 Resource Hacker 提取并修改

工具推荐 Resource Hacker,免费、轻量、支持批量操作。我一般用它做三件事:

  1. 提取:把资源导出为 .res 文件或单独文件(如 .ico、.bmp)
  2. 修改:直接替换图标、改字符串、调对话框布局
  3. 注入:把修改后的资源写回 PE 文件

举个例子,你想改一个程序的标题栏文字。用 Resource Hacker 打开,找到字符串表,搜索原文字,改成新文字,保存。就这么简单。但要注意:新字符串长度不能超过原字符串,否则会覆盖后面的数据。如果非要加长,你得先扩展整个资源节——这就要动 PE 头了。

避坑指南: 我曾经改一个对话框的按钮文本,从「确定」改成「确认并提交」,长度多了 3 个字节。保存后程序启动就崩。后来我用十六进制编辑器,在资源节末尾找了块空白区域,把新字符串写进去,再修改资源数据条目里的指针。嗯,这招叫「资源重定位」。

知识体系图:资源逆向的核心流程

资源逆向核心流程 PE 文件 (.exe/.dll) .rsrc 资源节 RT_ICON / RT_GROUP_ICON RT_STRING RT_DIALOG RT_MENU 提取 / 替换图标 修改字符串内容 调整布局 / 样式 改文本 / ID

总结

资源逆向的门槛不高,但细节很多。图标要注意缓存,字符串要注意块结构,对话框要注意 DLU 单位,菜单要注意 ID 关联。我个人觉得,最好的学习方式就是拿一个简单的程序练手——比如计算器或记事本,把它的图标换成自己的,改几个字符串,调一下对话框布局。等你把这些都做熟了,再碰那些加了资源加密或压缩的「硬骨头」。

嗯,资源逆向就聊到这儿。记住一句话:资源是程序的「面子」,改好了立竿见影,改砸了直接崩。动手之前,先备份原文件。


公众号:蓝海资料掘金营,微信deep3321