15 ม.ค. 2556

Extract ไฟล์ Pack Latale

เนื่องด้วยไฟล์ Pack ของเกม Latale ไม่ได้ Encrypt
เพราะฉะนั้นมาว่าแค่การ Binary Analysis

เริ่มจากไฟล์ขนาดเล็กก่อน *เพราะมันดูง่าย

CLAIRE.SPF

ใส่ Hex Editor เลย


เปิดมาก็งงเล็กน้อยเพราะเจอแต่ Header ของไฟล์ PNG เต็มๆ ทั้งๆที่ Pack ไฟล์ส่วนใหญ่จะต้องมี Header ที่บอกรายละเอียดของ Pack ไฟล์นั้นๆ ลองเลื่อนลงมาดู ล่างสุดละกัน


แปลกแต่จริง สรุปว่า Header มันอยู่ล่างสุดของไฟล์ (*แต่ก็ขอเรียก Header) เลื่อนไปดูแล้วเดาว่า มันสิ้นสุดที่ไหน


นับว่าโชคดีมาก ที่ จุดสิ้นสุดของ Data มันคือ Footer ของไฟล์ PNG มันมีเอกสารในเน็ต ทำให้รู้ว่า Footer ของ PNG มันคือ 49 45 4E 44 AE 42 60 82  -  (IEND) + 0x826042AE ดูอ้างอิงในเน็ตได้ที่ 

http://www.xbdev.net/image_formats/png/index.php  
const int CHUNK_CRC32_IEND = 0xae426082;

ทำให้รู้ว่า Header ของ Pack ไฟล์เริ่มที่  Offset  0x10573D
คาดว่า ข้อมูลของ แต่ละไฟล์ จะเป็นตามรูป 140 byte ต่อ 1 ไฟล์


จินตนาการเป็น structured ในภาษา C 
1. Path ของ file เดาว่า คนออกแบบตั้ง กำหนด Length เป็น แบบ 16,32,64,128 เดาไปก่อน

ได้
struct FILE_PACK_ELEMENT
{
CHAR FileName[128];
        ......
};

ยังเหลือ 76 22 00 00 76 22 00 00 02 00 00 0C
*ต้องเข้าใจ ข้อมูลแบบ Binary  พวก WORD , DWORD , BYTE ว่ามันมีขนาดเท่าไหร่

อย่าง 76 22 00 00 ให้สงสัยมันว่าเป็น DWORD ไปเลย เพราะ ใช้ 4 Byte 
ส่วน 76 22 00 00 อีกตัวก็คง DWORD 
เนื่องจากสงสัยว่า สองตัวนี้ มีตัวนึง ที่เป็น ที่อยู่ Offset ของ ไฟล์ ที่บอกไว้ใน FileName แน่ๆ
ส่วนอีกตัวมันต้องเป็น Size ของไฟล์ หรือ จุดสิ้นสุด Offset ของไฟล์  และคงไม่มีใครเก็บ Offset หรือ File Size เป็น WORD แน่ๆ  เพราะมันไม่พอ

ลองเปรียบเทียบกับไฟล์แรกที่อยู่ใน Pack  ก็พบว่า เป็น

00 00 00 00 76 22 00 00 01 00 00 0C

แต่ DWORD ชุดแรก เป็น 0 ซึ่ง ก็หมายความว่า Filed นี้ Offset แน่ๆ เพราะ FACE01_01.PNG มันอยู่บนสุดของไฟล์ Pack และมันตั้งอยู่ที่ Offset 0 ของไฟล์ Pack
เหลือ  76 22 00 00 ซึ่งยังไม่แน่ใจว่าเป็น FileSize หรือ Offset ที่บอกจุดสุดท้ายของไฟล์กันแน่

ลองไปเปรีบยเทียบ ไฟล์ที่ 3 เพื่อหาว่า อันที่ 3 มันคืออะไรกันแน่ระหว่าง  FileSize หรือ Offset
ไปดูไฟล์สุดท้ายเลย  2F ED 0F 00 0E 6A 00 00 0F 00 00 0C  <-- 0E 6A 00 00 มันอยู่ไฟล์ สุดท้าย แต่มันมีค่าแค่ 0x6A0E เป็นไปไม่ได้เลยที่มันจะเป็น Offset เพราะ ฉะนั้นมันคือ FileSize

ตอนนี้ได้ 
struct FILE_PACK_ELEMENT
{
CHAR FileName[128];
DWORD FilePos; 
DWORD FileSize;
        ....
};


ยังเหลือ  02 00 00 0C  ซึ่งมันคงไม่ใช่ DWORD เพราะหน้าตามันแปลกไป และมันก็ไม่ใช่ Signed Int ไม่ใช่ Float ด้วย เพราะมันไม่ได้หน้าตาแบบนี้ใน แบบ Binary เลยสงสัยว่ามันเป็น  WORD
จะสังเกตได้ว่า ไฟล์แรก มันคือ 01 00 ไฟล์ที่สองคือ 02 00  ไฟล์ต่อไป คือ 03 00 มันคือ!! FileIdx แน่ๆ

ตอนนี้ได้ 
struct FILE_PACK_ELEMENT
{
CHAR FileName[128];
DWORD FilePos; 
DWORD FileSize;
 WORD FileIdx;
};



ก็เหลือ 00 0C เป็นไปได้ทั้ง WORD และ BYTE 2 ตัว 
* สังเกต 0C เพราะ ทุกไฟล์มี 0C เหมือนกันหมด 

ได้
struct FILE_PACK_ELEMENT
{
CHAR FileName[128];
DWORD FilePos; 
DWORD FileSize;
WORD FileIdx;
BYTE Unknow;
BYTE Unknow2;
};

ยังเหลือส่วนที่เป็น Header ของ Pack ไฟล์ที่ไม่เกี่ยวกับ รายละเอียดแต่ละไฟล์อีก  140 Byte 



34 08 00 00 มาจาก 4 Byte แรก ที่คิดว่ามันน่าจะเป็น Type DWORD
ลองคิดว่า 0x00 00 08 34 (2100)  มันจะเป็นอะไรได้บ้าง อาจจะเป็น

- เนื่องจากยังไม่มี ส่วนไหนบอกจำนวน File ใน Pack ไฟล์ ก็สงสัยว่าเป็น จำนวนไฟล์ทั้งหมดใน Pack file  แต่ ตัดทิ้งได้เลย เพราะนับคร่าวๆ เอาจาก Hex ของ FILE_PACK_ELEMENT ได้แค่ 15 ไฟล์
- หรืออาจจะเป็น  Time stamp หรือ Version ซึ่ง ค่า 2100 ไม่ใช่ Time Stamp แน่ๆ แต่อาจจะเป็น Version 
- หรืออาจจะเป็น Size ของ Data  ก็ไม่ใช่อีกเพราะมันแค่ 2100 Byte เป็นไปไม่ได้


- หรืออาจจะเป็น Size ของ Header ทั้งหมด แต่ Size ของ Header ทั้งหมดมันคือ 2240
- แต่ถ้า Size ของ Header เฉพาะที่เกี่ยวกับ File List จะเป็น 2100 พอดี เป็นได้ได้ว่า 4 Byte แรกคือ Size ของ Header เฉพาะส่วนที่เกี่ยวกับ File List 

ต่อไปคือ 0C 00 00 00  คุ้นๆว่า มันเหมือนกับที่มี 0C อยู่ใน ทุก FILE_PACK_ELEMENT แต่เมื่อเปิด SPF ไฟล์อื่นๆ ปราฏว่ามันไม่ซำกัน อนมาณได้ว่ามันคือเลข PackFileIdx

*ส่วน 00 00 00 00 อีกหลายตัวไม่สามารถหาความหมายได้
และท้ายสุดของไฟล์ Pack
คือ C9 EA 9D 3B = 1000205001
สังเกตได้ว่า พอเป็นเลขฐาน 10 มันดูสวยงามผิดปกติ ดูใน SPF ไฟล์อื่น มันคล้ายๆกับเป็นเลขของวันที่ หรือ Version ก็ได้

จะได้ structured ในภาษา C


//PACK FILE
struct FILE_TAIL_PACK
{
DWORD FileListSize;
DWORD PackNo;
DWORD UnknowArr[32]; //*
DWORD DateVersion;
};

และรู้แล้วว่า Byte สุดท้าย ของ

ได้
struct FILE_PACK_ELEMENT
{
CHAR FileName[128];
DWORD FilePos; 
DWORD FileSize;
WORD FileIdx;
BYTE Unknow;
BYTE PackFileIdx;  //<---
};

เขียนโปรแกรมอ่าน และ Extract

เพื่ออ่าน Header ล่างสุดของไฟล์

fseek( fp_spf,0, SEEK_END );
_FileSize = ftell( fp_spf );
fseek( fp_spf, _FileSize - sizeof(FILE_TAIL_PACK) , SEEK_SET );
FILE_TAIL_PACK _Head;
fread(&_Head,sizeof(FILE_TAIL_PACK),1,fp_spf);

เก็บรายละเอียด List File ที่ที่ Pack จาก Header 

std::vector<FILE_PACK_ELEMENT*> _FileList;
if( _Head.FileListSize > 0 )
{
fseek( fp_spf, _FileSize - _Head.FileListSize - sizeof(FILE_TAIL_PACK) , SEEK_SET );
for(int i = 0 ; i <  _Head.FileListSize / sizeof(FILE_PACK_ELEMENT) ; ++i)
{
FILE_PACK_ELEMENT * _FileEle = new FILE_PACK_ELEMENT();
fread(_FileEle,sizeof(FILE_PACK_ELEMENT),1,fp_spf);
_FileList.push_back(_FileEle);
}
}


หลังจากนี้ ก็ ทำการ Extract ไฟล์ จาก Pack โดยอาศัยข้อมูลใน _FileList ที่มีทั้ง Path ของไฟล์และ Offset และ Size 




ไม่มีความคิดเห็น:

แสดงความคิดเห็น