您的位置:首页 > 其它

MTK 手机BIN文件加密的一点心得

2010-04-02 10:15 381 查看
MTK 手机BIN文件加密的一点心得

工具:IDA, UltraEdit, ARM250(ARM Project Manager 我专用来编译补丁文件), 打补丁工具(公司编的小工具)
第一次写这种东东,文笔又不好。见笑了。

MTK手机的Bin文件就是某款手机所对应的一整套原代码编译的目标程序(灼烧文件)。
在PC机上我们是把系统与应用程序分得很清楚的。但是MTK中则不同,系统与应用程序捆绑在一起的;当然这只对编译出来的系统BIN文件而言的,硬要单独加入应用程序也不是不可以。当然可以,那就要单独‘挂载’。前提是不要过度依赖硬件,如GPIO引脚之类的。

一般来说,当公司搞到MTK源工程文件后就可以修改所需内容,完之后就可以编译产生系统BIN文件,这时公司怕别人盗走成果往往会采用默认的加密方法。而这种加密方法现在很容易就可以破解的(当然针对这种形式破解补丁自己要先写好,以后就是死搬硬套)。所以想说说我现在加密的方法(当然这是从前辈那儿学来的,不是纯摸索的)。

加密效果:被加密的BIN文件只能运行在第一次烧录进的手机上!从手机里读出来的BIN,烧录到另一台手机上,则不开机!
思路:第一次烧录时,BIN文件原样读入进手机FLASH中,但要做个标记,用来确认是否本机器!可以把指定的关键代码(关键代码很多,如调用寄存器的代码一般都比较关键)提到补丁中去执行? MTK芯片上都有唯一的一个ID,我们就是用这个ID来加密关键代码的。当手机开机时,ROM先运行我们先前打进行去的一段检测代码补丁,内部密码判是否与标志相符。不符则关机!
总的来说就是用这个MTK芯片ID在ROM中加密和解密一段关键代码判断是否与标志匹配。被读出来的BIN文件关键代码将是与ID对应的密文!

我加密的过程随便描述一下。
1:找补丁位置,我找的是 INT_InitRegions 函数里面的 zi_init_32 函数。IDA显示如下:

ROM4:00418E94 EXPORT INT_InitRegions
ROM4:00418E94 INT_InitRegions ; CODE XREF: ROM:
ROM4:00418E94 0E 70 A0 E1 MOV R7, LR
ROM4:00418E98 10 01 9F E5 LDR R0, =0xDC2ECC
ROM4:00418E9C 10 11 9F E5 LDR R1, =_32khz_gpio_pin
ROM4:00418EA0 01 20 A0 E1 MOV R2, R1
ROM4:00418EA4 0C 41 9F E5 LDR R4, =unk_939C
ROM4:00418EA8 04 20 82 E0 ADD R2, R2, R4
ROM4:00418EAC 19 00 00 EB BL copy
ROM4:00418EAC
ROM4:00418EB0 04 21 9F E5 LDR R2, =unk_264660
ROM4:00418EB4 04 01 9F E5 LDR R0, =MPUChannelStatus
ROM4:00418EB8 00 10 A0 E1 MOV R1, R0
ROM4:00418EBC 02 10 81 E0 ADD R1, R1, R2
ROM4:00418EC0 1E 00 00 EB BL zi_init_32
ROM4:00418EC0
ROM4:00418EC4 F8 20 9F E5 LDR R2, =unk_16C6CC
ROM4:00418EC8 F8 00 9F E5 LDR R0, =g_applib_mem_ap_pool
ROM4:00418ECC 00 10 A0 E1 MOV R1, R0
ROM4:00418ED0 02 10 81 E0 ADD R1, R1, R2
ROM4:00418ED4 19 00 00 EB BL zi_init_32
ROM4:00418ED4
ROM4:00418ED8 EC 00 9F E5 LDR R0, =x$fpl$trapveneer
ROM4:00418EDC EC 10 9F E5 LDR R1, =x$fpl$trapveneer
ROM4:00418EE0 01 20 A0 E1 MOV R2, R1
ROM4:00418EE4 E8 40 9F E5 LDR R4, =x$fpl$trapveneer
ROM4:00418EE8 04 20 82 E0 ADD R2, R2, R4
ROM4:00418EEC 09 00 00 EB BL copy
ROM4:00418EEC
ROM4:00418EF0 E0 20 9F E5 LDR R2, =x$fpl$trapveneer
ROM4:00418EF4 E0 00 9F E5 LDR R0, =x$fpl$trapveneer
ROM4:00418EF8 00 10 A0 E1 MOV R1, R0
ROM4:00418EFC 02 10 81 E0 ADD R1, R1, R2
ROM4:00418F00 0E 00 00 EB BL zi_init_32 ;goto patch1 这儿将是我打补丁位置之一,在此把补丁代码引入ROM中进行标志判断
ROM4:00418F00
ROM4:00418F04 17 FF 2F E1 BX R7

注意:上面的代码我是用编译完生成的调试信息文件反汇编而得的。这样才会有真实函数名,全局变量名等的提示信息!
你真正在目标BIN文件中反汇编时,上面的实名就不复存在了,取代的将是IDA指定的名称。

2:关键代码:
把下面代码提取到补丁中加密,一定要变成密文,只有当与ID判断成功时,再转成明文!
ROM:0039DE90 03 49 LDR R1, =0xA00088E4
ROM:0039DE92 00 20 MOV R0, #0
ROM:0039DE94 08 60 STR R0, [R1]
ROM:0039DE96 03 49 LDR R1, =0xA00088E8
ROM:0039DE98 08 60 STR R0, [R1]
ROM:0039DE9A 03 49 LDR R1, =0xA00088EC
ROM:0039DE9C 08 60 STR R0, [R1]
ROM:0039DE9E 70 47 BX LR

3:自己写加密补丁(以下只是一小段样码,作为提示):

BLAddress EQU 0x300E40
....
Memory1 EQU 0xA00088E4
Memory2 EQU 0xA00088E8
Memory3 EQU 0xA00088EC
AREA |.JMPATCH_CODE|, CODE
CODE16

% BLAddress
BL MyPatch
..........

CODE32
MyPatch
STMFD SP!, {LR}
BL memclear
LDR R0, =No_Repaired+1
loc_BL
BLX R0
LDMFD SP!, {PC}
ALIGN
LTORG

CODE16
PatchStart
PUSH {R4,LR}
LDR R0, = CodeMemory - (Read_CPU_ID_End - loc_ValidateAdr2)
LDR R1, = ValidateAdrDATA
LDR R2, = Read_CPU_ID_End - loc_ValidateAdr2
BL Move_Code
MOV R4, SP
LDR R0, = CodeMemory - (Read_CPU_ID_End - loc_ValidateAdr2) - 4
MOV SP, R0
LDR R0, = CodeMemory - (Read_CPU_ID_End - loc_ValidateAdr2)
LDR R1, = Read_CPU_ID_End - loc_ValidateAdr2
BL JM_1
MOV SP, R4
LDR R0, = CodeMemory - (Read_CPU_ID_End - loc_ValidateAdr2) +1
BLX R0
POP {R4,PC}
ALIGN
LTORG
;======================================
loc_ValidateAdr2
PUSH {LR}
LDR R1, =Memory1
MOV R0, #0
STR R0, [R1]
LDR R1, =Memory2
STR R0, [R1]
LDR R1, =Memory3
STR R0, [R1]
BL TruePatch
POP {PC}
ALIGN
LTORG
;======================================
TruePatch
PUSH {R0-R3,LR}
SUB SP, #8
MOV R0, SP
BL Read_CPU_ID
LDR R1, = (ValidateAdr2+(CPU_ID-PatchStart))/4-0x60
ADD R1, #0x60
LSL R1, #2
LDR R2, [R1]
LDR R3, [R0]
CMP R2, R3
BNE Shutdown
;======================================
Shutdown
ADD SP, #8
MOV R1, #0
BLX R1
POP {R0-R3,PC}
ALIGN
LTORG
;======================================
Read_CPU_ID
;R0 = Put_ID_Address
PUSH {R0-R5,LR}
MOV R4, R0
MOV R1, #1
LSL R1, #31
MOV R2, #0xF
LSL R2, #12
ADD R2, R1
LDRH R0, [R2]
MOV R3, R1
LSR R3, #16
ORR R0, R3
STRH R0, [R2]
MOV R5, #0x5a
EOR R0, R5
STRH R0, [R4]
ADD R4, #2
ADD R1, #8
LDRH R0, [R1]
MOV R5, #0xa5
EOR R0, R5
STRH R0, [R4]
LDRH R0, [R2]
BIC R0, R3
STRH R0, [R2]
POP {R0-R5,PC}
ALIGN
LTORG
;======================================
ClearCode
LDR R0, = CodeMemory - (Read_CPU_ID - TruePatch)
LDR R1, = 0
LDR R2, = ClearCode - TruePatch
BL Move_Code_to_RAM_2
ADD SP, #8
POP {R0-R3,PC}

ALIGN
LTORG

...........
END

ARM250编译好补丁代码之后,就是用补丁工具打补丁了。
只能大大概概的说这些了,因为我也只是下小菜鸟!
只说说我个人的体会与心得,不当之处还请包涵!
上面所谓的术语“烧录”之类的。在我们这儿一般就直接叫做刷机!呵呵。

晕,发表时,不会对代码上色,一个个上色太麻烦了,只能这样了!
---------------------------------------------------------------

lonkil
2008-11-24, 03:40
学习了。

第一次烧录时,BIN文件原样读入进手机FLASH中,但要做个标记,用来确认是否本机器!

是指Bin在执行时,检测是否第一次执行,如果第一次执行,记下手机相关信息作标志。这份Bin如果被别人抠出来。由于已经被打上了标志,所以换了硬件就不能执行了。

是不是大体上这个道理?

我想请教一下楼主,怎么样将flash的Bin拷出来,在不知道烧入地址的情况下。
---------------------------------------------------------------------------

我想请教一下楼主,怎么样将flash的Bin拷出来,在不知道烧入地址的情况下。

般来说大部分BIN都是从0x0地址开始的,你就只要大胆的读出来就是了。如果你的FLASH是16M的,你就要读14M的BIN文件,因为后面2M是留给用户的(如保存短信、电话号码、歌曲。。)!介绍你一个工具: “Flash_tool” !用它来刷机和读出BIN文件非常好。并且可以写配制文件指定写入与读出BIN文件的地址!
-------------------------------------------------------------------------

般来说大部分BIN都是从0x0地址开始的,你就只要大胆的读出来就是了。如果你的FLASH是16M的,你就要读14M的BIN文件,因为后面2M是留给用户的(如保存短信、电话号码、歌曲。。)!介绍你一个工具: “Flash_tool” !用它来刷机和读出BIN文件非常好。并且可以写配制文件指定写入与读出...
---------------------------------------------------------------
同一段代码里面有32位的代码,还有16位的代码。
还可以切换指令集,这个就很难理解了。为什么要切换到那个什么thumb指令集呢?

另外,如果我修改Read_CPU_ID这个函数,让他每次都返回相同的CPUID呢。
------------------------------------------------------------------
 在我们自己编写时,一般都用THUMB指令(CODE16),因为它的比ARM占用空间小!但是在有些情况下是只能用ARM才能实现,比如启动代码的核心!
Read_CPU_ID是为了读取芯片ID,如果你固定的返回值,就不可能完成我们想要的加密功能!因为这个ID是芯片统一的。(如果返回唯一值,就相当没有加密!因为每个密要都一样了!)
--------------------------------------------------------------------
在我们自己编写时,一般都用THUMB指令(CODE16),因为它的比ARM占用空间小!但是在有些情况下是只能用ARM才能实现,比如启动代码的核心!
Read_CPU_ID是为了读取芯片ID,如果你固定的返回值,就不可能完成我们想要的加密功能!因为这个ID是芯片统一的 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息