############################################################
## Microsoft ACME Setup - decrypt setup.ini
##
## Version 1.1 nov 2020 Djamana
##
### definitions
# Most in here is just necessary 'code noise'
# Except mybytearray.getWord() nothing really interesting
# so scroll down (till # Init) ...
data_strOffset = 0xf
STF_CD_NAME_SIZE_MAX = 0x34
STF_CD_ORG_SIZE_MAX = 0x34
STF_CD_SER_SIZE = 0x14
spacefill = "LtRrBceHabCT AhlenN"
StrFmt_Pos = "@{:02X}..{:02X}"
def myprint(pos, value, description):
print ( pos , " {:14s}: '{}'\n".format( description, value ) )
# Encrypted word reader
class mybytearray( bytearray ):
global StrFmt_Pos
def getWord (self, pos, purpose):
byte1 = self[ pos ]
byte2 = self[ pos+1 ]
result = ( byte2 << 4 ) + byte1 - 1717
print ( (StrFmt_Pos + " {:14s}: '{:c}' & '{:c}' => 0x{:02X}")
.format( pos, pos+1 +1, purpose, byte1 , byte2 ,result )
)
return result
# Simple StringStreamReader
# (mis)used for binary data
# As long as binary data is in range from 0x20..0x7F that'll be fine
class myStream( str ):
pos = 0
def getStr (self, len):
result = self[ self.pos: self.pos+len ]
self.CRC_8 = sum(result.encode("utf-8") ) & 0xff
posnow = self.pos_absolute + self.pos
self.pos_last = StrFmt_Pos.format( posnow , posnow + len)
self.pos += len
return result
pos_absolute = 0
pos_last = ""
CRC_8 = 0
#######################################################################
# ... till HERE
#
### Init
Enc_dataSize = 0x80
Setup_ini = "setup.ini"
### Loading data...
# f=open( Setup_ini , "rb" )
# data = f.read( Enc_dataSize )
# STF_CD_SER = f.read( ); f.close()
# Vs6sp6B - setup.ini : Visual Basic 6 SP3 (2000)
data = b'Jj\x1f\x10&\x0fJ~K\x10&\x0fJ~Rjc&J~Rjc\x1e6,Rjc\x1e6 $\x0bM\x1e6 $\x0b]SI $\x0b]SrJJ<]SrJJ?0,rJJ?0\x06/j[?0\x06/j^rJ\x06/j^rJC>=^rJC>\x16\x00/JC>\x16\x00\x04+}I\x16\x00\x04+}sRIj+}sRjj\x1f.sRjj\x1f\x10&\x00'
STF_CD_SER = b'53501000000000000000\x00'
### Decrypting data...
# 1 descramble bytes (i = 127 + 17 * i)
i_data = len(data) - 1 ; descrambled = bytearray()
for i_descrambled in range( len(data) ):
i_data = (i_data + 0x11 ) & 0b1111111
descrambled.append ( data [i_data] )
# 2 Xor adjacent bytes
dec = bytearray()
for (byte1, byte2) in zip( descrambled, descrambled[1:] ):
dec.append (byte1 ^ byte2)
# 3 reverse array
dec = dec[::-1]
### Sequencing data...
myprint ( StrFmt_Pos.format (0, len(dec)),
dec.decode("utf-8" ) , "decrypted data", )
print("_"*80)
# Split the decoded data into a binary and a string part
data_bin = mybytearray( dec [ 0 : data_strOffset ] )
data_str = myStream ( (dec [ data_strOffset : ]).decode("utf-8" ))
data_str.pos_absolute = data_strOffset
#0 STF_CD_PIDMODE
STF_CD_PIDMODE = ( data_bin[0] & 0x1f ) + 0x40
myprint (StrFmt_Pos.format (0, 1),
chr(STF_CD_PIDMODE), "STF_CD_PIDMODE")
#1 STF_CD_NAME
Name_Len = data_bin.getWord( 0x1 , "Name_Len")
if Name_Len > STF_CD_NAME_SIZE_MAX: print ("Error_5 'Name_Len' not in range 1.." + hex(STF_CD_NAME_SIZE_MAX) )
Org_Len = data_bin.getWord( 0x3 , "Org_Len")
if Org_Len > STF_CD_ORG_SIZE_MAX : print ("Error_6 'Org_Len' not in range 1.." + hex(STF_CD_ORG_SIZE_MAX) )
STF_CD_NAME = data_str.getStr( Name_Len) # char smaller 0x20? -> Error_7
Name_CRC = data_bin.getWord( 0x5 , "Name_CRC") # checksum mismatch? -> Error_8
org_CRC = data_bin.getWord( 0x7 , "org_CRC") # checksum mismatch? -> Error_10
# Note: ... use data_str.CRC_8 later if you like to test the checksum
# dump remaining not used data.
# (If these are made to get read via getWord() is just speculation / interpolated.)
unused = (
data_bin.getWord( 0x9 , "unused word #1" ) ,
data_bin.getWord( 0xB , "unused word #2" ) ,
data_bin.getWord( 0xD , "unused word #3" )
)
myprint ( data_str.pos_last ,
STF_CD_NAME ,"STF_CD_NAME" )
#2 STF_CD_ORG
STF_CD_ORG = data_str.getStr( Org_Len ) # char smaller 0x20? -> Error_9
myprint ( data_str.pos_last ,
STF_CD_ORG, "STF_CD_ORG")
# check remaining fill space
remainingData = data_str.getStr( len(data_str) - data_str.pos)
myprint ( data_str.pos_last ,remainingData, "remainingData")
# print ("remainingData_CRC_8:", hex(data_str.CRC_8))
if not remainingData >= spacefill * ( len(remainingData) // len(spacefill) ):
print ( "Error_11 - Fillspace corrupted" )
#3 STF_CD_SER
myprint ( StrFmt_Pos.format (Enc_dataSize, Enc_dataSize+STF_CD_SER_SIZE),
STF_CD_SER, "STF_CD_SER" )
if len(STF_CD_SER) -1 != STF_CD_SER_SIZE: print ("Error_12 'STF_CD_TRIGGER_Len' is not " + hex(STF_CD_SER_SIZE))