Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import os
- import sys
- import struct
- import io
- import zipfile
- import vdf
- from Crypto.Cipher import AES
- def readNullTerminatedString(f,offset):
- prevOffset=f.tell()
- f.seek(offset)
- result=b""
- while 1:
- byte=f.read(1)
- if byte==b"\x00": break
- result+=byte
- f.seek(prevOffset)
- return result.decode()
- volHandles=dict()
- class Volume:
- def __init__(self,volName):
- self.f=open(volName,"rb")
- self.size=os.fstat(self.f.fileno()).st_size
- def openVolume(baseName,disc,vol):
- volName="%s_disk%d_%d.sid" % (baseName,disc,vol)
- if vol not in volHandles:
- while not os.path.isfile(volName):
- # Changing disc - close all volumes.
- closeVolumes()
- input("Need %s, insert disc %d and press Enter..." % (os.path.basename(volName),disc))
- volHandles[vol]=Volume(volName)
- return volHandles[vol].f
- def openNextVolume(baseName,disc,vol):
- vol+=1
- volName="%s_disk%d_%d.sid" % (baseName,disc,vol)
- if not os.path.isfile(volName):
- # Change disc.
- disc+=1
- vol=0
- f=openVolume(baseName,disc,vol)
- f.seek(0x00)
- return f,disc,vol
- def getVolumeSize(vol):
- return volHandles[vol].size
- def closeVolumes():
- for vol in volHandles.values():
- vol.f.close()
- volHandles.clear()
- def extractDepot(baseName,curDisc,targetDepot,keystring,outDir):
- if keystring:
- key=bytes.fromhex(keystring+"A8194D02193CD03792937D27590AECBD")
- else:
- key=None
- f=open("%s_disk%d.sim" % (baseName,curDisc),"rb")
- magic,version,discs,stringsSize=struct.unpack("<IIII",f.read(0x10))
- if magic!=0x3FD04C1F: raise Exception("Bad header magic in %s" % (f.name))
- if version!=1: raise Exception("Unknown version %d in %s" % (version,f.name))
- s=io.BytesIO(f.read(stringsSize))
- tableSize,numFiles=struct.unpack("<II",f.read(0x08))
- t=io.BytesIO(f.read(tableSize))
- f.close()
- for i in range(numFiles):
- nameOffset,pathOffset,depot,offset,size,disc,vol,isEnc,pad=struct.unpack("<IIIQQBBBB",t.read(0x20))
- if depot!=targetDepot:
- continue
- name=readNullTerminatedString(s,nameOffset)
- path=readNullTerminatedString(s,pathOffset)
- print(os.path.join(path,name))
- #print(t.tell()-0x20)
- if isEnc and not key:
- print("File is encrypted and no depot key was provided! Skipping...")
- continue
- f2=openVolume(baseName,disc,vol)
- f2.seek(offset)
- #print("%d %d 0x%08x" % (disc,vol,offset))
- os.makedirs(os.path.join(outDir,path),exist_ok=True)
- fname=os.path.join(outDir,path,name)
- out=open(fname,"wb")
- bytesWritten=0
- while bytesWritten!=size:
- if f2.tell()==getVolumeSize(vol):
- # Reached EOF, open next volume.
- f2,disc,vol=openNextVolume(baseName,disc,vol)
- chunkZSize,chunkSize=struct.unpack("<II",f2.read(0x08))
- padSize=(chunkZSize>>24)&0xFF
- chunkZSize&=0x00FFFFFF
- flags=(chunkSize>>24)&0xFF
- chunkSize&=0x00FFFFFF
- data=f2.read(chunkZSize)
- bytesWritten+=chunkSize
- if flags&0x01:
- if not key:
- print("Encountered encrypted chunk and no depot key was provided! Skipping the file...")
- out.close()
- os.remove(fname)
- break
- decSize=chunkZSize-padSize
- # Decrypt IV.
- cipher=AES.new(key,AES.MODE_ECB)
- iv=cipher.decrypt(data[:0x10])
- # Decrypt data.
- cipher=AES.new(key,AES.MODE_CBC,iv=iv)
- data=cipher.decrypt(data[0x10:])[:decSize]
- if flags&0x02:
- zipf=zipfile.ZipFile(io.BytesIO(data))
- out.write(zipf.read("zip"))
- zipf.close()
- else:
- out.write(data)
- out.close()
- closeVolumes()
- if __name__=="__main__":
- if len(sys.argv)<4:
- print("Usage: sim_extract.py <simpath> <depotid> <outpath>")
- sys.exit(0)
- fname=sys.argv[1]
- depotStr=sys.argv[2]
- outDir=sys.argv[3]
- if fname[-4:]!=".sim":
- raise Exception("Not a SIM file")
- kv=vdf.load(open("legacydepotdata.vdf","r"))
- if depotStr in kv["depots"]:
- keystring=kv["depots"][depotStr]
- print("Depot key: %s" % keystring)
- else:
- print("No depot key for depot %s in VDF, assuming the depot is unencrypted." % depotStr)
- keystring=""
- pos=fname.find("_disk")
- if pos==-1:
- raise Exception("Bad SIM name")
- baseName=fname[:pos]
- disc=int(fname[pos+5:-4])
- depot=int(depotStr)
- extractDepot(baseName,disc,depot,keystring,outDir)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement