Guest User

Untitled

a guest
Feb 19th, 2020
44
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #! /usr/bin/env python3
  2.  
  3. __author__  = 'Felis-Sapiens'
  4.  
  5. import argparse
  6. import struct
  7. import zlib
  8. from io import BytesIO
  9. from os import stat
  10. from Crypto.Cipher import AES
  11.  
  12. def read_aes_data(fd_in, key):
  13.     enc_data = b''
  14.     while True:
  15.         aes_chunk_header = fd_in.read(0xC)
  16.         if len(aes_chunk_header) != 0xC:
  17.             print('ERROR: failed to read AES chunk header')
  18.             return
  19.         aes_chunk_header = struct.unpack('>3I', aes_chunk_header)
  20.         print('AES chunk length:             ', hex(aes_chunk_header[1]))
  21.         chunk = fd_in.read(aes_chunk_header[1])
  22.         if len(chunk) != aes_chunk_header[1]:
  23.             print('ERROR: failed to read AES chunk data')
  24.             return
  25.         enc_data += chunk
  26.         if aes_chunk_header[2] == 0:
  27.             break
  28.    
  29.     aes_cipher = AES.new(key.ljust(16, b'\0')[:16])
  30.     fd_out = BytesIO()
  31.     fd_out.write(aes_cipher.decrypt(enc_data))
  32.     fd_out.seek(0)
  33.     return fd_out
  34.  
  35. def read_compressed_data(fd_in, enc_header):
  36.     print('encryption header CRC32:       0x{:08X}'.format(enc_header[6]))
  37.     header_crc = zlib.crc32(struct.pack('>6I', *enc_header[:6]))
  38.     if enc_header[6] != header_crc:
  39.         print("ERROR: CRC32 doesn't match")
  40.         return
  41.    
  42.     crc = 0
  43.     fd_out = BytesIO()
  44.     while True:
  45.         compr_chunk_header = fd_in.read(0xC)
  46.         if len(compr_chunk_header) != 0xC:
  47.             print('ERROR: failed to read compression chunk header')
  48.             return
  49.         compr_chunk_header = struct.unpack('>3I', compr_chunk_header)
  50.         print('compressed length:            ', hex(compr_chunk_header[1]))
  51.         print('uncompressed length:          ', hex(compr_chunk_header[0]))
  52.         chunk = fd_in.read(compr_chunk_header[1])
  53.         if len(chunk) != compr_chunk_header[1]:
  54.             print('ERROR: failed to read compression chunk data')
  55.             return
  56.         crc = zlib.crc32(chunk, crc)
  57.         chunk = zlib.decompress(chunk)
  58.         if len(chunk) != compr_chunk_header[0]:
  59.             print('ERROR: wrong length of uncompressed data')
  60.             return
  61.         fd_out.write(chunk)
  62.         if compr_chunk_header[2] == 0:
  63.             break
  64.    
  65.     print('compressed data CRC32:         0x{:08X}'.format(enc_header[5]))
  66.     if enc_header[5] != crc:
  67.         print("ERROR: CRC32 doesn't match")
  68.         return
  69.     fd_out.seek(0)
  70.     return fd_out
  71.  
  72. def read_config(fd_in, fd_out, key):
  73.     ver_header_1 = fd_in.read(0x14)
  74.     if len(ver_header_1) != 0x14:
  75.         print('ERROR: failed to read the first version header')
  76.         return
  77.     ver_header_1 = struct.unpack('>5I', ver_header_1)
  78.     print('first version header magic:   ',
  79.           ', '.join(map(lambda x: '0x{:08X}'.format(x), ver_header_1[:4])))
  80.     ver_header_2_offset = 0x14 + ver_header_1[4]
  81.     print('second version header offset: ', hex(ver_header_2_offset))
  82.     if ver_header_1[:4] != (0x99999999, 0x44444444, 0x55555555, 0xAAAAAAAA):
  83.         print('ERROR: expected magic is 0x99999999, 0x44444444, 0x55555555, 0xAAAAAAAA')
  84.         return
  85.    
  86.     fd_in.seek(ver_header_2_offset)
  87.     ver_header_2 = fd_in.read(0x2c)
  88.     if len(ver_header_2) != 0x2c:
  89.         print('ERROR: failed to read the second version header')
  90.         return
  91.     ver_header_2 = struct.unpack('>11I', ver_header_2)
  92.     ver_header_3_offset = ver_header_2[10]
  93.     print('third version header offset:  ', hex(ver_header_3_offset))
  94.    
  95.     fd_in.seek(ver_header_3_offset)
  96.     ver_header_3 = fd_in.read(0x18)
  97.     if len(ver_header_3) != 0x18:
  98.         print('ERROR: failed to read the third version header')
  99.         return
  100.     ver_header_3 = struct.unpack('>2H5I', ver_header_3)
  101.     signed_cfg_size = ver_header_3[3]
  102.     print('signed config size:           ', hex(signed_cfg_size))
  103.     file_size = stat(fd_in.name).st_size
  104.     if signed_cfg_size != file_size - 0x80:
  105.         print("ERROR: the config size (0x{:x} + 0x80) doesn't match the real file size (0x{:x})".format(signed_cfg_size, file_size))
  106.    
  107.     fd_in.seek(0x80)
  108.     sign_header = fd_in.read(0xC)
  109.     if len(sign_header) != 0xC:
  110.         print('ERROR: failed to read signature header')
  111.         return
  112.     sign_header = struct.unpack('>3I', sign_header)
  113.     print('signature header magic:        0x{:08X}'.format(sign_header[0]))
  114.     if sign_header[0] != 0x04030201:
  115.         print('ERROR: expected magic is 0x04030201')
  116.         return
  117.     print('signature length:             ', sign_header[2])
  118.     signature = fd_in.read(sign_header[2])
  119.     if len(signature) != sign_header[2]:
  120.         print('ERROR: failed to read the signature')
  121.         return
  122.     print('signature:                    ', signature.decode())
  123.    
  124.     encryption_header = fd_in.read(0x3C)
  125.     if len(encryption_header) != 0x3C:
  126.         print('ERROR: failed to read encryption header')
  127.         return
  128.     encryption_header = struct.unpack('>15I', encryption_header)
  129.     print('encryption header magic:       0x{:08X}'.format(encryption_header[0]))
  130.     if encryption_header[0] != 0x01020304:
  131.         print('ERROR: expected magic is 0x01020304')
  132.         return
  133.     enc_type = encryption_header[1]
  134.     print('encryption type:              ', enc_type)
  135.    
  136.     if enc_type == 2 or enc_type == 1:
  137.         if not key:
  138.             print('ERROR: specify the key, i.e ' + __file__ + " config.bin config.bin.xml --key 'MIK@0STzKpB%qJZe'")
  139.             return
  140.         fd_in = read_aes_data(fd_in,key)
  141.         if fd_in is None:
  142.             return
  143.    
  144.     if enc_type == 2:
  145.         encryption_header = fd_in.read(0x3C)
  146.         if len(encryption_header) != 0x3C:
  147.             print('ERROR: failed to read encryption header')
  148.             return
  149.         encryption_header = struct.unpack('>15I', encryption_header)
  150.         print('encryption header magic:       0x{:08X}'.format(encryption_header[0]))
  151.         if encryption_header[0] != 0x01020304:
  152.             print('ERROR: expected magic is 0x01020304 - probably the AES key is incorrect')
  153.             return
  154.         enc_type = 0
  155.    
  156.     if enc_type == 0:
  157.         fd_in = read_compressed_data(fd_in, encryption_header)
  158.         if fd_in is None:
  159.             return
  160.    
  161.     fd_out.write(fd_in.read())
  162.     return
  163.  
  164.  
  165. def main():
  166.     parser = argparse.ArgumentParser(description='Decode configuration file '\
  167.                                      '(config.bin) from ZTE routers',
  168.                                      formatter_class=argparse.RawDescriptionHelpFormatter,
  169.                                      epilog="""\
  170. Known AES keys:
  171.  zxhn h118n ert5                      - 'MIK@0STzKpB%qJZe'
  172.  zxhn h118n V2.1.3_ROSCNT?            - 'MIK@0STzKpB%qJZf'
  173.  zxhn h168n v3                        - '402c38de39bed665'
  174.  zxhn h298n hv17_fv116_mts?t1         - 'Wj' (due to bug, orig. is 'Wj%2$CjM')
  175.  zxhn h298a hw1.1.20_fw1.1.20_ros_t1? - 'm8@96&ZG3Nm7N&Iz'
  176.  zxhn h108n hw1.2_fw2.5.4_eg1t8_ted,
  177.  zxhn h108n hv11_fv2_5_4_*            - 'GrWM2Hz&LTvz&f^5'
  178.  zxhn h168n hv10_fv310t3_belt         - 'GrWM3Hz&LTvz&f^9'
  179.  zxhn h208n hv10_fv1010_belt16t1      - 'Renjx%2$CjM'
  180.  zxhn h267n hv10_fv100t3_belt         - 'tHG@Ti&GVh@ql3XN'""")
  181.    
  182.     parser.add_argument('infile', type=argparse.FileType('rb'),
  183.                         help='Encoded configuration file (config.bin)')
  184.     parser.add_argument('outfile', type=argparse.FileType('wb'),
  185.                         help='Output file')
  186.     parser.add_argument('--key', type=lambda x:x.encode(), default=b'',
  187.                         help="Key for AES encryption\n\n\n")
  188.     args = parser.parse_args()
  189.    
  190.     read_config(args.infile, args.outfile, args.key)
  191.  
  192. if __name__ == '__main__':
  193.     main()
RAW Paste Data