豆瓣不给力 放这里吧~~
最近要搞搞 ,爱语魔咒的资源提取,学习了简单的封包提取
爱语魔咒的封包就是对每个资源文件进行简单的zlib加密,然后将资源首尾连接一起,在后面加入文件的索引
资源文件:
Love Chronicles - The Spell.vst
工具:
UltraEdit, Notepad++
过程:
UltraEdit主要用来分析资源文件(幸好文件索引没有加密),分析出该资源文件所包含的文件数目,各文件文件名信息,文件的起始偏移地址。Notepad写代码的~~~
资源文件概述:
00000000h~10d6affch 是 存放所有资源文件的二进制代码
10d6afe0h: AE A1 68 67 4C 63 1A D3 98 C6 34 A6 31 8D 69 4C ; hgLc.訕??峣L
10d6aff0h: 63 1A D3 98 5A A3 FF 07 11 17 9A B2 19 1C 00 00 ; c.訕Z?...毑....
10d6b000h: 1D 00 00 00 43 45 5C 43 4F 4D 49 43 53 5C 30 31 ; ....CE\COMICS\01
10d6b010h: 5C 50 4C 49 56 45 54 5C 31 2D 30 2D 30 2E 42 4D ; \PLIVET\1-0-0.BM
10d6b020h: 50 00 00 00 00 87 A1 00 00 1E 00 00 00 43 45 5C ; P....嚒......CE\
10d6b030h: 43 4F 4D 49 43 53 5C 30 31 5C 50 4C 49 56 45 54 ; COMICS\01\PLIVET
10d6b040h: 5C 31 2D 30 2D 30 5F 2E 4A 50 47 87 A1 00 00 75 ; \1-0-0_.JPG嚒..u
10d6b050h: 88 01 00 1F 00 00 00 43 45 5C 43 4F 4D 49 43 53 ; ?.....CE\COMICS
10d6affch开始就是索引文件,从10d6affch开始,前4个字节 19 1c 00 00,是文件的个数,就是1c19,7193个资源文件。然后四个字节1d 00 00 00是首个文件的文件名长度,表示后面29(00 00 00 1d )个字节是第一个文件的文件名,略过29的字节的文件名后,开始的4个字节就是文件的起始地址,首个文件的起始地址就是00 00 00 00。然后四个字节表示文件的大小,单位是字节,87 A1 00 00 就表示这个文件长度为6791个字节,之后的4个字节就是下个文件的文件名长度了,以后就一次类推。
索引文件的起始信息10d6affch 起始存在这个文件的后4个字节里
10dadb60h: 00 00 00 54 55 54 4F 52 5C 31 2D 30 2D 30 2E 42 ; ...TUTOR\1-0-0.B
10dadb70h: 4D 50 E4 27 D6 10 77 24 00 00 0C 00 00 00 54 55 ; MP??w$......TU
10dadb80h: 54 4F 52 5C 49 50 2E 42 4D 50 5B 4C D6 10 A1 63 ; TOR\IP.BMP[L?
10dadb90h: 00 00 FC AF D6 10 ; ..?
ok 现在就可以写代码解包了,不要忘记数据还要zlib解压
再贴解包代码
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
#
#
# Usage:
# python <fileName> <资源文件> <目标文件夹>
#
# example:
# python extractor.py The_Spell.vst temp
import sys, os
import os.path
import binascii
import zlib
#转换小端模式 int
def lETransformInt(hexString):
sbr=""
j=0
for i in range(len(hexString)-1,-1,-1):
sbr = sbr + hexString[i]
return int(binascii.b2a_hex(sbr), 16)
#转换小端模式 String
def lETransformStr(hexString):
sbr=""
j=0
for i in range(len(hexString)-1,-1,-1):
sbr = sbr + hexString[i]
return binascii.b2a_hex(sbr)
#创建目录 并构造文件路径
def getRootDir(path):
fullPath = os.getcwd() + "\\"+ sys.argv[2] +"\\"
print fullPath
fileName = os.path.basename(path)
reFilePath = path.split(fileName)[0]
fullPath = fullPath + reFilePath
if not os.path.isdir(fullPath):
os.makedirs(fullPath)
return fullPath + fileName
#按路径写入文件
def wtiteFileWithPathAndHex(path, HexStr):
fileName = getRootDir(path)
hexF = open(fileName, "wb")
hexF.write(zlib.decompress(HexStr))
hexF.close()
if len(sys.argv) != 3 :
print "Usage:\n\tpython <fileName> <资源文件> <目标文件夹> \nexample:\n\tpython extractor.py The_Spell.vst temp "
else:
f = open(sys.argv[1], "rb")
#282505212 索引的偏移地址
f.seek(282505212, 0)
#读取文件数目
fileCount = lETransformStr(f.read(4))
#读取第一个文件长度
filePathLength = lETransformInt(f.read(4))
globalOffset = 282505212 + 8
fileNum = 0
while filePathLength != 282505212:
fileNum = fileNum + 1
#定位到偏移地址
f.seek(globalOffset, 0)
print "--------------" + str(globalOffset)
#读取文件路径
filePath = f.read(filePathLength)
print "path:" + binascii.b2a_hex(filePath) + "\n" +filePath
#读取偏移地址
originAdd = lETransformInt(f.read(4))
print "originAdd:" + str(originAdd)
#读取偏移长度
offsetAdd = lETransformInt(f.read(4))
print "offsetAdd:" + str(offsetAdd)
#获取下一个文件的路径长度
newFilePathLength = lETransformInt(f.read(4))
print "filePathLength:" + str(filePathLength)
#按偏移地址读取
f.seek(originAdd, 0)
#获取偏移的长度的数据
fileStr = f.read(offsetAdd)
wtiteFileWithPathAndHex(filePath, fileStr)
#计算文件索引位置
globalOffset = globalOffset + 12 + filePathLength
filePathLength = newFilePathLength