前文中虽然成功的运行了UBoot,但是因为内核损坏,依然无法正常启动。想要用UBoot刷写Flash,就必须进入UBoot的命令行模式,一般UBoot在引导过程中,会有短暂的时间让用户按下某些指定的按键来中断自动引导。可是之前运行的UBoot并没有这样的提示,感觉可能是华为禁用了UBoot的命令行。
曾经在网上看到过关于HG8245的UBoot的输出信息,其中包含如下字样的提示:
Press d key to abort autoboot: 10
一番周折后,找到了存在该信息的固件,不过是HG8245的,不是HG8245H的。提取UBoot后,尝试放到HG8245H里运行,但UART没有任何输出。
于是打算逆向UBoot,看看中断自动引导部分功能是否被禁用了,根据对字符串的引用参考分析,定位到了main_loop函数,以下为逆向的伪代码:
void __noreturn main_loop_1B038() { int v0; // r0@1 int v1; // r1@1 const char *lpszBootDelay; // r0@1 signed int nBootDelay; // r4@2 const char *lpszBootCmd; // r5@4 bool lpszBootCmd_Bak; // r3@4 int v6; // r4@8 int v7; // r0@12 int v8; // r1@12 signed int v9; // r4@13 int v10; // r0@14 int v11; // [sp+0h] [bp-10h]@0 int (__fastcall *v12)(_DWORD); // [sp+4h] [bp-Ch]@0 v0 = setenv_14038("ver", "U-Boot 2010.03 (R16C10 Jul 14 2016 - 14:19:37)"); sub_81F15B08(v0, v1); lpszBootDelay = (const char *)getenv_13B6C("bootdelay"); if ( lpszBootDelay ) nBootDelay = simple_strtol_20574(lpszBootDelay, 0, 10u); else nBootDelay = 1; sub_81F1AD70(); lpszBootCmd = (const char *)getenv_13B6C("bootcmd"); lpszBootCmd_Bak = lpszBootCmd != 0; if ( nBootDelay < 0 ) lpszBootCmd_Bak = 0; if ( lpszBootCmd_Bak && !abortboot_19138(nBootDelay) ) { v6 = sub_81F163A0(1); run_command_18D5C(lpszBootCmd, 0); sub_81F163A0(v6); } if ( !dword_81A65718 ) fn_reset_24100(dword_81A65718, dword_81A65718, dword_81A65718, dword_81A65718, v11, v12); sub_81F1D210(0); if ( (unk_81A65BCC & 0xFFFF00) == 0x20100 ) { v7 = fn_Printf2UART_162D8("DEBUG Mode & 5116T!\n"); sub_81F09F70(v7, v8); sub_81F0A5A0(); sub_81F0C524(); } v9 = 1; while ( 1 ) { v10 = readline_18CB4("hisilicon # "); if ( v10 > 0 ) break; if ( v10 ) { if ( v10 != -1 ) goto LABEL_19; puts_162A8("<INTERRUPT>\n"); LABEL_20: if ( v9 <= 0 ) lastcommand_81A6571C[0] = 0; } } strcpy_1F96C(lastcommand_81A6571C, console_buffer_81A65268); LABEL_19: v9 = run_command_18D5C(lastcommand_81A6571C, 0); goto LABEL_20; }
网上有很多关于UBoot引导流程分析的文章,阅读过后便可知道abortboot函数是中止自动引导的关键所在,一般这个函数会在bootdelay指定的时间内,检查bootstopkey设定的键码是否被按下。如果条件满足中止引导的话,就返回非0值,否则返回0。
所以看下abortboot函数的伪代码,就清楚问题出在哪里了:
int __fastcall abortboot_19138(int bootdelay) { int v1; // r4@1 unsigned __int64 v2; // r0@1 signed int v3; // r0@1 signed __int64 v4; // r2@1 __int64 v5; // r0@1 char *v6; // r0@1 char *v7; // r4@1 char *v8; // r0@1 char *v9; // r3@1 char v10; // zf@1 int v11; // r4@1 char *v12; // r6@3 char *v13; // r0@5 delaykey *v14; // r3@9 unsigned int v15; // r4@12 char *i; // r3@15 int v17; // r5@20 delaykey *v18; // r3@20 signed int v19; // r10@20 unsigned int v20; // r2@21 delaykey *v21; // ST04_4@23 int v22; // r0@23 unsigned __int64 v23; // r0@27 unsigned __int64 v25; // [sp+8h] [bp-78h]@1 char v26[32]; // [sp+10h] [bp-70h]@15 delaykey _dk[4]; // [sp+30h] [bp-50h]@1 char v28; // [sp+60h] [bp-20h]@16 v1 = bootdelay; LODWORD(v2) = get_ticks_23F34(); v25 = v2; v3 = sub_81F23F44(); v4 = get_tbclk_3B104(v3, 1000u) * (signed __int64)v1; HIDWORD(v5) = HIDWORD(v25); LODWORD(v5) = v25 + v4; v25 = v5 + v4; sub_81F1FD18(_dk, 0, 48); _dk[0].retry = 1; _dk[0].str = (char *)getenv_13B6C("bootdelaykey"); _dk[1].retry = 1; _dk[1].str = (char *)getenv_13B6C("bootdelaykey2"); v6 = (char *)getenv_13B6C("bootstopkey"); v7 = v6; _dk[2].str = v6; v8 = (char *)getenv_13B6C("bootstopkey2"); v10 = v7 == 0; v11 = 0; if ( v10 ) v9 = "read from corrupted volume %d" + 28; v12 = 0; _dk[3].str = v8; if ( v10 ) _dk[2].str = v9; do { v13 = _dk[v11].str; if ( v13 ) v13 = (char *)sub_81F1FAD4(v13); if ( (unsigned int)v13 >= 0x20 ) v13 = (char *)32; v14 = &_dk[v11]; ++v11; if ( v12 < v13 ) v12 = v13; v14->len = (unsigned int)v13; } while ( v11 != 4 ); v15 = 0; do { if ( sub_81F16248() ) { if ( v15 < (unsigned int)v12 ) { *(&v28 + v15++ - 80) = sub_81F16218(); } else { for ( i = v26; i - v26 < (unsigned int)(v12 - 1); ++i ) *i = i[1]; v12[(_DWORD)&v28 - 81] = sub_81F16218(); } } v17 = 0; v18 = _dk; v19 = 0; do { v20 = v18[v17].len; if ( v20 ) { if ( v15 >= v20 ) { v21 = v18; v22 = sub_81F1FE60((int)&v26[v15 - v20], (int)v18[v17].str, v20); v18 = v21; if ( !v22 ) v19 = 1; } } ++v17; } while ( v17 != 4 ); if ( v19 ) break; LODWORD(v23) = get_ticks_23F34(); } while ( v25 >= v23 ); fn_Printf2UART_162D8("U-boot Start from NORMAL Mode!\n"); sub_81F190F0(1); return 0; }
果不其然,可以发现这个函数,无论如何,都会返回0,即永远无法进入命令行模式。
那么修改该函数的返回值,应该就可以实现无条件进入命令行模式了吧。IDA Pro中转到return 0对应的机器码:
MOV R0, #0 //00 00 A0 E3
使用16进制编辑器,或者IDA的keypatch插件,修改该指令为:
MOV R0, #1 //01 00 A0 E3
保存后,重启光猫,继续通过OpenOCD写入内存运行UBoot,这时UART中输出如下:
HuaWei StartCode 2012.02 (R13C10 Apr 22 2014 – 18:06:02)
NAND: Nand(Hardware): 128 MiB
startcode select the uboot to load
the high RAM is :8080103c
startcode uboot boot count:0
Slave struct initializtion success!!
Use the UbootA to load first
Start from UbootA ERROR, Change to UbootB
Both UbootA and UbootB are wrong, load it by JTAG!
U-Boot 2010.03 (R16C10 Jul 14 2016 – 14:19:37)DRAM: 128 MB
Boot From NAND flash
Chip Type is SD5115T
NAND: Special Nand id table Version 1.23
Nand ID: 0x01 0xF1 0x00 0x1D 0x01 0xF1 0x00 0x1D
ECC Match pagesize:2K, oobzie:64, ecctype:4bit
Nand(Hardware): Block:128KB Page:2KB Chip:128MB*1 OOB:64B ECC:4bit
128 MiB
Using default environmentIn: serial
Out: serial
Err: serial
PHY power down !!!
[main.c__6080]::CRC:0x39e1f1ae, Magic1:0x5a5a5a5a, Magic2:0xa5a5a5a5, count:0, CommitedArea:0x0, Active:0xfffffffd, RunFlag:0xffffffff
0x000000100000-0x000008000000 : “mtd=1”
UBI: attaching mtd1 to ubi0
slave_paramA in flash, CRC:0x9789603f, Magic1:0x5a5a5a5a, Magic2:0xa5a5a5a5, count:0, CommitedArea:0x0, Active:0x0, RunFlag:0x2
use slave_paramA which is from flash, the RAM data is not OK!!!
Start from main system(0x0)!
CRC:0x9789603f, Magic1:0x5a5a5a5a, Magic2:0xa5a5a5a5, count:1, CommitedArea:0x0, Active:0x0, RunFlag:0x2
Main area (A) is OK!
CRC:0x39e1f1ae, Magic1:0x5a5a5a5a, Magic2:0xa5a5a5a5, count:1, CommitedArea:0x0, Active:0x0, RunFlag:0x2
UBIFS error (pid 0): ubifs_recover_master_node: failed to recover master node
Error reading superblock on volume ‘ubi:file_system’!
mount ubifs error!
Bootcmd:ubi read 0x85c00000 kernelA 0x19f28a; bootm 0x85c00054
BootArgs:noalign mem=118M console=ttyAMA1,115200 ubi.mtd=1 root=/dev/mtdblock11 rootfstype=squashfs mtdparts=hinand:0x100000(startcode),0x7f00000(ubifs),-(reserved) pcie0_sel=x1 maxcpus=0 l2_cache=l2hi coherent_pool=4M user_debug=0x1f panic=1 skb_priv=128 debug_ll=on
U-boot Start from NORMAL Mode!
resetting …
HuaWei StartCode 2012.02 (R13C10 Apr 22 2014 – 18:06:02)NAND: Nand(Hardware): 128 MiB
startcode select the uboot to load
the high RAM is :8080103c
startcode uboot boot count:0
Slave struct initializtion success!!
Use the UbootA to load first
Start from UbootA ERROR, Change to UbootB
Both UbootA and UbootB are wrong, load it by JTAG!
中止自动引导虽然成功了,但是UBoot直接重启了设备。接着分析main_loop函数,在调用完abortboot函数之后,有个可疑函数,会根据某内存地址的值而被决定是否调用(ps: 当时分析的时候,这个函数的名字还没有被我修改成fn_reset_24100):
if ( !dword_81A65718 ) fn_reset_24100(dword_81A65718, dword_81A65718, dword_81A65718, dword_81A65718, v11, v12);
跟入该函数后,发现它有向UART输出”resetting …\n”字串,那么导致设备重置的函数,应该就是这个了。尝试无条件跳过该函数:
BNE loc_81F1B0F0 //04 00 00 1A
修改为:
B loc_81F1B0F0 //04 00 00 EA
保存后,重新装载UBoot并运行:
HuaWei StartCode 2012.02 (R13C10 Apr 22 2014 – 18:06:02)
NAND: Nand(Hardware): 128 MiB
startcode select the uboot to load
the high RAM is :8080103c
startcode uboot boot count:-1
use the main slave_param area from flash, the RAM data is not OK!!!
Use the UbootA to load first
Use the UbootA to load success
U-Boot 2010.03 (R16C10 Jul 14 2016 – 14:19:37)DRAM: 128 MB
Boot From NAND flash
Chip Type is SD5115T
NAND: Special Nand id table Version 1.23
Nand ID: 0x01 0xF1 0x00 0x1D 0x01 0xF1 0x00 0x1D
ECC Match pagesize:2K, oobzie:64, ecctype:4bit
Nand(Hardware): Block:128KB Page:2KB Chip:128MB*1 OOB:64B ECC:4bit
128 MiB
Using default environmentIn: serial
Out: serial
Err: serial
PHY power down !!!
[main.c__6080]::CRC:0x9789603f, Magic1:0x5a5a5a5a, Magic2:0xa5a5a5a5, count:0, CommitedArea:0x0, Active:0x0, RunFlag:0x2
Start from main system(0x0)!
CRC:0x9789603f, Magic1:0x5a5a5a5a, Magic2:0xa5a5a5a5, count:1, CommitedArea:0x0, Active:0x0, RunFlag:0x2
0x000000100000-0x000008000000 : “mtd=1”
UBI: attaching mtd1 to ubi0
Main area (A) is OK!
CRC:0x39e1f1ae, Magic1:0x5a5a5a5a, Magic2:0xa5a5a5a5, count:1, CommitedArea:0x0, Active:0x0, RunFlag:0x2
UBIFS error (pid 0): ubifs_recover_master_node: failed to recover master node
Error reading superblock on volume ‘ubi:file_system’!
mount ubifs error!
Bootcmd:ubi read 0x85c00000 kernelA 0x19f28a; bootm 0x85c00054
BootArgs:noalign mem=118M console=ttyAMA1,115200 ubi.mtd=1 root=/dev/mtdblock11 rootfstype=squashfs mtdparts=hinand:0x100000(startcode),0x7f00000(ubifs),-(reserved) pcie0_sel=x1 maxcpus=0 l2_cache=l2hi coherent_pool=4M user_debug=0x1f panic=1 skb_priv=128 debug_ll=on
U-boot Start from NORMAL Mode!
hisilicon #
成功恢复海思UBoot命令行!
你好 楼主
请问 BOOT 正常的情况下 有刷机的命令没有??
求教
那要看引导到哪一步了:
如果web界面正常,那直接web刷机。
如果telnet开了,就load pack刷机。
要是kernel都引导不了,那就尝试JTAG写内存运行启用了命令行的uboot,然后写flash。
你好 楼主
光猫现在只能 无法正常加载 会无限重启 无法使用 TELNET 看不到 WEB ,PING不通光猫。 中断引导 到
BootArgs:noalign mem=118M console=ttyAMA1,115200 ubi.mtd=1 root=/dev/mtdblock11 rootfstype=squashfs mtdparts=hinand:0x100000(startcode),0x7f00000(ubifs),-(reserved) pcie0_sel=x1 maxcpus=0 l2_cache=l2hi coherent_pool=4M user_debug=0x1f panic=1 skb_priv=128 debug_ll=on
U-boot Start from NORMAL Mode!
hisilicon #
这个位置 。。如不中断会一直 无限重启
按照里面的设置 设置光猫IP和电脑IP后。在光猫里面能 PING 到我架设的 TFTP 服务器,能上传固件到光猫。但是不知道 U-boot的刷机 方式。
你的uboot未经破解就可以按键进入命令行,是不是V1开头的固件?
V1版本固件uboot的命令与V3版本固件uboot命令不太一样。你打个?看看支持哪些命令。
楼主高人,如果来个固件提取uboot的教程就好了
楼主你好,很想和你交朋友,方便的话加我QQ45201816,谢谢!
大佬, 有空帮忙给hs8545m的uboot打个补丁吗,不会用ida pro, 谢谢啦
链接: https://pan.baidu.com/s/1rb-o-URbDMjD7HfEKEzrvQ 提取码: 7zsq
这个自行处理吧,我不做支持。
能指导下吗,大佬,如何根据字符串找到对应的函数,我把uboot.bin托到ida pro6.8里找到 hisilicon #, 双击后,弹到 view- A 里对于的 rom地址上,strings在编译的时候应该被放到了data区,所以如何才能找到他对应的code区的函数呢?请大佬指导下,谢谢!
点击rom地址 右键 选择xrefs graph to, 提示 can not find any xrefs
IDA Pro的Strings窗口搜索关键字,找到后双击会跳转到IDA View窗口,在对应的字符串变量名上右键:List cross references to …,就可以找到对该字符串的相关代码引用。
网口开的吗?
PHY power down !!!
这个啥意思,貌似是网口是down的状态?
只记得出现这个提示,以太网口就不能用了。
这个能破掉吗?不太会逆向
在这里,有破解掉的:http://www.chinadsl.net/forum.php?mod=viewthread&tid=128798
或者这个:
https://github.com/csersoft/hi_sd5115_openocd_config/files/2956593/8245H_R16_UB_PAT_FULL.zip
因为你是HG8245H, 而我的是MA5675M, 这个uboot无法写我的flash,但是可以读,能否来一篇如何破PHY power down!,你文中是破command line和JTAG的。因为这个固件能找到的uboot默认网络功能都没开。用JTAG又不好做大文件传输。
8245H这个有破解PHY power down。
当时的发布链接在这里:http://www.chinadsl.net/thread-128798-1-1.html
具体破解的方法,时间太久了,记不清楚了。
你可以将破解版UBoot和原版UBoot进行差异对比,根据修改的字节,反向分析破解的地方。