Last active
February 22, 2024 08:09
-
-
Save danny8376/fd7104396827adeabb8c13780a6f65c6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pyctr.crypto import CryptoEngine | |
from Cryptodome.Cipher import AES | |
from hashlib import sha256 | |
a = CryptoEngine() | |
def print_diff(ori, enc, dec, postxt, *suffix): | |
if postxt == None: | |
return | |
if type(postxt) is tuple: | |
s = len(enc) // len(postxt) | |
for x in range(len(enc) // s): | |
b, e = x * s, (x + 1) * s | |
xori, xenc, xdec = ori[b:e], enc[b:e], dec[b:e] | |
if xori != xenc: | |
print(f"{postxt[x]} ori:", xori.hex(), *suffix) | |
print(f"{postxt[x]} fix:", xenc.hex(), xdec.hex(), *suffix) | |
elif ori != enc: | |
print(f"{postxt} ori:", ori.hex(), *suffix) | |
print(f"{postxt} fix:", enc.hex(), dec.hex(), *suffix) | |
def decrypt_otp_block(data, iv): | |
cipher = AES.new(a.otp_key, AES.MODE_CBC, iv) | |
return cipher.decrypt(data) | |
def crack_singlebit(indata, iv, check, postxt): | |
#if check(decrypt_otp_block(indata, iv)): | |
# return indata | |
ret = None | |
ints = bytearray(indata) | |
for x in range(len(indata)): | |
orig = ints[x] | |
for bit in range(8): | |
new = orig ^ (1 << bit) | |
ints[x] = new | |
data = decrypt_otp_block(ints, iv) | |
if check(data): | |
print_diff(indata, ints, data, postxt, "(single bit)") | |
ret = ints | |
return ret | |
ints[x] = orig | |
return ret | |
def crack_dataline(indata, iv, bit, check, postxt): | |
#if check(decrypt_otp_block(indata, iv)): | |
# return indata | |
set_size = len(indata) // 4 | |
ret = None | |
for combi in range(pow(2, set_size)): | |
ints = bytearray(indata) | |
for addr in range(set_size): | |
if (combi >> addr) & 1: | |
byte = 4 * addr + bit // 8 | |
orig = ints[byte] | |
ints[byte] = orig ^ (1 << (bit % 8)) | |
cipher = AES.new(a.otp_key, AES.MODE_CBC, iv) | |
data = cipher.decrypt(ints) | |
if check(data): | |
print_diff(indata, ints, data, postxt, "(data line)") | |
ret = ints | |
return ret | |
return ret | |
def crack_singlebit_dataline(indata, extract, check, postxt, bit = -1): | |
indata, iv = extract(indata) | |
ret = (-1, b"\x00" * len(indata)) | |
if check(decrypt_otp_block(indata, iv)): | |
if bit == -1: | |
bit = -2 | |
return (bit, indata) | |
if bit == -1 or bit == 32: | |
res = crack_singlebit(indata, iv, check, postxt) | |
if res != None: | |
ret = (32, res) | |
return ret | |
#if bit == 32: # force sigle bit -> fail | |
# return ret | |
if bit < 0: # -1: default, -2: no need to fix previously | |
for bit in range(32): | |
res = crack_dataline(indata, iv, bit, check, postxt) | |
if res != None: | |
ret = (bit, res) | |
return ret | |
else: | |
res = crack_dataline(indata, iv, bit, check, postxt) | |
if res != None: | |
ret = (bit, res) | |
return ret | |
return ret | |
def crack0x00(otp2fix): | |
def extract(data): | |
return data[0:0x10], a.otp_iv | |
def check(data): | |
return data[0:4] == b"\x0f\xb0\xad\xde" and data[0xD:0x10] == b"\x00\x00\x00" and data[0xC] in (0, 2) | |
ret = crack_singlebit_dataline(otp2fix, extract, check, "0x00") | |
if ret[0] == -1: | |
print("Can't fix 0x00") | |
exit(1) | |
return ret | |
def crack0x10(otp2fix, bit): | |
def extract(data): | |
return data[0x10:0x20], data[0:0x10] | |
def check(data): | |
return data[0x8:0xA] == b"\x05\x00" | |
ret = crack_singlebit_dataline(otp2fix, extract, check, "0x10", bit) | |
if ret[0] == -1: | |
print("Can't fix 0x10") | |
exit(1) | |
return ret | |
def crack0x70x80(otp2fix, bit): | |
def extract(data): | |
return data[0x70:0x90], data[0x60:0x70] | |
def check(data): | |
return data[0x10:0x20] == b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | |
ret = crack_singlebit_dataline(otp2fix, extract, check, ("0x70", "0x80"), bit) | |
if ret[0] == -1: | |
print("can't fix 0x70, 0x80") | |
#exit(1) | |
return ret | |
def showbits(bit): | |
for addr in range(0x100 // 4): | |
byte = 4 * addr + bit // 8 | |
orig = otp[byte] | |
print((orig >> (bit % 8)) & 1, end="\t") | |
if addr % 4 == 3: | |
print() | |
with open('otp.mem', 'rb') as f: | |
content = f.read(0x100) | |
otp = bytearray(content) | |
bit, otp[0:0x10] = crack0x00(otp) | |
#showbits(bit) | |
bit, otp[0x10:0x20] = crack0x10(otp, bit) | |
bit, otp[0x70:0x90] = crack0x70x80(otp, bit) | |
#showbits(bit) | |
print(f"Bit: {bit}") | |
for x in range(0x10): | |
print("--------------------------------") | |
start = 0x10 * x | |
end = start + 0x10 | |
print(content[start:end].hex()) | |
print(otp[start:end].hex()) | |
with open('otp_fixed.mem', 'wb') as f: | |
f.write(otp) | |
#for bit in range(32): | |
# ints = bytearray(content[0:0x10]) | |
# for combi in range(pow(2, 0x10 // 4)): | |
# for addr in range(0, 0x10, 4): | |
# if (combi >> addr) & 1: | |
# byte = addr + bit // 8 | |
# orig = ints[byte] | |
# ints[byte] = orig ^ (1 << (bit % 8)) | |
# cipher = AES.new(a.otp_key, AES.MODE_CBC, a.otp_iv) | |
# data = cipher.decrypt(ints) | |
# ohash = data[0xE0:] | |
# before_hash = data[0:0xE0] | |
# hash_before_hash = sha256(before_hash).hexdigest() | |
# if data[0:4].hex() == "0fb0adde": | |
# print(data[0:4].hex(), bit, combi) | |
# #print(bit, hash_before_hash, ohash.hex(), hash_before_hash == ohash.hex()) | |
# if hash_before_hash == ohash.hex(): | |
# print(beginning + before_hash + ohash) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment