ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

页游微端解包实操:Universal Extractor分层识别与资源提取

页游微端解包实操:Universal Extractor分层识别与资源提取

1. 先搞清楚要拆的东西是什么

标题里那款页游的名字我就不重复了,下文统一叫“目标微端”。做资源提取这行久了,我越来越确信一件事:Universal Extractor 这类工具本身不难,难的是判断你面前这个 exe 到底是哪一种“套娃”。目标微端在 Win10 上的分发形态,决定了你后面所有操作路径——它是一个 NSIS 安装包,还是一个自解压包里再套一个 Electron 应用,又或者是一个只有几 MB 的下载器、真正的资源在首次启动时才拉取,这几种情况的处理方式完全不同。很多人装完 Universal Extractor,把 exe 拖进去,跑完发现输出目录里只有几个 dll 和一个 launcher,就以为工具不行,其实是拆错了层。

这篇东西是我自己整理的操作笔记,偏实操,面向三类人:想从客户端里捞出图片、音频、配置文件做素材归档的;想搞清楚一个桌面微端内部结构的;以及手上有个来路不明的 exe 想先看看里面装了什么的。我不讲逆向,不碰任何在线服务,所有动作都在本地的一个离线副本上完成,拆出来的东西只用于自己看和自己学。Universal Extractor 在这个流程里扮演的角色是“第一层剥壳器”,它不保证能拆到最里层,但它能用最低的成本告诉你:这玩意儿是什么格式、里面大概有几层、下一层该用什么工具。这个定位想明白了,后面的操作会顺很多。

1.1 微端常见的几种打包形态

页游的 Win10 微端,我见过的基本逃不出下面这几类。第一种是标准安装包,NSIS 或者 Inno Setup 做的,双击出来一个安装向导,选路径、点下一步、装完在开始菜单留个快捷方式。这类是最好处理的,因为它们的结构是公开的、格式是固定的,Universal Extractor 基本能一把过。NSIS 的包里经常能看到$PLUGINSDIR这种临时目录,Inno Setup 的包里则常见{app}这样的占位目录,看到这两个名字,你心里就该有数了。

第二种是自解压包,本质是一个 exe 外壳加一个压缩流,常见的是 7z 或 RAR 的自解压模块,也有些是自己写的释放逻辑。这种包用 Universal Extractor 拆,通常能直接拿到里面的压缩包本体,然后再拆一次。第三种是“壳 + 资源”的结构,exe 只是一个浏览器内核的宿主(比如 CEF 或者 Electron),真正的界面和素材在旁边的resources、pak、asar文件里,这时候 Universal Extractor 只能帮你把安装包拆开,后面的活要换工具。

第四种最麻烦:微端只是个下载器,安装完目录里只有几十 MB,启动后才会把几百 MB 的资源拉到本地缓存目录。这种情况你拆安装包是拆不出素材的,得等它跑完一轮,去用户目录下的缓存路径里找。我吃过这个亏,对着一个 8 MB 的安装包折腾了半小时,最后发现在%LOCALAPPDATA%下面躺着两个 G 的资源。所以第一步永远是:先看安装包体积,体积和宣传的资源量对不上,就别急着拆包,先让它正常跑一次。

1.2 为什么第一层选 Universal Extractor

市面上能拆包的工具不少,7-Zip、Bandizip、PeaZip 都能打开不少安装包,那我为什么还是习惯先用 Universal Extractor 过一遍?原因很实在:它是一个“调度器”,不是单一格式的解压器。它的工作逻辑是先看扩展名,再看文件头签名,然后从自带的一堆小工具里挑一个最合适的去调用。NSIS 交给专门的解包器,Inno Setup 交给另一个,MSI 走系统自带的管理安装接口,CAB 走 expand,遇到认不出来的还会让你手动指定格式。这种“一接口多后端”的设计,在你不确定面前是什么包的时候特别省事。

7-Zip 也能打开 NSIS 和部分 Inno 包,但对一些加了壳或者改了头的安装包就无能为力了,而且它不会告诉你“我识别到这是 Inno Setup 5.x”。Universal Extractor 的日志里会明确写出它用了哪个后端、调用了哪个命令行,这对做笔记的人来说价值很大——你下次遇到同类包,就知道该直接上哪个工具,不用再走一遍弯路。

当然它也有明显短板。第一,它的更新早就停了,新版本的安装器格式它不认识;第二,它调用外部程序的方式比较粗暴,某些安全软件会拦;第三,它对 Unicode 路径和老式中文文件名的处理不算好,输出目录里出现乱码是常有的事。这些短板我在后面的章节里都会给出绕法。选它做第一层,是因为它“什么都试一遍”的性格,而不是因为它“什么都能拆”。

2. 动手前的准备:环境、备份与目录规划

我见过太多人第一步就翻车:直接把原始安装包扔进工具,拆完发现文件被改写了,或者输出目录把源文件覆盖了。Universal Extractor 默认会在源文件旁边生成输出目录,如果你把 exe 放在桌面,拆完桌面会多出一堆文件夹,运气不好还会和已有目录重名。所以我的规矩是:先复制一份原始文件到工作目录,原始文件放在一个只读的位置,永远不在它身上做操作。

工作目录我一般这么建:一个work根目录,下面分00_origin(原始安装包,只读)、01_stage1(第一层解包输出)、02_stage2(二次解包)、99_tools(工具本体)。这个结构看着啰嗦,但当你拆到第三层、目录里躺着几千个文件的时候,你会感谢自己当初多建了这几层。尤其是做笔记,路径清晰意味着三个月后你还能看懂自己当时干了什么。

2.1 工具本体放哪、怎么配

Universal Extractor 是绿色软件,解压即用,但它依赖同目录下的bin文件夹里那一堆小工具,整个文件夹必须完整保留,不能只把主程序 exe 拎出来。我一般把它放在D:\tools\uniextract这种非系统盘、路径全英文、没有空格的位置。路径里有中文或者空格,某些后端工具调用时会解析失败,这个坑很隐蔽,日志里只报一句“执行失败”,你得排查半天。

Win10 上还有两个设置建议提前处理。一是给工具目录加一个安全软件的排除项,因为它会频繁调用子进程、释放临时文件,被误拦的概率不低;二是如果你打算处理深层目录,提前把系统的长路径支持打开,注册表里LongPathsEnabled那一项设为 1,否则解到第五层目录时会出现“路径过长”的写入失败,而且失败得很安静。

注意:加排除项这个动作只针对你自己确认过来源的工具目录,别顺手把整个下载目录都排除了,那是给自己挖坑。

配置上我一般只改两处。一是把“解包后自动打开输出目录”关掉,因为批量处理时它弹窗弹得人心烦;二是把临时目录指到一个空间充足的盘,默认走系统临时目录,拆大包的时候容易把 C 盘塞满。这两项在工具的设置界面里都能找到,改完记得让它写进配置文件,不然下次启动又回去了。

2.2 判断包类型的几个土办法

在把文件拖进工具之前,我习惯先做三十秒的预判,能省掉很多无效操作。第一个办法是看体积和数字签名:正规渠道分发的安装包一般带签名,右键属性里能看到;体积在 30 MB 到 200 MB 之间的,多半是完整安装包;低于 20 MB 的,八成是下载器。

第二个办法是看文件头。用任意一个十六进制查看器打开前 16 个字节,对照下面这张表,基本能猜个八九不离十。这个动作看着原始,但比任何自动识别都可靠,因为文件头是骗不了人的,扩展名可以随便改。

偏移处可见字符大概率格式后续处理思路
PK开头ZIP 或其变体直接解压,或用 7-Zip 打开
MSCFCAB 压缩包系统自带 expand 或 7-Zip
Rar!RAR 压缩包7-Zip / WinRAR
NullsoftInstNSIS 安装包Universal Extractor 的 NSIS 后端
Inno Setup字样Inno Setup 安装包专门的 Inno 解包器
7z半角字符7z 压缩流7-Zip 直接打开
MZ开头且体积很小普通 PE 程序或下载器先运行一次看释放了什么

第三个办法更直接:把 exe 拖进 7-Zip 的窗口里试一下,能列出目录结构就说明它是标准压缩格式,列不出来再上 Universal Extractor。这个顺序是我自己摸索出来的,因为 7-Zip 打开速度快、不释放临时文件,试错成本几乎为零。

2.3 备份与“只读”原则

这一步我要单独强调,因为它关系到你后面所有操作能不能重来。原始安装包必须只读,我甚至会给它加一个只读属性,防止自己手滑。理由很简单:解包过程中工具有可能会往源目录写临时文件,某些后端的释放逻辑会覆盖同名文件,一旦源文件被污染,你就失去了唯一的参照物。

我的做法是算一遍原始文件的哈希值,记在笔记里,每次拆完回头核对一下,确认源文件没被动过。这一步听着像强迫症,但当你拆了几十个包、发现某次输出的文件数量和预期对不上时,只有哈希能证明问题出在解包环节而不是源文件本身。

3. 实操:用 Universal Extractor 完成第一层解包

准备工作做完,正式开拆。打开主程序,界面很朴素,一个文件选择框、一个输出目录框、几个勾选项。我一般这么填:源文件指向01_stage1里那份复制过来的副本,输出目录留空让它自动生成,勾上“递归解包”之外的选项先不动。第一次拆不建议开递归,因为你不知道里面有几层,递归解包有时候会在某一层陷入死循环,或者把一个几百兆的包拆出几万个碎文件,收拾起来很痛苦。

点开始之后,看日志比看进度条有用。日志里会依次出现“正在分析文件类型”“识别为 XXX 格式”“调用 XXX 解包器”“解包完成,共提取 N 个文件”。识别格式那一行是关键,它告诉你工具认定了什么,如果它认错了,你后面拿到的输出就是垃圾。我遇到过一次,工具把一个自解压的 7z 包识别成了普通 PE,只提取出一个图标和版本信息,那种情况下不用怀疑人生,手动在格式下拉框里指定 7z 再跑一次就好。

3.1 图形界面操作的几个细节

界面上有一个“提取方式”的选择,自动、仅解压、仅展开、复制文件这几项。大多数情况用自动就行,但有两种例外。第一种是包体很大、你只想快速看看里面有什么,这时候选“仅解压”会快很多,因为它跳过了一些深度分析步骤。第二种是遇到加过壳的安装包,自动模式会反复尝试各种后端、耗时很长,这时候直接指定你从文件头判断出来的格式,能省掉大量等待。

还有一个容易被忽略的点:输出目录的层级。NSIS 包解出来经常是$PLUGINSDIR、$INSTDIR这样的目录名,Inno 包解出来是{app}、{tmp}。这些不是错误,是安装器内部的占位符,真正的文件就在这些目录里面。我第一次拆的时候以为工具出 bug 了,把$PLUGINSDIR当成垃圾目录删掉,结果把真正的资源一起删了。正确的做法是先进去看,$PLUGINSDIR里通常是安装器自己的临时文件,价值不大;{app}对应的才是安装后的程序目录,那里面才有东西。

3.2 命令行批量处理

单个包用界面操作没问题,但当你需要反复试不同参数、或者一次处理十几个包的时候,界面就低效了。这里要说实话:Universal Extractor 的命令行参数在不同版本之间并不统一,我手上的版本和网上流传的参数对不上,硬套容易踩坑。所以我的实际做法是分工——第一层识别用它的界面跑一次,确认格式之后,批量处理交给 7-Zip,因为 7-Zip 的命令行参数稳定、文档齐全、脚本化友好。

:: 批量把 stage1 目录下所有 exe 用 7z 尝试展开 for %f in ("D:\work\01_stage1\*.exe") do ( 7z x "%f" -o"D:\work\02_stage2\%~nf" -y )

上面这段是 cmd 下的写法,.bat文件里要把百分号写成两个。它的作用是遍历目录、逐个解压到以原文件名命名的子目录、遇到提示一律选是。跑之前建议先拿一个文件试,确认输出路径没问题再全量跑。

# 统计每个输出目录的文件数和总体积,快速判断哪一层拆成功了 Get-ChildItem "D:\work\01_stage1" -Directory | ForEach-Object { $files = Get-ChildItem $_.FullName -Recurse -File -ErrorAction SilentlyContinue [PSCustomObject]@{ 目录 = $_.Name 文件数 = $files.Count 体积MB = [math]::Round(($files | Measure-Object Length -Sum).Sum / 1MB, 2) } } | Sort-Object 体积MB -Descending | Format-Table

这段 PowerShell 是我每次拆完必跑的。它能一眼告诉你哪个目录里装着真正的资源——通常体积最大的那个就是。有一次我拆完发现某个目录只有 3 个文件却有 400 MB,点进去一看是个压缩包本体,说明第一层只是剥了个壳,真正的活在第二层。

3.3 读懂输出,判断有没有拆到底

拆完之后怎么判断“拆到底了”?我的判断标准有三条。第一,目录里出现大量分散的小文件,比如成百上千张 png、jpg,或者一堆按数字编号命名的二进制文件,这通常说明资源已经散开了。第二,出现了resources、assets、pak、asar这类名字,说明还有一层没拆。第三,目录里只有一个 exe 加几个 dll,那基本可以确定这是个壳或者下载器,资源不在这里。

还有一种情况是拆出来的文件全是乱码名,比如一堆问号或者方块。这不是文件损坏,是编码问题。安装器在打包时用的是本地代码页,解包器按 UTF-8 去解释,就对不上了。这种情况下不要重命名,保留原样,用支持编码切换的工具(比如某些解包器自带的“按 GBK 解析文件名”选项)重新导一次,或者干脆用脚本批量转码。

4. 二次处理:把一堆文件变成能用的资源

第一层拆完,通常拿到的是一堆“半成品”:一个主程序、几个 dll、一个资源目录、可能还有一两个压缩包。这时候的工作重心从“解包”转向“分类和识别”。我的习惯是先按扩展名做一次粗分类,把图片、音频、文本、二进制分开,再针对每一类做深处理。这一步用 PowerShell 或者随便一个文件管理器都能做,重点是别急着打开每个文件看,先看清楚整体的分布。

4.1 资源格式的快速识别

页游微端里的资源,图片一般是 png、jpg、webp,音频是 mp3、ogg,这些都是通用格式,双击就能看。麻烦的是那些“看着不像资源”的文件:.dat、.bin、.pak、.pack、.res,扩展名是开发者自己定的,内容可能是任何东西。这时候还是老办法,看文件头。89 50 4E 47是 png,FF D8 FF是 jpg,OggS是 ogg,FWS、CWS、ZWS三个开头是 SWF 动画,PK开头说明它其实是个 zip。

我整理过一张常用的对照表,放在笔记里随时查:

文件头(十六进制)对应格式常见用途
89 50 4E 47PNG界面图、图标
FF D8 FFJPEG背景图、立绘
52 49 46 46RIFF 容器WAV 音频、WebP 图片
4F 67 67 53Ogg音效、背景音乐
46 57 53/43 57 53SWF动画、小游戏模块
50 4B 03 04ZIP资源包本体
1A 45 DF A3Matroska 容器视频或封装的资源流

用脚本批量读文件头很快,几十行 PowerShell 就能把整个目录扫一遍,把每个文件的“真实类型”输出成一张表。这张表的价值在于,它能让你在几分钟内知道这个客户端里大概有哪些东西,值不值得继续往下拆。

# 批量读取文件头前 4 字节,输出十六进制,用于人工比对 Get-ChildItem "D:\work\02_stage2" -Recurse -File | Where-Object { $_.Length -gt 4 } | ForEach-Object { $bytes = Get-Content $_.FullName -Encoding Byte -TotalCount 4 [PSCustomObject]@{ 文件 = $_.Name 头 = ($bytes | ForEach-Object { $_.ToString("X2") }) -join " " 大小KB = [math]::Round($_.Length / 1KB, 1) } } | Format-Table -AutoSize

4.2 嵌套包和特殊容器

第二层最常见的是 zip 变体。有些开发者会把资源打成 zip 之后改个扩展名,防止用户直接打开,但文件头骗不了人。改回.zip用 7-Zip 打开就行,这一步没什么技术含量。

稍微麻烦一点的是 Electron 应用的asar包。这类微端的外壳是一个浏览器,界面用前端技术写,资源全打进一个app.asar文件里。处理它需要 Node 环境,装一个 asar 工具,命令行执行解包,几秒钟就能把整个前端工程连素材一起导出来。这个操作我在笔记里记过很多次,要点只有一个:看清楚 asar 文件的位置,它通常在resources目录下,和app.asar.unpacked并列,别把 unpacked 那个目录当成完整资源。

# 解 Electron 的 asar 包,输出到指定目录 npx asar extract "D:\work\02_stage2\resources\app.asar" "D:\work\02_stage2\asar_out"

再往下就是各家自研的容器,比如 CEF 的pak、Unity 的assets、各种.dat打包文件。这些没有通用解包器,得靠社区工具或者自己写解析脚本,属于另一个话题了。我的建议是:先判断值不值得继续拆。如果第一层已经拿到了你想要的图片和音频,就别在自研格式上耗时间;如果目标资源确实封在自研容器里,那再去找对应的格式解析方案。

4.3 命名还原与清单化

拆出来的文件十有八九是乱名的,一堆数字编号或者哈希串。做素材归档的人会在这一步崩溃,因为几千个文件没法用。我的处理方式是先不重命名,而是生成一份清单:文件路径、大小、真实格式、哈希值,导出成 csv。这份清单是后续所有工作的索引,有了它,你重命名、去重、筛选都方便。

去重这一步特别重要。同一个微端里,同一张图可能被复制了十几份,只是文件名不同。按哈希值去重能砍掉一大半冗余。我给客户做素材整理的时候,一个 2 GB 的资源目录去重完通常只剩 600 MB 左右,剩下的都是真正独立的资源。

5. 常见问题与排查实录

拆包这件事,失败是常态,成功才是意外。下面这些是我这些年反复遇到的坑,整理成速查表放在前面,后面再展开说几个典型场景。

现象大概率原因处理方法
工具一闪而过,没有输出被安全软件拦截,或缺少运行库加排除项,管理员身份运行
输出目录为空格式识别错误手动指定格式后重跑
只提取出图标和版本信息遇到加壳程序或下载器换思路,先运行一次看释放了什么
文件名全是乱码编码不匹配用 GBK 解析或事后批量转码
解到一半报路径过长Win10 默认路径长度限制开启长路径支持或缩短输出路径
输出目录里嵌套了好几层同名文件夹递归解包开太深关掉递归,逐层手动处理
拆出来的图片打不开文件被分包或加密检查是否为分卷,确认是否需要解密

5.1 拆不动的时候先怀疑对象

遇到一个怎么都拆不开的包,我的第一反应不是换工具,而是怀疑“这东西是不是根本不需要拆”。前面说过,很多微端是下载器,安装包本身只有几 MB。这种情况下你拆它,能拆出来的就是几个 dll 和一个启动器,资源在别处。判断方法很简单:看一眼安装包体积和安装后的目录体积,差距超过五倍,基本可以确定资源是运行时下载的。

还有一个容易被忽略的点:有些安装包是分卷的,你得把所有分卷放在同一个目录里才能解开,单独拆其中一个只会报错。这种情况目录里通常会有.001、.002这样的文件,或者名字里带part1、part2。

5.2 安全软件与权限的干扰

Win10 自带的防护机制对这类工具不算友好。它会把“频繁调用子进程、释放临时 exe、读写大量文件”的行为判定为可疑,然后默默把子进程干掉。表现就是主程序还在跑,日志卡在某一步,输出目录里空了一半。遇到这种情况,先看安全软件的拦截记录,确认是它干的,再给工具目录加排除项。

权限问题也常见。把工具装在 C 盘的程序目录,普通用户权限写不进临时文件,解包就会失败。我的做法一直是装在非系统盘的用户目录下,实在要放系统盘就用管理员身份运行一次。但管理员运行有个副作用:解出来的文件所有者会变成管理员,后续用普通账户操作可能遇到权限不足,需要手动改一次所有权。

5.3 编码、长路径与文件名冲突

中文环境下的编码问题几乎躲不掉。老式安装器用 GBK 打包文件名,现代工具按 UTF-8 读,结果就是一屏幕乱码。这个问题的根治方法是让解包器按正确编码解析,但不是所有工具都提供这个选项。退而求其次的办法是事后转码,用脚本把乱码文件名按 GBK 重新解码一遍再重命名。这个操作有风险,因为有些文件名本来就不是中文,强行转码会把它们弄坏,所以一定要在副本上做,先小批量验证。

长路径的问题前面提过,这里补一个细节:即使开了长路径支持,部分老工具内部还是用固定长度的缓冲区,照样会失败。最稳的办法是把输出目录的层级压短,比如D:\w\s2,路径越短越安全。

6. 几条踩过坑之后定下来的规矩

第一,原始文件永远只读。我给自己定的规矩是,任何原始安装包在拆之前先复制、算哈希、加只读属性,三步做完再动手。这个习惯救过我很多次,尤其是拆到一半发现工具把源文件改写了的时候,有副本在手,一切可以重来。

第二,一层一层拆,不要贪心开递归。递归解包看着省事,实际上会让你失去对层级的掌控,出问题的时候根本不知道是哪一层出的错。手动逐层处理虽然慢一点,但每一步都有日志、有输出、可回溯,做笔记的时候也写得清楚。

第三,拆完先做清单,再谈使用。文件数量一多,没有清单就是一团乱麻。文件路径、大小、真实格式、哈希,这四项导出来,后面无论是去重、筛选还是归档,都有据可依。

第四,也是我最想强调的一条:这些东西拆出来只是给自己看、自己学。客户端里的素材、代码、配置,版权归原作者,拆包这个动作本身在很多场景下是灰色地带,所以我的底线是不传播、不二次分发、不用于任何商业用途,拆完研究明白了就把工作目录清掉。这条不是客套话,是这行能长期做下去的前提。

最后分享一个我个人觉得挺实用的小技巧:每次拆完一个包,我会在笔记里留一段“指纹记录”——安装包体积、文件头、识别出的格式、第一层输出的大致结构、用到的工具和参数。下次遇到同类微端,翻一眼记录就能直接上手,省掉大半个小时的试错。这份记录积累到几十条之后,你会发现页游微端这个圈子的打包习惯其实就那么几种,看体积和文件头就能猜个大概,剩下的都是体力活。

返回列表