├── README.md ├── minifs.png └── minifs_decompress.py /README.md: -------------------------------------------------------------------------------- 1 | # MINIFS-Decompression 2 | The Decompression tool for Vxworks MINIFS filesystem. 3 | 4 | ## USAGE 5 | 6 | ```bash 7 | python minifs_decompression.py [target_firmware] 8 | ``` 9 | 10 | The example of Mercury router firmware: 11 | 12 | ```bash 13 | $ python minifs_decompress.py ./MW305R.BIN 14 | 1173+0 records in 15 | 1173+0 records out 16 | 1173 bytes transferred in 0.006129 secs (191392 bytes/sec) 17 | 58+0 records in 18 | 58+0 records out 19 | 58 bytes transferred in 0.000298 secs (194616 bytes/sec) 20 | 2464+0 records in 21 | 2464+0 records out 22 | 2464 bytes transferred in 0.012085 secs (203890 bytes/sec) 23 | 127+0 records in 24 | 127+0 records out 25 | 127 bytes transferred in 0.000661 secs (192163 bytes/sec) 26 | 419+0 records in 27 | 419+0 records out 28 | 419 bytes transferred in 0.002342 secs (178908 bytes/sec) 29 | 1483+0 records in 30 | 1483+0 records out 31 | 1483 bytes transferred in 0.007509 secs (197497 bytes/sec) 32 | 10316+0 records in 33 | 10316+0 records out 34 | ``` 35 | 36 | The result of decompress: 37 | 38 | ```bash 39 | $ tree 40 | . 41 | ├── conf 42 | │   ├── mcbDesc.bin 43 | │   ├── modelDesc.bin 44 | │   ├── oem.txt 45 | │   ├── priv-key.pem 46 | │   └── server-cert.pem 47 | ├── minifs_decompress.py 48 | └── web 49 | ├── common 50 | │   ├── AccessCtrl.htm 51 | │   ├── Advance.htm 52 | │   ├── Basic.htm 53 | │   ├── BasicDynamicIp.htm 54 | │   ├── BasicEptManagement.htm 55 | │   ├── BasicHead.htm 56 | │   ├── BasicMenu.htm 57 | │   ├── BasicNetWork.htm 58 | │   ├── BasicPPPoE.htm 59 | │   ├── BasicStaticIp.htm 60 | │   ├── BasicWireless.htm 61 | │   ├── Content.htm 62 | │   ├── DHCPServer.htm 63 | │   ├── DMZCfg.htm 64 | │   ├── DateTimeCfg.htm 65 | │   ├── DdnsCfg.htm 66 | │   ├── Diagnostic.htm 67 | │   ├── DynamicIp.htm 68 | │   ├── Foot.htm 69 | │   ├── Help.htm 70 | │   ├── IPMACBind.htm 71 | │   ├── Index.htm 72 | │   ├── LanCfg.htm 73 | │   ├── Login.htm 74 | │   ├── LoginChgPwd.htm 75 | │   ├── MacClone.htm 76 | │   ├── ManageSettingUp.htm 77 | │   ├── PPPoE.htm 78 | │   ├── ParentControl.htm 79 | │   ├── PhoneBasicNetWork.htm 80 | │   ├── PhoneBasicWireless.htm 81 | │   ├── PhoneDynamicIp.htm 82 | │   ├── PhoneEquipManage.htm 83 | │   ├── PhoneEquipManageDetail.htm 84 | │   ├── PhoneIndex.htm 85 | │   ├── PhoneLogin.htm 86 | │   ├── PhoneLoginChgPwd.htm 87 | │   ├── PhoneMenu.htm 88 | │   ├── PhoneOtherSet.htm 89 | │   ├── PhoneOtherSetChgPwd.htm 90 | │   ├── PhonePPPoE.htm 91 | │   ├── PhoneStaticIp.htm 92 | │   ├── PhoneWizard.htm 93 | │   ├── PhoneWizardDynamicIp.htm 94 | │   ├── PhoneWizardEnd.htm 95 | │   ├── PhoneWizardPPPoE.htm 96 | │   ├── PhoneWizardStaticIp.htm 97 | │   ├── PhoneWizardWireless.htm 98 | │   ├── RouteTable.htm 99 | │   ├── StaticIp.htm 100 | │   ├── SysBakNRestore.htm 101 | │   ├── SysChangeLgPwd.htm 102 | │   ├── SysReboot.htm 103 | │   ├── SysReset.htm 104 | │   ├── SysUpgrade.htm 105 | │   ├── SystemLog.htm 106 | │   ├── UpnpCfg.htm 107 | │   ├── VirtualServerCfg.htm 108 | │   ├── WanCfg.htm 109 | │   ├── Wizard.htm 110 | │   ├── WizardDynamicIp.htm 111 | │   ├── WizardEnd.htm 112 | │   ├── WizardPPPoE.htm 113 | │   ├── WizardStaticIp.htm 114 | │   ├── WizardWireless.htm 115 | │   ├── WlanGuestNetWorkCfg.htm 116 | │   ├── WlanNetwork.htm 117 | │   ├── WlanWDSCfg.htm 118 | │   ├── WlanWDSCfgEnd.htm 119 | │   ├── WlanWDSCfgFirst.htm 120 | │   ├── WlanWDSCfgFive.htm 121 | │   ├── WlanWDSCfgFour.htm 122 | │   ├── WlanWDSCfgSecond.htm 123 | │   └── WlanWDSCfgThird.htm 124 | ├── dynaform 125 | │   ├── DataGrid.css 126 | │   ├── DataGrid.js 127 | │   ├── class.css 128 | │   ├── class.js 129 | │   ├── macFactory.js 130 | │   ├── menu.css 131 | │   ├── menu.js 132 | │   ├── phoneClass.css 133 | │   └── phoneClass.js 134 | ├── images 135 | │   ├── QRcode_me.png 136 | │   ├── advance_me.png 137 | │   ├── backwardBtn_me.png 138 | │   ├── basic_me.png 139 | │   ├── circleLeft_me.png 140 | │   ├── circleRight_me.png 141 | │   ├── detailArrow_me.png 142 | │   ├── equipMng_me.png 143 | │   ├── errorPic_me.png 144 | │   ├── icon_me.ico 145 | │   ├── icon_wifi_me.png 146 | │   ├── logo_me.png 147 | │   ├── mngPwd_me.png 148 | │   ├── netSet_me.png 149 | │   ├── otherSet_me.png 150 | │   ├── rightIcon_me.png 151 | │   ├── wanDetecting_me.gif 152 | │   ├── wdsDetect_me.gif 153 | │   ├── wifiSet_me.png 154 | │   ├── wzdWarningWhite_me.png 155 | │   └── wzd_me.png 156 | ├── language 157 | │   └── cn 158 | │   ├── error.js 159 | │   └── str.js 160 | ├── lib 161 | │   ├── DM.js 162 | │   ├── Quary.js 163 | │   ├── ajax.js 164 | │   ├── jquery-1.10.1.min.js 165 | │   ├── model.js 166 | │   └── verify.js 167 | └── upnp 168 | ├── ifc.xml 169 | ├── igd.xml 170 | ├── ipc.xml 171 | ├── l3f.xml 172 | ├── wfa.xml 173 | └── wps.xml 174 | 175 | 9 directories, 124 files 176 | ``` 177 | 178 | 179 | - The file items displayed in 010Editor: 180 | 181 | ![](./minifs.png) 182 | 183 | ## Reference 184 | 185 | 1. http://patentlib.net/mnt/sipo/A/20200818/5/CN102020000408790CN00001115525110AFULZH20200818CN00V/ 186 | -------------------------------------------------------------------------------- /minifs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/H4lo/MINIFS-Decompression/fc6f3de12c636f57b25e6add0f981f0a42d90bed/minifs.png -------------------------------------------------------------------------------- /minifs_decompress.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import os,sys,re 3 | import struct 4 | from pathlib import Path 5 | 6 | 7 | target_firmware = sys.argv[1] 8 | if(not target_firmware): 9 | exit(-1) 10 | 11 | def p32(data): 12 | return struct.pack(">I",data) 13 | 14 | def u32(data): 15 | '''Big endian''' 16 | return struct.unpack(">I",data)[0] 17 | 18 | def read_file_offset_name(path): 19 | _fd = open(path,"rb") 20 | if(not _fd): 21 | print('[-] Open target firmware failed!') 22 | exit(-1) 23 | content = _fd.read() 24 | mini_fs_offset = content.find("MINIFS") 25 | if(not mini_fs_offset): 26 | print("[-] The rootfs of target firmware is not MINIFS!") 27 | exit(-1) 28 | first_place = content.find("\x5A\x00\x00\x80") 29 | if(not first_place): 30 | print('[-] Not found the compression data!') 31 | exit(-1) 32 | compress_offset_list = [hex(i.start()) for i in re.finditer("\x5A\x00\x00\x80",content)] 33 | 34 | filenames_start = mini_fs_offset + 20 35 | 36 | file_list = [] 37 | idx = 0 38 | while(True): 39 | obj = [] 40 | filename_start = filenames_start+idx*88 41 | if(content[filename_start+8] == '/'): 42 | 43 | file_size = content[filename_start:filename_start+4] 44 | file_offset = hex(u32(content[filename_start+4:filename_start+8])) 45 | file_name = content[filename_start+8:filename_start+88].replace("\x00","") 46 | 47 | obj.append(file_offset) 48 | obj.append(file_name) 49 | file_list.append(obj) 50 | else: 51 | '''file end''' 52 | break 53 | idx += 1 54 | 55 | _fd.close() 56 | return first_place,content,file_list,compress_offset_list 57 | 58 | def create_dictionary(file_list): 59 | try: 60 | for obj in file_list: 61 | path = obj[1] 62 | if(path[0] == '/'): 63 | dic = Path(path).parent 64 | os.system("mkdir -p .%s"%(dic)) 65 | return True 66 | except: 67 | print('[-] Create dictionary failed!') 68 | exit(-1) 69 | 70 | def write_file(start_addr,file_content,file_list,compress_offset_list): 71 | try: 72 | for obj in file_list: 73 | offset = obj[0] 74 | file_path = obj[1] 75 | for idx in range(len(compress_offset_list)): 76 | #print(compress_offset_list[idx]) 77 | '''检查压缩数据的偏移和MINIFS中文件项的偏移是否相同''' 78 | if (start_addr+eval(offset) == eval(compress_offset_list[idx])): 79 | 80 | compress_size = eval(compress_offset_list[idx+1])-eval(compress_offset_list[idx]) 81 | 82 | dd_command = "dd if=%s of=.%s.bak bs=1 skip=%s count=%s"%(target_firmware,file_path,eval(compress_offset_list[idx]),compress_size) 83 | os.system(dd_command) 84 | 85 | lzma_command = "lzma -kdc .%s.bak> .%s;rm .%s.bak"%(file_path,file_path,file_path) 86 | os.system(lzma_command) 87 | else: 88 | #print("[*] Can not found the offset (%s) in firmware, pass."%(start_addr+eval(offset))) 89 | pass 90 | 91 | return True 92 | except: 93 | print("[-] Write file failed!") 94 | exit(-1) 95 | 96 | 97 | first_place,file_content,file_list,compress_offset_list = read_file_offset_name(target_firmware) 98 | 99 | if(create_dictionary(file_list)): 100 | write_file(first_place,file_content,file_list,compress_offset_list) 101 | --------------------------------------------------------------------------------