前往Shuct.Net首页

Shudepb PB反编译专家长时间以来,为业内同类软件事实上的唯一选择.细节,彰显专业.态度,决定品质.

关于反编译的搜索

VB6反编译详解 - 孤独剑 的专栏 - 博客频道 - CSDN.NET 孤独剑 的专栏 (CSDN: asftrhgjhkjlkttttttt 群内: LPZ) 目录视图 摘要视图 订阅 新年新气象------CSDN2014新版导航就要跟大家见面了 2014年1月微软MVP当选名单揭晓! 消灭0回答,赢下载分 “我的2013”年度征文活动火爆进行中! 专访何海涛:“不正经”程序员的进阶之路 VB6反编译详解 分类: VB编程技术 2011-05-18 14:07 1248人阅读 评论(2) 收藏 举报 vbobjectapimoduleexe语言 标 题: VB6反编译详解(一)作 者: kenmark时 间: 2006-07-09 16:59 链 接: http://bbs.pediy.com/showthread.php?threadid=28715 详细信息: VB6反编译详解 by Kenmark-Fenix**************************************************最新于2006-7-13更新!**************************************************写本文已经惦记了好几年了,由于一直没有完整的资料和充裕的时间,所以一直没有动手。在这里一方面是写给大家看看,另一方面是招募更多有志于反编译VB6的同志们一起来研究学习!我的E-MAIL:ken.mingyuan@hotmail.com ken.mingyuan@gmail.com我的BLOG: blog.csdn.net/kenmark我的QQ:188916915十分期待着与大家一起学习!&mdash;&mdash;KenmarkVB6是一个半编译半解释的语言,编译后程序主要在运行库MSVBVM60.DLL下转悠,通过与MSVBVM60的互动来完成程序运行的过程。1.引入(参考:《VB程序大揭密》我的博客上有转载http://blog.csdn.net/Kenmark/archive/2005/08/11/450985.aspx)我们用W32DASM打开一个中型的VB程序来反汇编,我们发现程序中用到的MSGBOX&divide;FileCopy等理应对应API函数居然一个都没有出现在编译后程序的IMPORT TABLE里,一般VC和DEPHI都是直接出现在编译后程序的IMPORT TABLE里的,而我们的VB程序用到了如此之多的API函数居然只使用了一个DLL&mdash;&mdash;MSVBVM60.DLL。然后用工具打开MSVBVM60.DLL,一看,输出的函数还真不少,其中有用__vba和rtc开头的也有直接就是函数名的,仔细一看,哇赛,可以说完全是一个windows API的代理,应有尽有:rtcRandomize :Randomize 函数的对应API; rtcMidCharVar :Mid 函数的对应API; rtcLeftCharVar、rtcRightCharVar :看出来了吧,这些是Left、Right函数的对应API; rtcUpperCaseVar :UCase 函数的对应API; rtcKillFiles :Kill 语句的对应API; rtcFileCopy :FileCopy 语句的对应API; rtcFileLength :EOF、FileLen函数的对应API; rtcGetTimer :Randomize Timer中获取Timer的对应API; rtcShell :Shell函数的的对应API; rtcMakeDir :MkDir 语句的对应API; rtcRemoveDir :RmDir 语句的对应API; rtcDir :Dir 函数的对应API; rtcSpaceVar :Space 函数的对应API; 原来,所有VB的操作函数都是在调用MSVBVM60.DLL里面实现前缀是rtc的是一般的语句和函数涉及字符串处理的都叫var,例如:__vbaUbound : UBound 的对应API; __vbaFileOpen :Open 语句的对应API; __vbaStrCmp :比较两个字符串:If String1 = String2 Then ...... __vbaVarOr :Or 运算符的对应API; __vbaRedim :Redim 语句的对应API; __vbaRedimPreserve :Redim 语句加上 Preserve 参数的对应API; __vbaGet、vbaPut :Get、Put语句的对应API&hellip;&hellip; 我们还看到一个DLL:DllFunctionCall,这个就是我们调用其他DLL时需要向MSVBVM60申请的,&hellip;&hellip;&hellip;&hellip;。可以说VB的程序是一个包裹在MSVBVM60阴影控制下的孩子,所有的操作都要直接向它请求,而MSVBVM60完全可以称得上是一个代理的机器。从程序开始,到运行中的所有操作,函数调用,错误报告等等,都是由它一手包办的。来吧,我们这里不是来介绍它是怎么构成的我们要搞掉它虚伪的外表,把我们的代码从MSVBVM60的封建保护下救出来。我的资料大量是参考一个开源的VB程序解析程序(居然也是用VB编写的),这个程序可以完全分析出VB程序(没有加壳)的PROJECT信息以及完全将FORM变回来,对于代码呢,可以获得SUB MAIN的汇编代码地址,但是不能返回到VB代码,里面还内置了一个假的反汇编器,以后我会说的!我提供了它的下载,大家去看看,不知道它的资料是哪里来的十分全面,就是用VB写的比较繁!还有由于界面控制太多,代码有点乱!2.程序初始化我们用W32DASM打开任何VB程序,跳到ENTRY POINT之后看到的总是一个PUSH *****一个地址,然构调用MSVBVM60.DLL的ThunRTMain而在VC程序里,我们至少要看到进程的创建什么的,其实这个VB函数是一切的开端,由它开始来解析整个编译后的程序,完成系统环境的初始化,然后找到真正的程序入口,跳转到程序的领空。所以这个PUSH指令压入栈的是VBEXE(姑且这么称呼)初始化结构的开始。我们存下这个地址(这个是一个VA要正确地转换成文件地OFFSET先要-ImageBase然后要对照块表,可以用工具完成,熟悉了一下就能看出来),然后我们跳到那里。看看是什么,哇赛,是VB程序的招牌也!&ldquo;VB5!&rdquo;是所有VB程序初始化结构入口地址指向的MAGIC字符,找到这里,开始能够读取VB初始化结构了(我们现在做的就是ThunRTMain要完成的)我们开始了!部分名词解读:RVA 相对虚拟地址,一般需要使用RVA2Offset来将其转换成绝对的文件偏移 变量前缀为pr或是aVA 虚拟地址,减去IMAGEBASE就是RVA 变量前缀为p或是aoffset 相对结构的偏移 变量前缀为o1)VBHEADER从PE文件的ENTRY POINT进入后第一个指令是压入一个指针来表示VBHEADER的位置,这个指令为push xxxxxxxx地址是经过基址IMAGE_BASE偏移后的地址,所以减去IMAGE_BASE后获得的就是VBHEADER开始的VA然后用PEFile类中的函数加以分析可以得到的是文件中VBHEADER的偏移量。这个指令在机器码中是这样表示的:68 C0 11 40 00 68是PUSH的机器码,而后是内存存储方式的地址化成汇编语言就是:push 004011c0 所以减去基址后就是11C0然后进行VA2OFFSET得到的是11c0的偏移,转向那段数据就能得到VBHEADER。这是VBHEADER结构的C语言描述:typedef struct{ char Signature[4]; // 四个字节的签名符号,和PEHEADER里的那个signature是类似性质的东西,VB文件都是"VB5!" WORD RtBuild; // 运行时创立的变量(类似编译的时间) BYTE LangDLL[14]; // 语言DLL文件的名字(如果是0x2A的话就代表是空或者是默认的) BYTE BakLangDLL[14]; // 备份DLL语言文件的名字(如果是0x7F的话就代表是空或者是默认的,改变这个值堆EXE文件的运行没有作用) WORD RtDLLVer; // 运行是DLL文件的版本 DWORD LangID; // 语言的ID DWORD BakLangID; // 备份语言的ID(只有当语言ID存在时它才存在) DWORD pSubMain; // RVA(实际研究下来是VA) sub main过程的地址指针(3.)(如果时00000000则代表这个EXE时从FORM窗体文件开始运行的) DWORD pProjInfo; // VA 工程信息的地址指针,指向一个ProjectInfo_t结构(2.) DWORD fMDLIntObjs; // ?详细见"MDL 内部组建的标志表" DWORD fMDLIntObjs2; // ?详细见"MDL 内部组建的标志表" DWORD ThreadFlags; // 线程的标志 //* 标记的定义(ThreadFlags数值的含义) //+-------+----------------+--------------------------------------------------------+ //| 值 | 名字 | 描述 | //+-------+----------------+--------------------------------------------------------+ //| 0x01 | ApartmentModel | 特别化的多线程使用一个分开的模型 | //| 0x02 | RequireLicense | 特别化需要进行认证(只对OCX) | //| 0x04 | Unattended | 特别化的没有GUI图形界面的元素需要初始化 | //| 0x08 | SingleThreaded | 特别化的静态区时单线程的 | //| 0x10 | Retained | 特别化的将文件保存在内存中(只对Unattended) | //+-------+----------------+--------------------------------------------------------+ //ex: 如果是0x15就表示是一个既有多线程,内存常驻,并且没有GUI元素要初始化 DWORD ThreadCount; // 线程个数 WORD FrmCount; // 窗体个数 WORD pExternalComponentCount; // VA 外部引用个数例如WINSOCK组件的引用 DWORD ThunkCount; // ?大概是内存对齐相关的东西 DWORD pGUITable; // VA GUI元素表的地址指针(指向一个GUITable_t结构(4.四)) DWORD pExternalComponentTable; // VA 外部引用表的地址指针// DWORD pProjDep; // VA 工程的描述的地址指针(这个其实没有) DWORD pComRegData; // VA COM注册数据的地址指针 DWORD oProjExename; // Offset 指向工程EXE名字的字符串 DWORD oProjTitle; // Offset 指向工程标题的字符串 DWORD oHelpFile; // Offset 指向帮助文件的字符串 DWORD oProjName; // Offset 指向工程名的字符串}VBHeader_t;//* MDL 内部组建的标志表//+---------+------------+---------------+//| ID | 值 | 组建名称 |//+---------+------------+---------------+//| 第一个标志 |//+---------+------------+---------------+//| 0x00 | 0x00000001 | PictureBox |//| 0x01 | 0x00000002 | Label |//| 0x02 | 0x00000004 | TextBox |//| 0x03 | 0x00000008 | Frame |//| 0x04 | 0x00000010 | CommandButton |//| 0x05 | 0x00000020 | CheckBox |//| 0x06 | 0x00000040 | OptionButton |//| 0x07 | 0x00000080 | ComboBox |//| 0x08 | 0x00000100 | ListBox |//| 0x09 | 0x00000200 | HScrollBar |//| 0x0A | 0x00000400 | VScrollBar |//| 0x0B | 0x00000800 | Timer |//| 0x0C | 0x00001000 | Print |//| 0x0D | 0x00002000 | Form |//| 0x0E | 0x00004000 | Screen |//| 0x0F | 0x00008000 | Clipboard |//| 0x10 | 0x00010000 | Drive |//| 0x11 | 0x00020000 | Dir |//| 0x12 | 0x00040000 | FileListBox |//| 0x13 | 0x00080000 | Menu |//| 0x14 | 0x00100000 | MDIForm |//| 0x15 | 0x00200000 | App |//| 0x16 | 0x00400000 | Shape |//| 0x17 | 0x00800000 | Line |//| 0x18 | 0x01000000 | Image |//| 0x19 | 0x02000000 | Unsupported |//| 0x1A | 0x04000000 | Unsupported |//| 0x1B | 0x08000000 | Unsupported |//| 0x1C | 0x10000000 | Unsupported |//| 0x1D | 0x20000000 | Unsupported |//| 0x1E | 0x40000000 | Unsupported |//| 0x1F | 0x80000000 | Unsupported |//+---------+------------+---------------+//| 第二个标志 |//+---------+------------+---------------+//| 0x20 | 0x00000001 | Unsupported |//| 0x21 | 0x00000002 | Unsupported |//| 0x22 | 0x00000004 | Unsupported |//| 0x23 | 0x00000008 | Unsupported |//| 0x24 | 0x00000010 | Unsupported |//| 0x25 | 0x00000020 | DataQuery |//| 0x26 | 0x00000040 | OLE |//| 0x27 | 0x00000080 | Unsupported |//| 0x28 | 0x00000100 | UserControl |//| 0x29 | 0x00000200 | PropertyPage |//| 0x2A | 0x00000400 | Document |//| 0x2B | 0x00000800 | Unsupported |//+---------+------------+---------------+//ex: 如果值是0x30F000 (那个被叫做 "静态二进制常量定义在大多数的地方")就是意味着来初始化打印机,窗体,屏幕,剪贴板,组建(0xF000)也有Drive/Dir 组建(0x30000).//这是VB工程的一个默认的设置因为这些组建都能从一个模块中获得module (例如,他们是没有图像的除了经常被创造窗体)2)工程信息从VBHEADER->ProjectInfo(是一个VA)-IMAGEBASE后在通过RAV2OFFSET得到的是 工程信息 的偏移地址.这是PROJECT_INFO结构的C语言描述:const long MAX_PATH = 260; //最长的PATH长度typedef struct{ DWORD Signature; // 结构的签名特性,和魔术字符类似 DWORD pObjectTable; // VA 结构指向的组件列表的地址指针(很重要的!(7.)) DWORD Null1; // ?没有用的东西 WORD pStartOfCode; // VA 代码开始点,类似PEHEAD->EntryPoint这里告诉了VB代码实际的开始点 DWORD Flag1; // 标志1 DWORD ThreadSpace; // 多线程的空间????????????????? DWORD pVBAExcrptionhandler; // VA VBA意外处理机器地址指针 DWORD pNativeCode; // VA 本地机器码开始位置的地址指针 WORD oProjectLocation; // Offset 工程位置????????????????? WORD Flag2; // 标志2 WORD Flag3; // 标志3 BYTE OriginalPathName[MAX_PATH*2]; // 原文件地址,一个字符串,长度最长为MAX_PATH BYTE NullSpacer; // 无用的东西,用来占位置???????????????????? DWORD pExternalTable; // VA 引用表的指针地址 DWORD ExternalCount; // 引用表大小(个数) // sizeof() = 0x23c}ProjectInfo_t;这个东西基本包含了这个PROJECT的信息,但是主要的意义还是提供了之后的结构的索引,最重要的是它提供了传说中的OBJECT TABLE的入口地址,对于EXE里面有多少FORM,MODULE十分重要。3)SubMain从VBHEADER->SubMain可以获得SubMain代码的入口处,但是有些VB程序是从FORM开始运行的所以当这个值为0时就代表此程序不是从SubMain开始运行的而是从FORM开始运行的.4)GUITable从VBHEADER->GUITable可以获得GUI元素表的地址指针,也就是指向WINDOWS图形元素的表.这是GUITable结构的C语言描述:typedef struct{ DWORD lStructSize; // 这个结构的总大小 BYTE uuidObjectGUI[15]; // Object GUI的UUID DWORD Unknown1; // ??????????????????????????????????? DWORD Unknown2; // ??????????????????????????????????? DWORD Unknown3; // ??????????????????????????????????? DWORD Unknown4; // ??????????????????????????????????? DWORD lObjectID; // 当前工程的组件ID DWORD Unknown5; // ??????????????????????????????????? DWORD fOLEMisc; // OLEMisc标志 BYTE uuidObject[15]; // 组件的UUID DWORD Unknown6; // ??????????????????????????????????? DWORD Unknown7; // ??????????????????????????????????? DWORD pFormPointer; // VA 指向GUI Object Info结构的地址指针 DWORD Unknown8; // ??????????????????????????????????? // sizeof() = 0x50}GUITable_t;这个表没有什么重要,主要就是那个pFormPointer比较有用。5)ExternalComponentTable从VBHEADER->ExternalComponentTable可以获得外部引用表的地址指针.这是ExternalTable以及ExternalLibrary的VB结构以及C语言描述:typedef struct{ DWORD Flag; // 标志 DWORD pExternalLibrary; // VA 指向ExternalLibrary结构的地址指针}ExternalTable_t;typedef struct{ DWORD pLibraryName; // VA 指向 NTS DWORD pLibraryFunction; // VA 指向 NTS}ExternalLibrary_t;6)ComRegData and COMRegInfo从VBHEADER->ComRegData可以获得COM注册数据的地址指针.这是COMRegData以及COMRegInfo结构的C语言描述:typedef struct{ DWORD oRegInfo; //Offset 指向COM Interfaces Info结构(COM接口信息) DWORD oNTSProjectName; //Offset 指向Project/Typelib Name(工程名) DWORD oNTSHelpDirectory; //Offset 指向Help Directory(帮助文件目录) DWORD oNTSProjectDescription; //Offset 指向Project Description(工程描述) BYTE uuidProjectClsId(15); //Project/Typelib的CLSID DWORD lTlbLcid; //Type Library的LCID WORD iPadding1; //没有用的内存对齐空间1 WORD iTlbVerMajor; //Typelib 主版本 WORD iTlbVerMinor; //Typelib 次版本 WORD iPadding2; //没有用的内存对齐空间2 DWORD lPadding3; //没有用的内存对齐空间3 // sizeof() = 0x30}COMRegData_t;typedef struct{ DWORD oNextObject; //Offset to COM Interfaces Info DWORD oObjectName; //Offset to Object Name DWORD oObjectDescription; //Offset to Object Description DWORD lInstancing; //Instancing Mode DWORD lObjectID; //Current Object ID in the Project BYTE uuidObjectClsID[15]; //CLSID of Object DWORD fIsInterface; // Specifies if the next CLSID is valid DWORD oObjectClsID; // Offset to CLSID of Object Interface DWORD oControlClsID; // Offset to CLSID of Control Interface DWORD fIsControl; // Specifies if the CLSID above is valid DWORD lMiscStatus; // OLEMISC Flags (see MSDN docs) BYTE fClassType; // Class Type BYTE fObjectType; // Flag identifying the Object Type WORD iToolboxBitmap32; // Control Bitmap ID in Toolbox WORD iDefaultIcon; // Minimized Icon of Control Window WORD fIsDesigner; // Specifies whether this is a Designer DWORD oDesignerData; // Offset to Designer Data // sizeof() = 0x44}COMRegInfo_t;'Object Type part of tCOMRegInfo//没有翻译的意义,就没有翻译,只是看看而已'+-------+---------------+-------------------------------------------+'| Value | Name | Description |'+-------+---------------+-------------------------------------------+'| 0x02 | Designer | A Visual Basic Designer for an Add.in |'| 0x10 | Class Module | A Visual Basic Class |'| 0x20 | User Control | A Visual Basic ActiveX User Control (OCX) |'| 0x80 | User Document | A Visual Basic User Document |'+-------+---------------+-------------------------------------------+*7)ObjectInfo这些东西十分重要,是提取VB工程元素的重要标志,从这里我们可以得到这个工程里有多少FORM,多少MODULE,以及他们的重要索引数据,可以说重要性和SECTION HEAD在EXE程序中重要性相同。入口的地址是由ProjectInfo_t结构提供的(semi提供关于这里提供的资料少之又少,所以需要自己摸索)从ProjectInfo_t开始指向的是一个ObjectTable_t,由ObjectTable_t提供第一个OBJECT_t结构的地址typedef struct //这个是OBJECT 的总表,可以索引以后的每个OBJECT{ DWORD lNull1 As Long; //没有用的填充东西 DWORD aExecProj; //VA指向一块内存结构(研究下来既不没见着这个东西由什么用处 DWORD aProjectInfo2; //VA指向Project Info 2 DWORD Const1; //没有用的填充东西 DWORD Null2; //没有用的填充东西 DWORD lpProjectObject As Long ' 0x14 DWORD Flag1; //标志1 DWORD Flag2; //标志2 DWORD Flag3; //标志3 DWORD Flag4; //标志4 WORD fCompileType; //Internal flag used during compilation WORD ObjectCount1; //OBEJCT数量1???? WORD iCompiledObjects; //编译后OBJECT数量 WORD iObjectsInUse As Integer; //Updated in the IDE to correspond the total number ' but will go up or down when initializing/unloading modules. DWORD aObject; //VA指向第一个OBJECT_t结构,很重要 DWORD Null3; //没有用的填充东西 DWORD Null4; //没有用的填充东西 DWORD Null5; //没有用的填充东西 DWORD aProjectName; //执行工程名字的字符串 DWORD LangID1; //language ID1 DWORD LangID2; //language ID2 DWORD Null6; //没有用的填充东西 DWORD Const3; //没有用的填充东西 ' 0x54}ObjectTable_t;type struct//这个就是每个OBJECT的结构,{ DWORD aObjectInfo; //VA 指向一个ObjectInfo_t类型,来显示这个OBJECT的数据 DWORD Const1; //没有用的填充东西 DWORD aPublicBytes; //VA 指向公用变量表大小 DWORD aStaticBytes; //VA 指向静态变量表地址 DWORD aModulePublic; //VA 指向公用变量表 DWORD aModuleStatic; //VA 指向静态变量表 DWORD aObjectName; //VA 字符串,这个OBJECT的名字 DWORD ProcCount; // events, funcs, subs(时间/函数/过程)数目 DWORD aProcNamesArray; //VA 一般都是0 DWORD oStaticVar; //OFFSET 从aModuleStatic指向的静态变量表偏移 DWORD ObjectType; //比较重要显示了这个OBJECT的实行,具体见下表 DWORD Null3; //没有用的填充东西 //sizeof() = 0x30}Object_t;'Object_t.ObjectTyper 属性...//重要的属性表部分'#########################################################'form: 0000 0001 1000 0000 1000 0011 --> 18083' 0000 0001 1000 0000 1010 0011 --> 180A3' 0000 0001 1000 0000 1100 0011 --> 180C3'module: 0000 0001 1000 0000 0000 0001 --> 18001' 0000 0001 1000 0000 0010 0001 --> 18021'class: 0001 0001 1000 0000 0000 0011 --> 118003' 0001 0011 1000 0000 0000 0011 --> 138003' 0000 0001 1000 0000 0010 0011 --> 18023' 0000 0001 1000 1000 0000 0011 --> 18803' 0001 0001 1000 1000 0000 0011 --> 118803'usercontrol: 0001 1101 1010 0000 0000 0011 --> 1DA003' 0001 1101 1010 0000 0010 0011 --> 1DA023' 0001 1101 1010 1000 0000 0011 --> 1DA803'propertypage: 0001 0101 1000 0000 0000 0011 --> 158003' | || | | | | |'[moog] | || | | | | |'HasPublicInterface ---+ || | | | | | (有公用的接口)'HasPublicEvents --------+| | | | | | (有公用的事件)'IsCreatable/Visible? ----+ | | | | | (是否可以创建,可见)'Same as "HasPublicEvents" -----+ | | | | '[aLfa] | | | | |'usercontrol (1) ---------------+ | | | | (用户控制)'ocx/dll (1) ----------------------+ | | | (OCX/DLL)'form (1) ------------------------------+ | | (是不是FORM是就是1)'vb5 (1) ---------------------------------+ | (是不是VB5是就是1)'HasOptInfo (1) -------------------------------+ (有没有额外的信息信息由就是1,决定是不是指向OptionalObjectInfo_t类似与PEHEAD里的Optional信息一样)' |'module(0) ------------------------------------+ (如果是Module模块就这里是0)typedef struct//这个是显示这个OBJECT信息的结构,每一个OBJECT都有一个{ WORD Flag1; WORD ObjectIndex; DWORD aObjectTable; DWORD Null1; DWORD aSmallRecord; // when it is a module this value is -1 [better name?] DWORD Const1; DWORD Null2; DWORD aObject; DWORD RunTimeLoaded; //[can someone verify this?] DWORD NumberOfProcs; DWORD aProcTable; WORD iConstantsCount; // Number of Constants WORD iMaxConstants; // Maximum Constants to allocate. DWORD Flag5; WORD Flag6; WORD Flag7; WORD aConstantPool; // sizeof() = 0x38 'the rest is optional items[OptionalObjectInfo]}ObjectInfo_t;Private Type tOptionalObjectInfo ' if ((tObject.ObjectType AND &H80)=&H80) fDesigner As Long ' 0x00 (0d) If this value is 2 then this object is a designer aObjectCLSID As Long ' 0x04 Null1 As Long ' 0x08 aGuidObjectGUI As Long ' 0x0C lObjectDefaultIIDCount As Long ' 0x10 01 00 00 00 aObjectEventsIIDTable As Long ' 0x14 lObjectEventsIIDCount As Long ' 0x18 aObjectDefaultIIDTable As Long ' 0x1C ControlCount As Long ' 0x20 aControlArray As Long ' 0x24 iEventCount As Integer ' 0x28 (40d) Number of Events iPCodeCount As Integer ' 0x2C oInitializeEvent As Integer ' 0x2C (44d) Offset to Initialize Event from aMethodLinkTable oTerminateEvent As Integer ' 0x2E (46d) Offset to Terminate Event from aMethodLinkTable aEventLinkArray As Long ' 0x30 Pointer to pointers of MethodLink aBasicClassObject As Long ' 0x34 Pointer to an in-memory Null3 As Long ' 0x38 Flag2 As Long ' 0x3C usually null ' 0x40 &lt;-- Structure sizeEnd TypeType tProjectInfo2 lNull1 As Long ' 0x00 (00d) aObjectTable As Long ' 0x04 (04d) Pointer to Object Table lConst1 As Long ' 0x08 (08d) lNull2 As Long ' 0x0C (12d) aObjectDescriptorTable As Long ' 0x10 (16d) Pointer to a table of ObjectDescriptors lNull3 As Long ' 0x14 (20d) aNTSPrjDescription As Long ' 0x18 (24d) Pointer to Project Description aNTSPrjHelpFile As Long ' 0x1C (28d) Pointer to Project Help File lConst2 As Long ' 0x20 (32d) lHelpContextID As Long ' 0x24 (36d) Project Help Context ID ' 0x28 (40d) <- Structure sizeEnd TypeType ObjectDescriptor lNull1 As Long '0x00 (00d) aObjectInfo As Long '0x04 (04d) Pointer to Object Info lConst1 As Long '0x08 (08d) lNull2 As Long '0x0C (12d) lFlag1 As Long '0x10 (16d) lNull3 As Long '0x14 (20d) aUnknown1 As Long '0x18 (24d) lNull4 As Long '0x1C (28d) aUnknown2 As Long '0x20 (32d) aUnknown3 As Long '0x24 (36d) aUnknown4 As Long '0x28 (40d) lNull5 As Long '0x2C (44d) lNull6 As Long '0x30 (48d) lNull7 As Long '0x34 (52d) lFlag2 As Long '0x38 (56d) fObjectType As Long '0x3C (60d) Flags for this Object '0x40 (64d) <- Structure SizeEnd Type&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;未完待续!!!!!(还有很大大大大一部分类!!!)&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times;&times; 标 题: VB6反编译详解(二)作 者: kenmark时 间: 2006-07-20 10:57 链 接: http://bbs.pediy.com/showthread.php?threadid=29307 详细信息: ****************************************************************************************************上次说到最重要的部分OBJECT TABLE就断了实在是对不起大家,所以最近加紧研究马上出了第二篇(连载会很长哦,要考验大家的耐心的哦)*****************************************************************************************************7)ObjectInfo这些东西十分重要,是提取VB工程元素的重要标志,从这里我们可以得到这个工程里有多少FORM,多少MODULE,以及他们的重要索引数据,可以说重要性和SECTION HEAD在EXE程序中重要性相同。我们反编译只是初期水平,现在由于笔者能力有限,我们只讨论到如何完全反会MOD,VBP,FRX和FRM文件,关于其他文件例如.CLS类文件什么的不再本文讨论范围之内。入口的地址是由ProjectInfo_t结构提供的(semi提供关于这里提供的资料少之又少,所以需要自己摸索)从ProjectInfo_t开始指向的是一个ObjectTable_t,由ObjectTable_t提供第一个OBJECT_t结构的地址,索引其他的OBJECT和Import Table里索引IID一样。typedef struct //这个是OBJECT 的总表,可以索引以后的每个OBJECT{ DWORD lNull1 As Long; //没有用的填充东西 DWORD aExecProj; //VA指向一块内存结构(研究下来既不没见着这个东西由什么用处 DWORD aProjectInfo2; //VA指向Project Info 2 DWORD Const1; //没有用的填充东西 DWORD Null2; //没有用的填充东西 DWORD lpProjectObject As Long ' 0x14 DWORD Flag1; //标志1 DWORD Flag2; //标志2 DWORD Flag3; //标志3 DWORD Flag4; //标志4 WORD fCompileType; //Internal flag used during compilation WORD ObjectCount1; //OBEJCT数量1???? WORD iCompiledObjects; //编译后OBJECT数量 WORD iObjectsInUse As Integer; //Updated in the IDE to correspond the total number ' but will go up or down when initializing/unloading modules. DWORD aObject; //VA指向第一个OBJECT_t结构,很重要 DWORD Null3; //没有用的填充东西 DWORD Null4; //没有用的填充东西 DWORD Null5; //没有用的填充东西 DWORD aProjectName; //执行工程名字的字符串 DWORD LangID1; //language ID1 DWORD LangID2; //language ID2 DWORD Null6; //没有用的填充东西 DWORD Const3; //没有用的填充东西 ' 0x54}ObjectTable_t;type struct//这个就是每个OBJECT的结构,{ DWORD aObjectInfo; //VA 指向一个ObjectInfo_t类型,来显示这个OBJECT的数据 DWORD Const1; //没有用的填充东西 DWORD aPublicBytes; //VA 指向公用变量表大小 DWORD aStaticBytes; //VA 指向静态变量表地址 DWORD aModulePublic; //VA 指向公用变量表 DWORD aModuleStatic; //VA 指向静态变量表 DWORD aObjectName; //VA 字符串,这个OBJECT的名字 DWORD ProcCount; // events, funcs, subs(事件/函数/过程)数目 DWORD aProcNamesArray; //VA 一般都是0 DWORD oStaticVar; //OFFSET 从aModuleStatic指向的静态变量表偏移 DWORD ObjectType; //比较重要显示了这个OBJECT的实行,具体见下表 DWORD Null3; //没有用的填充东西 //sizeof() = 0x30}Object_t;'Object_t.ObjectTyper 属性...//重要的属性表部分'#########################################################'form: 0000 0001 1000 0000 1000 0011 --> 18083' 0000 0001 1000 0000 1010 0011 --> 180A3' 0000 0001 1000 0000 1100 0011 --> 180C3'module: 0000 0001 1000 0000 0000 0001 --> 18001' 0000 0001 1000 0000 0010 0001 --> 18021'class: 0001 0001 1000 0000 0000 0011 --> 118003' 0001 0011 1000 0000 0000 0011 --> 138003' 0000 0001 1000 0000 0010 0011 --> 18023' 0000 0001 1000 1000 0000 0011 --> 18803' 0001 0001 1000 1000 0000 0011 --> 118803'usercontrol: 0001 1101 1010 0000 0000 0011 --> 1DA003' 0001 1101 1010 0000 0010 0011 --> 1DA023' 0001 1101 1010 1000 0000 0011 --> 1DA803'propertypage: 0001 0101 1000 0000 0000 0011 --> 158003' | || | | | | |'[moog] | || | | | | |'HasPublicInterface ---+ || | | | | | (有公用的接口)'HasPublicEvents --------+| | | | | | (有公用的事件)'IsCreatable/Visible? ----+ | | | | | (是否可以创建,可见)'Same as "HasPublicEvents" -----+ | | | | '[aLfa] | | | | |'usercontrol (1) ---------------+ | | | | (用户控制)'ocx/dll (1) ----------------------+ | | | (OCX/DLL)'form (1) ------------------------------+ | | (是不是FORM是就是1)'vb5 (1) ---------------------------------+ | (是不是VB5是就是1)'HasOptInfo (1) -------------------------------+ (有没有额外的信息信息由就是1,决定是不是指向OptionalObjectInfo_t类似与PEHEAD里的Optional信息一样)' |'module(0) ------------------------------------+ (如果是Module模块就这里是0)typedef struct//这个是显示这个OBJECT信息的结构,每一个OBJECT都有一个{ WORD Flag1; WORD ObjectIndex; //OBJECT的索引???????????????????????? DWORD aObjectTable; //指向OBJECT TABLE?????????????????? DWORD Null1; //没有用的填充东西 DWORD aSmallRecord; // 如果这个对象是一个模块(module)那么这个数值是-1 DWORD Const1; //没有用的填充东西 DWORD Null2; //没有用的填充东西 DWORD aObject; //指向OBJECT?????????????????????????????? DWORD RunTimeLoaded; //[can someone verify this?] DWORD NumberOfProcs; //proc个数 DWORD aProcTable; //指向proc表 WORD iConstantsCount; // 常量个数 WORD iMaxConstants; // 最大的要求分配的常量 DWORD Flag5; WORD Flag6; WORD Flag7; WORD aConstantPool; //指向常量池 // sizeof() = 0x38 'the rest is optional items[OptionalObjectInfo]}ObjectInfo_t;typedef struct // 这个是可选的OBJECT_INFO和PEHEADER里的OPTIONAL_HEADER类似,是否有要看每个Object_t里面的ObjectTyper表里的倒数第二个位(详细看上表){ DWORD fDesigner; // 如果这个数值是2则表示是一个designer DWORD aObjectCLSID; //指向CLSID对象 DWORD Null1; //没有用的填充东西 DWORD aGuidObjectGUI; //????????????????????????????? DWORD lObjectDefaultIIDCount; // 01 00 00 00 ??????????????????????????? DWORD aObjectEventsIIDTable; //指向对象行为IID表 DWORD lObjectEventsIIDCount; //对象行为IID个数 DWORD aObjectDefaultIIDTable; //指向默认对象IID表 DWORD ControlCount; //控件个数 DWORD aControlArray; //指向控件表 WORD iEventCount; // 行为的个数,比较重要,知道有几个行为 WORD iPCodeCount; // PCode个数 WORD oInitializeEvent; // offset从aMethodLinkTable指向初始化行为 WORD oTerminateEvent; // offset从aMethodLinkTable指向终止行为 DWORD aEventLinkArray; //Pointer to pointers of MethodLink DWORD aBasicClassObject; // Pointer to an in-memory DWORD Null3; //没有用的填充东西 DWORD Flag2; //一般都是空的 //sizeof() = 0x40}OptionalObjectInfo_t;typedef struct{ WORD Flag1;//Integer ' 0x00 WORD EventCount;//Integer ' 0x02 DWORD Flag2;//Long ' 0x04 DWORD aGUID;//Long ' 0x08 WORD index;//Integer ' 0x0C WORD Const1;//Integer ' 0x0E DWORD Null1;//Long ' 0x10 DWORD Null2;//Long ' 0x14 DWORD aEventTable;//Long ' 0x18 BYTE Flag3;//Byte ' 0x1C BYTE Const2;//Byte ' 0x1D WORD Const3;//Integer ' 0x1E DWORD aName;//Long ' 0x20 WORD Index2;//Integer ' 0x24 WORD Const1Copy;//Integer ' 0x26 // 0x28 &lt;-- Structure Size}Control_t; 看到这里我们已经可以通过这个表粗略地勾画出那个工程是怎样的,通过PROJECT_INFO和其他的一些东西,我们已经能够重建VBP文件,而且我们已经知道这个工程到底有多少源文件(FRM,MOD不包括FRX)接下来,我们来读取EXE文件中保存的数据来重建每个MOD,FRM,CLS,VBP重建VBP我们本文不是主要介绍VB工程组文件的内部结构,所以只是一笔带过,VBP文件内部格式和普通的配置文件类似都是(关键词,对应值)对的形式主要有这么几个字段我们要注意(输出的东西和SEMI一样,关于VERSION会比SEMI详细,将在之后介绍)Type=Exe(这个就是这个工程是什么我们当然是EXE)Startup="frmMain"(这个就是工程的启动项目,关于它我们后面要详细介绍)Description="Visual Basic Decompiler"(这个是描述,(char*)COMRegData+COMRegData->oNTSProjectDescription)HelpFile=""(帮助文件(char*)VBHEADER+VBHEADER->oHelpFile就是其在文件中的偏移)Name="VBDecompiler"(工程名字,获得方式和HELPFILE类似,只要看VBHEADER里面就有存储其偏移地址)Title="VBDecompiler"(工程标题,获得方式和HELPFILE类似,只要看VBHEADER里面就有存储其偏移地址)ExeName32="SemiVBDecompiler"(工程EXE32的名字,获得方式和HELPFILE类似,只要看VBHEADER里面就有存储其偏移地址)注意:每找到一个OBJECT对应的文件,我们要将其添加到VBP工程里面,具体的方式是:如果这个OBJECT是FRM文件,只要在VBP文件里面添加一条Form=窗体文件的名字(文件名)(没有空格要求=以后紧跟)如果这个OBJECT是MOD文件,只要在VBP文件里面添加一条Module=内部标识名;文件名(之间需要一个分号来格开)如果这个OBJECT是CLASS文件,只要在VBP文件里面添加一条Class=内部标识名;文件名(之间需要一个分号来格开)这样的话,在VBP文件中维护各个工程文件的工作就大致完成了。其他重要的项还有例如OBJECT项(添加使用的控件)以及版本信息相关的(在后面的资源反编译一节会着重介绍)剩下的就是关于编译时的优化选项了,这些不是很重要,所以就没有加入。其实VBP文件里包含了很多工程的细节,但是我们主要只要抓住重要的字段。重建MODMOD文件比较简单,由于文件名可能和模块名不同,编译的时候舍弃了实际文件名,而用模块名来作为标识,所以我们生成的MOD文件的名字选用模块名,可能与原始的源文件组不同。获得一个OBJECT之后,我们看Object_t.ObjectType通过查表我们能够确定它的性质我们确定这个是MOD文件之后,我们通过Object_t.aObjectName(指向一个字符串)这个就是这个模块的名字,也是这个模块在编译后的文件中的标识。我们用这个标识名来作为文件名,创建一个文件,然后我们通过Object_t.ProcCount知道这个MOD里存储着多少个FUNCTION和SUB,并且由于MOD是全编译,我们得不到具体的SUB和FUNCTION的名字,这些名字在编译的时候被丢弃的所以我们只能知道到底有多少个SUB和FUNCTION。所以MOD的重建并不能得到什么东西,只能空创建一个文件然后最多写入:'There is totally 100 methods in this module.But we can't show you them.:)还要记得一点就是我们要为这个BAS文件写上它的VB_ATTRIB,具体的格式就是Attribute VB_Name = "模块的名字(内部标识名)"这部分的具体代码重建(一般来说不能完全重建),我们只能有待更加强大的代码反编译来完成。重建FRMFRM和MOD不同的是我们可以得到FRM里面的所有控件的基本静态状态(属性),并且我们可以得到里面存储的SUB 和FUNCTION的名字(不同于MOD)同样如何知道这个OBJECT是一个FRM文件还是要查表知道它是一个FRM文件之后我们首先要了解一下FRM文件的结构,FRM文件是类似配置文件的格式存储的,主要有外部的VB_ATTRIB定义以及FORM成员的定义VERSION 5.00//文件的编译版本Begin VB.Form 内部标识名(表示这个FORM的开始)Begin VB.VB内部控件对象 内部标识名EndEndAttribute VB_Name = "FORM的内部标识名"多重的嵌套就完成了这个FORM里面控件的从属关系(例如一个PICTUREBOX从属与FORM,而一个TEXT从属于一个FRAME)之后我们要得到这个FRM文件里面的控件信息和SUB以及FUNCTION的信息,来完成我们的FRM写入每个OBJECT里有一个TYPE表示这个OBJECT的属性,我们已经知道凡是是一个FRM都是有OptionalObjectInfo这个结构告诉我们很多元素的索引,获取的方式十分简单,只要先确定有OptionalObjectInfo然后它的地址就是这个Object的(char*)ObjectInfo+sizeof(ObjectInfo)其实就是紧紧跟在ObjectInfo之后的。结构的描述已经在上面列出了,这个结构中的信息十分复杂,我们要注意这么几个项目ControlCount 列出控件个数aControlArray 指向控件表控件表是一个紧紧挨着的一个指针数组,我们可以逐个读取获得信息伪代码:for (i = 0 ; i<=this->ObjectTable->ObjectCount1 -1 ; ++i,++t){//循环获得所有的OBJECT的指针 s = this->Get_OptionalObjectInfo(t); //获取一个OBJECT的OptionalObjectInfo if (s==NULL) // it is a module and haven't any optional object info continue; cout<<"One frm found!"<<endl;//打印出:获得一个FRM ct = this->Get_Control_t(s);//获取第一个Control的指针 for (d = 0 ; d<=s->ControlCount-1 ; d++)//循环获得每一个CONTROL的索引 cout<<"one control:"<<this->Get_Control_Name(ct++)<<endl;//获得了一个Control打印出它的名字}inline BYTE * VBEXE::Get_Control_Name(VBST::Control_t *x){ return (this->buffer + this->sf.VA2Offset(x->aName));}这里其实是我的DECOMPILER的一些片段,仅仅是用作调试的还未成型所以就不敢贴出来丢脸了:)。每个Control_t的aName是一个VA指向一个字符串就是表示这个控件的名字,至于控件的属性我们以后再说:)我们看看我的VBDECOMPILER输出的读取那个SEMI的DECOMPILER的东西Load file sucessfully!Get contols in objectOne frm found!one control:mnuFileone control:mnuHelpAboutone control:txtFinalone control:mnuFileOpenone control:mnuToolsone control:Label1one control:Formone control:Label2one control:mnuFileRecent1one control:mnuFileSep1one control:mnuFileRecent2one control:mnuFileRecent3one control:mnuFileRecent4one control:mnuFileSep2one control:lblObjectNameone control:mnuOptionsone control:mnuFileDebugProcessone control:mnuToolsPCodeProcedureone control:txtCodeone control:tvProjectone control:StatusBar1one control:sstViewFileone control:fxgEXEInfoone control:picPreviewone control:mnuFileAntiDecompilerone control:mnuFileExportMemoryMapone control:mnuFileGenerateone control:lstMembersone control:lstTypeInfosone control:mnuFileSaveExeone control:txtBufferone control:txtFunctionsone control:txtEditArrayone control:lblArrayEditone control:buffCodeAvone control:buffCodeApone control:mnuFileExitone control:txtResultone control:cmdCancelone control:txtStatusone control:mnuHelpone control:FrameStatusOne frm found!one control:imgFlameone control:lblTitleone control:TmrLightone control:tmrIconone control:FormOne frm found!one control:chkShowOffsetsone control:chkSkipCOMone control:chkDumpControlsone control:cmdCloseone control:chkPCODEone control:chkShowColorsone control:FormOne frm found!one control:ClassOne frm found!one control:ClassOne frm found!one control:lblTitleone control:cmdCloseone control:Formone control:Label1one control:lstProceduresone control:txtView到这里,我们以及能够基本将原来的工程组还原出来了,但是仍然有缺点:1)我们得不到(应该说实我水平不够)VBP文件里的Reference2)我们即将讨论关于VERSION信息的东西(要从一个EXE的RESOURCE中看出端倪)3)我们的CODE仍然还是一大问题4)我们的STARTUP开始段,(马上会研究出来的)5)我们还不知道哪个FRM有FRX文件哪个没有而且不能还原,而且FRM里面的控件还是不能获得属性6)PCODE一点都没有讨论7)还有一些细节的信息没能弄出来 更多 上一篇:获取外网IP的几种方法 下一篇:VB6.0 Windows API 查看评论 * 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场 核心技术类目 全部主题 Java VPN Android iOS ERP IE10 Eclipse CRM JavaScript Ubuntu NFC WAP jQuery 数据库 BI HTML5 Spring Apache Hadoop .NET API HTML SDK IIS Fedora XML LBS Unity Splashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStack FTC coremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide Maemo Compuware 大数据 aptech Perl Tornado Ruby Hibernate ThinkPHP Spark HBase Pure Solr Angular Cloud Foundry Redis Scala Django Bootstrap 个人资料 asftrhgjhkjlkttttttt 访问:48251次 积分:777分 排名:第17700名 原创:21篇 转载:29篇 译文:0篇 评论:25条 文章搜索 文章分类 VB编程技术(43) 杂类文章(7) 文章存档 2011年06月(2)2011年05月(1)2010年12月(1)2010年11月(1)2010年08月(1)2010年07月(2)2010年06月(2)2010年04月(3)2010年03月(5)2010年02月(1)2010年01月(1)2009年12月(5)2009年11月(24)2009年05月(1) 阅读排行 VB mschart控件的使用(5013) VB中Shell和ShellExecute函数的使用方法和区别(3731) 如何将EXCEL表导入SQL2000(2601) 教你如何用VB做控件*.ocx (2531) 如何拉伸图片至整个屏幕(1622) 完美隐藏系统托盘图标(1609) 在VB下使用Printer对象使用心得(1581) 关于漂亮控件的说明(1392) vb调用excel方法大全(1368) VB6反编译详解(1248) 评论排行 关于漂亮控件的说明(6) 教你如何用VB做控件*.ocx (4) 如何将EXCEL表导入SQL2000(3) VB6反编译详解(2) 实现播放音乐的几种方法(2) 完美隐藏系统托盘图标(1) 如何用VB编写FLASH动画播放器(1) WebBrowser 控件使用详解(1) DOS命令大全(1) VB中Shell和ShellExecute函数的使用方法和区别(1) 推荐文章 最新评论 教你如何用VB做控件*.ocx daomoren: 我用VB6制作了自定义控件有两个,然后“工程”-“部件”加载调用,为何不能同时调用不同的两个自定义控... VB中Shell和ShellExecute函数的使用方法和区别 hu08070527: 写的挺不错的 实现播放音乐的几种方法 DE1202: 怎么打开文件夹里面的歌曲啊这样只能打开VB里的歌曲求指导啊 VB6反编译详解 JiLuoXingRen: 你说的那个反编译出工程文件和窗体的反编译器我用过,但是翻出来的文件Vb跟本无法打开~~汗 VB6反编译详解 spt_petrolor: 这个东西,网上转了很多,但是里面很多错误,完全按照他的能解出一个vbp来那就鬼了. 关于漂亮控件的说明 pingle209: 我按照里面所说的注册了,可这些东西怎么在VB中使用呢 set A = NEW OBJ和SET A = CreateObject(OBJ)有什么区别 hyjavahy: 使SQL语句不被Sql Profiler/事件探查器捕获跟踪 biptwhisky: 完美隐藏系统托盘图标 wp8893657: 学习了 如何将EXCEL表导入SQL2000 asftrhgjhkjlkttttttt: 回复 匿名用户:那就将你说的EXCEL中的行和列数据用代码复制到新的excel表里,再导入吧