Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 58 additions & 4 deletions neolite_unpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import pefile
import struct
import zlib
from zipfile_deflate64.deflate64 import Deflate64

def hexdump(src, length=16, sep='.'):
FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or sep for x in range(256)])
Expand Down Expand Up @@ -165,7 +166,7 @@ def next_command(self):
if command < 2:
self.back(0, command + 3)
else:
self.back_base(command * 256, 3)
self.back_base(command << 8, 3)
case 5: self.back_extend16(4)
case 6: self.back_extend16(5)
case 7: self.back_offset0(6)
Expand Down Expand Up @@ -246,6 +247,17 @@ def zlib_uncompress(data, usize):

return ret

def deflate64_uncompress(data, usize):
obj = Deflate64()
ret = obj.decompress(data)

if len(ret) > usize:
raise Exception(f'{len(ret)=:x} {usize=:x}')

if not obj.eof:
raise Exception

return ret

def is_neolite(data):
pe = pefile.PE(data=data)
Expand Down Expand Up @@ -312,6 +324,37 @@ def print_info(data):
v = f'0x{val:x}'
print(f'rev.{key:22} {v:>10}')

def fixup_calls(buf, section_size):
data = bytearray(buf)

i = 0
while i < len(data) - 4:
if data[i] == 0xE8: # CALL rel32
i += 1
addr = int.from_bytes(data[i:i+4], 'little', signed=True)

# Equivalent to ExeLock runtime logic:
#
# if target is inside section range:
# if addr < 0:
# new = section_size + addr
# else:
# new = addr - current_position
#
if i + addr >= 0 and addr < section_size:
if addr < 0:
new = section_size + addr
else:
new = addr - i

data[i:i+4] = int(new).to_bytes(4, 'little', signed=True)

i += 4
else:
i += 1

return bytes(data)

def fixup(data):
pe = pefile.PE(data=data)

Expand Down Expand Up @@ -349,6 +392,7 @@ def fixup(data):
zpos_start = pos

zpos = zpos_start
exelock = hdr.use_zlib == 2
if hdr.use_zlib:
# Decompress the included decompressor. It's just zlib, so we just use
# python's zlib, but we need to advance the pos value.
Expand All @@ -360,7 +404,7 @@ def fixup(data):

zpos += hdr.zlib_relocations_sz

uncompress = zlib_uncompress
uncompress = deflate64_uncompress if exelock else zlib_uncompress
else:
uncompress = neo_uncompress

Expand Down Expand Up @@ -532,7 +576,14 @@ def fixup(data):

if offset > len(new_data):
new_data += bytes(offset - len(new_data))
new_data += sdata
if exelock and section.Characteristics & 0x20000000: # IMAGE_SCN_MEM_EXECUTE
new_data += fixup_calls(sdata, section.SizeOfRawData)
else:
new_data += sdata
if len(sdata) < section.SizeOfRawData:
new_data += bytes(section.SizeOfRawData - len(sdata))
elif len(sdata) > section.SizeOfRawData:
raise Exception(f'Section {section_name} overflowed')
section.PointerToRawData = offset

if imports_offset >= section.VirtualAddress and imports_offset < section.VirtualAddress + section.SizeOfRawData:
Expand Down Expand Up @@ -599,7 +650,10 @@ def fixup(data):
# Copy data at end of file to end of file.
if hdr.extra_data_csize:
if hdr.use_zlib:
udata = zlib.decompress(data[extra_data_offset:extra_data_offset+extra_data_size])
if exelock:
udata = Deflate64().decompress(data[extra_data_offset:extra_data_offset+extra_data_size])
else:
udata = zlib.decompress(data[extra_data_offset:extra_data_offset+extra_data_size])
if len(udata) != hdr.extra_data_usize:
raise Exception
else:
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pefile==2023.2.7
zipfile-deflate64==0.2.0