Guest User

Untitled

a guest
Feb 23rd, 2020
1,173
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.        
  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.        
  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.        
  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

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×