Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Treeki
Last active September 24, 2022 00:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Treeki/71c783920fc55c52c2c14caa78b08eff to your computer and use it in GitHub Desktop.
Save Treeki/71c783920fc55c52c2c14caa78b08eff to your computer and use it in GitHub Desktop.
# runs under Python 2 (yes, I know...)
# required modules: pip install unicorn pefile
# this code is made available under the MIT license, as follows:
# Copyright (c) 2018 Ash Wolf
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from unicorn import *
from unicorn.x86_const import *
import pefile
import struct
import binascii
# figure out our memory stuff
pe = pefile.PE('asiolink.dll')
base_addr = pe.OPTIONAL_HEADER.ImageBase
base_image = pe.get_memory_mapped_image()
base_end = base_addr + len(base_image)
base_region = (base_addr, (base_end + 0xFFFFF) & ~0xFFFFF)
heap_size = 1 * 1024 * 1024
heap_region = (base_region[1], base_region[1] + heap_size)
print('Base Region: %x - %x' % base_region)
print('Heap Region: %x - %x' % heap_region)
# create emulator
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(base_region[0], base_region[1] - base_region[0])
mu.mem_map(heap_region[0], heap_region[1] - heap_region[0])
mu.mem_write(base_addr, base_image)
mu.reg_write(UC_X86_REG_ESP, heap_region[1])
# okay let's try doing some shit
def stack_push(mu, var):
esp = mu.reg_read(UC_X86_REG_ESP)
esp -= 4
mu.reg_write(UC_X86_REG_ESP, esp)
mu.mem_write(esp, struct.pack('<I', var))
def decompress(blob):
in_buf = heap_region[0]
in_buf_size = len(blob)
out_buf = heap_region[0] + in_buf_size
out_buf_size = 0x80000
# for some reason, a different decompression function is used
# depending on the first byte of the data
first_thing = (ord(blob[0]) >> 5) + 1
if first_thing == 1:
func = 0x1004A600
ret = 0x10024387
elif first_thing == 2:
func = 0x1004ABA0
ret = 0x100243A1
else:
raise 'oops'
# prepare function params
mu.reg_write(UC_X86_REG_EDX, in_buf_size)
mu.reg_write(UC_X86_REG_ECX, in_buf)
stack_push(mu, out_buf_size)
stack_push(mu, out_buf)
stack_push(mu, ret)
mu.mem_write(in_buf, blob)
mu.emu_start(func, ret)
amount = mu.reg_read(UC_X86_REG_EAX)
buffer = mu.mem_read(out_buf, amount)
return buffer
def my_decompressor_2(blob):
in_data = bytearray(blob)
in_ptr = 0
out_data = bytearray(0x80000)
out_ptr = 0
# read our first control byte, and filter off the bits
# that tell the wrapper code which decompressor to use
control = in_data[0] & 0x1F
in_ptr += 1
while in_ptr < len(in_data) and out_ptr < len(out_data):
if control < 0x20:
# Literal copy
for i in xrange(control + 1):
out_data[out_ptr] = in_data[in_ptr]
in_ptr += 1
out_ptr += 1
else:
# LZ copy
offset = (control & 0x1F) * 256
write_count = (control >> 5)
if write_count == 7:
# Allow larger write counts
while True:
next_byte = in_data[in_ptr]
in_ptr += 1
write_count += next_byte
if next_byte != 255:
break
offset += in_data[in_ptr]
in_ptr += 1
if offset == 0x1FFF:
# Allow offsets even bigger than 0x1FFF
# (This may be wrong!)
offset += ((in_data[in_ptr] << 8) | in_data[in_ptr + 1])
in_ptr += 2
# Now, do the actual copying
for i in xrange(write_count + 2):
out_data[out_ptr] = out_data[out_ptr - offset - 1]
out_ptr += 1
# Prepare for the next turn
if in_ptr >= len(in_data):
break
control = in_data[in_ptr]
in_ptr += 1
return out_data[:out_ptr]
def decompress_(blob):
first_thing = (ord(blob[0]) >> 5) + 1
if first_thing == 1:
return my_decompressor_1(blob)
elif first_thing == 2:
return my_decompressor_2(blob)
else:
raise 'oops'
def parse_packet_dump(f):
while True:
block = f.read(0x20)
if not block:
break
magic, payload_size, decomp_size, packet_type, unk_10, sequence_number = struct.unpack('<IIIIQQ', block)
payload = f.read(payload_size)
assert magic == 0xDEEDBEE0
print('Seq:%8d Unk:%12d Compressed:%d Decompressed:%d' % (sequence_number, unk_10, payload_size, decomp_size))
if packet_type == 1:
print('Wave Format found')
elif packet_type == 0:
decomp_payload = decompress(payload)
decomp_payload_ = decompress_(payload)
assert decomp_payload == decomp_payload_
#with open('bitsE/%d.bin' % sequence_number, 'wb') as f2:
# f2.write(payload)
#with open('bits/%d.bin' % sequence_number, 'wb') as f2:
# f2.write(decomp_payload)
print('Decompressed to %d bytes' % len(decomp_payload))
#if sequence_number == 20:
# break
if __name__ == '__main__':
with open('sGw7.bin', 'rb') as f:
parse_packet_dump(f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment