Theme Preview

TP-LINK VxWorks系统路由器固件升级文件格式(三)

由 李晓岚 在 2014年05月31日发表

TP-LINK VxWorks系统路由器固件升级文件格式(一)中,经过一定的逻辑推理分析,虽然分辨出了固件升级文件中的有效载荷部分,但这种方法对偏移0x00-0x5c的文件头信息却无能为力。想要知道这部分头信息的确切含义,只能依靠分析反汇编代码。

loc_800D9468:                            # CODE XREF: sysmgr_lib_fwupMain+38j
                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+9Cj
                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+110j
                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+13Cj
                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+150j
                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