Skip to content

Instantly share code, notes, and snippets.

@KasparNagu
Last active February 12, 2026 11:54
Show Gist options
  • Select an option

  • Save KasparNagu/9ee02cb62d81d9e4c7a833518a710d6e to your computer and use it in GitHub Desktop.

Select an option

Save KasparNagu/9ee02cb62d81d9e4c7a833518a710d6e to your computer and use it in GitHub Desktop.
Script to extract Advanced Installer Exes
#!/usr/bin/env python
import sys
import struct
import os
#inspired by https://aluigi.altervista.org/bms/advanced_installer.bms
#with some additionaly reverse engeneering, quite heursitic (footer search, xor guessing etc)
#licence: public domain
class AdvancedInstallerFileInfo:
def __init__(self, name, size, offset, xorSize):
self.name = name
self.size = size
self.offset = offset
self.xorSize = xorSize
def __repr__(self):
return "[%s size=%d offset=%d]" % (self.name, self.size, self.offset)
class AdvancedInstallerFileReader:
def __init__(self,filehandle,size,keepOpen,xorLength):
self.filehandle = filehandle
self.size = size
self.xorLength = xorLength
self.pos = 0
self.keepOpen = keepOpen
def xorFF(self,block):
if isinstance(block,str):
return "".join([chr(ord(i)^0xff) for i in block])
else:
return bytes([i^0xff for i in block])
def read(self,size = None):
if size is None:
return self.read(self.size - self.pos)
if self.pos < self.xorLength:
xorLen = min(self.xorLength - self.pos, size)
xorBlock = self.filehandle.read(xorLen)
xorLenEffective = len(xorBlock)
self.pos += xorLenEffective
xorBlock = self.xorFF(xorBlock)
if xorLenEffective < size:
return xorBlock + self.read(size - xorLenEffective)
return xorBlock
blk = self.filehandle.read(min(size,self.size - self.pos))
self.pos += len(blk)
return blk
def close(self):
if not self.keepOpen:
self.filehandle.close()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
class AdvancedInstallerReader:
def __init__(self,filename,debug=None):
self.filename = filename
self.filehandle = open(filename,"rb")
self.search_back = 10000
self.xorSize = 0x200
self.footer_position = None
self.debug = debug
self.threadsafeReopen = False
self.files = []
def close(self):
self.filehandle.close()
def search_footer(self):
for i in range(0,10000):
self.filehandle.seek(-i,os.SEEK_END)
magic = self.filehandle.read(10)
if magic == b"ADVINSTSFX":
self.footer_position = i + 0x48 - 12
break
if self.footer_position is None:
raise Exception("ADVINSTSFX not found")
def read_footer(self):
if self.footer_position is None:
self.search_footer()
self.filehandle.seek(-self.footer_position,os.SEEK_END)
footer = self.filehandle.read(0x48)
offset, self.nfiles, dummy1, offset1, self.info_off, file_off, hexhash, dummy2, name, = struct.unpack("<llllll32sl12s", footer)
if self.debug:
self.debug.write("offset=%d files=%d offset1=%d info_off=%d file_off=%d hexhash=%s name=%s\n" % (offset,self.nfiles,offset1,self.info_off,file_off,hexhash,name))
def read_info(self):
self.read_footer()
self.files = []
self.filehandle.seek(self.info_off,os.SEEK_SET)
for i in range(0,self.nfiles):
info = self.filehandle.read(24)
dummy1, dummy2, dummy3, size, offset, namesize = struct.unpack("<llllll",info)
if self.debug:
self.debug.write(" size=%d offset=%d namesize=%d dummy1=0x%x dummy2=0x%x dummy3=0x%x\n" % (size,offset,namesize,dummy1,dummy2,dummy3))
if namesize < 0xFFFF:
name = self.filehandle.read(namesize*2)
name = name.decode("UTF-16")
if self.debug:
self.debug.write(" name=%s\n" % name)
self.files.append(AdvancedInstallerFileInfo(name,size,offset,self.xorSize if dummy3 == 2 else 0))
else:
raise Exception("Invalid name size %d" % namesize)
def open(self,infoFile):
if isinstance(infoFile,AdvancedInstallerFileInfo):
if self.threadsafeReopen:
fh = open(self.filename,"rb")
else:
fh = self.filehandle
fh.seek(infoFile.offset,os.SEEK_SET)
return AdvancedInstallerFileReader(fh,infoFile.size,not self.threadsafeReopen,infoFile.xorSize)
else:
if not self.files:
self.read_info()
for f in files:
if f.name == infoFile:
return self.open(f)
return None
def infolist(self):
if not self.files:
self.read_info()
return self.files
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
def __repr__(self):
return "[path=%s footer=%s nFiles=%d]" % (self.filename,self.footer_position,len(self.files))
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Advanced Installer Extractor")
parser.add_argument('file', type=str, help="Advanced Installer to open")
parser.add_argument('files', type=str,nargs="*", help="Files to consider")
parser.add_argument('-x','--extract', default=False, action="store_true",help="Extract to current directory")
parser.add_argument('-l','--list', default=False, action="store_true",help="List files")
parser.add_argument('-v','--verbose', default=False, action="store_true",help="Debug output")
args = parser.parse_args();
considerFiles = set(args.files)
with AdvancedInstallerReader(args.file,sys.stdout if args.verbose else None) as ar:
for f in ar.infolist():
if not considerFiles or f.name in considerFiles:
if args.list:
print(f)
if args.extract:
path = f.name.replace("\\","/")
dirname = os.path.dirname(path)
if dirname:
if not os.path.exists(dirname):
os.makedirs(dirname)
with ar.open(f) as inf, open(path,"wb") as out:
while True:
blk = inf.read(1<<16)
if len(blk) == 0:
break
out.write(blk)
if args.verbose:
print(ar)
@Siradankullanici
Copy link

okay it seems like it's semi bad ai but hard to see is it's really AI. Even the AI detector can't find that correctly.

@cw2k
Copy link

cw2k commented Feb 12, 2026

okay it seems like it's semi bad ai but hard to see is it's really AI. Even the AI detector can't find that correctly.

'semi bad ai' ? - sorry I don't get the point.

Btw please consider use of
"Edit" of your comments to specify or correct things and
"Delete" to clean things up

Instead of creating a new one.

Like maybe edit your old comment
..and I'll just delete my reply. ;^)

@Siradankullanici
Copy link

your code looks like ai generated because ai suggests whitespace handleded by python but flake8 gives error due to that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment