赞助论坛
  • 15210阅读
  • 0回复

海尔BIN分析方法(uC/OS-II入口地址增加到50个左右,余下的实在找不到了) [复制链接]

楼层直达
byzx  

发帖
445
精华
12
金币
658
威望
178
贡献
331
好评
134
注册
2010-03-02
楼主    byzx 发表于: 2010-04-30 08:50:16 
经过对海尔0301版BIN长期的分析,发现了一些方法,不敢独享,说出来让愿意进行分析的人参考。

想分析BIN需要有一定的51汇编基础,还要有一定的c语言基础,如果二者都不会,可以不用往下看了。

要是有过逆向工程的经验,分析起来要容易得多。

分析的第一步,是需要将代码正确的反汇编,这个难度比较大,目前我还在继续整理中,最主要的任务是将代码和数据分离,并将代码反汇编出来,分离数据的工作目前已经基本完成,相关的资料在我的另一个帖子中(关于文字显示位置重定位的,昨天发的,找不到的搜索一下即可)。

有了源码后,需要找出关键部分代码,比如说与输入输出相关的部分,然后从点到线,再到面,将重要模块整理出来,并注释到源程序中,再看程序的时候才能更容易些,也更能发现问题。

第二步,将数据整理成易读的形式,并将标号重新修改。比如说原来全是16字节一行的DB数据,经过美化后变成这个样子:
L724397:   ;从机已连接
  DB   0B4H,0D3H,0BBH,0FAH,0D2H,0D1H,0C1H,0ACH,0BDH,0D3H,0
L7243A2:   ;设置波特率
  DB   0C9H,0E8H,0D6H,0C3H,0B2H,0A8H,0CCH,0D8H,0C2H,0CAH,0
L7243AD:   ;不兼容从机硬件
L7243BC:   ;擦除,请稍候
L7243C9:   ;写入数据,请稍候
L7243DA:   ;等待从机
L7243E3:   ;连接错误,等待从机
L7243F6:   ;升级成功, 等待从机

字符串部分比较好处理,因为可以看到,更可恨的是有一部分貌似数据,实际是程序入口,例如这些数据:
L72B2AD: DB 0F3H,0B9H,0E9H,00BH,0F3H,0B2H,0CCH,00DH
实际上应该转换为下面这样,0F3代码72程序段,后面的两个字节是地址偏移量,再往后是序号。(感谢经验丰富的quicktime大侠的指正,单字节应该是switch分支,双字节是偏移量)
L72B2AD:     ;转移表,共9项
  DW   L72B9E9
  DB   00BH
  DW   L72B2CC
  DB   00CH
  DW   L72B2CC
  DB   00DH
  DW   L72B542
  DB   00EH
  DW   L72B542
  DB   00FH
  DW   L72B92B
  DB   010H
  DW   L72B9E7
  DB   011H
  DW   L72B6C5
  DB   01BH
  DW   L72B6C5
  DB   01CH
  DW   0,L72BA19

这样的地址转移表在程序中有十几处,比较大的表也30多项,需要一一整理出来。

在应用程序的最后部分,还有一些数据,凡是3字节一组,以0F3H到0F8H打头的也是转移表,需要一一整理出来,有若干组,每组少的只有3-4项,多的有几组47项的。


如果只是理论上的分析,有上面这两步就可以看明白程序在搞什么了,甚至可以将程序弄到KEIL中跟踪运行,以观察其实际运行情况,可以参考Q大侠的相关帖子,对KEIL进行相关设置。

如果想真正的对程序进行修改,还需要将代码改为可浮动的,因为BIN的代码是已经链接过的代码,转移地址和数据地址全是绝对地址,想增加一段代码只能采用“飞地”的方法,不利于中型和大型的修改。

数据部分可以不浮动,因为海尔的BIN使用了 uC/OS-II 实时操作系统,即使新增的代码要使用内存,也可以通过内存管理函数来申请,即使要使用固定位置的变量,那7D0000和7E0000段有大量的空间可以用来设置far类型的变量,应该不需要担心。否则程序中的MOV DPTR,#xxxxxx指令就有2万1千多条,足够半年忙活了。

代码的浮动需要将所有的绝对转移地址都改为标号,例如下面这样的代码:
L76D4D1:   MOV   DPTR, #7DB13FH
  MOV   A, #03H
  MOVX   @DPTR, A
  MOV   R3, #0F9H
  MOV   R2, #00H
  MOV   R1, #0B4H
改成:
L76D4D1:   MOV   DPTR, #7DB13FH
  MOV   A, #03H
  MOVX   @DPTR, A
  MOV   R3, #BYTE2 (L7800B4 + 810000H)       ;3项转移表
  MOV   R2, #BYTE1 L7800B4
  MOV   R1, #BYTE0 L7800B4
这样在重新汇编时才能生成正确的地址, 这样的地方约有几千处,需要手工处理,如果能使用程序脚本来处理,效率会提高很多,但是还有一些不是这样简单的形式,比如在767000附近的代码,地址的几部分是分开的,且每处可能不一样,程序处理有相当的难度,需要手工进行。

除了代码中的直接地址,凡是数据中是函数指针的部分,也需要照此办理。当然难度较大,工作量也不小,关键是分析出哪些数据代表的是地址,且要分析出其构造方式。

[b]最后要说的,也是相当重要的是,海尔的BIN采用了uOS-II实时操作系统[/b],此系统为开放源码的系统,其c语言的各版本源码可以在网上下载,具体功能就不需要我介绍了。据中9STB的开发时间,当时的OS版本应该在2.8左右,要分析的各位大侠可以自行从网上搜索并下载系统的c语言源码。网上关于此系统的资料相当多,有大量的资料可供参考。

目前已经确认,在应用程序区中发现了一个很关键的OS函数:OSTaskCreate(),具体地址位于61000解包后的38BDD至38D4B处,SDRAM中的地址为758BDD至758D4B。
[b](
增补部分:uC/OS-II系统函数在BIN中的入口地址及结束地址。适用于0301版高星原厂BIN。
L73A204    L73A5C5    OS_FLAGS     OSFlagPend(OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *err);
L73BB98    L73BF1C    INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt);
L73FA78    L73FD95    INT8U       OSQPostOpt(OS_EVENT *pevent, void *msg, INT8U opt);
L741584    L74187F    OS_FLAGS     OSFlagPost(OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *err);
L743504    L7437C4    void       *OSQPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
L744A7F    L744D18    OS_EVENT   *OSQCreate(void **start, INT16U size);
L7483D4    L748626    void OS_FlagBlock (OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, OS_FLAGS flags, INT8U wait_type, INT16U timeout)
L74A603    L74A837    INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)
L74B966    L74BB7F    INT8U       OSQQuery(OS_EVENT *pevent, OS_Q_DATA *p_q_data);
L74D861    L74DA62    void       *OSMboxPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
L74F5C0    L74F7AB    INT8U       OSQPostFront(OS_EVENT *pevent, void *msg);
L75078C    L750969    INT8U       OSTimeDlyHMSM(INT8U hours, INT8U minutes, INT8U seconds, INT16U milli);
L751BE3    L751DB0    INT8U       OSQPost(OS_EVENT *pevent, void *msg);
L7532E9    L7534A5    void       *OSQAccept(OS_EVENT *pevent, INT8U *err);
L75381E    L7539D4    INT8U       OSTaskSuspend(INT8U prio);
L7545BC    L754767    void       OSTimeTick(void);
L757A4B    L757BCC    void       OSSemPend(OS_EVENT *pevent, INT16U timeout, INT8U *err);
L758BDD    L758D4B    INT8U       OSTaskCreate(void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT8U prio);
L759A10    L759B66    static BOOLEAN OS_FlagTaskRdy (OS_FLAG_NODE *pnode, OS_FLAGS flags_rdy)
L759B67    L759CC8    INT8U       OSSemQuery(OS_EVENT *pevent, OS_SEM_DATA *p_sem_data);
L759F8C    L75A0EB    void OS_EventTaskWait (OS_EVENT *pevent);
L75C691    L75C7C9    INT8U       OSTaskResume(INT8U prio);
L75CF13    L75D041    void OS_FlagUnlink (OS_FLAG_NODE *pnode);
L75E097    L75E1BC    OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags, INT8U *err);
L75E409    L75E52D    static void OS_InitEventList (void);
L75E776    L75E894    OS_STK     *OSTaskStkInit(void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt);
L75FD65    L75FE78    void OS_EventTO (OS_EVENT *pevent);
L760110    L76021E    void       OSTimeDly(INT16U ticks);
L76032C    L760437    static void OS_InitTCBList (void);
L760868    L760972    void OS_FlagInit (void);
L7613AE    L7614AD    OS_EVENT   *OSSemCreate(INT16U cnt);
L761C94    L761D8B    OS_EVENT   *OSMboxCreate(void *msg);
L761D8C    L761E83    INT8U       OSMboxPost(OS_EVENT *pevent, void *msg);
L762529    L762619    void OS_QInit (void);
L7627FC    L7628EB    INT8U       OSQFlush(OS_EVENT *pevent);
L766D2A    L766DE8    void       OSIntExit(void);
L767023    L7670DF    void OS_Sched (void);
L7670E0    L76719C    INT8U       OSSemPost(OS_EVENT *pevent);
L7673D3    L76748E    OS_FLAGS     OSFlagQuery(OS_FLAG_GRP *pgrp, INT8U *err);
L769400    L7694A6    void       OSStart(void);
L76954E    L7695F3    void       *OSMboxAccept(OS_EVENT *pevent);
L76AF07    L76AF9B    static void OS_InitRdyList (void);
L76B031    L76B0C4    void OS_EventWaitListInit (OS_EVENT *pevent);
L76B9D7    L76BA64    INT16U     OSSemAccept(OS_EVENT *pevent);
L773471    L7734B6    OS_FLAGS     OSFlagPendGetFlagsRdy(void);
L774041    L77407B    static void OS_InitMisc (void);
L77464F    L774684    INT32U     OSTimeGet(void);
L775162    L77518F    void       OSSchedUnlock(void);
L775275    L7752A1    void       OSTimeSet(INT32U ticks);
L775E7C    L775EA2    static void OS_InitTaskIdle (void);
L77606F    L776094    void OS_TaskIdle (void);
L776B5A    L776B76    void       OSStartHighRdy(void);
L776CE5    L776D00    void       OSInit(void);
L7770C5    L7770DB    void       OSSchedLock(void);
L777247    L77725C    void       OSIntEnter(void);
)[/b]

其它函数当会被陆续发现,因为应用程序部分的系统代码占据了相当的空间(保守估计得有一半儿吧),如果分析出哪些是系统函数,那些是应用函数,则分析的工作量会少很多。

如果你用过ucOS-II,那分析起来肯定会事半功倍,如果没用过,但是会c语言,也可以进行分析工作,要是顺便学会了51汇编(比c语言容易多了),那就如虎添翼了。


最后附上新编的SDRAM映像图,供分析时使用。

程序的主要流程是:
开机->00段(检测有没有上位机,如果有,进入刷机部分)
->5D-5E段(升级软件部分,汉字库尚不可用,文字信息全是英文)
->41段(对应用程序、字库、开机画面等进行解码)
->72-77段(应用程序部分,主循环)

海尔机SDRAM内存映像图:
[b]000000-0FFFFF FLASH ROM区
260000-283FFF 数据,升级软件用的数据区(包括开机自检)
410000-42FFFF 代码,初始化时将应用程序代码等进行LZSS解码并转移到720000
460000-48C0CC 数据,字库(未解压前) (确认)
4DA800-56556F 数据,解压后的24X24点阵的字模(确认)
560570-5CE3F0 数据,开机画面等(确认)
5D0000-5F23FF 代码,升级软件部分,然后转到410000执行
720000-78FFFF 代码段,主应用程序即在此范围,后面部分包括了相当多的数据
7CF400-7CFFFF 代码段,经过截获,只有一些返回指令,看来是没多大用。
7D0000-7DFFFF 数据段,标准XDATA段,由应用程序使用,包括文字提示信息和图形参数
7E0000-7EFFFF 数据段,扩展数据段。[/b]
本帖最近评分记录: 6 条评分