当前位置:文档之家› 浅谈VFP程序的破解

浅谈VFP程序的破解

浅谈VFP程序的破解
浅谈VFP程序的破解

浅谈VFP程序的破解

由于VFP程序的编译是一种伪编译过程,经过一定的处理,可以得到完整的源代码。自从ReFox、UnFoxAll等反编译软件出现后,为保护作者自己的利益,软件的加密保护就显得十分重要,相应的,VFP程序的加密也越来越严。但由于VFP固有的特点—即解释执行,VFP的解释器必须要得到可识别的代码,所以VFP程序的破解相对其他语音编译的程序来说,还是比较简单的。

一、VFP EXE程序的特点

VFP标准的编译EXE文件是如下一种格式:

可执行部分+APP文件+结构说明

其中可执行部分是标准的PE文件,APP部分就是VFP编译的应用程序代码,最后的结构为14个字节,用来描述APP文件,其中重要的是最后4个字节,反映的是APP文件的大小。

头部的可执行部分只是简单地加载VFP的解释器(解释器名称为vfp6r.dll、vfp7r.dll、vfp8r.dll分别对应6.0、7.0、8.0.版本)执行app文件。现在的加密软件大多利用这个特点,自己构造一个PE头,利用各种壳的技术保护APP代码。

因此我们可以这样认为,对于VFP的可执行文件,除APP文件以外的可执行部分,都可认为是壳。

二APP文件的结构

1.app文件结构

app文件是vfp生成的应用程序或Active Document

其结构为:

字节偏移说明

0-1 文件标识&Hf2fe为vfp的app

2 加密标识bit 0 为1,未加密

bit 0 为0,加密,此时bit 4(0或1)区分为两类

3-4 编译版本&H0220 -vfp 6.0/7.0

&H021f -vfp 5.0

5-6 文件数目

7-8 主文件位置(从0开始)

9-12 文件名列表地址

13-16 文件说明结构列表地址

17-20 文件名列表长度

21-36 加密类型密码表

37-38 解密key

39-40 文件校验和

文件名列表地址

[目录名],00,文件名,00,文件名,00,...

文件说明结构列表地址

每个文件占用25个byte,总长度为文件数*25

0 文件类型0为代码其他数据

1-4 文件开始地址

5-8 文件结束地址

9-12 文件名相对文件名列表的首地址

其他不详

三、VFP的加密特点及脱壳

VFP的加密基本上可以分为两种—文件型加密和内存型加密,这两种加密的区分主要在APP文件的存放位置,存放在某个文件中就为文件型,存放在内存中就叫内存型。但对解密者来说,关心的是算法。以上的分类加不加以区别问题不大。

1、

文件头简单替换型

这种加密方式是比较早期的一种加密方式,能够阻止反编译软件,但APP代码在文件中以明码出现,如xx王5.05B(https://www.doczj.com/doc/a417533626.html,)

脱壳方法:

打开HEX,查找FEF2找到后与APP文件的结构对比一下,发现没有问题,把从FEF2开始到文件尾的数据存成一个文件,取名XXX.app,脱壳完成。

2、文件隐藏型

这类加密在exe文件中已经没有app的明码了,app文件是由主程序运行过程中动

态生成的,以文件形式存在硬盘的某处。如xx通用计划管理系统

6.02(https://www.doczj.com/doc/a417533626.html,)

用TRW2000加载程序

下断bpx createfilea

createfilea的定义为:

HANDLE CreateFile(

LPCTSTR lpFileName, // pointer to name of the file

DWORD dwDesiredAccess, // access (read-write) mode

DWORD dwShareMode, // share mode

LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDisposition, // how to create

DWORD dwFlagsAndAttributes, // file attributes

HANDLE hTemplateFile // handle to file with attributes to copy

);

每次中断后观察打开的文件名,经过两次foxpro.int下面一个就是脱壳后的文件名了。

文件放在c:\windows\history\...\ (x)

因为c:\windows\history\是windows的系统目录,下面的文件不可显示,程序运行结束后又会删除这个文件,所以必须在程序没有结束前得到这个文件

方法一:用suspend将程序挂起,用procdump kill现有进程,回dos利用xcopy /s 将所有文件考出,处理

方法二、利用copyfilea函数

BOOL CopyFile(

LPCTSTR lpExistingFileName,

// pointer to name of an existing file

LPCTSTR lpNewFileName, // pointer to filename to copy to

BOOL bFailIfExists // flag for operation if file exists

);

在上图的位置r eax 0 r ebx 63e630 r edx 63e660

将63e660地址的内容改成目的文件如 d:\ab\s.exe

然后编一段代码

a eip

push eax

push edx

push ebx

call copyfilea

最后一句不能直接输入,要用exescope找到import中copyfilea的位置,计算相对地址用ff 15 xx xx xx xx填入

单步运行完copyfilea后,隐藏的文件就被考出来了。

考出的文件是exe文件,用1的方法就能得到app文件,但这个app文件可运行,用unfoxall反编译会出错,后面会讲到app文件的标准化处理。

3 改变解释器动态解码

这种加密方式采用了狗的方式,用trw2000加载跟踪时,在文件开始运行的代码部分会看到大量的花指令,再将主文件加密的同时,它把解释动态连接库也进行了加壳,运行时用壳中的代码将app文件解码后执行。因vfp6r.dll被改动,无法放到系统目录下,因此文件安装目录下能看到vfp6r.dll,用exescope文件观察此文件,能看到gtide段,这就是这种文件的特征。

例如:xx建筑工程预结算系统6.6版(https://www.doczj.com/doc/a417533626.html,)

处理方法:采用2的方法下断createfilea,得到调用文件后,下断readfile,

readfile定义如下:

BOOL ReadFile(

HANDLE hFile, // handle of file to read

LPVOID lpBuffer, // pointer to buffer that receives data

DWORD nNumberOfBytesToRead, // number of bytes to read

LPDWORD lpNumberOfBytesRead, // pointer to number of bytes read

LPOVERLAPPED lpOverlapped // pointer to structure for data

);

第3次读200byte时中断,在读出的代码处下断,bpm xxxxxxxx,观察程序如何解码

解码部分的指令

0167:0C2FA505 INC DWORD [EBP-04] 已处理字节数

0167:0C2FA508 MOV EAX,[EBP+0C] 要处理字节数

0167:0C2FA50B CMP [EBP-04],EAX

0167:0C2FA50E JNC 0C2FA53A

0167:0C2FA510 MOV EAX,[EBP-04]

0167:0C2FA513 MOV ECX,[EBP+08] 要处理数据的首地址

0167:0C2FA516 XOR EDX,EDX

0167:0C2FA518 MOV DL,[ECX+EAX] 要处理的数据送DL

0167:0C2FA51B MOV AL,[EDX+0C3352E2] 0C3352E2—0C3354E2 512个字节为密钥0167:0C2FA521 MOV [EBP-08],AL

0167:0C2FA524 XOR EAX,EAX

0167:0C2FA526 MOV AL,[EBP-08]

0167:0C2FA529 MOV AL,[EAX+0C3353E2]

0167:0C2FA52F MOV ECX,[EBP-04]

0167:0C2FA532 MOV EDX,[EBP+08]

0167:0C2FA535 MOV [EDX+ECX],AL

JMP 0C2FA505

W 0C3352E2 0C3354E2 key.bin

记下读出的内容,用hex workshop 在主文件中查找,将到文件尾的内容写入另一个文件code.bin 用VB的语言,上述的解密算法为

Dim keyfiledata(0 to 511) As Byte

Dim codefiledata() As Byte

Dim middata() As Byte

Dim keyfilelen As Long

Open " Key.bin" For Binary As #1

Get #1, 1, keyfiledata()

Close #1

keyfilelen = FileLen("code.bin")

Redim keyfiledata(0 to keyfilelen-1) as byte

Redim middata(0 to keyfilelen-1) as byte

Open "code.bin" For Binary As #2

Get #2, i, codefiledata

Close #2

For I=0 to keyfilelen-1

Middata(i) = keyfiledata(keyfiledata(codefiledata (i)) + 256)

Next i

Open "code.app" For Binary As #2

Put #2, 1, middata()

Close #2

MsgBox "finish"

得到app文件

4 改变解释器的加密方式

这种文件的加密方式的app文件是以加密app的方式出现,加密者将vfp6r.dll的解密部分代码和文件头标志加以改变,变成自己的动态连接库,这个库文件同样放在文件的安装目录下,但有的程序采用了一定的手段让用户看不到这个文件。

例如:xx工程造价软件6.6版(https://www.doczj.com/doc/a417533626.html,)

这个软件安装后,改变注册表

HKEY_LOCAL_MACHINE\software\Microsoft\windows\currentversion\explorer\advanced\fold er\hidden\showall\checkedvalue

将键值由0改为1,这样隐含系统文件你就看不到了,我认为这种方法是不可取得,文件加密的同时不应干扰用户其他的功能,利用这种方法有点缺德之嫌。

就以这个程序为例,首先比较一下正规的vfp6r.dll和程序用的vfp6r.dll有何不同

0167:0C02102E MOV ECX,02

0167:0C021033 MOV EDI,0C2F24C8 [edi]为c4c5 正常为fef2 0167:0C021038 MOV ESI,EBX

0167:0C02103A XOR EDX,EDX

0167:0C02103C REPE CMPSB

0167:0C02103E JNZ NEAR 0C0EF608 不等则跳,与其它值比较

0167:0C021044 MOV AL,[EBX+02]

0167:0C021047 NOT EAX

0167:0C021049 TEST AL,01

0167:0C02104B JNZ 0C021096 是加密的则跳

0167:0C02104D MOV ESI,01

0167:0C021052 MOV BYTE [0C30D2FC],00

0167:0C021059 MOVZX CX,[EBX+04]

0167:0C02105E MOVZX AX,[EBX+03]

0167:0C021063 SHL ECX,08

0167:0C021066 ADD EAX,ECX

0167:0C021068 MOV ECX,[0C2F24C4]

0167:0C02106E AND EAX,FFFF

0167:0C021073 CMP EAX,ECX 比较文件的版本0167:0C021075 JNZ NEAR 0C0EF5E8

0167:0C02107B MOV ECX,EBX

0167:0C02107D CALL 0C0210C6

0167:0C021082 CMP AX,[EBX+27]

0167:0C021086 JNZ NEAR 0C0EF5FB

0167:0C02108C MOV EAX,ESI

0167:0C02108E POP EDI

0167:0C02108F POP ESI

0167:0C021090 POP EBP

0167:0C021091 POP EBX

0167:0C021092 POP ECX

0167:0C021093 RET 0C

0167:0C021096 MOV ECX,EBX

0167:0C021098 CALL 0C0A863D 解密部分0 0167:0C02109D MOV ECX,EBX

0167:0C02109F CALL 0C0A8727 解密部分1

0167:0C0210A4 MOV ESI,[ESP+1C]

0167:0C0210A8 MOV ECX,[ESI]

0167:0C0210AA CALL 0C005392 解密部分2

0167:0C0210AF MOV ECX,EBX

0167:0C0210B1 CALL 0C0A879D 解密部分3

0167:0C0210B6 MOV [ESI],EAX

0167:0C0210B8 MOV BYTE [0C30D2FC],01

0167:0C0210BF MOV ESI,02

0167:0C0210C4 JMP SHORT 0C021059

0167:0C0A863D SUB ESP,BYTE +10

0167:0C0A8640 MOV AL,[ECX+02]

0167:0C0A8643 PUSH EBX

0167:0C0A8644 NOT EAX

0167:0C0A8646 SHR EAX,04

0167:0C0A8649 MOV BX,[ECX+25] 25-26位解密的密钥0167:0C0A864D AND EAX,BYTE +01

0167:0C0A8650 MOV [ESP+10],EAX

0167:0C0A8654 LEA EAX,[ECX+25]

0167:0C0A8657 PUSH EBP

0167:0C0A8658 PUSH ESI

0167:0C0A8659 XOR ESI,ESI

0167:0C0A865B AND EBX,FFFF

0167:0C0A8661 PUSH EDI

0167:0C0A8662 MOV [ESP+14],ECX

0167:0C0A8666 MOV [ESP+18],EAX

0167:0C0A866A MOV [0C3171EE],SI

0167:0C0A8671 MOV [ESP+10],EBX

0167:0C0A8675 MOV EBP,0F

0167:0C0A867A MOV EAX,ESI

0167:0C0A867C CDQ

0167:0C0A867D XOR EAX,EDX

0167:0C0A867F SUB EAX,EDX

0167:0C0A8681 AND EAX,BYTE +07

0167:0C0A8684 XOR EAX,EDX

0167:0C0A8686 MOV EDI,EAX

0167:0C0A8688 MOV AL,[ESI+ECX+15]

0167:0C0A868C SUB EDI,EDX

0167:0C0A868E MOV EDX,01

0167:0C0A8693 MOV ECX,EDI

0167:0C0A8695 SHL EDX,CL

0167:0C0A8697 MOV ECX,EBP

0167:0C0A8699 AND DL,AL

0167:0C0A869B NEG DL

0167:0C0A869D SBB EDX,EDX

0167:0C0A869F NEG EDX

0167:0C0A86A1 SHL EDX,CL

0167:0C0A86A3 MOV ECX,ESI

0167:0C0A86A5 OR [0C3171EE],DX 计算的key1,以后还要用到0167:0C0A86AC MOV EDX,01

0167:0C0A86B1 SHL EDX,CL

0167:0C0A86B3 MOV ECX,EDI

0167:0C0A86B5 AND EDX,EBX

0167:0C0A86B7 MOV BL,01

0167:0C0A86B9 NEG EDX

0167:0C0A86BB SBB EDX,EDX

0167:0C0A86BD SHL BL,CL

0167:0C0A86BF NEG EDX

0167:0C0A86C1 SHL DL,CL

0167:0C0A86C3 MOV ECX,[ESP+14]

0167:0C0A86C7 NOT BL

0167:0C0A86C9 AND BL,AL

0167:0C0A86CB OR DL,BL

0167:0C0A86CD MOV [ESI+ECX+15],DL

0167:0C0A86D1 INC ESI

0167:0C0A86D2 DEC EBP

0167:0C0A86D3 CMP EBP,BYTE -01

0167:0C0A86D6 JNG 0C0A86DE

0167:0C0A86D8 MOV EBX,[ESP+10]

0167:0C0A86DC JMP SHORT 0C0A867A

0167:0C0A86DE MOV EDI,[ESP+18]

0167:0C0A86E2 LEA EAX,[ECX+03]

0167:0C0A86E5 CMP EAX,EDI

0167:0C0A86E7 MOV DL,FE

0167:0C0A86E9 JNC 0C0A871F

0167:0C0A86EB MOV ESI,[ESP+1C]

0167:0C0A86EF MOV CX,[0C3171EE]

0167:0C0A86F6 MOV BL,[EAX]

0167:0C0A86F8 XOR DL,CL

0167:0C0A86FA XOR BL,DL

0167:0C0A86FC TEST ESI,ESI

0167:0C0A86FE MOV [EAX],BL

0167:0C0A8700 MOV DL,BL

0167:0C0A8702 JZ NEAR 0C0D34C6

0167:0C0A8708 IMUL CX,CX,273D 正常为184d

0167:0C0A870D ADD ECX,236D 正常为347d

0167:0C0A8713 INC EAX

0167:0C0A8714 CMP EAX,EDI

0167:0C0A8716 JC 0C0A86F6

0167:0C0A8718 MOV [0C3171EE],CX

0167:0C0A871F POP EDI

0167:0C0A8720 POP ESI

0167:0C0A8721 POP EBP

0167:0C0A8722 POP EBX

0167:0C0A8723 ADD ESP,BYTE +10

0167:0C0A8726 RET

其他几处call中也有改动,这里就不细说了,因为这部分代码很短写个解密程序处理最为方便,处理前首先用hex workshop查找c4c5ee,将从这开始到最后的代码存成一个文件,处理完后将app文件中的c4c5全部改为fef2,注意这时文件的checksum值会变动,运行时会报告不是vfp

的对象文件,动态跟踪一下,在上面第一段代码ret之后就是chexksum的比较,按正确的改过来就可以了.

5 vfpexenc内存加密

vfpexenc的加密方式比较特殊,它把动态解出的加密app文件放在内存中而不是放在一个文件里,但这对解密者没有什么不同,难度是vfpexenc在代码中增加了anti-debug代码,发现有跟踪立即停止运行,报告”文件无法打开”,结束。可是幸运的是,加密的vfp程序中并没有采用vfpexenc 中的seh、sidt判断int1的技术,而只是简单地判断内存进程标题名,这种厚己薄彼的做法给破解者带来了极大的方便。

先看看程序是如何反跟踪的(vfpexenc3.7)

0167:0041994A PUSH DWORD FF

0167:0041994F PUSH EDI

0167:00419950 PUSH EBX

0167:00419951 CALL `USER32!GetClassNameA`

0167:00419956 TEST EAX,EAX

0167:00419958 JNG 004199BC

0167:0041995A LEA EDX,[EBP+FFFFFEF8]

0167:00419960 MOV EAX,EDI

0167:00419962 CALL 00407E90

0167:00419967 MOV EAX,[EBP+FFFFFEF8]

0167:0041996D LEA EDX,[EBP-04]

0167:00419970 CALL 00407684

0167:00419975 MOV EAX,[EBP-04]

0167:00419978 MOV EDX,00419A70 edx 是要判断的文件名

0167:0041997D CALL 00404620

0167:00419982 JZ 004199B1 相等就结束了

0167:00419984 MOV EAX,[EBP-04]

0167:00419987 MOV EDX,00419A80 比较第二个

0167:0041998C CALL 00404620

0167:00419991 JZ 004199B1

0167:00419993 MOV EAX,[EBP-04]

0167:00419996 MOV EDX,00419A98 比较第3个

0167:0041999B CALL 00404620

0167:004199A0 JZ 004199B1

0167:004199A2 MOV EAX,[EBP-04]

0167:004199A5 MOV EDX,00419AA8 比较第4个

0167:004199AA CALL 00404620

0167:004199AF JNZ 004199BC

0167:004199B1 PUSH BYTE +00

0167:004199B3 PUSH EBX

0167:004199B4 CALL `USER32!EnableWindow`

0167:004199B9 OR ESI,BYTE -01

0167:004199BC PUSH DWORD FF

0167:004199C1 PUSH EDI

0167:004199C2 PUSH EBX

0167:004199C3 CALL `USER32!GetWindowTextA` 取WindowText 0167:004199C8 TEST EAX,EAX

0167:004199CA JNG 00419A1D

0167:004199CC LEA EDX,[EBP+FFFFFEF4]

0167:004199D2 MOV EAX,EDI

0167:004199D4 CALL 00407E90

0167:004199D9 MOV EAX,[EBP+FFFFFEF4]

0167:004199E2 CALL 00407684

0167:004199E7 MOV EDX,[EBP-04]

0167:004199EA MOV EAX,00419AB4

0167:004199EF CALL 004047BC

0167:004199F4 TEST EAX,EAX

0167:004199F6 JG 00419A1A

0167:004199F8 MOV EDX,[EBP-04]

0167:004199FB MOV EAX,00419AC4

0167:00419A00 CALL 004047BC

0167:00419A05 TEST EAX,EAX

0167:00419A07 JG 00419A1A

0167:00419A09 MOV EDX,[EBP-04]

0167:00419A0C MOV EAX,00419AE4

0167:00419A11 CALL 004047BC

0167:00419A16 TEST EAX,EAX

0167:00419A18 JNG 00419A1D

0167:00419A1A OR ESI,BYTE -01

0167:00419A1D PUSH BYTE +02

0167:00419A1F PUSH EBX

0167:00419A20 CALL `USER32!GetWindow`

0167:00419A25 MOV EBX,EAX

0167:00419A27 TEST EBX,EBX

0167:00419A29 JNZ NEAR 0041994A

用d 00419A70就能看到要比较的文件,分别是whxmdi0、filemonclass、ollydbg、trw2000、import reconstructor、prodump

我用的是trw2000,只要将内存中的trw2000改为其他的名字就不会有问题了,为了一劳永逸,我用hex workshop将trw2000.exe及.sys中的ansi、unicode码的trw都改成了trd 再运行时这段反跟踪代码就不起作用了。

反跟踪解决了,下一步就是脱壳了

例子:xx大师3.57b (https://www.doczj.com/doc/a417533626.html,/)

这个软件是由vfpexenc加密的, vfpexenc加密的软件会有一个vfpnc段,是这种加密方式的一个重要标志。下面看看它的动态解密算法:

0167:0041D79A MOV EAX,[00421AC8]

0167:0041D79F SUB EAX,BYTE +0E

0167:0041D7A2 CMP EDI,EAX

0167:0041D7A4 JNZ 0041D7AA

0167:0041D7A6 XOR EBX,EBX

0167:0041D7A8 JMP SHORT 0041D7B5

0167:0041D7AA MOV EBX,EDI

0167:0041D7AC SUB EBX,[00421AC8]

0167:0041D7B2 ADD EBX,BYTE +0E

0167:0041D7B5 MOV EAX,[00421AC0]

0167:0041D7BA SUB EAX,EBX

0167:0041D7BF JC 0041D7C6

0167:0041D7C1 MOV ESI,[EBP+10]

0167:0041D7C4 JMP SHORT 0041D7C8

0167:0041D7C6 MOV ESI,EAX

0167:0041D7C8 MOV EDX,[EBP+0C] 目的地址

0167:0041D7CB MOV EAX,[00421ACC]

0167:0041D7D0 ADD EAX,EBX * 源地址—从此地址开始内存

放的是加密的app文件0167:0041D7D2 MOV ECX,ESI 个数

0167:0041D7D4 CALL 0040282C 将源地址内容移动到目的地址0167:0041D7D9 CMP BYTE [00421AD6],00 flag 1成功

0167:0041D7E0 JZ 0041D7EE

0167:0041D7E2 LEA EAX,[EBP+0C] 解密数据地址

0167:0041D7E5 MOV EDX,ESI 数据个数

0167:0041D7E7 CALL 0041D5A0 解密算法

0167:0041D7EC JMP SHORT 0041D7FA

0167:0041D7EE LEA EAX,[EBP+0C]

0167:0041D7F1 MOV ECX,EBX

0167:0041D7F3 MOV EDX,ESI

0167:0041D7F5 CALL 0041D5DC

0167:0041D7FA MOV EAX,[EBP+14]

0167:0041D7FD MOV [EAX],ESI

0167:0041D7FF OR EDI,BYTE -01

0167:0041D802 MOV EAX,EDI

0167:0041D804 POP EDI

0167:0041D5A0 PUSH EBX

0167:0041D5A1 PUSH ESI

0167:0041D5A2 MOV EBX,EDX

0167:0041D5A4 MOV ESI,EAX

0167:0041D5A6 CALL 0041D578 处理解密的密钥,得到正确的密钥0167:0041D5AB MOV EDX,EBX

0167:0041D5AD DEC EDX

0167:0041D5AE TEST EDX,EDX

0167:0041D5B0 JL 0041D5D2

0167:0041D5B2 INC EDX

0167:0041D5B3 XOR EAX,EAX

0167:0041D5B5 MOV ECX,[ESI] 加密数据地址

0167:0041D5B7 MOV CL,[ECX+EAX] 取加密数据

0167:0041D5BA AND ECX,FF

0167:0041D5C0 MOV EBX,[00421AD0] 密钥的地址

0167:0041D5C6 MOV CL,[EBX+ECX] 得到正确的数据

0167:0041D5C9 MOV EBX,[ESI]

0167:0041D5CE INC EAX

0167:0041D5CF DEC EDX

0167:0041D5D0 JNZ 0041D5B5

0167:0041D5D2 CALL 0041D578 将密钥重新加密

0167:0041D5D7 POP ESI

算法有了,首先要得到密钥,0041D5C0 MOV EBX,[00421AD0] ebx开始的512个字节就是了,按3的方法存成一个文件。因为程序用完密钥后,会再次加密,只能在这部分代码处得到正确的key。

关键是得到app,看这一句0167:0041D7D0 ADD EAX,EBX ,这时eax就是app的开始地址,文件的长度可通过在此设断,eax会逐渐增大,得到最大值+长度就是app的末尾。同样按3的方法存成一个文件,再编个程序处理,就能得到正确的app。

四、A pp文件的标准化处理

用上面的方法得到的app文件可以在vfp的解释环境下运行,但加密者利用vfp程序动态运行和静态调试的不同,将app文件的结构加以改变,用来阻止unfoxall等软件得到源码。

其主要的方法有如下几种:

1.改变文件描述表的起始地址数据

①文件头标志

②FF 未加密

③0220 VFP6.0/7.0版本

④文件数295

⑤主文件位置第2个(0为第一个)

⑥文件名列表位置505B9F

⑦文件描述表位置5067AF

看5057AF内容00—可执行程序00707866—文件开始地址00000041—文件结束地址文件的结束地址小于文件的开始地址,文件的长度为负值,UNFOXALL反编译时一定

出错,但运行时为何不出错呢?因为这个文件是加入的一个垃圾文件,运行是永远用不到它,当然不会出错了,它的用途就是对付反编译的。将66 78 70 改成29 00 00 就不会有问题了。

2.改变fxp mpx vct sct文件结构

fxp 具有与app文件相同的结构,0-40字节定义同上,不同的是其文件数目为1

从第&h29开始为fxp文件的定义

字节偏移说明

0-1 自定义过程和函数数目

2-3 自定义类数目

4-7 指向代码开始位置

8-11 自定义过程和函数定义开始位置

12-15 自定义类定义开始位置

16-19 与调试有关,具体不详

20-23 调试信息数量

24-27 调试信息开始地址

自定义过程或函数定义

0-1 过程名长度

2-n+1 过程名

n+2-n+5 过程代码开始位置

n+6-n+9 状态

自定义类定义

0-1 类名长度

2-n+1 类名

n+2-n+3 父类名长度m

n+3-n+m+3 父类名

~4 byte 类代码开始地址

~2 byte 状态

下面举个例子,这个是xx大师的主文件。

①自定义函数或过程数量171个

②自定义类数量 3个

③程序开始地址

④自定义函数或过程描述表地址

⑤自定义类描述表地址

⑥文件代码总长度

⑦第1行代码长

⑧第2行代码长

标准结构③应为25,UNFOXALL反编译时如果③不是25就会反编译出一些乱码,将③变成25,在85前插入一个0,这样还得修正各种指针,包括自定义函数或过程、自定义类描述表中的地址指针

自定义函数或过程

①第1个自定义函数或过程名称长度 9

②第1个自定义函数或过程名称 hd_is_errX

③代码开始地址1458

④第2个自定义函数或过程名称长度 6

①第一个自定义类名称长度 9

②第一个自定义类名称 mytoolbar

③第一个自定义类父类名称长度 7

④第一个自定义类父类名称 Toolbar

⑤第一个自定义类代码位置 014869

⑥第2个自定义类名称长度 12

将相应的全部指针按移动的字节数加以修正,如果子程序特别多,最好写个程序处理比较方

便

另外vct sct中保存的代码也可以按如上方式处理。但必须要保证长度不能改变。

3 改变scx vcx结构

加密者将scx vcx文件最后去掉若干个0,这样modi form 是会告知不是表。因为scx vcx 是结构固定的表,可参照vfp关于表结构的帮助加以修订,修订比较简单,这里就不多说了。

五、总结

目前vfp文件的加密强度不是很大,主要是壳与解释库之间的界限还比较分明,vfpexenc

在模糊它们之间的界限方面做了些工作,我想这可能是今后vfp文件加密的方向。

Vfp文件的破解与其他语言编写文件的破解不同,vfp文件一旦被破,得到的将是文件的源代码,因此,希望破解者能最大限度地保护作者的著作权。

行者孙

2005.09.12

相关主题
文本预览
相关文档 最新文档