继续F9,中断到了fread上,参数如下: 0012F8F4 004317AF RETURN to NyxQuest. 004317AF from NyxQuest. 005F4FBD 0012F8F8 013055D8 ASCII " 0012F8FC 00000001 0012F900 00008160 0012F904 006C6C60 NyxQuest. 006C6C60 可以看出来这里把所有的文件信息部分都读取到了内存。 分析到了这里,我们已经可以不用在分析了,已经完全可以凭猜测加测试搞定。根据分析结 果HEDA结构体可以冲洗定义成这样: HEAD STRUCT dwFlag DWORD ? dwUnKnownl DWORD ? dwFilelnfoSize DWORD ? dwZero DWORD 5 dup(?) HEAD ENDS 再看DataPC.PAK文件的文件信息部分的第一个FILEIOFO结构体,最开始的的100h字节 是文件名,往后的有数据的双字则是重点,它们应该包含文件名所指的这个文件在这个pak包中的大小,偏移等信息,经过试验发现第二个双字经过反转(同上面方法一样)之后(不用乘以120h)是这个文件压缩后的数据的大小,因为zlib解压的时候要求输入解压完的文 件大小,这个大小一般都是在压缩之前保存好的,而正好第一个双字的数值大小经过反转(不乘以120h)后大小比较合适,就假设他是文件的大小。第三个双字反转后则是这个文件pak中的偏移,但是这个偏移没有什么太大用处,因为每个文件之间都是没有空隙的,读取 完了一个直接读取下一个就可以了。由于剩下的部分都是一样的,可以不用在乎。这样我么 可以把FILEIORD重新修改成这样 FILEIOFO STRUCT szFileName BYTE 100h dup(?) dwExpFileSize DWORD ? dwCompFileSize DWORD ? dwOffset DWORD ? dwUnKnown DWORD 5 dup(?) FILEIOFO ENDS 文件数据结构的分析就到这里了,对于完整了解这个pak,还需要很多工作要做,不过对于编写一个解包器,以上的分析就足够了。 编程实现 根据分析所得的这些信息,写一个解包程序就不难了,大体流程如下: 1.读取文件的HEAD,检查HEAD.dwFlag是否为5041434Bh,不是则说明不是我们分析的格式的pak文件,不在往下执行。 2.读取HEAD.dwFilelnfoSize,然后按照前面说的方法计算出文件信息部分的大小。 相关的代码在WM_COMMAND消息处理逻辑中 invoke SendDlgItemMessage, hWin, LST_INF0, LB_RESETCONTENT, 0, 0 invoke RtlZeroMemory, addr @stOF, sizeof @stOF mov @stOF. lStructSize, sizeof @stOF push hWin pop @stOF. hwndOwner mov @stOF. lpstrFilter, offset szFilter mov @stOF. lpstrFile, offset szFileName mov @stOF. nMaxFile, MAX_PATH mov @stOF. Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or 0FN_HIDEREAD0NLY invoke GetOpenFileName, addr @stOF .if eax invoke SendDlgItemMessage, hWin, EDT_PAKPATH, WM_SETTEXT, 0, offset szFileName invoke CreateFile, offset szFileName, GENERIC_READ, \ FILE_SHARE_DELETE, NULL, OPEN_EXISTING, NULL, NULL .if eax==-l invoke MessageBox, hWin, offset 0penError, NULL, MB_0K invoke ExitProcess, 0 .endif mov hFile, eax invoke GetFileSize, eax, NULL mov dwFileSize, eax invoke CreateFileMapping, hFile, NULL, PAGE_READONLY, 0, 0, NULL .if !eax invoke MessageBox, hWin, offset 0penError, NULL, MB_0K invoke CloseHandle, hFile invoke ExitProcess, 0 .endif mov hFileMap, eax invoke MapViewOfFile, eax, FILE_MAP_READ, 0,0, 0 .if !eax invoke MessageBox, hWin, offset OpenError, NULL, MB_OK invoke CloseHandle, hFileMap invoke CloseHandle, hFile invoke ExitProcess, 0 .endif mov dwBaseAddress, eax assume eax:ptr HEAD .if [eax]. dwF1ag!=PACK invoke MessageBox, hWin, CTXT (〃不支持的 PAK 格式' 0,0,MB_OK invoke EndDialog, hWin, 0 .endif mov ebx, [eax]. dwFilelnfoSize mov byte ptr dwFilelnfoSize[3], bl mov byte ptr dwFileInfoSize[2], bh shr ebx, 16 mov byte ptr dwFileInfoSize[l], bl mov byte ptr dwFilelnfoSize, bh ;pop dwFilelnfoSize assume eax:nothing mov ebx, dwBaseAddress add ebx, dwFileSize mov @dwMaxOffset, ebx imul eax, dwFilelnfoSize, 120h sub ebx, eax mov @dwFilePoint, ebx assume ebx:ptr FILEINFO .while ebx<@dwMaxOffset invoke SendDlgItemMessage, hWin, LST_INF0, LB_ADDSTRING, 0, addr [ebx]. szFileName add ebx, sizeof FILEINFO .endw assume ebx:nothing 3.用一个大的循环读取文件的信息,根据信息用zlib的解压函数解压数据,并将数据写到文件中。 y^- |