Initial Commit

This commit is contained in:
Don Barber 2021-05-11 20:19:10 -04:00
parent 0bf9dde01a
commit 9b8d504a13
11 changed files with 1075 additions and 1 deletions

View File

@ -1,4 +1,22 @@
# depace
Code to remove PACE anti-piracy on select early 68k Macintosh abandonware
These scripts are written to modify the application stored in MacBinary format, and expect the resource fork to be located at 0x80.
In the mid-80s, software publishers sought solutions to prevent copying of software to new floppies. PACE Anti-Piracy, Inc offered a solution for the early Macintoshes. PACE created self-modifying code that would decrypt and execute anti-piracy routines on the fly. These routines would check the floppy disk for the existence of a bad block. If the block was not bad, the software would refuse to run as likely someone had copied the floppy.
Since the floppy-checking routines were encrypted, it was more difficult to bypass the anti-piracy check. Additionally, a few applications (MacWars and Seven Cities of Gold), the entire application was encrypted, not just the anti-piracy code. The anti-piracy routines also include checks to make sure debugging software is not in use, even going as far as checking how much time has passed between different stages of decryption and rebooting if it detects anything unusual.
However, as the original disks are failing at 35+ years old and this software is often accessed via emulators today, these anti-piracy routines make the software unusable.
These scripts decrypt and patch these applications so they can be used again today with new floppies and on emulators.
Please note these scripts are written to modify the application stored in MacBinary format, and expect the resource fork to be located at 0x80. If you are operating directly on resource fork files, you may need to modify the code to remove the "+0x80" directives in the seek() calls.
The decrypt/ dir contains the scripts that decrypt the application binaries, so the application code and anti-piracy code is available for inspection in forensic tools/disassemblers/etc. Note that decryption alone is not enough to make the applications usable, as the anti-piracy checks are still in place.
The patch/ dir contains scripts that modify the application binaries to bypass the anti-piracy routines.
For MacWars and Seven Cities of Gold, the entire application is encrypted and must be decrypted. For these, run the decryption scripts, then run the patch scripts.
The other applications only have the anti-piracy routines encrypted, so one can just run the patch scripts without first decrypting, as the patch will bypass the encrypted routines altogether. The decryption scripts for these applications are more of interest for researchers and computer archeologists.

View File

@ -0,0 +1,140 @@
#!/usr/bin/env python3
import sys
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def getkey1(start,end):
key = int("0x50414345",0)
i = start + 0x80
while(i<=(end + 0x80)):
fh.seek(i);
ib = int.from_bytes(fh.read(1),byteorder='big')
key+=ib
i+=1
return key
def get_bit(i):
i=i%8
return (0x1 << i)
def getkey2(key,start,end,inflag,obfuscator):
i = start
while(i<=end):
bitnum = 0x80
if inflag==0:
bitnum=0x1
fh.seek(i+0x80);
ib = int.from_bytes(fh.read(1),byteorder='big')
while True:
key = key << 1
test_mask=get_bit(bitnum)
if key<(2**32):
if((test_mask & ib)==0):
key = key ^ obfuscator
else:
key = key & 0xFFFFFFFF
if((test_mask & ib)!=0):
key = key ^ obfuscator
if (inflag!=0):
bitnum = ror(bitnum,1,8)
if ((bitnum & 0x80)!=0):
break
else:
bitnum = rol(bitnum,1,8)
if ((bitnum & 0x1)==0x1):
break
i+=1
return key
def write_decrypt1(start,end,key):
fh.seek(start+0x80)
inblock=bytearray(fh.read(end-start+1))
outblock=decrypt1(key,inblock[:])
fh.seek(start+0x80)
fh.write(bytes(outblock))
def decrypt1(key,block):
def rotate_key(d0,d1,d2):
if d2==0:
d0 = ror(d0,d1,32)
else:
d0 = rol(d0,d1,32)
return d0
i=0
while i<len(block):
key_lb = key&0xFF
i_lb = i&0xFF
if (i_lb&0x1 == 0):
key_lb = key_lb & 0xF
else:
key_lb = (key_lb >> 4) &0xFFFF
key = rotate_key(key,key_lb,0)
ib = block[i]
key_lb = key&0xFF
output = ib ^ key_lb
block[i]=output
i+=1
return block
def write_decrypt2(i,end,key,salt):
fh.seek(i+0x80)
block=fh.read(end-i+1)
fh.seek(i+0x80)
fh.write(decrypt2(block,key,salt))
def swap(inbyte):
in_th = inbyte>>16
in_bh = (inbyte & 0xFFFF)
out = (in_bh << 16) + in_th
return out
def decrypt2(block,key,salt):
blockarray=bytearray(block)
i=0
while(i<len(blockarray)):
d2=key
d4=key
d2=swap(d2)
key+=d2
key=key & 0xFFFF
d4=swap(d4)
d4=d4 & 0xFFFF0000
key+=d4
key=swap(key)
key+=salt
key=key&0xFFFFFFFF
ib = blockarray[i]
output=ib ^ (key & 0xFF)
blockarray[i]=output
i+=1
return bytes(blockarray)
def copybytes(source,target,count):
fh.seek(source+0x80)
block=fh.read(count)
fh.seek(target+0x80)
fh.write(block)
def savebytes(filename,start,end):
fh.seek(start+0x80)
oh=open(filename,"wb")
oh.write(fh.read(end-start+1))
oh.close()
fh = open("StarTrek.bin","r+b")
key= 0x9ad33b77 #0x1d448
write_decrypt2(0x1d498,0x1d498+0x8fe-1,key,0x5a6b7c8d) #0x1d456
fh.close()

140
decrypt/SwordOfKadash-decrypt.py Executable file
View File

@ -0,0 +1,140 @@
#!/usr/bin/env python3
import sys
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def getkey1(start,end):
key = int("0x50414345",0)
i = start + 0x80
while(i<=(end + 0x80)):
fh.seek(i);
ib = int.from_bytes(fh.read(1),byteorder='big')
key+=ib
i+=1
return key
def get_bit(i):
i=i%8
return (0x1 << i)
def getkey2(key,start,end,inflag,obfuscator):
i = start
while(i<=end):
bitnum = 0x80
if inflag==0:
bitnum=0x1
fh.seek(i+0x80);
ib = int.from_bytes(fh.read(1),byteorder='big')
while True:
key = key << 1
test_mask=get_bit(bitnum)
if key<(2**32):
if((test_mask & ib)==0):
key = key ^ obfuscator
else:
key = key & 0xFFFFFFFF
if((test_mask & ib)!=0):
key = key ^ obfuscator
if (inflag!=0):
bitnum = ror(bitnum,1,8)
if ((bitnum & 0x80)!=0):
break
else:
bitnum = rol(bitnum,1,8)
if ((bitnum & 0x1)==0x1):
break
i+=1
return key
def write_decrypt1(start,end,key):
fh.seek(start+0x80)
inblock=bytearray(fh.read(end-start+1))
outblock=decrypt1(key,inblock[:])
fh.seek(start+0x80)
fh.write(bytes(outblock))
def decrypt1(key,block):
def rotate_key(d0,d1,d2):
if d2==0:
d0 = ror(d0,d1,32)
else:
d0 = rol(d0,d1,32)
return d0
i=0
while i<len(block):
key_lb = key&0xFF
i_lb = i&0xFF
if (i_lb&0x1 == 0):
key_lb = key_lb & 0xF
else:
key_lb = (key_lb >> 4) &0xFFFF
key = rotate_key(key,key_lb,0)
ib = block[i]
key_lb = key&0xFF
output = ib ^ key_lb
block[i]=output
i+=1
return block
def write_decrypt2(i,end,key,salt):
fh.seek(i+0x80)
block=fh.read(end-i+1)
fh.seek(i+0x80)
fh.write(decrypt2(block,key,salt))
def swap(inbyte):
in_th = inbyte>>16
in_bh = (inbyte & 0xFFFF)
out = (in_bh << 16) + in_th
return out
def decrypt2(block,key,salt):
blockarray=bytearray(block)
i=0
while(i<len(blockarray)):
d2=key
d4=key
d2=swap(d2)
key+=d2
key=key & 0xFFFF
d4=swap(d4)
d4=d4 & 0xFFFF0000
key+=d4
key=swap(key)
key+=salt
key=key&0xFFFFFFFF
ib = blockarray[i]
output=ib ^ (key & 0xFF)
blockarray[i]=output
i+=1
return bytes(blockarray)
def copybytes(source,target,count):
fh.seek(source+0x80)
block=fh.read(count)
fh.seek(target+0x80)
fh.write(block)
def savebytes(filename,start,end):
fh.seek(start+0x80)
oh=open(filename,"wb")
oh.write(fh.read(end-start+1))
oh.close()
fh = open("kad_main.bin","r+b")
key= 0x997e04cd
write_decrypt2(0xaf58,0xaf58+0x8fe-1,key,0x5a6b7c8d) #CODE2's encrypted block
write_decrypt2(0xb8e6,0xb8e6+0x8fe-1,key,0x5a6b7c8d) #CODE3's encrypted block
fh.close()

199
decrypt/macwars-D-decrypt.py Executable file
View File

@ -0,0 +1,199 @@
#!/usr/bin/env python3
import sys
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def getkey1(start,end):
key = int("0x50414345",0)
i = start + 0x80
while(i<=(end + 0x80)):
fh.seek(i);
ib = int.from_bytes(fh.read(1),byteorder='big')
key+=ib
i+=1
return key
def get_bit(i):
i=i%8
return (0x1 << i)
def getkey2(key,start,end,inflag,obfuscator):
i = start
while(i<=end):
bitnum = 0x80
if inflag==0:
bitnum=0x1
fh.seek(i+0x80);
ib = int.from_bytes(fh.read(1),byteorder='big')
while True:
key = key << 1
test_mask=get_bit(bitnum)
if key<(2**32):
if((test_mask & ib)==0):
key = key ^ obfuscator
else:
key = key & 0xFFFFFFFF
if((test_mask & ib)!=0):
key = key ^ obfuscator
if (inflag!=0):
bitnum = ror(bitnum,1,8)
if ((bitnum & 0x80)!=0):
break
else:
bitnum = rol(bitnum,1,8)
if ((bitnum & 0x1)==0x1):
break
i+=1
return key
def write_decrypt1(start,end,key):
fh.seek(start+0x80)
inblock=bytearray(fh.read(end-start+1))
outblock=decrypt1(key,inblock[:])
fh.seek(start+0x80)
fh.write(bytes(outblock))
def decrypt1(key,block):
def rotate_key(d0,d1,d2):
if d2==0:
d0 = ror(d0,d1,32)
else:
d0 = rol(d0,d1,32)
return d0
i=0
while i<len(block):
key_lb = key&0xFF
i_lb = i&0xFF
if (i_lb&0x1 == 0):
key_lb = key_lb & 0xF
else:
key_lb = (key_lb >> 4) &0xFFFF
key = rotate_key(key,key_lb,0)
ib = block[i]
key_lb = key&0xFF
output = ib ^ key_lb
block[i]=output
i+=1
return block
def write_decrypt2(i,end,key,salt):
fh.seek(i+0x80)
block=fh.read(end-i+1)
fh.seek(i+0x80)
fh.write(decrypt2(block,key,salt))
def swap(inbyte):
in_th = inbyte>>16
in_bh = (inbyte & 0xFFFF)
out = (in_bh << 16) + in_th
return out
def decrypt2(block,key,salt):
blockarray=bytearray(block)
i=0
while(i<len(blockarray)):
d2=key
d4=key
d2=swap(d2)
key+=d2
key=key & 0xFFFF
d4=swap(d4)
d4=d4 & 0xFFFF0000
key+=d4
key=swap(key)
key+=salt
key=key&0xFFFFFFFF
ib = blockarray[i]
output=ib ^ (key & 0xFF)
blockarray[i]=output
i+=1
return bytes(blockarray)
def copybytes(source,target,count):
fh.seek(source+0x80)
block=fh.read(count)
fh.seek(target+0x80)
fh.write(block)
def savebytes(filename,start,end):
fh.seek(start+0x80)
oh=open(filename,"wb")
oh.write(fh.read(end-start+1))
oh.close()
fh = open("D.bin","r+b")
#round 1
key= getkey1(0x5204,0x5369) # 0x5234
key2 = getkey1(0x5204,0x6d19) # 0x5220
write_decrypt1(0x536a,0x6d88-1,key) # 0x524C
#round 2
key= getkey2(0,0x5204,0x56b5,0,0x8005) #0x539E
key2 = key2 + getkey2(0x50414345,0x5204,0x6d19,0xFF,0x8005) #0x5406
write_decrypt2(0x56b6,0x6d80-1,key,0x776de01d) # 0x5424
#round 3
key= (getkey2(0xAAAAAAAA,0x5204,0x6535,0,0x1021) + 0xF085) & 0xFFFFFFFF #0x5738
# the 0xf085 is loaded in at 0x56c8
key2 = key2 + getkey2(0x50414345,0x5204,0x6d19,0xFF,0x1021) # 0x595C-0x5960
write_decrypt2(0x6536,0x6d7f-1,key,0xdddaac4d) # 0x598E
#round 4 (jump table and code tables)
key= getkey2(0x55555555,0x536a,0x6d19,0xFF,0x8005) # 0x65F4
key = (key + key2 + getkey2(0x50414345,0x6536,0x6d19,0x0,0x8005)) & 0xFFFFFFFF # 0x65CE-0x65D2
#the entire jump table was encrypted, then the first 8 bytes stored in CODE4.
#then an entry jumping to the PACE code was put in.
#round4 copies these 8 bytes out of CODE4, restoring the entire applications
#jump table and then decrypts it
#0x66F0 says this is stored in CODE4
#0x65ac loads it into memory and copies it over the jump
copybytes(0x6d8f,0x114,0xD-0x5)
#decryption happens at 0x6654
write_decrypt2(0x114,0x114+0x88-1,key,0xd975bb1d)
#bruteforce this instead of stepping through all the code
#between 0x57b0 and 0x492F to figure out what to add at 0x669a
#basically, the first byte of a code segment must be \x00, unless
#the jump table is over 256 bytes (which it isn't in this case)
#so loop until the \x00 has been found.
#this only works because the encryption algorithm really only uses the last
#single byte of the key...so really there are only 256 possibilities.
#no idea why PACE didnt use all 32 bits available to them; it would have
#been much more difficult
i=0
fh.seek(0x1a0 + 0x80) #use the first byte of CODE1 as the target
testblock=bytearray(fh.read(1))
while i<0xFF:
testkey = (key+i)&0xFFFFFFFF
outblock=decrypt2(testblock[:],testkey,0xad95322d)
if outblock[0]==0:
print("Key add:",hex(i),outblock)
break
i+=1
key=testkey
#with this key, PACE now decrypts anything in memory at 0x66AE
#and then overloads the trap to load a new code segment to decrypt
#them on the fly at 0x66C6. This way, it still works when the Macintosh
#memory manager swaps code segments in from disk and out from memory.
write_decrypt2(0x1a0,0x1a0+0x4544-1,key,0xad95322d) #CODE1
write_decrypt2(0x46e8,0x46e8+0x3a4-1,key,0xad95322d) #CODE2
write_decrypt2(0x4a90,0x4a90+0x570-1,key,0xad95322d) #CODE3
write_decrypt2(0x5004,0x5004+0x46-1,key,0xad95322d) #CODE255
fh.close()

180
decrypt/macwars-_-decrypt.py Executable file
View File

@ -0,0 +1,180 @@
#!/usr/bin/env python3
import sys
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def getkey1(start,end):
key = int("0x50414345",0)
i = start + 0x80
while(i<=(end + 0x80)):
fh.seek(i);
ib = int.from_bytes(fh.read(1),byteorder='big')
key+=ib
i+=1
return key
def get_bit(i):
i=i%8
return (0x1 << i)
def getkey2(key,start,end,inflag,obfuscator):
i = start
while(i<=end):
bitnum = 0x80
if inflag==0:
bitnum=0x1
fh.seek(i+0x80);
ib = int.from_bytes(fh.read(1),byteorder='big')
while True:
key = key << 1
test_mask=get_bit(bitnum)
if key<(2**32):
if((test_mask & ib)==0):
key = key ^ obfuscator
else:
key = key & 0xFFFFFFFF
if((test_mask & ib)!=0):
key = key ^ obfuscator
if (inflag!=0):
bitnum = ror(bitnum,1,8)
if ((bitnum & 0x80)!=0):
break
else:
bitnum = rol(bitnum,1,8)
if ((bitnum & 0x1)==0x1):
break
i+=1
return key
def write_decrypt1(start,end,key):
fh.seek(start+0x80)
inblock=bytearray(fh.read(end-start+1))
outblock=decrypt1(key,inblock[:])
fh.seek(start+0x80)
fh.write(bytes(outblock))
def decrypt1(key,block):
def rotate_key(d0,d1,d2):
if d2==0:
d0 = ror(d0,d1,32)
else:
d0 = rol(d0,d1,32)
return d0
i=0
while i<len(block):
key_lb = key&0xFF
i_lb = i&0xFF
if (i_lb&0x1 == 0):
key_lb = key_lb & 0xF
else:
key_lb = (key_lb >> 4) &0xFFFF
key = rotate_key(key,key_lb,0)
ib = block[i]
key_lb = key&0xFF
output = ib ^ key_lb
block[i]=output
i+=1
return block
def write_decrypt2(i,end,key,salt):
fh.seek(i+0x80)
block=fh.read(end-i+1)
fh.seek(i+0x80)
fh.write(decrypt2(block,key,salt))
def swap(inbyte):
in_th = inbyte>>16
in_bh = (inbyte & 0xFFFF)
out = (in_bh << 16) + in_th
return out
def decrypt2(block,key,salt):
blockarray=bytearray(block)
i=0
while(i<len(blockarray)):
d2=key
d4=key
d2=swap(d2)
key+=d2
key=key & 0xFFFF
d4=swap(d4)
d4=d4 & 0xFFFF0000
key+=d4
key=swap(key)
key+=salt
key=key&0xFFFFFFFF
ib = blockarray[i]
output=ib ^ (key & 0xFF)
blockarray[i]=output
i+=1
return bytes(blockarray)
def copybytes(source,target,count):
fh.seek(source+0x80)
block=fh.read(count)
fh.seek(target+0x80)
fh.write(block)
def savebytes(filename,start,end):
fh.seek(start+0x80)
oh=open(filename,"wb")
oh.write(fh.read(end-start+1))
oh.close()
fh = open("_.bin","r+b")
#round 1
key= getkey1(0xb504,0xb669)
key2 = getkey1(0xb504,0xd019)
write_decrypt1(0xb66a,0xd088-1,key)
#round 2
key= getkey2(0,0xb504,0xb9b5,0,0x8005)
key2 = (key2 + getkey2(0x50414345,0xb504,0xd019,0xFF,0x8005)) & 0xFFFFFFFF
write_decrypt2(0xb9b6,0xd080-1,key,0x776de01d)
#round 3
key= (getkey2(0xAAAAAAAA,0xb504,0xc835,0,0x1021) + 0x41BA) & 0xFFFFFFFF
key2 = (key2 + getkey2(0x50414345,0xb504,0xd019,0xFF,0x1021)) & 0xFFFFFFFF
write_decrypt2(0xc836,0xd07f-1,key,0xdddaac4d)
#round 4 (jump table and code tables)
key= getkey2(0x55555555,0xb66a,0xd019,0xFF,0x8005) & 0xFFFFFFFF
key = (key + key2 + getkey2(0x50414345,0xc836,0xd019,0x0,0x8005)) & 0xFFFFFFFF
copybytes(0xd08f,0x114,0xD-0x5)
write_decrypt2(0x114,0x784-1,key,0xd975bb1d)
#bruteforce the key. Use CODE1's first byte as the target.
i=0
fh.seek(0x788 + 0x80)
testblock=bytearray(fh.read(1))
while i<0xFF:
testkey = (key+i)&0xFFFFFFFF
outblock=decrypt2(testblock[:],testkey,0xad95322d)
if outblock[0]==0:
print("Key add:",hex(i),outblock)
break
i+=1
key=testkey
write_decrypt2(0x788,0x788+0x23A-1,key,0xad95322d) #CODE1
write_decrypt2(0x9c6,0x9c6+0x4bb0-1,key,0xad95322d) #CODE2
write_decrypt2(0x557a,0x557a+0x21ec-1,key,0xad95322d) #CODE3
write_decrypt2(0x776a,0x776a+0x3282-1,key,0xad95322d) #CODE4
write_decrypt2(0xa9f0,0xa9f0+0x352-1,key,0xad95322d) #CODE5
write_decrypt2(0xad46,0xad46+0x570-1,key,0xad95322d) #CODE6
write_decrypt2(0xb2ba,0xb2ba+0x5e-1,key,0xad95322d) #CODE255
fh.close()

187
decrypt/seven_cities_decrypt.py Executable file
View File

@ -0,0 +1,187 @@
#!/usr/bin/env python3
import sys
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def getkey1(key,start,end):
i = start + 0x80
while(i<=(end + 0x80)):
fh.seek(i);
ib = int.from_bytes(fh.read(1),byteorder='big')
key+=ib
i+=1
return key
def get_bit(i):
i=i%8
return (0x1 << i)
def getkey2(key,start,end,inflag,obfuscator):
i = start
while(i<=end):
bitnum = 0x80
if inflag==0:
bitnum=0x1
fh.seek(i+0x80);
ib = int.from_bytes(fh.read(1),byteorder='big')
while True:
key = key << 1
test_mask=get_bit(bitnum)
if key<(2**32):
if((test_mask & ib)==0):
key = key ^ obfuscator
else:
key = key & 0xFFFFFFFF
if((test_mask & ib)!=0):
key = key ^ obfuscator
if (inflag!=0):
bitnum = ror(bitnum,1,8)
if ((bitnum & 0x80)!=0):
break
else:
bitnum = rol(bitnum,1,8)
if ((bitnum & 0x1)==0x1):
break
i+=1
return key
def write_decrypt1(start,end,key):
fh.seek(start+0x80)
inblock=bytearray(fh.read(end-start+1))
outblock=decrypt1(key,inblock[:])
fh.seek(start+0x80)
fh.write(bytes(outblock))
def decrypt1(key,block):
def rotate_key(d0,d1,d2):
if d2==0:
d0 = ror(d0,d1,32)
else:
d0 = rol(d0,d1,32)
return d0
i=0
while i<len(block):
key_lb = key&0xFF
i_lb = i&0xFF
if (i_lb&0x1 == 0):
key_lb = key_lb & 0xF
else:
key_lb = (key_lb >> 4) &0xFFFF
key = rotate_key(key,key_lb,0)
ib = block[i]
key_lb = key&0xFF
output = ib ^ key_lb
block[i]=output
i+=1
return block
def write_decrypt2(i,end,key,salt):
fh.seek(i+0x80)
block=fh.read(end-i+1)
fh.seek(i+0x80)
fh.write(decrypt2(block,key,salt))
def swap(inbyte):
in_th = inbyte>>16
in_bh = (inbyte & 0xFFFF)
out = (in_bh << 16) + in_th
return out
def decrypt2(block,key,salt):
blockarray=bytearray(block)
i=0
while(i<len(blockarray)):
d2=key
d4=key
d2=swap(d2)
key+=d2
key=key & 0xFFFF
d4=swap(d4)
d4=d4 & 0xFFFF0000
key+=d4
key=swap(key)
key+=salt
key=key&0xFFFFFFFF
ib = blockarray[i]
output=ib ^ (key & 0xFF)
blockarray[i]=output
i+=1
return bytes(blockarray)
def copybytes(source,target,count):
fh.seek(source+0x80)
block=fh.read(count)
fh.seek(target+0x80)
fh.write(block)
def savebytes(filename,start,end):
fh.seek(start+0x80)
oh=open(filename,"wb")
oh.write(fh.read(end-start+1))
oh.close()
fh = open("Seven_Cities.bin","r+b")
#round 1
rolling_key=getkey1(0x50414345,0x2dccc,0x305d1)
r1key=getkey1(0x50414345,0x2dccc,0x2de67)
write_decrypt1(0x2de68,0x30642-1,r1key)
#round2
r2key=getkey2(0,0x2dccc,0x2e247,0,0x8005) #0x2dea4
rolling_key+=getkey2(0x50414345,0x2dccc,0x305d1,0xff,0x8005) #0x2df2a
write_decrypt2(0x2e248,0x30642-1,r2key,0x776de01d) #0x2df44
#round3
r3key=getkey2(0xAAAAAAAA,0x2dccc,0x2fde5,0,0x1021) #2e2ee -$24(a6)
rolling_key+=getkey2(0x50414345,0x2dccc,0x305d1,0xff,0x1021) #0x2e7a8 -$20(a6)
r3key=(r3key+0xcb838d42)&0xFFFFFFFF #added from 0x2e810
write_decrypt2(0x2fde6,0x30641-1,r3key,0xdddaac4d) #0x2e7d6
#round4
r4key=getkey2(0x55555555,0x2de68,0x305d1,0xFF,0x8005) #2fec4 -$24(a6)
rolling_key+=getkey2(0x50414345,0x2fde6,0x305d1,0x0,0x8005) #2fe9e -$20(a6)
r4key=(r4key+rolling_key)&0xFFFFFFFF #added at 0x2fecc put in -2C(a6)
#replace PACE routine in jump table with application original and decrypt
copybytes(0x30667,0x114,0xD-0x5) #2ff02
write_decrypt2(0x114,0x114+0x28-1,r4key,0xd975bb1d) #0x2ff32
#round5
#decrypt all application code segments now
#bruteforce this instead of stepping through all that code to figure it out
#basically, the first byte of a code segment must be \x00, unless
#the jump table is over 256 bytes (which it isn't in this case)
#so loop until the \x00 has been found.
fh.seek(0x140+0x80)
testbytes=fh.read(1)
i=0
while True:
outbytes=decrypt2(testbytes,(r4key+i)&0xFFFFFFFF,0xad95322d)
print(i,outbytes)
if outbytes==b'\x00':
break
i+=1
print("Delta:",i)
r5key = (r4key + i)&0xFFFFFFFF
write_decrypt2(0x140,0x140+0x2260-1,r5key,0xad95322d) #0xCODE1
write_decrypt2(0x23a4,0x23a4+0xcb3e-1,r5key,0xad95322d) #0xCODE2
write_decrypt2(0xeee6,0xeee6+0xc554-1,r5key,0xad95322d) #0xCODE3
write_decrypt2(0x1b43e,0x1b43e+0x6e36-1,r5key,0xad95322d) #0xCODE4
write_decrypt2(0x22278,0x22278+0x8b68-1,r5key,0xad95322d) #0xCODE5
write_decrypt2(0x2ade4,0x2ade4+0x2d0e-1,r5key,0xad95322d) #0xCODE255
fh.close()

143
decrypt/shanghaiv1-decrypt.py Executable file
View File

@ -0,0 +1,143 @@
#!/usr/bin/env python3
import sys
ror = lambda val, r_bits, max_bits: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
rol = lambda val, r_bits, max_bits: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
def getkey1(start,end):
key = int("0x50414345",0)
i = start + 0x80
while(i<=(end + 0x80)):
fh.seek(i);
ib = int.from_bytes(fh.read(1),byteorder='big')
key+=ib
i+=1
return key
def get_bit(i):
i=i%8
return (0x1 << i)
def getkey2(key,start,end,inflag,obfuscator):
i = start
while(i<=end):
bitnum = 0x80
if inflag==0:
bitnum=0x1
fh.seek(i+0x80);
ib = int.from_bytes(fh.read(1),byteorder='big')
while True:
key = key << 1
test_mask=get_bit(bitnum)
if key<(2**32):
if((test_mask & ib)==0):
key = key ^ obfuscator
else:
key = key & 0xFFFFFFFF
if((test_mask & ib)!=0):
key = key ^ obfuscator
if (inflag!=0):
bitnum = ror(bitnum,1,8)
if ((bitnum & 0x80)!=0):
break
else:
bitnum = rol(bitnum,1,8)
if ((bitnum & 0x1)==0x1):
break
i+=1
return key
def write_decrypt1(start,end,key):
fh.seek(start+0x80)
inblock=bytearray(fh.read(end-start+1))
outblock=decrypt1(key,inblock[:])
fh.seek(start+0x80)
fh.write(bytes(outblock))
def decrypt1(key,block):
def rotate_key(d0,d1,d2):
if d2==0:
d0 = ror(d0,d1,32)
else:
d0 = rol(d0,d1,32)
return d0
i=0
while i<len(block):
key_lb = key&0xFF
i_lb = i&0xFF
if (i_lb&0x1 == 0):
key_lb = key_lb & 0xF
else:
key_lb = (key_lb >> 4) &0xFFFF
key = rotate_key(key,key_lb,0)
ib = block[i]
key_lb = key&0xFF
output = ib ^ key_lb
block[i]=output
i+=1
return block
def write_decrypt2(i,end,key,salt):
fh.seek(i+0x80)
block=fh.read(end-i+1)
fh.seek(i+0x80)
fh.write(decrypt2(block,key,salt))
def swap(inbyte):
in_th = inbyte>>16
in_bh = (inbyte & 0xFFFF)
out = (in_bh << 16) + in_th
return out
def decrypt2(block,key,salt):
blockarray=bytearray(block)
i=0
while(i<len(blockarray)):
d2=key
d4=key
d2=swap(d2)
key+=d2
key=key & 0xFFFF
d4=swap(d4)
d4=d4 & 0xFFFF0000
key+=d4
key=swap(key)
key+=salt
key=key&0xFFFFFFFF
ib = blockarray[i]
output=ib ^ (key & 0xFF)
blockarray[i]=output
i+=1
return bytes(blockarray)
def copybytes(source,target,count):
fh.seek(source+0x80)
block=fh.read(count)
fh.seek(target+0x80)
fh.write(block)
def savebytes(filename,start,end):
fh.seek(start+0x80)
oh=open(filename,"wb")
oh.write(fh.read(end-start+1))
oh.close()
fh = open("P1.rsrc","r+b")
key= 0x9aee1dcd #key found at 0x15082
#inputs set up in 0x1508C
#end decryption called at 0x15090
write_decrypt2(0x150d6,0x150d6+0x9d8-1,key,0x5a6b7c8d)
fh.close()

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python3
noops = [
[0x354,0x35d], #jump to CODE 2 and jump if 0 return
[0x40aa,0x40bd], #jump to code 3 and jump if 0 return
[0x8fd6,0x8fd7] #control trap used for saving the game to bypass
#read-only lock flag on MFS filesystem
]
fh=open("kad_main.bin","r+b")
for myrange in noops:
i=myrange[0]+0x80
while i<=(myrange[1]+0x80):
fh.seek(i)
fh.write((0x4e71).to_bytes(2,'big'))
i+=2
fh.close()

16
patch/macwars-patchT.py Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
noops = [
[0x132e,0x1363]
]
fh=open("T.bin","r+b")
for myrange in noops:
i=myrange[0]+0x80
while i<=(myrange[1]+0x80):
fh.seek(i)
fh.write((0x4e71).to_bytes(2,'big'))
i+=2
fh.close()

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
noops = [
[0x50c,0x541]
]
fh=open("D.bin","r+b")
for myrange in noops:
i=myrange[0]+0x80
while i<=(myrange[1]+0x80):
fh.seek(i)
fh.write((0x4e71).to_bytes(2,'big'))
i+=2
fh.close()

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
noops = [
[0xa812,0xa843]
]
fh=open("_.bin","r+b")
for myrange in noops:
i=myrange[0]+0x80
while i<=(myrange[1]+0x80):
fh.seek(i)
fh.write((0x4e71).to_bytes(2,'big'))
i+=2
fh.close()