Skip to content

Instantly share code, notes, and snippets.

@shinyquagsire23
Last active June 18, 2019 00:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shinyquagsire23/14cd897874112b7c7b6eca49f5de02a1 to your computer and use it in GitHub Desktop.
Save shinyquagsire23/14cd897874112b7c7b6eca49f5de02a1 to your computer and use it in GitHub Desktop.
Python script for verifying ELF aboot images
#!/usr/bin/env python2
import struct
import sys
import hashlib
from pyasn1_modules import rfc2437,rfc2459
from pyasn1.codec.der import decoder
from pyasn1.codec.native import encoder
from Crypto.PublicKey import RSA
import rsa
from rsa import common, transform, core
def sha256tostring(val):
a,b,c,d = struct.unpack(">QQQQ", val)
return "%016x%016x%016x%016x" % (a, b, c, d)
def sha256(data):
mode = hashlib.sha256()
mode.update(data)
return mode.digest()
# from https://github.com/nelenkov/aboot-parser
def extract_raw_hash(signature, pub_key, is_sha256):
hash_size = 0x20 if is_sha256 else 0x18
keylength = common.byte_size(pub_key.n)
encrypted = transform.bytes2int(signature)
decrypted = core.decrypt_int(encrypted, pub_key.e, pub_key.n)
clearsig = transform.int2bytes(decrypted, keylength)
# unpad
if (clearsig[0] != '\x00' or clearsig[1] != '\x01'):
raise Exception('Invalid signature format')
null_idx = clearsig.find('\x00', 2)
if null_idx < 0:
raise Exception('Invalid signature format')
padding = clearsig[2:null_idx]
if len(padding) != keylength - 2 - 1 - hash_size:
raise Exception('Invalid signature format')
if not all(p == '\xff' for p in padding):
raise Exception('Invalid signature format')
raw_hash = clearsig[null_idx + 1:]
if len(raw_hash) != hash_size:
raise Exception('Invalid signature format.')
return raw_hash
# BEGIN EXEC
contents = open(sys.argv[1], "rb").read()
e_magic, e_ident_4, e_ident_5, e_ident_6, e_ident_7, e_ident_8 = struct.unpack("<4sBBBBQ", contents[:0x10])
e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags, e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx = struct.unpack("<HHLLLLLHHHHHH", contents[0x10:0x34])
if (e_ident_4 == 2): #ELF64
e_type, e_machine, e_version, e_entry, e_phoff, e_shoff, e_flags, e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx = struct.unpack("<HHLQQQLHHHHHH", contents[0x10:0x40])
print e_phentsize
if (e_magic != '\x7FELF'):
print "aboot image not an ELF!"
print "exiting..."
exit(0)
off_certs = 0
vaddr_certs = 0
hashes = []
print "Sections:"
print "Type Offset Vaddr Paddr Filesz Memsz Align Perms Hash"
for i in range(0, e_phnum):
start = e_phoff + i * e_phentsize
p_type, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_flags, p_align = [0,0,0,0,0,0,0,0]
if (e_ident_4 == 2): #ELF64
p_type, p_flags, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_align = struct.unpack("<LLQQQQQQ", contents[start:start+e_phentsize])
else:
p_type, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_flags, p_align = struct.unpack("<LLLLLLLL", contents[start:start+e_phentsize])
seg_type = p_flags >> 20
seg_perm = p_flags & 0xFF
outstr = ""
if (seg_type == 0x70):
outstr += "HEADER "
elif (seg_type == 0x22):
outstr += "CERTS "
off_certs = p_offset
vaddr_certs = p_vaddr
else:
outstr += "SECT "
outstr += '%08x %08x %08x %08x %08x %08x ' % (p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_align)
outstr += 'R' if seg_perm & 4 else ' '
outstr += 'W' if seg_perm & 2 else ' '
outstr += 'X' if seg_perm & 1 else ' '
outstr += ' '
mode = hashlib.sha256()
mode.update(contents[p_offset:p_offset+p_filesz])
outstr += mode.hexdigest()
# Don't calculate CERTS hash
if (seg_type == 0x22 or p_filesz == 0):
hashes = hashes + ['\0' * 0x20]
else:
hashes = hashes + [mode.digest()]
print outstr
# Parse out the hash table
a, h_sections, c, h_tablevaddr, h_totalsize, h_hashessize, h_signature, h_signaturesize, h_certchain, h_certchainsize = struct.unpack("<LLLLLLLLLL", contents[off_certs:off_certs+0x28])
off_hashes = off_certs + 0x28
off_sig = off_hashes + h_hashessize
off_certchain = off_sig + h_signaturesize
print ""
print "Stuff %08x %08x %08x" % (a, h_sections, c)
print "Hash Table @ %08x (vaddr %08x), total size %08x, hashes size %08x" % (off_hashes, h_tablevaddr, h_totalsize, h_hashessize)
print "Signature @ %08x (vaddr %08x), size %08x" % (off_sig, h_signature, h_signaturesize)
print "Cert chain @ %08x (vaddr %08x), size %08x" % (off_certchain, h_certchain, h_certchainsize)
print ""
print "Hash table:"
print "---"
print "Stored Calculated"
for i in range(0, e_phnum):
hashval = contents[off_hashes + i * 0x20:off_hashes + (i+1) * 0x20]
print sha256tostring(hashval) + " " + sha256tostring(hashes[i]) + " " + ("OK" if hashes[i] == hashval else "BAD")
# Save all of this aboot image's certificates
certs = []
certs_dec = []
certs_bytes = []
cert_sizes = []
cert_raw = contents[off_certchain:]
cert_offset = off_certchain
print ""
print "Certificates:"
while True:
certType = rfc2459.Certificate();
try:
cert, cert_raw = decoder.decode(cert_raw, asn1Spec=certType)
cert_size = len(contents)-cert_offset-len(cert_raw)
#decoded_alt_names, _ = decoder.decode(cert.get_extension(0).get_data(), asn1Spec=SubjectAltName())
cert_enc = encoder.encode(cert)
ou = cert_enc['tbsCertificate']['subject'][''][1][0]['value'][2:]
fname = ou.replace(' ', '_') + ".crt"
print "Found: %-40s" % (ou) + "...saving to " + fname
open(fname, "wb").write(contents[cert_offset:cert_offset + cert_size])
cert_sizes = cert_sizes + [cert_size]
certs = certs + [cert_enc]
certs_dec = certs_dec + [cert]
certs_bytes = certs_bytes + [contents[cert_offset:cert_offset+cert_size]]
cert_offset += cert_size
#print cert.prettyPrint()
except:
break
# Grab all of our attestation cert values and print them nicely
key_vals = {}
print ""
print "Attestation Cert:"
for val in certs[0]['tbsCertificate']['subject']['']:
val = val[0]
if val['type'] == '2.5.4.11':
line = val['value'][2:]
if not line.split(' ')[0].isdigit():
continue
split = line.split(' ')
key = split[2]
key_val = split[1]
key_vals[key] = int(key_val, 16)
print '%-10s %s' % (key, key_val)
# Calculate signature message
i_pad = 0x3636363636363636
o_pad = 0x5c5c5c5c5c5c5c5c
SW_ID = int(key_vals['SW_ID'])
HW_ID = int(key_vals['HW_ID'])
h0 = sha256(contents[off_certs:off_sig])
h1 = sha256(struct.pack(">Q", SW_ID ^ i_pad) + h0)
# Final message
m = struct.pack(">Q", HW_ID ^ o_pad) + h1
hm = sha256(m)
rsakey = RSA.importKey(certs_bytes[0])
print ""
sighash = '\0' * 0x20
try:
sighash = extract_raw_hash(contents[off_sig:off_sig+h_signaturesize], rsakey, True)
except:
print "Failed to get signature hash!"
print "Signature Calculated"
print sha256tostring(sighash) + " " + sha256tostring(hm) + " " + ("OK" if sighash == hm else "BAD")
# END EXEC
$ python2 aboot-verify.py aboot_a.image
Sections:
Type Offset Vaddr Paddr Filesz Memsz Align Perms Hash
HEADER 00000000 00000000 00000000 000000b4 00000000 00000000 c6c6f853dd5d083775592bf864d12e967b805822410c28eab5c7d64c03251c3e
CERTS 00001000 8f685000 8f685000 000019a8 00002000 00001000 19ad70ec604b975aaf0a4fd21d24d5887ebca69f85e1681db354e89a367d84b1
SECT 0008c2d0 8f6842d0 8f6842d0 00000020 00000020 00000004 R 795abb80f531cbdb11cd5ba90a566185b8ba767adf2e96ed81c329b1cc74180b
SECT 00008000 8f600000 8f600000 00097df4 000c879c 00008000 RWX c5b90657a99565917ca92db0ac64c421119d5481c37f65a8c7ca0b03e8a3a656
Stuff 00000000 00000003 00000000
Hash Table @ 00001028 (vaddr 8f685028), total size 00001980, hashes size 00000080
Signature @ 000010a8 (vaddr 8f6850a8), size 00000100
Cert chain @ 000011a8 (vaddr 8f6851a8), size 00001800
Hash table:
---
Stored Calculated
c6c6f853dd5d083775592bf864d12e967b805822410c28eab5c7d64c03251c3e c6c6f853dd5d083775592bf864d12e967b805822410c28eab5c7d64c03251c3e OK
0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 OK
795abb80f531cbdb11cd5ba90a566185b8ba767adf2e96ed81c329b1cc74180b 795abb80f531cbdb11cd5ba90a566185b8ba767adf2e96ed81c329b1cc74180b OK
c5b90657a99565917ca92db0ac64c421119d5481c37f65a8c7ca0b03e8a3a656 c5b90657a99565917ca92db0ac64c421119d5481c37f65a8c7ca0b03e8a3a656 OK
Certificates:
Found: General LGE attestation ...saving to General_LGE_attestation.crt
Found: General LGE attestation CA ...saving to General_LGE_attestation_CA.crt
Found: General LGE rootca ...saving to General_LGE_rootca.crt
Attestation Cert:
SHA256 0001
MODEL_ID 0000
SW_SIZE 000000A8
OEM_ID 0031
DEBUG 0000000000000002
HW_ID 0009A0E100310000
SW_ID 0000000000000009
Signature Calculated
aee3035616e5a698b1606300c7323d1ab9b93a17ef4e3cf75022349f99fff4a0 aee3035616e5a698b1606300c7323d1ab9b93a17ef4e3cf75022349f99fff4a0 OK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment