会以570, 两次均读入4字节到CC和D0.(01和0F)
然后每次读取3FC (0F*44), 并且开始解密.
00437C99 |. 50 PUSH EAX
00437C9A |. 8B45 00 MOV EAX,DWORD PTR SS:[EBP]
00437C9D |. 50 PUSH EAX
00437C9E |. E8 3D040000 CALL LilianFo.004380E0
00437CA3 |. 8B06 MOV EAX,DWORD PTR DS:[ESI] EAX=0F
00437CA5 |. 83C4 0C ADD ESP,0C
00437CA8 |. 33D2 XOR EDX,EDX EDX = 0
00437CAA |. 85C0 TEST EAX,EAX 0F dec?
00437CAC |. 7E 64 JLE SHORT LilianFo.00437D12
00437CAE |. 33FF XOR EDI,EDI EDI = 0
I := 0;
00437CB0 |> 33C9 /XOR ECX,ECX ECX = 0
do begin
00437CB2 |> 8BB5 18010000 |/MOV ESI,DWORD PTR SS:[EBP+118] do ESI = SourceAddr
00437CB8 |. 8BC7 ||MOV EAX,EDI EAX = EDI
00437CBA |. 03C6 ||ADD EAX,ESI INC(EAX, ESI)
00437CBC |. B3 03 ||MOV BL,3 EBX = 3
00437CBE |. 8D3408 ||LEA ESI,DWORD PTR DS:[EAX+ECX] ESI = 0 + I (Current)
00437CC1 |. 8AC2 ||MOV AL,DL AL = DL (0, y)
00437CC3 |. F6E9 ||IMUL CL AX = AL*CL (0,i*y)
00437CC5 |. F6EB ||IMUL BL AX = AL*3 (0,3*i*y)
00437CC7 |. 8A1E ||MOV BL,BYTE PTR DS:[ESI] BL = Buffer[ipos];
00437CC9 |. 04 3D ||ADD AL,3D INC (AL, 3D) (3D,3D+3*i*y)
00437CCB |. 32D8 ||XOR BL,AL BL = BL XOR AL
00437CCD |. 41 ||INC ECX INC (I)
00437CCE |. 83F9 3B ||CMP ECX,3B CMP I, 3B
00437CD1 |. 881E ||MOV BYTE PTR DS:[ESI],BL Buffer[ipos] = BL
00437CD3 |.^ 7C DD |\JL SHORT LilianFo.00437CB2 while I < 3B
end while I <= 3B
00437CD5 |. 8B8D 18010000 |MOV ECX,DWORD PTR SS:[EBP+118] ECX = SourceAddr
00437CDB |. 8B7424 10 |MOV ESI,DWORD PTR SS:[ESP+10] ESI = [ESP+10]
00437CDF |. 8B5C0F 40 |MOV EBX,DWORD PTR DS:[EDI+ECX+40] EBX = (SoruceAddr + 40)^
00437CE3 |. 8D440F 40 |LEA EAX,DWORD PTR DS:[EDI+ECX+40] EAX = SourceAddr + 40
00437CE7 |. 81F3 AC59DFE3 |XOR EBX,E3DF59AC EBX = EBX xor E3DF59AC
00437CED |. 8918 |MOV DWORD PTR DS:[EAX],EBX (SoruceAddr + 40)^ = EBX
00437CEF |. 8B85 18010000 |MOV EAX,DWORD PTR SS:[EBP+118] EAX = SourceAddr
00437CF5 |. 8B4407 40 |MOV EAX,DWORD PTR DS:[EDI+EAX+40] EAX = (SoruceAddr + 40)^
00437CF9 |. 03F0 |ADD ESI,EAX ESI = ESI + EAX
00437CFB |. 85C0 |TEST EAX,EAX IF EAX != 0
00437CFD |. 897424 10 |MOV DWORD PTR SS:[ESP+10],ESI [ESP+10] = ESI
00437D01 |.^ 0F84 CFFEFFFF |JE LilianFo.00437BD6 ENDO?
00437D07 |. 8B45 10 |MOV EAX,DWORD PTR SS:[EBP+10] EAX = [EBP+10] (0F)
00437D0A |. 42 |INC EDX INC(EDX)
00437D0B |. 83C7 44 |ADD EDI,44 EDI = EDI + 44
00437D0E |. 3BD0 |CMP EDX,EAX CMP EDX, EAX
00437D10 |.^ 7C 9E \JL SHORT LilianFo.00437CB0
00437D12 |> 8B4D 00 MOV ECX,DWORD PTR SS:[EBP]
加密方式应该是分为44字节一块, 其中0~3A个字节是使用动态xor, 然后3B~3F五个字节不加密, 40~43四个字节固定使用E3,DF,59,AC来xor.
动态xor的字节值是3*i*y+3D, 其中i为0~3A时候递增的循环内变量, 而y为按照每次44递增的上层循环变量.(0~F)
山百合是某人推荐给我的游戏, 因为总是挂, 没有精力去一次次通, 遂于当晚制作了99命的hack版, 然后第二天发现有隐藏组合, 是红玫瑰里面攻击力很弱的妹妹作为姐姐到手了一个很强的小小妹妹, 为啥米妹妹这么强因为其实这个被强推的是第一关最后面的BOSS, 哦也. 组合出现条件是完整的使用红白黄三对姊妹各穿关一次.
然后, 使用隐藏角色再次穿关, 在标题画面将出现special菜单, 可以进行无穷战, 限时战, 限分战, 千人讨四种训练场景, 和选择和各大小boss的对决战.
音乐很不错听, 为了rip下来, 决定按照国际惯例解之, 于是有上文.
很困了, VMBR和VFAT的分析需要先按照目前的分析将外层解掉, 过几天有空在作.
然后过了一天, 加班到两点, 脑子剧痛睡不着叫, 打开OD在读写文件调试了很久, 无果, 发现跟头部的读取不一样, 是CreateFileMapping后MapViewOfFile, 但是看着数据没有MPG头, 觉得不对, 做了种种的合理推测, 最后耐不住寂寞, 手动按照可能性很小的直觉拷贝了一段数据下来, 居然可以播放了….
原来, 除了文件头部分后, 直接指向的数据完全没有加密, 害得我在DSound.dll里面来回跟了半天thiscall的东西, 倒是记录下来一堆dss的东西.
也就是昨天得到的解密过程, 就是完全是目录区的解密.
意识稀薄中, 好像有人说所谓小心驶得万年船其实是本来只争朝夕的路程要跑一万年么…
然后推得vfat格式. 文件名部分, 从结尾$#0后, 应该是某种规律的填充, 冒充有意义数据.
tagRecBlock = packed record
Filename:array[0..$3B] of Char;
Offset: DWORD;
Size: DWORD;
end;
tagVMBR = packed record
r1: Cardinal;
ItemCount: Cardinal;
end;
介个就是结构.
r1可能和数据排列方式/dummy entry等有关.
遂写了解压程序一个, 从00b.p解压出音乐14首. 第一个00无后缀名, 用途未知, 因为此文件内容有相当大的再压缩率, 所以应该不是mp3数据.
关卡, boss, 角色选择/OP/ED/清关等音乐都齐了.
2,952,882 BOSS1.MP3
2,755,187 BOSS2.MP3
3,196,552 BOSS3.MP3
957,255 CHARASEL.MP3
159,660 CLEAR.MP3
1,536,836 ENDING.MP3
128,859 GAMEOVER.MP3
192,807 OPENING.MP3
3,813,588 ST01.MP3
3,950,678 ST02.MP3
3,182,887 ST03.MP3
3,374,730 ST04.MP3
3,731,250 ST05.MP3
2,993,552 ST06.MP3
今天还有一个收获, 就是脑子抽筋打发时间的时候, 发现010 Editor的Template功能比我之前想象的自由得多, 给要编辑的结构化文件数据进行结构分析并着色, 列出各结构项目都是可以做到的, 不过使用中, 发现要隐藏掉某个field或者要禁止string/char[]展开, 后者没有找到功能, 前者也只能在上面的编辑器将颜色改为很浅, 下面的输出区还是有的.
上面的编辑区的原始数据的悬浮提示也很萌, 简直就是QuickWatch的感觉.
如果输出区允许非原始数据的输出的话, 直接在模板脚本里面完成解密应该也是可以的, 不过现在来说, 它发现你修改后, 就建议用它的计算功能和脚本(不针对特定文件, 没有模板的Inspector功能)去做, 但是用属性的read/write函数还是可以修改到原始数据, 目前好像只能这样了, 没法达到不编辑原始数据而在结果输出解密后的recblock项的, 而且因为read函数是单入的, 离奇到char xx[a]会执行a次, 每次函数需要处理一个char, 上面的需要上下文相关的解密貌似做不成了.
010 Editor, 03还是04年世纪上有人介绍, 那时用起来是惨不忍睹, 今年我忽然搞了一个一用, 多了很多特性, 少了以前的一些bug, 使用它的频率也高了很多, 有空给作者报报需求和bug去.
诶当年的小alice已经成为初有外形的小萝莉2.1.3版了, 希望不要成为winhex这种纯拿来用的欧巴桑啊~~
刚才谈到的后面数据加密是我过虑, 其实随后在接其他包(se音效包)时候, 发现数据果然有加密, 真是不枉废我对作者的期待, 然后我根据前面的作者风格, 推出数据加密的方式, 既是取文件项数据头部$2173字节, 文件项大小不满$2173的取该文件大小, 然后轮流取出vfat中该项文件名的每一个字节进行xor, 按照文件名长度轮回, 不包含文件名末尾0.
而前面的VMBR里面的r1(reserved1), 为1则是不加密, 为0则是用该办法加密.