2014-3-2 21:08 /
FVP就是favorite御用引擎。
为移植色鸟鸟做准备的。
色鸟鸟的移植将会是去H的日文版
没有为什么

玩得很渣请多多谅解~

反正blog也没人会来,于是就当做是笔记吧。
首先是FVP的内部函数,记录在offset为[0043DC40]的stack里面。
[0043F131]为stack结束处。
其实这个就是vm真正的输入表。在hcb里面的输入表只是供脚本按照编号调用。
应该是有144条,脚本里输入表之前的WORD就是ImportTableCount。
在vm中,每条systemFunction对应的结构就是:

typedef struct hcbImportTable{
    uchar VarCount; //参数个数
    uchar NameLen;
    char*  FuncName;
};


有生之年锁定本blog发布233
===============================================
继续更新。管他作业没做,反正做不完放弃了
脚本就是hcb文件
但是hcb文件的名字是没有锁定的,以系统找到的第一个hcb脚本为准的【旁边有API调用的
所以说,汉化的时候把hcb的后缀改成其他名字如“pck”是最省力的。
简直迷233


004374CF  |. 50             PUSH EAX                                 ; /pFindFileData
004374D0  |. 68 A4BB4500    PUSH World.0045BBA4                      ; |FileName = "*.hcb"
004374D5  |. 8BF9           MOV EDI,ECX                              ; |
004374D7  |. FF15 BCB04500  CALL DWORD PTR DS:[<&KERNEL32.FindFirstF>; \FindFirstFileA



多废话几句,FVP优先读取未封包的图片【完全就是方便汉化啊23333333333
说一点正经的吧,最开始我先追到这一段

004434F0   > 8B86 1C080000  MOV EAX,DWORD PTR DS:[ESI+81C]      
004434F6   . 8B4E 04        MOV ECX,DWORD PTR DS:[ESI+4]         
004434F9   . 0FB60C01       MOVZX ECX,BYTE PTR DS:[ECX+EAX]
004434FD   . 0FB6D1         MOVZX EDX,CL                    
00443500   . 40             INC EAX              
00443501   . 8986 1C080000  MOV DWORD PTR DS:[ESI+81C],EAX  
00443507   . 8B0495 A0F5470>MOV EAX,DWORD PTR DS:[EDX*4+47F5A0]  ;轮番取出指令
0044350E   . 8BCE           MOV ECX,ESI                          ;
00443510   . FFD0           CALL EAX                             ;调用当前指令
00443512   . 80BE 10080000 >CMP BYTE PTR DS:[ESI+810],0          ;当前指令与0比较,如果是0,就nop并且进入下一次循环
00443519   .^74 D5          JE SHORT World.004434F0
0044351B   > 5E             POP ESI                              ;弹出当前对象
0044351C   . C3             RETN



由此看出,0x00在VM脚本里面等于机器码的NOP,而47F5A0就是我们要关注的地址。
多说一点,到这里,我也不知道ESI+81C这个地址的具体含义是什么,但是我们可以看出来:
1.[ESI+81C]里面的值在执行的过程中会加1
2.[ESI+81C]这个地址在之后的出现很频繁。
3.[ESI+81C]会和0x00做比较,那么[ESI+81C]保存的值一定和VMCode有关。
疑问我们在后面再解答。
每次都是通过一个DWORD值来确定call的地址,也就说,47F5A0之后的某一段就是VM的字节码相关的。其实这个不难看出,每次都是EDX*4(DWORD)来取offset的。
找到这个地址,然后就会发现...


0047F5A0  0041A500  ..   Entry address
0047F5A4  004438D0  ?D.   World.004438D0
0047F5A8  00443900  .9D.  World.00443900
0047F5AC  00443980  €9D.  World.00443980
0047F5B0  00442920   )D.  World.00442920
0047F5B4  00442940  @)D.  World.00442940
0047F5B8  00443A50  P:D.  World.00443A50
0047F5BC  00443A70  p:D.  World.00443A70
0047F5C0  00442980  €)D.  World.00442980
0047F5C4  004429A0  ?D.   World.004429A0
0047F5C8  00443AB0  ?D.   World.00443AB0
0047F5CC  00443AE0  ?D.   World.00443AE0
0047F5D0  00443B20   ;D.  World.00443B20
0047F5D4  00443B50  P;D.  World.00443B50
0047F5D8  00443B90  ?D.   World.00443B90
0047F5DC  00443BD0  ?D.   World.00443BD0
0047F5E0  00443C60  `<D.  World.00443C60
0047F5E4  00443CF0  ?D.   World.00443CF0
0047F5E8  00443D70  p=D.  World.00443D70
0047F5EC  004429C0  ?D.   World.004429C0
0047F5F0  00442A30  0*D.  World.00442A30
0047F5F4  00443DF0  ?D.   World.00443DF0
0047F5F8  00443E40  @>D.  World.00443E40
0047F5FC  004442C0  繠D.   World.004442C0
0047F600  00444370  pCD.  World.00444370
0047F604  00442A60  `*D.  World.00442A60
0047F608  00442AA0  ?D.   World.00442AA0
0047F60C  00442C90  ?D.   World.00442C90
0047F610  00442D20   -D.  World.00442D20
0047F614  00442DB0  ?D.   World.00442DB0
0047F618  00442E30  0.D.  World.00442E30
0047F61C  00442E80  €.D.  World.00442E80
0047F620  00442ED0  ?D.   World.00442ED0
0047F624  00442F10  /D.  World.00442F10
0047F628  00442F50  P/D.  World.00442F50
0047F62C  00443060  `0D.  World.00443060
0047F630  004430A0  ?D.   World.004430A0
0047F634  004431C0  ?D.   World.004431C0
0047F638  00443200  .2D.  World.00443200
0047F63C  00443320   3D.  World.00443320


这里就是call Table
整整齐齐0x27条指令,接下来的分析也就不是很难了。
[容我吃个饭,回来再更]
=====================================================

码字麻烦,我在写一个0x0E的。
为了方便说明,我们设定*zFile为VM脚本在内存里的首地址
zPos为当前VM脚本的地址(类似于EIP)
uchar就是unsigned __int8


00443B90   . 8B81 20080000  MOV EAX,DWORD PTR DS:[ECX+820]   
00443B96   . 8D50 01        LEA EDX,DWORD PTR DS:[EAX+1]
00443B99   . 8991 20080000  MOV DWORD PTR DS:[ECX+820],EDX
00443B9F   . C644C1 08 04   MOV BYTE PTR DS:[ECX+EAX*8+8],4
00443BA4   . 8B91 1C080000  MOV EDX,DWORD PTR DS:[ECX+81C]     ;EDX = zPos
00443BAA   . 56             PUSH ESI
00443BAB   . 8B71 04        MOV ESI,DWORD PTR DS:[ECX+4]
00443BAE   . 0FB63416       MOVZX ESI,BYTE PTR DS:[ESI+EDX]    ;一个op
00443BB2   . 42             INC EDX
00443BB3   . 8991 1C080000  MOV DWORD PTR DS:[ECX+81C],EDX     ;Str的位置
00443BB9   . 8954C1 0C      MOV DWORD PTR DS:[ECX+EAX*8+C],EDX  ;拿去执行,PushStr
00443BBD   . 01B1 1C080000  ADD DWORD PTR DS:[ECX+81C],ESI      ;zPos+=callLength(指令长度)
00443BC3   . 5E             POP ESI
00443BC4   . C3             RETN


哪天有心情再更。
这样可以看出了,为什么色鸟、光鸟的补丁要如此加密。
还不是被因为hcb文件太简单了。

题外话:
汉化有两个办法
1、提取Str,再封包回去(你得注意各种call、jmp的offset)
我是用map暴力的。
2、hook PushStr,比较简单,又方便调试。
Tags: favorite