commit 79be228610c5e6ba890ee8881fdfaed8a2578c60 Author: Misty Date: Sat Jun 13 22:03:59 2020 +0800 Initial commit diff --git a/analysis/MiWifiFirmware.bt b/analysis/MiWifiFirmware.bt new file mode 100644 index 0000000..bdf3bd6 --- /dev/null +++ b/analysis/MiWifiFirmware.bt @@ -0,0 +1,47 @@ +//------------------------------------------------ +//--- 010 Editor v10.0 Binary Template +// +// File: MiWifiFirmware.bt +// Authors: Misty +// Version: 1.0.0 +// Purpose: Decode xiaomi router's file structure +// Category: +// File Mask: +// ID Bytes: 48 44 52 31 +// History: +//------------------------------------------------ + +struct MiRomHdr { + uint32 magic; + uint32 rsaLen; + uint32 crc; + short romType; // 0 - normal, 12 - ssh + short model; +} hdr; + +struct MiRomFile { + uint16 magic; + uint16 rsvd0; + uint32 flashaddr; + uint32 filesize; + uint16 mtdid; // /dev/mtd%d + uint16 unk5; + char name[32]; + char data[filesize]; +}; + +uint32 fileOffs[8]; + +local int i; +for (i = 0; i < 8; i++) { + if (fileOffs[i] != 0) { + FSeek(fileOffs[i]); + MiRomFile file; + } +} +FSeek(hdr.rsaLen); +struct MiRomSig { + uint32 sigsize; + char unk[12]; + char sigdata[sigsize]; +} sig; diff --git a/analysis/mkxqimage.i64 b/analysis/mkxqimage.i64 new file mode 100644 index 0000000..de9a076 Binary files /dev/null and b/analysis/mkxqimage.i64 differ diff --git a/analysis/mkxqimage_ori b/analysis/mkxqimage_ori new file mode 100644 index 0000000..c2f3ff5 Binary files /dev/null and b/analysis/mkxqimage_ori differ diff --git a/mkxq b/mkxq new file mode 100644 index 0000000..d87781a Binary files /dev/null and b/mkxq differ diff --git a/mkxqimage.c b/mkxqimage.c new file mode 100644 index 0000000..948e837 --- /dev/null +++ b/mkxqimage.c @@ -0,0 +1,1173 @@ +/* This file was generated by the Hex-Rays decompiler. + Copyright (c) 2007-2020 Hex-Rays + + Detected compiler: GNU C++ +*/ +//#include "defs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct __attribute__((aligned(4))) +{ + uint32_t magic; + uint32_t rsaLen; + uint32_t crc32sum; + uint16_t romType; + int16_t model; + uint32_t fileOffs[8]; +} MiRomHdr; + +typedef struct +{ + uint16_t magic; + uint16_t rsvd0; + uint32_t flashaddr; + uint32_t filesize; + uint16_t mtdid; + uint16_t unk5; + char name[32]; +} MiRomFile; + + + +//------------------------------------------------------------------------- +// Function declarations +void error_exit(); +size_t util_get_file_len(FILE *a1); +int util_check_model_idx(int16_t model_idx); +int main(int argc, const char **argv, const char **envp); +int for_each_file(FILE *f, int (*callback)(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata), void *userData); +int load_image(FILE *f, int disableVerify); +int command_verify_image(const char *filename); +int extract_normal_rom_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata); +int command_extract_file(const char *filename, const char *sshFile, int disableVerify, const char *fname, int outputToFile); +int flash_mtd_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata); +int command_mtd_flash(const char *filename, int needVerify); +int dump_file_desc(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata); +int command_list_files(const char *image, const char *a2); +int get_version_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata); +int command_get_image_version(const char *a1); +int command_get_ssh_key(); +unsigned int crc32_update(uint8_t *buf, int64_t size, unsigned int state); +uint32_t calc_crc32(FILE *f, int start, unsigned int size); +int64_t init_pkey(EVP_MD_CTX *ctx, RSA **pem, EVP_PKEY **ppkey, int isSsh); // idb +int j_verify_rsa(FILE *f, unsigned int start, unsigned int size, const unsigned char *sigbuf, unsigned int siglen, unsigned int isSsh); +int verify_rsa(FILE *f, int start, unsigned int size, const unsigned char *sigbuf, unsigned int siglen, unsigned int isSsh); +int64_t write_buf(int fd, void *buf, unsigned int size); +int open_and_erase_mtd(unsigned int mtdId); +int64_t calcMd5(unsigned char *a1, const char *a2); +int64_t transpostGuid(uint8_t *a1, char *outbuf); +int64_t get_ssh_key(); +int extract_ssh_rom_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata); + +//------------------------------------------------------------------------- +// Data declarations + +uint32_t crc32_table[256] = +{ + 0, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + + +char *model_nr[30] = +{ + "NULL", + "NULL", + "NULL", + "R1CM", + "R2D", + "R1CL", + "R2CM", + "R3", + "R3D", + "R3L", + "R3P", + "P01", + "R3A", + "R3G", + "R4", + "R4C", + "D01", + "R4A", + "R4CM", + "R4AC", + "R3GV2", + "R2600", + "R2100", + "RM2100", + "R3600", + "R1350", + "R2200", + "R2350", + "IR1200G", + "R1800" +}; // weak +int max_model_nr = 30; // weak + +//----- (0000000000401730) ---------------------------------------------------- +void error_exit() +{ + fwrite("Ouch!\n", 1u, 6u, stderr); + exit(1); +} + +//----- (00000000004017A4) ---------------------------------------------------- +size_t util_get_file_len(FILE *a1) +{ + size_t v3; // [xsp+28h] [xbp+28h] + int v4; // [xsp+2Ch] [xbp+2Ch] + + v4 = ftell(a1); + fseek(a1, 0LL, 2); + v3 = ftell(a1); + fseek(a1, v4, 0); + return v3; +} + +//----- (00000000004017F8) ---------------------------------------------------- +int util_check_model_idx(int16_t model_idx) +{ + int result; // w0 + char v3[8]; // [xsp+20h] [xbp+20h] BYREF + FILE *stream; // [xsp+28h] [xbp+28h] + + memset(v3, 0, 8); + stream = popen("cat /proc/xiaoqiang/model", "r"); + if ( stream ) + { + if ( fgets(v3, 8, stream) ) + { + pclose(stream); + if ( model_idx < max_model_nr ) + { + result = strcmp(v3, model_nr[model_idx]); + } + else + { + fprintf( + stderr, + "Illegal model: model_idx=%d,max_model_nr=%d \n", + (unsigned int)model_idx, + (unsigned int)max_model_nr); + result = -1; + } + } + else + { + fwrite("Failed to get model \n", 1u, 0x15u, stderr); + result = -1; + } + } + else + { + fwrite("Failed to run command\n", 1u, 0x16u, stderr); + result = -1; + } + return result; +} + +//----- (0000000000401918) ---------------------------------------------------- +int main(int argc, const char **argv, const char **envp) +{ + int v6; // [xsp+20h] [xbp+20h] + int ret; // [xsp+24h] [xbp+24h] + const char *filename; // [xsp+28h] [xbp+28h] + const char *a2; // [xsp+30h] [xbp+30h] + const char *file; // [xsp+38h] [xbp+38h] + int toStdout; // [xsp+44h] [xbp+44h] + int disableVerify; // [xsp+48h] [xbp+48h] + int mode; // [xsp+4Ch] [xbp+4Ch] + + mode = -1; + disableVerify = 0; + toStdout = 0; + file = 0LL; + a2 = 0LL; + filename = 0LL; + OPENSSL_add_all_algorithms_noconf(); + while ( 1 ) + { + v6 = getopt(argc, (char *const *)argv, "-v:x:w:c:V:Io:s:m:t:p:f:S:rn"); + if ( v6 == -1 ) + break; + switch ( v6 ) + { + case 'I': + mode = 6; + continue; + case 'S': + a2 = optarg; + continue; + case 'V': + mode = 5; + filename = optarg; + continue; + case 'c': + mode = 4; + filename = optarg; + continue; + case 'f': + if ( mode != 2 && mode != 4 ) + continue; + if ( file ) + { + fwrite("Multiple files specified\n", 1u, 0x19u, stderr); + return -22; + } + file = optarg; + break; + case 'n': + toStdout = 1; + continue; + case 'r': + disableVerify = 1; + continue; + case 'v': + mode = 1; + filename = optarg; + continue; + case 'w': + mode = 3; + filename = optarg; + continue; + case 'x': + mode = 2; + filename = optarg; + continue; + default: + error_exit(); + } + } + switch ( mode ) + { + case 1: + ret = command_verify_image(filename); + break; + case 2: + ret = command_extract_file(filename, a2, disableVerify, file, toStdout); + break; + case 3: + ret = command_mtd_flash(filename, disableVerify); + break; + case 4: + ret = command_list_files(filename, file); + break; + case 5: + ret = command_get_image_version(filename); + break; + case 6: + ret = command_get_ssh_key(); + break; + default: + error_exit(); + } + return ret; +} + +//----- (0000000000401BAC) ---------------------------------------------------- +int for_each_file(FILE *f, int (*callback)(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata), void *userData) +{ + MiRomFile filehdr; // [xsp+30h] [xbp+30h] BYREF + MiRomHdr buf; // [xsp+60h] [xbp+60h] BYREF + size_t readret; // [xsp+90h] [xbp+90h] + unsigned int off; // [xsp+94h] [xbp+94h] + int ret; // [xsp+98h] [xbp+98h] + int fileid; // [xsp+9Ch] [xbp+9Ch] + + ret = 0; + off = 0; + if ( !callback ) + return -1; + rewind(f); + readret = fread(&buf, 1u, 0x30u, f); + if ( ferror(f) ) + return 0xFFFFFFFB; + for ( fileid = 0; fileid <= 7; ++fileid ) + { + off = buf.fileOffs[fileid]; + if ( !off ) + break; + ret = fseek(f, off, 0); + if ( ret ) + break; + readret = fread(&filehdr, 1u, 0x30u, f); + if ( readret != 48 ) + return -5; + ret = callback(&buf, (unsigned char)fileid, &filehdr, f, userData); + if ( ret ) + return ret; + } + return ret; +} + +//----- (0000000000401D08) ---------------------------------------------------- +int load_image(FILE *f, int disableVerify) +{ + unsigned char sigbuf[4096]; // [xsp+20h] [xbp+20h] BYREF + size_t sigsize[4]; // [xsp+1020h] [xbp+1020h] BYREF + MiRomHdr hdr; // [xsp+1030h] [xbp+1030h] BYREF + uint32_t crcret; // [xsp+1064h] [xbp+1064h] + short model_idx; // [xsp+106Ah] [xbp+106Ah] + size_t ret; // [xsp+106Ch] [xbp+106Ch] + size_t len; // [xsp+1070h] [xbp+1070h] + uint16_t v12; // [xsp+1076h] [xbp+1076h] + unsigned int isSsh; // [xsp+1078h] [xbp+1078h] + int verify_ret; // [xsp+107Ch] [xbp+107Ch] + + memset(sigbuf, 0, sizeof(sigbuf)); + v12 = -1; + verify_ret = 0; + len = 0; + isSsh = 0; + rewind(f); + ret = fread(&hdr, 1u, 0x30u, f); + if ( ret != 0x30 ) + return 0xFFFFFFFB; + if ( hdr.magic != '1RDH' ) + { + fwrite("Invalid image block\n", 1u, 0x14u, stderr); + return -22; + } + model_idx = hdr.model; + if ( util_check_model_idx(hdr.model) ) + { + fwrite("Model mismatch\n", 1u, 0xFu, stderr); + return -22; + } + len = util_get_file_len(f); + rewind(f); + crcret = calc_crc32(f, 12, len - 12); + if ( hdr.crc32sum != crcret ) + { + fwrite("Image checksum is invalid\n", 1u, 0x1Au, stderr); + return -22; + } + v12 = hdr.romType; + if ( hdr.romType == 12 ) + isSsh = 1; + if ( disableVerify ) + { + verify_ret = 0; + } + else + { + fseek(f, hdr.rsaLen, SEEK_SET); + ret = fread(sigsize, 1u, 0x10u, f); + if ( ret != 16 ) + return -5; + ret = fread(sigbuf, 1u, sigsize[0], f); + if ( sigsize[0] != ret ) + return -5; + rewind(f); + verify_ret = j_verify_rsa(f, 12u, hdr.rsaLen - 12, sigbuf, sigsize[0], isSsh); + } + if ( !verify_ret ) + return 0; + fwrite("Image verify failed, not formal image\n", 1u, 0x26u, stderr); + return -22; +} + +//----- (0000000000401FBC) ---------------------------------------------------- +int command_verify_image(const char *filename) +{ + FILE *stream; // [xsp+20h] [xbp+20h] + int v4; // [xsp+2Ch] [xbp+2Ch] + + stream = fopen(filename, "r"); + if ( stream ) + { + v4 = load_image(stream, 0); + fclose(stream); + } + else + { + fprintf(stderr, "can not open \"%s\" for reading\n", filename); + v4 = -2; + } + return v4; +} + +//----- (0000000000402048) ---------------------------------------------------- +int extract_normal_rom_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata) +{ + int64_t v5; // x0 + size_t v9; // [xsp+4Ch] [xbp+4Ch] + void *ptr; // [xsp+50h] [xbp+50h] + char *fname; // [xsp+58h] [xbp+58h] + int v13; // [xsp+6Ch] [xbp+6Ch] + size_t chunksize; // [xsp+70h] [xbp+70h] + uint32_t filesize; // [xsp+74h] [xbp+74h] + FILE *s; // [xsp+78h] [xbp+78h] + + v13 = 0; + fname = *(char **)userdata; + if ( fildhdr->filesize <= 7 || fildhdr->magic != 0xBABE ) + return 0; + if ( fname && strcmp(fildhdr->name, fname) ) + return 0; + if ( *((uint32_t *)userdata + 2) ) + { + s = (FILE *)stdout; + } + else + { + s = fopen(fildhdr->name, "w"); + if ( !s ) + { + fprintf(stderr, "can not open \"%s\" for writing\n", fildhdr->name); + return -5; + } + } + ptr = malloc(0x10000u); + if ( ptr ) + { + filesize = fildhdr->filesize; + while ( filesize ) + { + v9 = fread(ptr, 1u, 0x10000u, f); + if ( filesize < v9 ) + { + chunksize = filesize; + v5 = fwrite(ptr, filesize, 1u, s); + } + else + { + chunksize = v9; + v5 = fwrite(ptr, v9, 1u, s); + } + if ( !v5 || fflush(s) ) + { + fwrite("fwrite failed\n", 1u, 0xEu, stderr); + v13 = -5; + goto LABEL_26; + } + filesize -= chunksize; + if ( feof(f) && filesize ) + { + fwrite("File too short while required write length too long\n", 1u, 0x34u, stderr); + v13 = -5; + goto LABEL_26; + } + } + if ( fname ) + v13 = 1; +LABEL_26: + free(ptr); + } + else + { + fwrite("malloc failed\n", 1u, 0xEu, stderr); + v13 = -12; + } + if ( !*((uint32_t *)userdata + 2) ) + fclose(s); + return v13; +} +// 414DC8: using guessed type int64_t stdout; + +//----- (00000000004022F8) ---------------------------------------------------- +int command_extract_file(const char *filename, const char *sshFile, int disableVerify, const char *fname, int outputToFile) +{ + void *v10[2]; // [xsp+38h] [xbp+38h] BYREF + MiRomHdr hdr; // [xsp+48h] [xbp+48h] BYREF + size_t v12; // [xsp+78h] [xbp+78h] + uint16_t v13; // [xsp+7Eh] [xbp+7Eh] + FILE *stream; // [xsp+80h] [xbp+80h] + int ret; // [xsp+8Ch] [xbp+8Ch] + + ret = 0; + v13 = 0; + v10[1] = (void *)outputToFile; + v10[0] = fname; + stream = fopen(filename, "r"); + if ( stream ) + { + ret = load_image(stream, disableVerify); + if ( !ret ) + { + rewind(stream); + v12 = fread(&hdr, 1u, 0x30u, stream); + if ( v12 == 48 ) + { + v13 = hdr.romType; + if ( hdr.romType == 12 ) + ret = for_each_file(stream, extract_ssh_rom_callback, (void *)sshFile); + else + ret = for_each_file(stream, extract_normal_rom_callback, v10); + if ( fname ) + { + if ( ret <= 0 ) + { + if ( !ret ) + ret = -2; + } + else + { + ret = 0; + } + } + } + else + { + ret = -5; + } + } + fclose(stream); + } + else + { + fprintf(stderr, "can not open \"%s\" for reading\n", filename); + ret = -2; + } + return ret; +} + +//----- (0000000000402484) ---------------------------------------------------- +int flash_mtd_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata) +{ + unsigned int v8; // [xsp+44h] [xbp+44h] + void *buf; // [xsp+48h] [xbp+48h] + int fd; // [xsp+50h] [xbp+50h] + int v11; // [xsp+54h] [xbp+54h] + unsigned int size; // [xsp+58h] [xbp+58h] + unsigned int filesize; // [xsp+5Ch] [xbp+5Ch] + + v11 = 0; + if ( fildhdr->filesize <= 7 || fildhdr->magic != 0xBABE ) + return v11; + if ( fildhdr->mtdid == 0xFFFF ) + { + printf("Skip offset[%hhu]\n", (unsigned char)fileid); + } + else + { + fd = open_and_erase_mtd(fildhdr->mtdid); + buf = malloc(0x10000u); + if ( buf ) + { + filesize = fildhdr->filesize; + while ( filesize ) + { + v8 = fread(buf, 1u, 0x10000u, f); + if ( filesize < v8 ) + { + size = filesize; + write_buf(fd, buf, filesize); + } + else + { + size = v8; + write_buf(fd, buf, v8); + } + filesize -= size; + if ( feof(f) && filesize ) + { + fwrite("File too short while required write length too long\n", 1u, 0x34u, stderr); + free(buf); + v11 = -5; + break; + } + } + } + else + { + fwrite("malloc failed\n", 1u, 0xEu, stderr); + v11 = -12; + } + close(fd); + } + return v11; +} + +//----- (0000000000402628) ---------------------------------------------------- +int command_mtd_flash(const char *filename, int needVerify) +{ + FILE *stream; // [xsp+20h] [xbp+20h] + int v6; // [xsp+2Ch] [xbp+2Ch] + + stream = fopen(filename, "r"); + if ( stream ) + { + v6 = load_image(stream, needVerify); + if ( !v6 ) + { + system("nvram set flashing=1"); + system("nvram commit"); + v6 = for_each_file(stream, flash_mtd_callback, 0LL); + if ( !v6 ) + { + system("nvram unset flashing"); + system("nvram commit"); + fwrite("system will reboot\n", 1u, 0x13u, stderr); + reboot(0x1234567); + } + } + fclose(stream); + } + else + { + fprintf(stderr, "can not open \"%s\" for reading\n", filename); + v6 = -2; + } + return v6; +} + +//----- (0000000000402754) ---------------------------------------------------- +int dump_file_desc(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata) +{ + if ( !(uint8_t)fileid ) + { + if ( hdr->magic != '1RDH' ) + { + printf("Invalid MAGIC 0x%x, 0x%x\n", hdr->magic, 827475016LL); + return 0xFFFFFFEA; + } + printf("version %d, file type: %d\n", hdr->model, hdr->romType); + } + if ( userdata && strcmp(fildhdr->name, (const char *)userdata) ) + return 0; + printf("Segment %d: Offset 0x%x\n", (unsigned char)fileid, hdr->fileOffs[(unsigned char)fileid]); + if ( fildhdr->magic == 0xBABE ) + { + printf("Filename %s\n", fildhdr->name); + printf("Flash addr = 0x%x, length = 0x%x, partition = %d\n", fildhdr->flashaddr, fildhdr->filesize, fildhdr->mtdid); + if ( userdata ) + return 1; + } + else + { + printf("Invalid sub MAGIC,magic:0x%x le_mag:0x%x rsvd0:0x%x\n", fildhdr->magic, fildhdr->magic, fildhdr->rsvd0); + } + return 0; +} + +//----- (00000000004028E0) ---------------------------------------------------- +int command_list_files(const char *image, const char *a2) +{ + FILE *stream; // [xsp+20h] [xbp+20h] + int v6; // [xsp+2Ch] [xbp+2Ch] + + stream = fopen(image, "r"); + if ( stream ) + { + v6 = for_each_file(stream, dump_file_desc, (void *)a2); + if ( a2 ) + { + if ( v6 <= 0 ) + { + if ( !v6 ) + v6 = -2; + } + else + { + v6 = 0; + } + } + fclose(stream); + } + else + { + fprintf(stderr, "can not open \"%s\" for reading\n", image); + v6 = -2; + } + return v6; +} + +//----- (00000000004029B0) ---------------------------------------------------- +int get_version_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata) +{ + char *ptr; // [xsp+50h] [xbp+50h] + uint32_t size; // [xsp+58h] [xbp+58h] + int size_4; // [xsp+5Ch] [xbp+5Ch] + + size_4 = 0; + if ( fildhdr->filesize <= 7 || fildhdr->magic != 47806 ) + return 0; + size = fildhdr->filesize; + if ( strcmp(fildhdr->name, "xiaoqiang_version") ) + return size_4; + if ( malloc(0x10000u) && (ptr = (char *)malloc(size)) != 0LL ) + { + if ( fread(ptr, 1u, size, f) == size ) + { + printf("%s", ptr); + size_4 = 1; + } + else + { + size_4 = -5; + } + free(ptr); + } + else + { + fwrite("malloc failed\n", 1u, 0xEu, stderr); + size_4 = -12; + } + return size_4; +} + +//----- (0000000000402B20) ---------------------------------------------------- +int command_get_image_version(const char *a1) +{ + FILE *stream; // [xsp+20h] [xbp+20h] + int v4; // [xsp+2Ch] [xbp+2Ch] + + stream = fopen(a1, "r"); + if ( stream ) + { + v4 = for_each_file(stream, get_version_callback, 0LL); + if ( v4 <= 0 ) + { + if ( !v4 ) + v4 = -2; + } + else + { + v4 = 0; + } + fclose(stream); + } + else + { + fprintf(stderr, "can not open \"%s\" for reading\n", a1); + v4 = -2; + } + return v4; +} + +//----- (0000000000402BE0) ---------------------------------------------------- +int command_get_ssh_key() +{ + get_ssh_key(); + return 0; +} + +//----- (0000000000402C78) ---------------------------------------------------- +unsigned int crc32_update(uint8_t *buf, int64_t size, unsigned int state) +{ + while ( size ) + { + state = crc32_table[(unsigned char)(*buf ^ state)] ^ (state >> 8); + --size; + ++buf; + } + return state; +} + +//----- (0000000000402CF4) ---------------------------------------------------- +uint32_t calc_crc32(FILE *f, int start, unsigned int size) +{ + uint32_t result; // w0 + unsigned int v6; // [xsp+24h] [xbp+24h] + uint8_t *ptr; // [xsp+28h] [xbp+28h] + unsigned int chunk_size; // [xsp+34h] [xbp+34h] + unsigned int crc; // [xsp+3Ch] [xbp+3Ch] + + crc = -1; + ptr = malloc(0x10000u); + if ( ptr ) + { + fseek(f, start, 0); + while ( size ) + { + v6 = fread(ptr, 1u, 0x10000u, f); + if ( size < v6 ) + chunk_size = size; + else + chunk_size = v6; + crc = crc32_update(ptr, chunk_size, crc); + size -= chunk_size; + if ( feof(f) && size ) + { + fwrite("File too short while required CRC length too long\n", 1u, 0x32u, stderr); + return 1; + } + } + free(ptr); + rewind(f); + result = crc; + } + else + { + fwrite("malloc failed\n", 1u, 0xEu, stderr); + result = 1; + } + return result; +} + +//----- (0000000000402E4C) ---------------------------------------------------- +int64_t init_pkey(EVP_MD_CTX *ctx, RSA **pem, EVP_PKEY **ppkey, int isSsh) +{ + int64_t result; // x0 + const EVP_MD *algo; // x0 + FILE *stream; // [xsp+38h] [xbp+38h] + + if ( isSsh == 1 ) + stream = fopen("/usr/share/xiaoqiang/public_ssh.pem", "rb"); + else + stream = fopen("/usr/share/xiaoqiang/public.pem", "rb"); + if ( stream ) + { + *pem = PEM_read_RSA_PUBKEY(stream, 0LL, 0LL, 0LL); + if ( *pem ) + { + fclose(stream); + *ppkey = EVP_PKEY_new(); + if ( *ppkey ) + { + if ( EVP_PKEY_set1_RSA(*ppkey, *pem) == 1 ) + { + EVP_MD_CTX_init(ctx); + algo = EVP_sha1(); + if ( EVP_DigestInit_ex(ctx, algo, 0LL) == 1 ) + { + result = 0LL; + } + else + { + fwrite("error EVP_VerfyInit_ex\n", 1u, 0x17u, stderr); + RSA_free(*pem); + EVP_PKEY_free(*ppkey); + result = 0xFFFFFFFFLL; + } + } + else + { + fwrite("error EVP_PKEY_st1_RSA\n", 1u, 0x17u, stderr); + RSA_free(*pem); + EVP_PKEY_free(*ppkey); + result = 0xFFFFFFFFLL; + } + } + else + { + fwrite("error EVP_PEKY_new\n", 1u, 0x13u, stderr); + RSA_free(*pem); + result = 0xFFFFFFFFLL; + } + } + else + { + fwrite("error PEM_read_RSAPublicKey\n", 1u, 0x1Cu, stderr); + fclose(stream); + result = 0xFFFFFFFFLL; + } + } + else + { + fwrite("error fopen public key \n", 1u, 0x18u, stderr); + result = 0xFFFFFFFFLL; + } + return result; +} + +//----- (000000000040307C) ---------------------------------------------------- +int j_verify_rsa(FILE *f, unsigned int start, unsigned int size, const unsigned char *sigbuf, unsigned int siglen, unsigned int isSsh) +{ + return verify_rsa(f, start, size, sigbuf, siglen, isSsh); +} + +//----- (00000000004030C0) ---------------------------------------------------- +int verify_rsa(FILE *f, int start, unsigned int size, const unsigned char *sigbuf, unsigned int siglen, unsigned int isSsh) +{ + int result; // w0 + EVP_PKEY *pkey; // [xsp+30h] [xbp+30h] BYREF + RSA *pem; // [xsp+38h] [xbp+38h] BYREF + EVP_MD_CTX ctx; // [xsp+40h] [xbp+40h] BYREF + unsigned int v15; // [xsp+74h] [xbp+74h] + void *buf; // [xsp+78h] [xbp+78h] + size_t cnt; // [xsp+84h] [xbp+84h] + unsigned int v18; // [xsp+88h] [xbp+88h] + int v19; // [xsp+8Ch] [xbp+8Ch] + + v18 = size; + cnt = 0; + pkey = 0LL; + buf = malloc(0x10000u); + if ( buf ) + { + v19 = init_pkey(&ctx, &pem, &pkey, isSsh); + if ( v19 ) + { + fwrite("malloc failed\n", 1u, 0xEu, stderr); + result = 1; + } + else + { + fseek(f, start, 0); + while ( v18 ) + { + v15 = fread(buf, 1u, 0x10000u, f); + if ( v18 < v15 ) + cnt = v18; + else + cnt = v15; + if ( EVP_DigestUpdate(&ctx, buf, cnt) != 1 )// EVP_VerifyUpdate + { + fwrite("error EVP_VerifyUpdate\n", 1u, 0x17u, stderr); + v19 = 1; + goto finish; + } + v18 -= cnt; + if ( feof(f) && v18 ) + { + fwrite("File too short while required RSA length too long\n", 1u, 0x32u, stderr); + v19 = 1; + goto finish; + } + } + if ( EVP_VerifyFinal(&ctx, sigbuf, siglen, pkey) == 1 ) + { + v19 = 0; + } + else + { + fwrite("error EVP_VerifyFinal\n", 1u, 0x16u, stderr); + v19 = 1; + } +finish: + rewind(f); + free(buf); + RSA_free(pem); + EVP_PKEY_free(pkey); + EVP_MD_CTX_cleanup(&ctx); + result = v19; + } + } + else + { + fwrite("malloc failed\n", 1u, 0xEu, stderr); + result = 1; + } + return result; +} + +//----- (0000000000403318) ---------------------------------------------------- +int64_t write_buf(int fd, void *buf, unsigned int size) +{ + signed int i; // [xsp+2Ch] [xbp+2Ch] + + for ( i = 0; i < (int)size; i += write(fd, (char *)buf + i, size - i) ) + ; + return size; +} + +//----- (0000000000403394) ---------------------------------------------------- +int open_and_erase_mtd(unsigned int mtdId) +{ + char v3[16]; // [xsp+20h] [xbp+20h] BYREF + unsigned int i; // [xsp+30h] [xbp+30h] BYREF + unsigned int v5; // [xsp+34h] [xbp+34h] + char v6[8]; // [xsp+38h] [xbp+38h] BYREF + unsigned int v7; // [xsp+40h] [xbp+40h] + unsigned int v8; // [xsp+44h] [xbp+44h] + int fd; // [xsp+5Ch] [xbp+5Ch] + + memset(v3, 0, sizeof(v3)); + sprintf(v3, "/dev/mtd%d", mtdId); + printf("target mtd %s\n", v3); + fd = open(v3, 2); + ioctl(fd, 0x80204D01uLL, v6); + printf("MTD Type: %x\nMTD total size: %x bytes\nMTD erase size: %x bytes\n", (unsigned char)v6[0], v7, v8); + v5 = v8; + printf("Beging Eraseing Block %#x\n", i); + for ( i = 0; i < v7; i += v5 ) + { + ioctl(fd, 0x40084D06uLL, &i); + ioctl(fd, 0x40084D02uLL, &i); + } + lseek(fd, 0LL, 0); + puts("End..."); + return fd; +} + +//----- (00000000004034BC) ---------------------------------------------------- +int64_t calcMd5(unsigned char *a1, const char *a2) +{ + size_t v2; // w0 + MD5_CTX v6; // [xsp+20h] [xbp+20h] BYREF + + if ( MD5_Init(&v6) ) + { + v2 = strlen(a2); + if ( MD5_Update(&v6, a2, v2) ) + { + if ( MD5_Final(a1, &v6) ) + return 0LL; + puts("MD5_Final error"); + } + else + { + puts("MD5_Update error"); + } + } + else + { + puts("MD5_Init error"); + } + return 0xFFFFFFFFLL; +} + +//----- (000000000040355C) ---------------------------------------------------- +int64_t transpostGuid(uint8_t *a1, char *outbuf) +{ + char *v2; // x0 + int64_t result; // x0 + char mat[8][32]; // [xsp+28h] [xbp+28h] BYREF + size_t n; // [xsp+12Ch] [xbp+12Ch] + char *curRow; // [xsp+130h] [xbp+130h] + int rowI; // [xsp+138h] [xbp+138h] + unsigned int row; // [xsp+13Ch] [xbp+13Ch] + char a9[32]; // [xsp+140h] [xbp+140h] BYREF + + row = 0; + rowI = 0; + n = 0; + memset(mat, 0, sizeof(mat)); + while ( *a1 ) + { + if ( *a1 == '-' ) + { + a9[32 * row++ - 0x118 + rowI] = 0; + rowI = 0; + } + else + { + a9[32 * row - 0x118 + rowI++] = *a1; + } + ++a1; + } + a9[32 * row - 0x118 + rowI] = 0; + curRow = outbuf; + while ( 1 ) + { + result = row; + if ( (row & 0x80000000) != 0 ) + break; + n = strlen(mat[row]); + strncpy(curRow, mat[row], n); + curRow += (int)n; + if ( row ) + { + v2 = curRow++; + *v2 = '-'; + } + else + { + *curRow = 0; + } + --row; + } + return result; +} + +//----- (00000000004036EC) ---------------------------------------------------- +int64_t get_ssh_key() +{ + char magic[100]; // [xsp+EA8h] [xbp+18h] BYREF + char snStr[100]; // [xsp+F10h] [xbp+80h] BYREF + char Sn[100]; // [xsp+F78h] [xbp+E8h] BYREF + unsigned char md5Output[16]; // [xsp+FE0h] [xbp+150h] BYREF + FILE *stream; // [xsp+FF0h] [xbp+160h] + int i; // [xsp+FFCh] [xbp+16Ch] + + memset(md5Output, 0, 16); + memset(Sn, 0, 100); + memset(snStr, 0, 100); + memset(magic, 0, 100); + stream = popen("nvram get SN", "r"); + if ( !stream ) + return puts("Failed to run command"); + while ( fgets(Sn, 100, stream) ) + sscanf(Sn, "%s", snStr); + pclose(stream); + transpostGuid("d44fb0960aa0-a5e6-4a30-250f-6d2df50a", magic); + sprintf(Sn, "%s%s", snStr, magic); + calcMd5(md5Output, Sn); + memset(Sn, 0, sizeof(Sn)); + for ( i = 0; i <= 3; ++i ) + printf("%x%x", (md5Output[i] >> 4) & 0xF, md5Output[i] & 0xF); + return puts(Sn); +} + +//----- (00000000004038A4) ---------------------------------------------------- +int extract_ssh_rom_callback(MiRomHdr *hdr, int64_t fileid, MiRomFile *fildhdr, FILE *f, void *userdata) +{ + return 1; +} + +// nfuncs=134 queued=28 decompiled=28 lumina nreq=0 worse=0 better=0 +// ALL OK, 28 function(s) have been successfully decompiled