Skip to content

Instantly share code, notes, and snippets.

@pratikone
Last active September 2, 2021 09:16
Show Gist options
  • Save pratikone/f0fbd11c3e16a4e852e9c0bbef891b73 to your computer and use it in GitHub Desktop.
Save pratikone/f0fbd11c3e16a4e852e9c0bbef891b73 to your computer and use it in GitHub Desktop.
This is script to reverse engineer and extract images and sounds assets from Zombie Wars game (also known as Halloween Harry 2)
# Utility to extract image and sound assets from Zombie Wars game (also known as Halloween Harry 2)
# takes some inspiration from Wombat https://www.szevvy.com/
# Pratik Anand 2021 (twitter : @pratikone)
# Blog post : https://pratikone.github.io/gaming/2021/09/02/reverse-engineer-zombiewars.html
# Running :
# Download DEARK from https://entropymine.com/deark/ and keep it somewhere and modify DEARK_PATH_WIN to point to deark.exe
# set GAME_FOLDER_PATH to point to folder containing game assets like GFX.SB0, SFX.SB0
# run the script (install binario using pip). You don't need to provide any args.
# folders will be created for each .SB0 like gfx. If the extracted assets contain RAW files deark convert it to png and store
# it in converted folder within the parent folder like gfx.
import binario
import os
import subprocess
cwd = os.getcwd()
# for converting HSI RAW images to png
DEARK_PATH_WIN = cwd + "\\deark\\x64\\deark.exe" # https://entropymine.com/deark/
print("DEARK : " + DEARK_PATH_WIN )
GAME_FOLDER_PATH = "C:\games\ZWARS"
print("game path : " + GAME_FOLDER_PATH )
# swap bytearray to little endian
def swap_endian(x):
return int.from_bytes(x, byteorder='little', signed=False)
def write_file(name : str, path : str, filedata) :
filepath = os.path.join(path, name)
print("creating file " + filepath)
f = binario.Writer(filepath, binario.LITTLE_ENDIAN)
f.write(filedata)
f.close()
def convert_png(name : str, path : str, output : str ) :
print("converting file " + name)
filepath = os.path.join(path, name)
subprocess.run([DEARK_PATH_WIN, filepath, "-o", os.path.join(output, name)])
def decode_SB0_file(filename, folder) :
l = []
r = binario.Reader(filename, binario.LITTLE_ENDIAN)
r.read(12) #ignore
name = r.read(12)
while name != b'------------' :
name = name.decode().strip()
name = ''.join(x for x in name if x.isprintable())
name = name.split('.')[0] + '.' + name.split('.')[1][:3] # only take first 3 letters of extension for name, rest is filler
offset = swap_endian(bytearray(r.read(4)))
size = swap_endian(bytearray(r.read(4)))
skip = r.read()
l.append([name, offset, size])
name = r.read(12)
# r.read(8) #skip 8 bytes of gap - not needed as we are going to read by offset
print(l)
targetPath = os.path.join(cwd, folder)
if not os.path.exists(targetPath):
print("creating folder :" + targetPath)
os.mkdir(targetPath)
os.chdir(targetPath)
png_path = os.path.join(targetPath, "converted")
if not os.path.exists(png_path):
print("creating folder :" + png_path)
os.mkdir(png_path)
for entry in l :
name, offset, size = entry
r.seek(0 + offset)
filedata = r.read(size)
# print(filedata)
write_file(name, targetPath, filedata)
convert_png(name, targetPath, png_path) # will be no-op for non-RAW files
print("====")
# print(r.read(6))
if __name__ == '__main__' :
decode_SB0_file(GAME_FOLDER_PATH + "\GFX.SB0", "gfx")
decode_SB0_file(GAME_FOLDER_PATH + "\SFX.SB0", "sfx")
decode_SB0_file(GAME_FOLDER_PATH + "\local.SB0", "local")
decode_SB0_file(GAME_FOLDER_PATH + "\levels.SB0", "levels")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment