2020-7-13 15:48 /
**贴吧,死活发不出去。
嘛,那就在这里发好了,排版还能好看一点。
本帖分析内容与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。
现在,选一个你最擅长的语言,开始写解包吧。
Tags: mts