Skip to content

Instantly share code, notes, and snippets.

@yunzheng
Created November 13, 2011 17:01
Show Gist options
  • Save yunzheng/1362334 to your computer and use it in GitHub Desktop.
Save yunzheng/1362334 to your computer and use it in GitHub Desktop.
ei.cfg removal/restore util in Python
#!/usr/bin/env python
"""
eicfg_remover.py
Based on Kai Liu's eicfg_remover.c @ http://code.kliu.org/misc/winisoutils/
"""
import sys
from binascii import crc_hqx, hexlify
from collections import namedtuple
from struct import calcsize, pack, unpack
WORK_RANGE = 0x1000000
UDFTAG_STRUCT = 'HHBBHHHI'
LONGALLOC_STRUCT = 'I6s6s'
UDFDESC_STRUCT = '%isHBB%isH2s' % (calcsize(UDFTAG_STRUCT), calcsize(LONGALLOC_STRUCT))
UDFTag = namedtuple('UDFTag', 'ident version checksum reserved serial crc crclen location')
UDFDesc = namedtuple('UDFDesc', 'tag_ version characteristics identifier icb_ cb_iu misc')
WCHAR_FILENAME = '\x00'.join(list('ei.cfg')) + '\x00'
def main():
if len(sys.argv) < 2:
print 'Usage: %s [iso file]' % sys.argv[0]
return 1
iso = sys.argv[1]
with open(iso, 'rb') as f:
pbuffer = f.read(WORK_RANGE)
if len(pbuffer) < WORK_RANGE:
print 'Image is too small'
print ''
print 'Make sure that you use the correct iso image.'
return 1
found_eicfg = False
for i in xrange(0x100, WORK_RANGE-0x100):
if pbuffer[i:i+len(WCHAR_FILENAME)] == WCHAR_FILENAME:
udf_startpos = i - calcsize(UDFDESC_STRUCT)
udf_buffer = pbuffer[udf_startpos:udf_startpos+calcsize(UDFDESC_STRUCT)]
udfdesc = UDFDesc._make(unpack(UDFDESC_STRUCT, udf_buffer))
udftag = UDFTag._make(unpack(UDFTAG_STRUCT, udfdesc.tag_))
udf_filestart = udf_startpos+calcsize(UDFTAG_STRUCT)
crc_buffer = pbuffer[udf_filestart:udf_filestart+udftag.crclen]
calc_crc = crc_hqx(crc_buffer, 0)
# Perform sanity checks
sane = (udftag.ident == 257
and udftag.version == 2
and udftag.reserved == 0
and udftag.crclen == (calcsize(UDFDESC_STRUCT) - calcsize(UDFTAG_STRUCT) + len(WCHAR_FILENAME))
and udftag.crc == calc_crc
and udfdesc.identifier == len(WCHAR_FILENAME)+1
and udfdesc.cb_iu == 0
and udfdesc.characteristics in (0, 5))
if sane:
found_eicfg = True
break
if found_eicfg:
# Toggle the Hidden+Deletion flag on the file
# 0 = Normal (restore the file)
# 5 = HIDDEN (1) + DELETED (4)
if udfdesc.characteristics:
udfdesc = udfdesc._replace(characteristics=0)
else:
udfdesc = udfdesc._replace(characteristics=5)
# Recalculate CRC-16
udf_raw = pack(UDFDESC_STRUCT, *udfdesc) + WCHAR_FILENAME
crc_buffer = udf_raw[calcsize(UDFTAG_STRUCT):calcsize(UDFTAG_STRUCT)+udftag.crclen]
crc = crc_hqx(crc_buffer, 0)
udftag = udftag._replace(crc=crc)
udfdesc = udfdesc._replace(tag_=pack(UDFTAG_STRUCT, *udftag))
udf_raw = pack(UDFDESC_STRUCT, *udfdesc)
# Recalculate checksum
checksum = 0
for i in xrange(0, 4):
checksum += ord(udf_raw[i])
for i in xrange(5, 16):
checksum += ord(udf_raw[i])
checksum = checksum & 0xFF
udftag = udftag._replace(checksum=checksum)
udfdesc = udfdesc._replace(tag_=pack(UDFTAG_STRUCT, *udftag))
udf_raw = pack(UDFDESC_STRUCT, *udfdesc)
# Write back the changes of the UDF FileDescriptor
with open(iso, "r+b") as f:
#print 'Write @', udf_startpos, hexlify(udf_raw)
f.seek(udf_startpos)
f.write(udf_raw)
if udfdesc.characteristics:
print 'ei.cfg removed.'
else:
print 'ei.cfg restored.'
return 0
else:
print 'ei.cfg not found.'
print ''
print 'Make sure that the disc image is uncorrupted and that the file system is UDF, not Joliet.'
return 1
if __name__ == '__main__':
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment