超雪核心代码
核心代码部分,相对来说比较难懂,需要有一定的 ARM 汇编, C 语言的基础才行,首先我们来看看 ultraSn0w解锁所用的 at 命令的详细内容,我们用一个二进制工具打开 ultraSn0w 的主程序,检索“ at+xapp ” , 可以看到如下内容。虽然 at 命令都需要是可见的字符,但是我们的注入代码并不能这样,所以有一部分还是 hex 码。
这么看比较难懂,那么我把这部分内容用 C 语言进行描述,大概如下。
[cpp] view plaincopy
- #pragma pack(push,1)
- typedef unsigned long uint_32;
- typedef unsigned char byte;
- typedef unsigned short uint_16;
- typedef struct _tagUNLOCK_STRING
- {
- char at_cmd[9];
- uint_32 padding_data[9];
- uint_32 exploit_data[13];
- uint_16 payload_code[26];
- char end_code;
- char inject_code[800];
- }sUNLOCK_STRING;
- /* for 05.13.04 */
- sUNLOCK_STRING _unlock_at_cmd = {
- { 'a','t','+','x','a','p','p','=','"'}, // at+xapp="
- {
- 0x41414141, 0x41414141, 0x41414141, 0x41414141, // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- 0x41414141, 0x41414141, 0x41414141, 0x41414141,
- 0x41414141
- },
- {
- 0x2e2e2e2e, // r4 padding
- 0xffff1e80, // r5 ? unknow ?
- 0x2e2e2e2e, // r6 padding
- 0x2e2e2e2e, // r7 padding
- 0x20283c01, // pc the exploit address which is running in thumb mode.
- 0x20202020, // padding data.
- 0x20202020, // padding data.
- 0x406ca2b8, // ? unknow
- 0x01110110, // ? unknow
- 0x20266689, // r4
- 0x406ca358, // r5
- 0x401f443e, // r6 inject_code address(exploit stack address)
- 0xffff1e81 // pc "return pc address , unknow! sram? or interrupt LUT?
- // pc will run on the ram which is overwrited by the payload code."
- },
- {
- 0x2111, //MOVLS R1, 0x110
- 0x0109,
- 0x3106, //ADDS R1, #6
- 0x0902, //LSLS R1, R1, #8
- 0x1c4a, //ADDS R2, R1, #1
- //loc_32
- 0x2021, //MOVLS R0, 0x22 ;'"'
- 0x3001,
- 0x7833, //LDRB R3, [R6]
- 0x4298, //CMP R0, R3
- 0x7870, //LDRB R0, [R6,#1]
- 0xd007, //BEQ loc_4E;
- 0x3b41, //SUBS R3, #0x41 ; A
- 0x3841, //SUBS R0, #0x41 ; A
- 0x011b, //LSLS R3, R3, #4
- 0x0b18, //ADDS R3, R3, R0
- 0x700b, //STRB R3, [R1]
- 0x3101, //ADDS R1, #1
- 0x3602, //ADDS R6, #2
- 0xe7f1, //B loc_32
- //loc_4e
- 0x4790, //BLX R2
- 0x2001, //MOVLS R0, 0
- 0x3801,
- 0x1c01, //ADDS R1, R0, #0
- 0x47a0, //BLX R4
- 0x46ad, //MOV SP, R5
- 0xbd7f //POP {R0-R6,PC}
- },
- '/"',
- "/x3B/"AALFAIEIAKKBCGKCFCBKAFELJIEHAGEICHKBEPKCFCBKACELJIEHADEIIAEHAALNNINKBDCAKADPED"
- "EAAADMEDEAMAEGMAEGPOFPCNOJAAAAAAPKPOJPLNOIDALFBBENIFLABBELCIBMGJEGPPCCJIEHAAJLANCLBBNBABJ"
- "JANELAKGIBKGAAEDDEKGIBKGAIKGIALELBDGAALELFDGAALELJDGAABCDMLGACACDAAJDCIBMGJEGPPCCAHELJIEH"
- "NPOHAAAABELEBOEAPINOBGCAIAAJDCEAAAPPAAABABAEACAEADAEAEAEEADKEDCAMAEGMAEGMAEGMAEGMAEGMAEGM"
- "AEGMAEGPOFPCNOJAAAAAAPKPOJPLNOIPALFBFELIACECEABIJLABIIABDENCABMAPBMKIEHAGBMJICAKIEHAACCEE"
- "CDBAEJMCGAADJDAKCDAFJDAMCDAAJCACJEAEJCAGJDAMEKABJGAACDALEMKAEHACBMAACIAENBAKEJDIBMAKELJIE"
- "HADOAAJEJDIBMAHELJIEHAJLAPALNCMAFBPEADMDCBECAIEDMEDEAKADPEDEACAMPBHCAJADMEDEAKEOEELCAJEDM"
- "EDEAGEGFHGHEGFGBGNDBAAAAAAAAEPELCBAAEFFCFCEPFCCACFGEAAAA/""
- };
- /* BBSendData( (char*)&_unlock_at_cmd ); */
溢出用的 at 命令大概分为 6 部分:
1 、 at_cmd :
这部分是 at 命令的起始部分,也就是前面我们说的 at+xapp 命令。
2 、 padding_data :
这部分数据没有实际的意义,只是为了让执行 at+xapp 命令函数堆栈溢出的填充代码。
3 、 exploit_data :
这部分是一个关键的部分,其中主要填充了溢出后要给寄存器, r4 , r5, r6,pc 的地址,以及 Inject code 部分的内存地址。其中还有一些未知的部分,这部分在后续的解锁过程中都要攻克。那么这部分怎么溢出的呢 ?
先看一段汇编指令。一般 ARM 的函数调用返回时候的反汇编代码大概如下。
[c-sharp] view plaincopy
- ROM:2028A234 PUSH {R4-R7,LR}
- ROM:2028A236 LDR R6, =0x40255230
- ………………………………………………
- ROM:2028A24A CMP R0, #0
- ROM:2028A24C BNE loc_2028A252
- ROM:2028A24E LSLS R0, R5, #0
- ROM:2028A250 POP {R4-R7,PC}
关键的是对堆栈操作的代码 PUSH 和 POP ,程序返回的时候会把堆栈的内容,返回到寄存器 R4-R7 , PC
当然这里面存的应该是上一个函数使用的中间值,可是如果我们溢出之后,他就是我们想要的内容喽, PC 将跳转到我们想要的地方。如果是一个 B [SP] (不符合语法)就是最理想的了,因为这样我们可以马上跳回堆栈执行我们溢出部分的代码了,可是事情不会有那么好地,所以我们要寻觅一个类似这样功能的代码,去哪里找,只能在基带原有的代码里面找,看看我们的程序调到了那里?看上面的溢出结构就知道了是0x20283c01 一个奇数的地址,说明这里应该是 thumb 指令,那这部分是啥呢,我们需要解密基带的代码!基带的代码在那里呢?且听下回分解。
4 、 payload_code :
这部分是一个装载器,他将在溢出之后被 cpu 执行,主要作用是用来对后续的 Inject code 进行解码,并跳转到 Inject Code 处继续执行。我直接贴出了程序的二进制编码和汇编代码的注释,可以参考一下。反汇编我是使用 IDA Pro ,一个神器啊,当年不知道帮助我破解了多少 WindowMobile 的程序,嘿嘿 ~
大家仔细看这部分二进制码,有没有发现其中没有一个字节是 0 ,为什么要这样呢?因为 at 指令是一个字符串,那么字符串的默认约定就是 0 代表字符串的结束。如果我们在发给基带的命令中夹有了 0 ,那么就会被程序无情了认为字符串结束而达不到溢出的目的了,所以这部分代码要写的非常精巧。要对汇编的二进制编码很熟悉才行。而且这部分也写不了太大,因为我们很难避免一个程序不写出一个 0 出来。可以看出大神门的功底了得。这部分代码是 thumb 代码,因为 ARM 代码都是 4 字节的,遍地都是 0 啊 ~
大家说了,汇编也很难懂,那好我翻译成 C 语言大概就是类似下面的代码。如果你说 c 语言也很难懂,那对不起了,先学学再过来看。
[cpp] view plaincopy
- typedef void (*jmp_fun)();
- void Decode( byte* des, char *src )
- {
- byte l, h;
- while( *src != '"' ){
- h = *(src++) - 'A';
- l = *src - 'A';
- *(des++) = (h << 4) + l;
- }
- *(jmp_fun)des)();
- }
哈哈,一下子变得这么精炼了,高级语言的诞生绝对是程序届的革命啊。内容很容易懂了吧,就是把 Inject代码两个字符串分别减去 A 然后拼成一个字节,最终所有的字符串全部转换为二进制代码了。解码之后,payload 部分完成了使命,跳转到 Inject 部分继续执行。
6 、 Inject_code
一大堆字符串,看起来来好像没啥规律,不过仔细看看有规律哦,没有大于 V 的字符,嘿嘿 ~ 如果上面的说明你看懂了,你也就知道为什么了! 通过 payload 部分解码之后,出场的将是 ultraSn0w 的核心解锁的代码了。就好比一个绝色美女,已经脱光了所有的外衣,接下来的事情就非常让人期待了 ~~~ 那我们来看看金玉其外的里面是什么?
……
……
……
……
……
一大堆不知所云的汇编代码。
[c-sharp] view plaincopy
- ; Segment type: Pure code
- AREA ROM, CODE, READWRITE, ALIGN=0
- CODE16
- PUSH {LR}
- LDR R0, =0x40492FC0
- ADR R1, loc_30
- ADR R2, unk_A0
- SUBS R2, R2, R1
- LDR R3, =0x2040882C
- BLX R3
- LDR R0, =0x40492C20
- ADR R1, loc_B0
- ADR R2, 0x150
- SUBS R2, R2, R1
- LDR R3, =0x2040882C
- BLX R3
- LDR R0, =0x40492C20
- BLX R0
- POP {PC}
- ; ---------------------------------------------------------------------------
- dword_20 DCD 0x2040882C ; DATA XREF: ROM:0000000A_r
- ; ROM:00000016_r
- dword_24 DCD 0x40492FC0 ; DATA XREF: ROM:00000002_r
- dword_28 DCD 0x40492C20 ; DATA XREF: ROM:0000000E_r
- ; ROM:0000001A_r
- DCB 0xC0 ; À
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- ; ---------------------------------------------------------------------------
- CODE32
- loc_30 ; DATA XREF: ROM:00000004_o
- STMFD SP!, {R1-R12,LR}
- BLX sub_3C
- ; ---------------------------------------------------------------------------
- LDMFD SP!, {R1-R12,PC}
- CODE16
- ; =============== S U B R O U T I N E =======================================
- ; Attributes: noreturn
- sub_3C ; CODE XREF: ROM:00000034_p
- var_20 = -0x20
- var_1C = -0x1C
- PUSH {R4,R5,LR}
- LDR R5, =0x401E829C
- SUB SP, SP, #0x14
- loc_42 ; CODE XREF: sub_3C+44_j
- LDR R3, =0x2042FFD8 ; NU_Receive_From_Mailbox
- ADDS R0, R5, #0
- MOV R1, SP ; message void*
- MOVS R2, #0xFF ; timeout
- BLX R3 ; NU_Receive_From_Mailbox
- LDR R3, [SP,#0x20+var_20] ; [SP]
- CMP R3, #0xD
- BNE loc_76
- LDR R1, [SP,#0x20+var_1C] ; [SP+4]
- LDR R3, =0x40301650 ; sec_task_var1
- LDR R2, [R1]
- STR R2, [R3]
- ADDS R3, #4
- LDR R2, [R1,#4]
- STR R2, [R3]
- LDR R2, [R1,#8]
- LDR R3, =0x100FF00
- STR R3, [R2]
- LDR R3, =0x4020401
- STR R3, [R2,#4]
- LDR R3, =0x4040403
- STR R3, [R2,#8]
- MOVS R3, #1
- STR R3, [R1,#0xC]
- MOVS R3, #0x20 ; ' '
- STR R3, [SP,#0x20+var_20]
- loc_76 ; CODE XREF: sub_3C+14_j
- ADDS R0, R5, #0
- MOV R1, SP
- MOVS R2, #0xFF
- LDR R3, =0x20430040
- BLX R3
- B loc_42 ; NU_Receive_From_Mailbox
- ; End of function sub_3C
- ; ---------------------------------------------------------------------------
- DCB 0
- DCB 0
- dword_84 DCD 0x401E829C ; DATA XREF: sub_3C+2_r
- dword_88 DCD 0x2042FFD8 ; DATA XREF: sub_3C:loc_42_r
- dword_8C DCD 0x40301650 ; DATA XREF: sub_3C+18_r
- dword_90 DCD 0x100FF00 ; DATA XREF: sub_3C+26_r
- dword_94 DCD 0x4020401 ; DATA XREF: sub_3C+2A_r
- dword_98 DCD 0x4040403 ; DATA XREF: sub_3C+2E_r
- dword_9C DCD 0x20430040 ; DATA XREF: sub_3C+40_r
- unk_A0 DCB 0xC0 ; À ; DATA XREF: ROM:00000006_o
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- DCB 0xC0 ; À
- DCB 0x46 ; F
- ; ---------------------------------------------------------------------------
- CODE32
- loc_B0 ; DATA XREF: ROM:00000010_o
- STMFD SP!, {R1-R12,LR}
- BLX loc_BC
- LDMFD SP!, {R1-R12,PC}
- ; ---------------------------------------------------------------------------
- CODE16
- loc_BC ; CODE XREF: ROM:000000B4_p
- PUSH {R4-R7,LR}
- LDR R3, =0x401ED3B8
- MOVLS R4, 0x800
- SUB SP, SP, #0x24
- STRH R0, [R3]
- LDR R5, =0x201493F0
- ADDS R0, R4, #0
- ADDS R7, R1, #0
- BLX R5
- ADDS R6, R0, #0
- MOVS R0, #0x98 ; '・
- BLX R5
- MOVS R2, #0
- MOVS R3, #0x44 ; 'D'
- LDR R1, =0x40492CA4
- STR R2, [R0,#0xC]
- STR R3, [SP,#0xC]
- MOVS R3, #0xA
- STR R3, [SP,#0x14]
- MOVS R3, #0xC
- STR R2, [SP]
- STR R4, [SP,#8]
- STR R2, [SP,#0x10]
- STR R3, [SP,#0x18]
- LDR R2, =0x40492FC0
- STR R6, [SP,#4]
- MOVS R3, #0
- LDR R4, =0x2043E5B4
- BLX R4
- ADDS R2, R0, #0
- CMP R0, #0
- BNE loc_108
- LDR R1, =0x40492CB0
- ADDS R0, R7, #0
- LDR R3, =0x204B11F0
- BLX R3
- B loc_110
- ; ---------------------------------------------------------------------------
- loc_108 ; CODE XREF: ROM:000000FC_j
- LDR R1, =0x40492CB4
- ADDS R0, R7, #0
- LDR R3, =0x204B11F0
- BLX R3
- loc_110 ; CODE XREF: ROM:00000106_j
- ADD SP, SP, #0x24
- POP {R4-R7,PC}
- ; ---------------------------------------------------------------------------
- dword_114 DCD 0x401ED3B8 ; DATA XREF: ROM:000000BE_r
- dword_118 DCD 0x201493F0 ; DATA XREF: ROM:000000C8_r
- dword_11C DCD 0x40492CA4 ; DATA XREF: ROM:000000DA_r
- dword_120 DCD 0x40492FC0 ; DATA XREF: ROM:000000EE_r
- dword_124 DCD 0x2043E5B4 ; DATA XREF: ROM:000000F4_r
- dword_128 DCD 0x40492CB0 ; DATA XREF: ROM:000000FE_r
- dword_12C DCD 0x204B11F0 ; DATA XREF: ROM:00000102_r
- ; ROM:0000010C_r
- dword_130 DCD 0x40492CB4 ; DATA XREF: ROM:loc_108_r
- aDevteam1 DCB "devteam1",0
- DCB 0
- DCB 0
- DCB 0
- aOk DCB "OK!",0
- aErrorD DCB "ERROR %d",0
- DCB 0
- ; ROM ends
哈哈,贴了这么长的代码,有点骗稿费的嫌疑啊,没事接下来马上将其变成美丽的 C 妹妹。不过在这之前先来点前奏,用语言叙述一下原理,据大神的 wiki 上介绍,基带里面运行了一个完整的操作系统名字叫Nucleus ,是由 ATI 公司开发的,实时嵌入式操作系统,据说相当的稳定安全(苹果是不是图这个来的,可惜自己代码漏洞太多。)。我也没有用过,因为这个是一个商业系统,只对授权的公司开放源代码,但是如果你想找源码,还是有滴! ultrasn0w 的解锁代码,实际上创建了一个截获解锁事件监视 task (通过调用Nucleus 的 API )。经过处理之后,替换掉你 SIM 卡的传递过来的数据,将可以通过验证的数据向下传递,让基带认为你这个是一个合法的可以使用的 SIM 卡。从而达到软解的目的。站在了前人的肩膀上来看这个过程很简单吧,可以想象当初一穷二白的时候,大神们突破重围是会有多么艰辛。
讲道这里可能有人会说,那这部分代码不是每回都一样了?为何每次解锁都要等那么久,其实这部分核心代码是不会有大变化了,但是每次基带升级之后其中的一些地址会发生变化,因为苹果为了修复漏洞重新编译了代码,所有函数的 link 地址都将发生细微的变化,而我们必须找出当初一一对应的关系。才能保证系统调用是好用的。好了,说了这么多现在看翻译后的解锁 C 代码。
[cpp] view plaincopy
- NU_MAILBOX sec_mailbox;
- UNSIGNED sec_task_ver1;
- UNSIGNED sec_task_ver2;
- void task_jmp ( void )
- {
- task_creator();
- }
- VOID task_creator( void )
- {
- VOID *stack_addr;
- NU_TASK *task;
- OPTION priority;
- OPTION preempt;
- UNSIGNED time_slice;
- OPTION auto_start;
- UNSIGNED stack_size;
- char task_name[] = "yifengling0";
- stack_size = 0x800;
- stack_addr = malloc( stack_size );
- task = (NU_TASK*)(malloc( sizeof(NU_TASK) ) );
- priority = 0x44;
- preempt = NU_PREEMPT;
- time_slice = 0;
- auto_start = NU_START;
- NU_Create_Task( task, task_name, (PF_task_entry)(unlock_task),
- 1, p, stack_addr, stack_size, priority, time_slice, preempt, auto_start);
- }
- static VOID unlock_task (UNSIGNED argc, VOID *argv )
- {
- S_SEC_MESSAGE msg;
- while(1){
- NU_Receive_From_Mailbox( sec_mailbox, &msg, 0xFF );
- if( msg.message0 == 0x0D ){
- *(sec_task_var1) = msg.message1.field0;
- *(sec_task_var2) = msg.message1.field1;
- msg.message1.field2[0] = data1; //0x100FF00
- msg.message1.field2[1] = data2; //0x4020401
- msg.message1.field2[2] = data3; //0x4040403
- msg.message1.field3 = 1;
- msg.message0 = 0x20;
- }
- NU_Send_To_Mailbox( sec_mailbox, &msg, 0xFF );
- }
- }