2020-7-13 15:48 /
**贴吧,死活发不出去。
嘛,那就在这里发好了,排版还能好看一点。
本帖分析内容与crass存在差异,我也不知道为什么(草)。
-------------------------------------------------------------------------------------------------------------
用winhex打开,你可以看得到magic是DATA$TOP,还有个0x8EB不知道是什么鬼(或许是entry个数)。
中间还有一大段00,意味不明。
让我们打开ollydbg,来到这段代码:
我们可以看到,那个0x8EB最后是在后面控制循环操作(虽然写法很让人迷惑),每一次都会从封包读取0x40字节,去内存窗口看,你能看见一些文件名还有其他数据,我们可以猜测,这个0x8EB就是entry数量。
把我们的结论稍微整理一下:
中间那个unk我也不知道是什么,crass说是reserved。
接下来看entry部分。
随便挑了一段entry出来:
保险起见,猜测文件名长度还是0x30.
然后看每一个entry的最后一排,前0x8个字节全是0,后面记录了一个0x6A9A,看不懂。
再看下面一段entry最后0x16字节,前0x8字节记录了两个0x6A9A,后面记录了一个0x62B,接着看。
第三排前面记录了俩0x70C5,后面记录了一个0x12C2。
……
是不是能够看出什么。
上一个entry最后八位内的那个数字加上下一个entry最后八位数字等于下一个entry前面的数字。
或者说,当前entry的最后十六位中,前八位的数字加上后八位的数字等于下一个entry中前八位的数字。
拿一个实例来讲:0x6A9A+0x62B=0x70C5
是不是能猜到什么。
我们可以猜测,后八位的数字其实就是文件长度,前八位的数字其实就是文件偏移。
整理一下这个entry结构:
需要注意的是,这个offset记录的是相对offset,如果你要计算那还得加上sizeof(pak_header_t)以及entries_size。
现在,选一个你最擅长的语言,开始写解包吧。
嘛,那就在这里发好了,排版还能好看一点。
本帖分析内容与crass存在差异,我也不知道为什么(草)。
-------------------------------------------------------------------------------------------------------------
Offset 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
00000000 44 41 54 41 24 54 4F 50 00 00 00 00 00 00 00 00 DATA$TOP
00000016 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000032 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000048 00 00 00 00 00 00 00 00 EB 08 00 00 00 00 00 00 ?
用winhex打开,你可以看得到magic是DATA$TOP,还有个0x8EB不知道是什么鬼(或许是entry个数)。
中间还有一大段00,意味不明。
让我们打开ollydbg,来到这段代码:
0040A9E8 |. 6A 00 push 0x0 ; /pOverlapped = NULL
0040A9EA |. 52 push edx ; |pBytesRead = asita.<ModuleEntryPoint>
0040A9EB |. 6A 40 push 0x40 ; |BytesToRead = 40 (64.)
0040A9ED |. 50 push eax ; |Buffer = 0019FFCC
0040A9EE |. 51 push ecx ; |hFile = 0043B072
0040A9EF |. FFD5 call ebp ; \ReadFile
0040A9F1 |. 8B86 50010000 mov eax,dword ptr ds:[esi+0x150] ; eax->0x8EB
0040A9F7 |. BF 01000000 mov edi,0x1
0040A9FC |. 3BC7 cmp eax,edi ; asita.<ModuleEntryPoint>
0040A9FE |. 8946 10 mov dword ptr ds:[esi+0x10],eax ;存入常量
0040AA01 |. 7E 22 jle short asita.0040AA25
0040AA03 |. 53 push ebx
0040AA04 |. 8D9E 58010000 lea ebx,dword ptr ds:[esi+0x158] ; 跳过文件头部分
0040AA0A |> 8B06 /mov eax,dword ptr ds:[esi]
0040AA0C |. 8D5424 10 |lea edx,dword ptr ss:[esp+0x10]
0040AA10 |. 6A 00 |push 0x0
0040AA12 |. 52 |push edx ; asita.<ModuleEntryPoint>
0040AA13 |. 6A 40 |push 0x40 ; 每一个entry的大小为0x40
0040AA15 |. 53 |push ebx
0040AA16 |. 50 |push eax
0040AA17 |. FFD5 |call ebp ;ReadFile
0040AA19 |. 8B46 10 |mov eax,dword ptr ds:[esi+0x10] ;从常量中取出
0040AA1C |. 47 |inc edi ; +1
0040AA1D |. 83C3 40 |add ebx,0x40 ;指针移动
0040AA20 |. 3BF8 |cmp edi,eax ;比较
0040AA22 |.^ 7C E6 \jl short asita.0040AA0A
我们可以看到,那个0x8EB最后是在后面控制循环操作(虽然写法很让人迷惑),每一次都会从封包读取0x40字节,去内存窗口看,你能看见一些文件名还有其他数据,我们可以猜测,这个0x8EB就是entry数量。
把我们的结论稍微整理一下:
typedef struct {
char magic[0x30]; /* "DATA$TOP" */
unsigned int unk1;
unsigned int unk2;
unsigned int index_entries;
unsigned int zero;
} pak_header_t;
中间那个unk我也不知道是什么,crass说是reserved。
接下来看entry部分。
随便挑了一段entry出来:
Offset 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
00000064 73 65 6C 65 63 74 2E 77 61 76 00 00 00 00 00 00 select.wav
00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000096 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000112 00 00 00 00 00 00 00 00 9A 6A 00 00 00 00 00 00 歫
00000128 74 78 74 5C 30 33 32 37 65 70 5F 70 72 2E 74 78 txt\0327ep_pr.tx
00000144 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 t
00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000176 9A 6A 00 00 9A 6A 00 00 2B 06 00 00 00 00 00 00 歫 歫 +
00000192 74 78 74 5C 30 30 30 32 2E 74 78 74 00 00 00 00 txt\0002.txt
00000208 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000224 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000240 C5 70 00 00 C5 70 00 00 C2 12 00 00 00 00 00 00 舙 舙 ?
00000256 74 78 74 5C 30 30 30 33 2E 74 78 74 00 00 00 00 txt\0003.txt
00000272 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000288 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000304 87 83 00 00 87 83 00 00 54 09 00 00 00 00 00 00 噧 噧 T
00000320 74 78 74 5C 30 30 30 34 2E 74 78 74 00 00 00 00 txt\0004.txt
00000336 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000352 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000368 DB 8C 00 00 DB 8C 00 00 0E 1F 00 00 00 00 00 00 蹖 蹖
保险起见,猜测文件名长度还是0x30.
然后看每一个entry的最后一排,前0x8个字节全是0,后面记录了一个0x6A9A,看不懂。
再看下面一段entry最后0x16字节,前0x8字节记录了两个0x6A9A,后面记录了一个0x62B,接着看。
第三排前面记录了俩0x70C5,后面记录了一个0x12C2。
……
是不是能够看出什么。
上一个entry最后八位内的那个数字加上下一个entry最后八位数字等于下一个entry前面的数字。
或者说,当前entry的最后十六位中,前八位的数字加上后八位的数字等于下一个entry中前八位的数字。
拿一个实例来讲:0x6A9A+0x62B=0x70C5
是不是能猜到什么。
我们可以猜测,后八位的数字其实就是文件长度,前八位的数字其实就是文件偏移。
整理一下这个entry结构:
typedef struct {
char name[0x30];
unsigned int offset0;
unsigned int offset1;//offset0=offset1
unsigned int length;
unsigned int zero;
} pak_entry_t;
需要注意的是,这个offset记录的是相对offset,如果你要计算那还得加上sizeof(pak_header_t)以及entries_size。
现在,选一个你最擅长的语言,开始写解包吧。