
简介这是一款使用VB6编写的EXE反编译工具主要解决把已编译的EXE文件还原为Visual Basic源代码的问题面向VB6开发者、软件逆向分析人员和需要维护旧版VB项目的工程师。工具覆盖PE文件结构解析、本机代码与P-code反编译、窗体及控件重建等核心环节有助于理解编译器生成的二进制格式和VB内部运行机制。资源包采用RAR压缩共30个文件总体积约278KB内容包含多个.bas代码模块、.frm窗体文件、.cls类模块以及.frx资源、.olb类型库、.txt说明文档等。代码模块各自承担PE解析、汇编反编译、P-code还原、控件与窗体恢复等任务目录结构清晰适合分模块研读。目前已有734人学习下载。解压后可获得完整VB工程源码.vbp/.vbw与界面设计文件既可作为反编译工具直接运行也可作为教学样例逐模块研究PE解析、P-code还原、汇编反编译等实现细节对深入了解VB6程序底层原理很有帮助。1. 把 exe 还原成 VB 源码这工具到底能恢复到什么程度开发VB6老项目时最怕遇到这样的场景源码丢了或者接手一个只留下exe的系统。找人重写成本太高想改个按钮逻辑、把标题栏文字换掉都得把二进制翻个底朝天。这个VB6反编译工具就是把“翻底朝天”自动化的那一部分输入exe先解析PE结构再按P-Code或Native Code两条路径把指令还原成接近VB语法的源码最后重建窗体、控件和工程文件。工具本身用Visual Basic 6编写源码包随程序完整给出既能当反编译工具用也能当VB6逆向实现样本来研究。适合三类人要维护VB6老系统但没有完整源码的开发、想研究别人程序思路的技术分析人员以及想弄懂VB6编译产物结构的逆向初学者。边界也很清楚它只还原VB6编译的exe对VC、Delphi或加了强壳的程序效果有限。下面按原理、实操、避坑三条线拆开讲。2. 反编译引擎拆解P-Code 与 Native Code 的双路径还原2.1 VB6 编译的两种产物P-Code 与 Native CodeVB6编译时“编译为P-Code”或“编译为Native Code”是工程属性里的一个选项。在VB6 IDE的“工程属性-编译”选项卡里可以看到这两个单选项Native下还有“针对 Pentium Pro(tm) 优化”等子项。P-Code是伪代码由运行时解释执行体积小但速度略慢Native Code是直接生成的x86机器码执行效率高但逆向还原的难度比P-Code高一个量级。多数老项目默认选Native因为追求运行速度小工具类程序反而常用P-Code因为体积小这个选择直接决定了反编译工具的还原质量。对反编译工具来说这两种产物决定了后续走完全不同的处理路径。P-Code有稳定的指令集定义指令索引到VB语法的映射关系相对固定还原质量通常最好能输出相对完整的事件过程和函数体。Native Code则需要先反汇编成汇编指令再通过识别VB运行时函数调用模式比如MSVBVM60.DLL里的字符串拼接、MsgBox调用、对象创建逐段“猜”回VB语句。工具源码包里的modPCode4.bas和modAsm.bas恰好分别对应这两条路径。除了编译模式VB6还有一个对还原友好的特征局部变量和参数的结构信息会被编译器写进调试信息块即使去掉“产生符号调试信息”选项函数结构本身仍会保留在导出表附近。这是工具能还原出Sub/Function骨架的基础。不同Service Pack版本的VB6编译出的P-Code指令编号有细微差别如果目标程序是SP5编译的工具默认按SP6指令表解析还原到一半很可能遇到指令越界。第4章有一条专门讲这个坑实操时先记住这个变量。2.2 源码包模块拆解每个文件负责哪一段还原这个工具包附带完整源码核心是十几个模块文件。我按每个文件在反编译链路里的位置整理了一张分工表方便你拿到源码后直接定位要改的地方。模块文件职责在还原链路中的位置modPCode4.basP-Code解析与语句还原输入P-Code指令流输出VB语句modAsm.basx86反汇编器把Native机器码转成汇编指令modPeSkeleton.basPE文件骨架解析读取DOS/NT头、节表、导入表、资源clsMemoryMap.cls内存映射封装把exe映射到内存避免手工维护偏移clsFile.cls文件读写封装底层文件IO供其他模块统一调用modControls.bas控件属性还原重建窗体上的按钮、文本框等控件modFrx.basFRX二进制资源解析还原窗体中图片、图标等二进制资源modCOM.basCOM接口还原还原类模块与COM接口声明modGlobals.bas全局配置与数据表控制还原粒度、指令表版本等modOutput.bas结果组织与写盘把还原内容整合成.frm/.bas/.vbp整个还原链路概括为三步先用clsPeSkeleton和clsMemoryMap把exe的PE结构读出来判断目标编译模式然后由modPCode4.bas或modAsm.bas把代码段还原成接近VB语法的语句最后由modControls.bas、modFrx.bas配合modOutput.bas把窗体、控件和工程文件重新组织起来。包内还有frmAbout.frm、frmOptions.frm和frmMain.frm这三个窗体构成工具的操作界面frmPcode.frm是P-Code模式下的专用查看窗体展示还原过程的中间指令流。分析源码时从frmMain.frm的菜单事件入手能最快看到整个反编译调用顺序。ReadMe.txt是工具使用说明优先看它ComFix.txt记录COM组件修复要点分析COM还原报错时可以查阅MSSCCPRJ.SCC是VB6源码管理器生成的辅助文件忽略即可。2.3 为什么用VB6写反编译工具选型理由与实际边界市面上大多数反编译工具用C或Python写这个工具反其道而行之用VB6本身写VB6的反编译工具。这个选择有工程上的道理VB6的变量类型体系、控件事件命名规律、工程文件结构在VB6环境里天然一致不用担心类型映射损失。还原出一个Form上的CommandButton和TextBox工具直接用VB6对象模型重建二次编译时兼容性最好。VB6还能很方便地调用Windows API做文件映射和PE解析实现成本比想象中低得多。用VB6写反编译工具的边界也很明显它只能还原VB6编译的exe对VB5的识别能力取决于运行时DLL判断VB5对应MSVBVM50.DLL需要区分对VB.NET或C#编译的程序只能识别到PE层面的信息无法还原成源码对VC和Delphi程序顶多输出反汇编结果离“可用源码”相差很远。和C#程序的IL反编译不同VB6 Native Code产物没有类似MSIL的稳定中间语言只能做模式匹配式还原因此工具定位从一开始就是“辅助还原”而不是“全自动恢复源码”。使用前把这个预期摆正后面所有环节都会顺利很多。提示反编译还原的结果是“接近原始”的源码原始变量名、注释和部分表达式结构不可能100%恢复这个预期要贯穿所有实操步骤。3. 动手实操编译工具、加载 exe 并导出还原源码3.1 编译工具前的环境准备拿到源码包后先不要急着双击exe包内的VBDecompiler.vbp是源码工程推荐在自己机器上重新编译一遍。环境上需要安装Visual Basic 6最好补上SP6运行库因为modGlobals.bas里涉及的API声明和控件引用很多依赖SP6的公共文件。编译前先确认MSCOMCTL.OCX等公共控件已注册否则IDE会提示缺少引用。编译时可以直接用命令行。在VB6安装目录或已注册的命令行环境下执行# /make 表示静默编译/out 指定输出exe路径 VB6.EXE /make VBDecompiler.vbp /out D:\tools\VBDecompiler.exe/make参数用于静默编译/out指定输出exe的完整路径。如果机器上装了多个VB6版本命令行编译可能因引用路径问题中断。常见做法是先在VB6 IDE里手动打开VBDecompiler.vbp编译一次让IDE自动修正引用再用命令行做重复编译。命令行编译若报错看VB6安装目录下的VB6.log文件里面会记录具体是哪个模块引用失败。工程编译成功后生成VBDecompiler.exe这才是反编译工具主程序。3.2 加载目标 exePE 解析与引擎分发启动工具后主窗体是frmMain.frm上面有文件选择框和若干选项。我习惯把目标exe放在全英文路径下避免中文路径编码问题。选中文件后工具内部先走一遍PE解析和运行时特征判断逻辑和下面这段示意代码基本一致。Dim pe As New clsPeSkeleton If Not pe.Load(txtFile.Text) Then MsgBox 文件不是合法 PE 格式, vbExclamation Exit Sub End If If pe.HasImport(MSVBVM60.DLL) Then If pe.IsPCode Then modPCode4.Decompile pe Else modAsm.DecompileWithPattern pe End If Else MsgBox 未识别到 VB6 运行时特征疑似非 VB6 程序, vbExclamation End If关键判断点是HasImport和IsPCode。HasImport检查导入表里是否存在MSVBVM60.DLL这个DLL是VB6程序运行的虚拟机核心标准VB6 exe都会引用它。IsPCode属性通过分析代码段指令特征判断目标是用P-Code还是Native模式编译结果决定走modPCode4还是modAsm。如果目标exe加过UPX壳导入表通常被破坏HasImport返回假需要在加载前先脱壳处理方式见第4章。加载大体积exe时如果工具卡顿先确认物理内存是否充足再考虑关闭其他程序工具读入整个PE文件并建立内存映射资源占用偏高是正常现象。3.3 还原结果保存生成 VBP 与模块文件解析完成后工具把还原出的窗体、模块和工程骨架写入磁盘。还原出的文件类型包括frm窗体、bas标准模块、cls类模块、frx窗体二进制资源和vbp工程文件。其中vbp文件的组织方式直接影响还原工程能否被VB6直接打开下面这段代码示意最基础的vbp写入逻辑。Private Sub WriteProject(files() As String, projName As String) Dim f As Integer Dim i As Integer f FreeFile Open projName .vbp For Output As #f Print #f, TypeExe Print #f, Form files(0) For i 1 To UBound(files) Print #f, Module files(i) Next i Close #f End SubTypeExe声明这是标准EXE工程Form和Module分别登记窗体文件和模块文件。数组files(0)必须是启动窗体否则VB6打开工程后会提示找不到启动对象。实际操作中工具还会写入Object和Reference声明列出原工程引用过的控件库和类型库。frm文件本身有固定格式顶部是“VERSION 5.00”和“Begin VB.Form xxx”开头的窗体块中间是控件属性End结束。如果原窗体带图片或图标还原时必须同时生成对应的frx文件否则VB6打开frm会提示资源缺失。4. 避坑指南六次反编译翻车的排查记录下面六条是本工具最容易踩的坑按现象、原因、解决三个层次记录每条都来自真实使用场景。4.1 拿VC程序硬当VB6目标现象用工具打开一个用C或Delphi写的exe程序能加载但还原出来的内容全是汇编指令和二进制数据完全没法编译成VB源码。原因目标exe的导入表里没有MSVBVM60.DLL工具并没有进入真正的VB6还原链路只停留在通用PE解析和反汇编层面。很多新接触反编译的读者会把“能打开”和“能还原”混为一谈。解决加载前先确认目标是否有VB6运行时特征。工具界面如果有“编译模式”或“运行时检测”字段先看那个字段的输出拿不准时用modPeSkeleton的检测逻辑跑一遍确认导入表存在MSVBVM60.DLL再继续。遇到VB5程序要特别注意运行时DLL可能是MSVBVM50.DLL老版本工具不一定识别这个特征。4.2 加壳程序导致PE解析直接中断现象加载UPX压缩过的exe时工具报“读取节表失败”或某个偏移量溢出窗体上什么都没显示就退出了。原因UPX壳会重写导入表并把原始入口点替换为壳的入口。PE头里节区数量和名称都变了工具按标准VB6程序结构去解析偏移错位后自然崩溃。解决先做壳检测。常见做法是看节区名UPX特征名字段会出现UPX0、UPX1或者用PE查看工具看入口点是否落在非标准节区。对UPX壳用UPX -d脱壳后再加载对VMP、Themida这类强壳不要指望直接还原建议改为行为分析。我在实操中一般会在加载前先给exe做一次快速节区检查发现异常直接进脱壳流程。4.3 P-Code版本不匹配还原到一半报指令越界现象反编译P-Code工程时前面几个窗体正常遇到某个窗体或函数时报“运行时函数索引越界”还原进程中断输出文件不完整。原因VB6不同Service Pack版本对P-Code指令编号有微调工具modPCode4.bas里维护的指令表与目标程序编译版本不一致常见于SP5编译的目标遇到SP6默认指令表。解决查看modGlobals.bas里的版本配置把P-Code指令表版本切到和目标一致。如果不知道目标版本用PE查看工具读exe的版本信息或看ReadMe.txt里对SP版本兼容性的说明。改完指令表后重新解析多数情况下能跑完。这个参数切换在源码里通常是一个全局常量改成对应SP版本号后重新编译工具即可。4.4 FRX资源解析后控件全部堆在左上角现象还原出的frm文件里控件都在但坐标全是0布局全乱图片控件显示空白。原因frm对应的frx二进制资源保存了控件的图片、图标等属性部分控件的定位信息也依赖frx中的索引。modFrx.bas解析时如果按16位边界读偏一个字段后续属性就全错。解决把原始exe对应目录下的frx文件和还原出的frm放在同一目录重新用modControls.bas解析一次。单个frx解析问题可以用十六进制编辑器查frx文件头部的长度字段对比工具输出的偏移量手动修正。实际操作中最方便的验证方式是直接打开还原工程看控件布局是否正常不正常就换回工具里的“严格frx模式”重新生成。4.5 Native Code还原结果几乎全是汇编现象对Native模式编译的目标执行反编译还原结果大段是MOV EAX, [ESP8]这类汇编没有变成VB语句。原因Native还原的核心是识别VB运行时的函数调用模式例如rtcMsgBox、rtcInputBox等内部函数。工具modAsm.bas在反汇编后需要对CALL的目标地址查函数字典字典里没有对应条目时只能保留汇编原文。解决检查VB60_APIDEF.txt是否在工具同目录且内容完整这个文件是运行时函数字典决定汇编到VB语句的映射质量。字典缺失时从VB6安装目录复制完整API定义文件替换。另外Native目标中结构简单的过程纯赋值、字符串拼接优先还原复杂表达式要做好人工修改准备。4.6 还原后的vbp工程在VB6里无法编译现象用VB6打开还原出的vbp提示“找不到对象”或“未找到方法或数据成员”编译直接报错。原因原工程引用了第三方OCX控件或ActiveX组件工具没有把这些引用写进还原后的vbp另一种情况是还原输出的变量类型与原类型不兼容比如把Long还原成了Integer。解决先看还原工程里是否有对应ocx控件的引用行没有就手动加。常见做法是用文本方式打开原始工程信息把缺失引用列表抄到还原工程vbp里。若数据库相关内容还原错乱在VB6中打开工程后用“工程-引用”对话框重新勾选缺失库编译报错会列出具体模块按模块逐个修复。5. 反编译结果进阶处理参数调整与二次编译验证5.1 还原粒度控制先改这三个开关工具在modGlobals.bas里预留了几个全局开关控制还原结果能细到什么程度。默认值偏向完整还原但目标程序很大时输出文件非常长反而不利于定位逻辑。我一般按分析需求调整下面三个配置。 modGlobals.bas 中控制还原粒度的全局开关 Global Const g_bKeepLineNumbers As Boolean True True 保留 P-Code 行号 Global Const g_bExtractStrings As Boolean True True 提取字符串表 Global Const g_bAutoRenameVars As Boolean True True 自动重命名变量名g_bKeepLineNumbers保留行号信息方便把还原代码与原始代码行号对应起来但会让输出膨胀。g_bExtractStrings提取字符串常量单独输出到一个清单对定位关键逻辑很有用。g_bAutoRenameVars决定变量名是沿用工具推测的Var1、Var2还是你手工改名后回填。调整参数后要重新执行反编译一般还要清空原输出目录避免旧文件干扰。分析单窗体小工具时全开影响不大分析大型程序时把g_bKeepLineNumbers置False能明显减少输出体积定位逻辑反而更快。5.2 用字符串表定位关键逻辑入口分析陌生exe时最高效的入口不是逐行读汇编而是先看字符串表。登录功能总有“用户名或密码错误”提示网络请求总有URL和协议头版权信息总有作者名。工具提取出的字符串表天然就是这些功能位置的索引。实际操作时我先打开modOutput输出的strings清单搜几个和业务特征相关的词比如http、sql、error或中文提示搜到以后记录字符串所在的段偏移再去还原出的对应代码区域找引用位置。由于VB6的字符串通常作为常量直接嵌入代码段字符串地址和指令引用地址之间的映射比较直接定位准确率很高。例如字符串表里出现一段SQL语句沿着对应偏移回到代码区能找到连接数据库的相关过程。这一步对Native Code还原结果尤其有用汇编代码难读但字符串表仍然清楚。5.3 还原工程的二次编译验证闭环反编译工具把代码吐出来只是第一步不能直接信以为真。我最常做的验证流程是用VB6打开还原后的vbp先编译一次把编译错误清单记下来再把原始exe跑起来对比界面行为和关键交互逻辑。如果原始exe里点按钮弹出一个提示框还原程序也应当有相同行为不一致的地方就是还原失真区域。验证项检查内容预期结果启动窗体exe启动时显示的窗体还原程序启动窗体一致控件布局按钮、文本框位置与大小与截图或原始exe基本一致点击事件主要按钮的行为提示文字和弹窗一致数据存储读写配置文件/注册表读写键名与原始一致验证过程中不要只开还原工程要把原始exe也放在旁边用同一输入数据跑一遍再对比输出。另外要注意编译选项一致性原程序是P-Code编译的你二次编译用Native程序行为可能有细微差异。这轮验证下来基本能判断工具对这个目标的还原度到底行不行。如果某个函数体为空或窗体属性明显错误回到第4章对应排查项检查参数和模块状态比闷头修改输出文件省时间得多。6. 先判编译模式再动手一个让我少返工三倍的验证习惯拿到一个exe我现在的第一反应不是直接拖进工具而是先确认它的编译模式。这个判断直接决定后面所有步骤的预期P-Code模式还原质量高可以花时间深挖Native Code模式还原结果以汇编为主投入产出比低要提前想清楚值不值得做。判断方法很简单。工具打开目标exe后看窗体标题栏或状态栏有没有“P-Code”或“Native”标识如果没有显式标识点一次快速分析按钮看输出日志的第一行。日志里写着类似“Code section indicates P-Code”就是P-Code写着“Native code found”就是Native。也可以在打开前用PE工具看代码段特征但工具本身已内置检测没必要再开一个软件。确认编译模式后我还会顺手把三行信息记在分析笔记里编译模式、运行时DLL版本、壳信息。这三行看起来简单实际价值极大。遇到过太多次中途还原失败的情况回头翻笔记才发现是SP版本对不上或者UPX没脱干净。笔记里记下运行时DLL版本后直接对照modGlobals.bas里的指令表配置两分钟就能定位是不是版本问题。我早期不是这样的。那时候拿到exe就直接拖进反编译工具指望一次出结果结果几次翻车都发生在Native Code工程上反汇编输出几百行真正能用的没几段一整天就耗在人工翻译汇编上了。从那以后我每次拿到exe都强制先走一遍模式检测把编译方式、运行时DLL、是否加壳这三条信息写进笔记再决定要不要深入还原。这个习惯让我的无效返工少了至少三分之二希望对你以后的分析工作也有帮助。本文还有配套的精品资源点击获取