TP-LINK VxWorks系统路由器固件升级文件格式(三)
由 李晓岚 在 2014年05月31日发表
在TP-LINK VxWorks系统路由器固件升级文件格式(一)中,经过一定的逻辑推理分析,虽然分辨出了固件升级文件中的有效载荷部分,但这种方法对偏移0x00-0x5c
的文件头信息却无能为力。想要知道这部分头信息的确切含义,只能依靠分析反汇编代码。
loc_800D9468: # CODE XREF: sysmgr_lib_fwupMain+38
lw $v0, 0($a0) # <------------ file size
beq $v0, $a1, loc_800D9490
lui $a1, 0x806E
la $a0, aErrorS05dFileS # "[Error](%s) %05d: file-size section is "...
la $a1, aSysmgr_lib_f_1 # "sysmgr_lib_fwupcheckHeader"
jal printf
li $a2, 0x93
j loc_800D942C
li $s1, 0xFFFFFFFE
# ---------------------------------------------------------------------------
loc_800D9490: # CODE XREF: sysmgr_lib_fwupMain+9C
addiu $s0, $a0, 4 # <------------ md5 hash
addiu $s2, $sp, 0x270+var_250
move $a1, $s0
li $a2, 0x10
jal memcpy
move $a0, $s2
lui $a1, 0x8089
move $a0, $s0
la $a1, md5key # <------------ md5 initial vector
li $a2, 0x10
jal memcpy
addiu $s1, $sp, 0x270+var_240
move $a1, $s0
addiu $a2, $s3, -4
jal md5_calc
move $a0, $s1
move $a0, $s2
move $a1, $s1
jal memcmp
li $a2, 0x10
beqz $v0, loc_800D9504
lui $a0, 0x807E
lui $a1, 0x806E
la $a0, aErrorS05dMd5Ch # "[Error](%s) %05d: md5 checksum is not c"...
la $a1, aSysmgr_lib_f_1 # "sysmgr_lib_fwupcheckHeader"
jal printf
li $a2, 0xB8
j loc_800D942C
li $s1, 0xFFFFFFFE
# ---------------------------------------------------------------------------
loc_800D9504: # CODE XREF: sysmgr_lib_fwupMain+110
jal sysmgr_cfg_getProductInfoFromNvram
addiu $a0, $sp, 0x270+var_230
bltz $v0, loc_800D9548
addiu $a0, $sp, 0x270+var_210
addiu $a1, $s4, 0x14 # <----------- vendor name
jal memcmp
li $a2, 0x40
beqz $v0, loc_800D9568
addiu $a0, $sp, 0x270+var_1B0
lui $a0, 0x807E
lui $a1, 0x806E
la $a0, aErrorS05dVendo # "[Error](%s) %05d: vendor full name is n"...
la $a1, aSysmgr_lib_f_1 # "sysmgr_lib_fwupcheckHeader"
jal printf
li $a2, 0xC7
j loc_800D942C
li $s1, 0xFFFFFFFD
# ---------------------------------------------------------------------------
loc_800D9548: # CODE XREF: sysmgr_lib_fwupMain+13C
lui $a0, 0x807E
lui $a1, 0x806E
la $a0, aErrorS05dGet_7 # "[Error](%s) %05d: get productInfo faile"...
la $a1, aSysmgr_lib_f_1 # "sysmgr_lib_fwupcheckHeader"
jal printf
li $a2, 0xBF
j loc_800D942C
li $s1, 0xFFFFFFFE
# ---------------------------------------------------------------------------
loc_800D9568: # CODE XREF: sysmgr_lib_fwupMain+150
addiu $a1, $s4, 0x54 # <---------- model id
jal memcmp
li $a2, 8
beqz $v0, loc_800D959C
addiu $s0, $s4, 0x5C
lui $a0, 0x807E
lui $a1, 0x806E
la $a0, aErrorS05dModel # "[Error](%s) %05d: model Id is not corre"...
la $a1, aSysmgr_lib_f_1 # "sysmgr_lib_fwupcheckHeader"
jal printf
li $a2, 0xCF
j loc_800D942C
li $s1, 0xFFFFFFFD
这段汇编代码比较简单,很容易看出开始的四个字节是大端uint32
类型,指出整个升级文件的大小。接下来16个字节是文件的MD5校验值。再接下来的64个字节制造商的名字。最后的八个字节是产品型号。
计算文件MD5校验值时,表示文件长度的头四个字节是不参与计算的。并且用'\x7a\x2b\x15\xed\x9b\x98\x59\x6d\xe5\x04\xab\x44\xac\x2a\x9f\x4e'
来填充MD5值占据的这16个字节,也可以看作是MD5 Hash的初始向量。
制造商的名字固定为64字节,不足使用0x00
填充。目前已知的取值为"TP-LINK_TECHNOLOGIES_CO."
。而产品型号则顾名思义,不需要多余的解释。
于是,升级文件的头可以如下定义:
struct FirmwareUpdateHeader{
uint32 fileSize;
uint8[0x10] md5;
uint8[0x40] vendorName;
uint8[0x08] modelId;
};
有了上述信息和部分(一)中分析,就可以将在部分(一)中提取到的分区文件,重新打包成固件升级文件。
./fw pack -r DIR FILE
DIR
是各个分区文件所在目录,目录中不能包含其它多余文件。FILE
是期望生成的固件升级文件名。
fw源代码,目前代码中仅包含WVR300V1的型号ID。
值得一提的是,名为"partition-table"
的分区,在升级文件中,必须位于第一位,其它分区对顺序不敏感。另外,位于偏移0x5c
的分区信息表的大小固定为0x800
。这一切都是由于下面这段代码决定的。
jal nm_lib_parsePtnIndexFile
addiu $a1, $s2, 0x804 # <--------
上述汇编代码,均来自于os-image
中,对os-image
进行加载内存地址定位,反汇编分析,即可知道其中大部分数据为zlib
压缩数据流,解压到特定地址后运行。解压后才是路由器实际运行的代码。uncompress-os-image.py可以用来从os-image
中定位压缩流并解压出实际代码。
./uncompress-os-image.py OS-IMAGE
至此,固件升级文件中的重要部分都一一分析完成了。
comments powered by Disqus