#15145 - xti - Sun Jan 18, 2004 12:46 am
Hello, over at the treo600 (smartphone) forums, we're attempting to unlock our treos since many of us ended up with locked ATT treos under the assumption that an unlock solution was just around the corner.
We have come very close, however, our community doesnt seem to have many ARM ASM coders. One person has partially sifted through the code and seems to have given a solution (but has not actually implemented it in).
If anyone here could assist, it would be much appreciated. Thanks for your help!
http://perso.wanadoo.fr/fmol/Treo600/resources/crashed.zip - The zip package with a number of files, the file we are interested in is Firmwarestackrel.pdb
Heres what we know so far
---------------------------
The Treo is based on ARM7TDMI core (check in ARM's online database), using WinArm the ARM7TDMI disassembler used in the Nokia community on the crashed firmware posted earlier (FirmwareStackRel.pdb), the following was found.
Near the addres 3a191e there a number of functions handling simlock and three small functions called encrypt, decrypt, fuzz ... The firmware contains symbols for the functions just before the code so its pretty easy to pick them.
Here is an example of my take I understanding on of the funcs in the firmware (SIMLockCheckNetworkLock).
Hope this will help others to go on ...
Basically what it does is that it get a 6 byte string input and check it against an encrypted string that is decrypted on the fly using the decrypt function.
It uses also a func called BATTMgrResumeCharging ... probably something wrong here with the addressing ...
Well not that much here .. except that I'm wondering if simply modify the code so that SIMLockCheckNetworkLock returns always 1 would not do the trick ;-) - This would be the proposed solution
Code with comments
---------------------------
3a1078 :b5b0 ?? : PUSH { R4,R5,R7, LR } // Save R4,R5,R7 on stack - save LR as well for function call return
3a107a :45d5 E? : CMP SP, H2 // Check on all funcs ... probably some heap overflow check
3a107c :da01 ?. : BGE 3a1082 //
3a107e :f00af863: BL 3ab148 (Routine (11 calls)) //
3a1082 :1c07 .. : MOV R7, R0 // R7 = R0 (1st parameter, let's call it Parm1), so R7 = Parm1
3a1084 :b083 ?? : ADD SP, #-000c // Reserve 12 bytes on the stack for function usage
3a1086 :482c H, : LDR R0, #003f8060 // Load a structure pointer into R0, let's call it Ptr1
3a1088 :7cc0 |? : LDRB R0, [R0, #13] // R0 = *((char *)Ptr1 + 13) , let's call it Ptr1->Byte1
3a108a :ab02 ?. : ADD R3, SP, #0008 // R3 points on the 9th char of the 12 we reserved on stack (let's call this LocByte1), so R3 = &LocByte1
3a108c :7018 p. : STRB R0, [R3, #0] // LocByte1 = R0 = Ptr1->Byte1
3a108e :207f : MOV R0, #7f // R0 = #7f
3a1090 :03c0 .? : LSL R0, R0, #.15 // R0 = R0<<15 = #7f0000, let's cal it PtrByte2 (a special reserver part of the memory ? Why is it computed like this ?)
3a1092 :7800 x. : LDRB R0, [R0, #0] // R0 = PtrByte2[0]
3a1094 :2501 %. : MOV R5, #1 // R5 = 1
3a1096 :2800 (. : CMP R0, #0 // if (R0 == 0)
3a1098 :d004 ?. : BEQ 3a10a4 // Goto Branch1
3a109a :1c38 .8 : MOV R0, R7 // R0 = Parm1 (R0 is used as 1st parm for function calls)
3a109c :f6b7fba4: BL 2587e8 (Routine (4 calls)) // R0 = Routine1(Parm1)
3a10a0 :2800 (. : CMP R0, #0 // if (R0 == 0)
3a10a2 :d001 ?. : BEQ 3a10a8 // Goto Branch2
Branch1
3a10a4 :1c28 .( : MOV R0, R5 // R0 = R5 = 1
3a10a6 :e044 ?D : B 3a1132 // goto Branch8 (return (1))
Branch2
3a10a8 :2101 !. : MOV R1, #1 // R1 = 1
3a10aa :a802 ?. : ADD R0, SP, #0008 // R0 = &LocByte1, LocByte1 = Ptr1->Byte1
3a10ac :f000fc37: BL 3a191e (Routine (11 calls)) // DecryptData(&LocByte1, 1) (call using a reference, not a direct value)
3a10b0 :2400 $. : MOV R4, #0 // R4 = 0
3a10b2 :a802 ?. : ADD R0, SP, #0008 // R0 = &LocByte1 (modified)
3a10b4 :7800 x. : LDRB R0, [R0, #0] // R0 = LocByte1
3a10b6 :2800 (. : CMP R0, #0 // if (LocByte1 <= 0)
3a10b8 :dd3a ?: : BLE 3a1130 // goto Branch7 (return(0))
Branch6
3a10ba :0060 .` : LSL R0, R4, #.1 // R0 = R4 << 1 = 0 ??? I don't understand ...
3a10bc :1900 .. : ADD R0, R0, R4 // R0 += R4
3a10be :0040 .@ : LSL R0, R0, #.1 // R0 = R0 << 1 = 0 ???
3a10c0 :4b1e K. : LDR R3, #003f8074 // R3 = Ptr2
3a10c2 :18c1 .? : ADD R1, R0, R3 // R1 = &Ptr2->Data1
3a10c4 :4668 Fh : MOV R0, SP // R0 = stack pointer = LocString2 (points on the 1st char of the 12 we reserved on stack)
3a10c6 :2206 ". : MOV R2, #6 // R2 = 6
3a10c8 :f005fa2c: BL 3a6524 (Routine (13 calls)) // BATTMgrResumeCharging(LocString2 , &Ptr2->Data1, 6)
3a10cc :4668 Fh : MOV R0, SP // R0 = stack pointer = LocString2
3a10ce :2106 !. : MOV R1, #6 // R1 = 6
3a10d0 :f000fc25: BL 3a191e (Routine (11 calls)) // DecryptData(LocString2 , 6)
3a10d4 :a800 ?. : ADD R0, SP, #0000 // R0 = LocString2
3a10d6 :7800 x. : LDRB R0, [R0, #0] // R0 = LocString2[0] (modified by DecryptData)
3a10d8 :7839 x9 : LDRB R1, [R7, #0] // R1 = Parm1[0]
3a10da :4288 B? : CMP R0, R1 // if (LocString2[0] != Parm1[0])
3a10dc :d121 ?! : BNE 3a1122 // goto Branch3
3a10de :a800 ?. : ADD R0, SP, #0000 // R0 = LocString2
3a10e0 :7840 x@ : LDRB R0, [R0, #1] // R0 = LocString2[1]
3a10e2 :7879 xy : LDRB R1, [R7, #1] // R1 = Parm1[1]
3a10e4 :4288 B? : CMP R0, R1 // if (LocString2[1] != Parm1[1])
3a10e6 :d11c ?. : BNE 3a1122 // goto Branch3
3a10e8 :a800 ?. : ADD R0, SP, #0000 // R0 = LocString2
3a10ea :7880 x? : LDRB R0, [R0, #2] // R0 = LocString2[2]
3a10ec :78b9 x? : LDRB R1, [R7, #2] // R1 = Parm1[2]
3a10ee :4288 B? : CMP R0, R1 // if (LocString2[1] != Parm1[1])
3a10f0 :d117 ?. : BNE 3a1122 // goto Branch3
3a10f2 :a800 ?. : ADD R0, SP, #0000 //
3a10f4 :78c0 x? : LDRB R0, [R0, #3] //
3a10f6 :78f9 x? : LDRB R1, [R7, #3] //
3a10f8 :4288 B? : CMP R0, R1 // if (LocString2[3] != Parm1[3])
3a10fa :d112 ?. : BNE 3a1122 // goto Branch3
3a10fc :a801 ?. : ADD R0, SP, #0004 //
3a10fe :7800 x. : LDRB R0, [R0, #0] //
3a1100 :7939 y9 : LDRB R1, [R7, #4] //
3a1102 :4288 B? : CMP R0, R1 // if (LocString2[4] != Parm1[4])
3a1104 :d10d ?. : BNE 3a1122 // goto Branch3
3a1106 :a801 ?. : ADD R0, SP, #0004
3a1108 :78402800: : x@(. // ????? - probably a problem with the disassembler ...
3a110c :d0ca ?? : BEQ 3a10a4
3a110e :a801 ?. : ADD R0, SP, #0004
3a1110 :7840 x@ : LDRB R0, [R0, #1]
3a1112 :7979 yy : LDRB R1, [R7, #5]
3a1114 :4288 B? : CMP R0, R1 // if (LocString2[5] != Parm1[5])
3a1116 :d101 ?. : BNE 3a111c // goto Branch4
3a1118 :2001 . : MOV R0, #1 // R0 = 1
3a111a :e000 ?. : B 3a111e // goto Branch5
Branch4
3a111c :2000 . : MOV R0, #0 // R0 = 0
Branch5
3a111e :2800 (. : CMP R0, #0 // if (R0 != 0)
3a1120 :d1c0 ?? : BNE 3a10a4 // goto Branch1 (return(1))
Branch3
3a1122 :1c60 .` : ADD R0, R4, #1 // RO = R4 + 1
3a1124 :06040e24: AND R4, R0, #000000ff // R4 = R0 & #ff
3a1128 :a802 ?. : ADD R0, SP, #0008 // R0 = &LocByte1
3a112a :7800 x. : LDRB R0, [R0, #0] // R0 = LocByte1
3a112c :4284 B? : CMP R4, R0 // if(R4 == R0)
3a112e :dbc4 ?? : BLT 3a10ba // goto Branch6
Branch7
3a1130 :2000 . : MOV R0, #0 // return(0)
Branch8
3a1132 :b003 ?. : ADD SP, #000c // Liberate the 12 bytes on the stack
3a1134 :bdb0 ?? : POP { R4,R5,R7, PC } // Restore registers and return
-----------------------------------------^ end routine
I'm sure I missed something vital which is needed to help fix the code. Please post with any additional info you may need and I'll look it up.
Again, thanks for your time!
We have come very close, however, our community doesnt seem to have many ARM ASM coders. One person has partially sifted through the code and seems to have given a solution (but has not actually implemented it in).
If anyone here could assist, it would be much appreciated. Thanks for your help!
http://perso.wanadoo.fr/fmol/Treo600/resources/crashed.zip - The zip package with a number of files, the file we are interested in is Firmwarestackrel.pdb
Heres what we know so far
---------------------------
The Treo is based on ARM7TDMI core (check in ARM's online database), using WinArm the ARM7TDMI disassembler used in the Nokia community on the crashed firmware posted earlier (FirmwareStackRel.pdb), the following was found.
Near the addres 3a191e there a number of functions handling simlock and three small functions called encrypt, decrypt, fuzz ... The firmware contains symbols for the functions just before the code so its pretty easy to pick them.
Here is an example of my take I understanding on of the funcs in the firmware (SIMLockCheckNetworkLock).
Hope this will help others to go on ...
Basically what it does is that it get a 6 byte string input and check it against an encrypted string that is decrypted on the fly using the decrypt function.
It uses also a func called BATTMgrResumeCharging ... probably something wrong here with the addressing ...
Well not that much here .. except that I'm wondering if simply modify the code so that SIMLockCheckNetworkLock returns always 1 would not do the trick ;-) - This would be the proposed solution
Code with comments
---------------------------
3a1078 :b5b0 ?? : PUSH { R4,R5,R7, LR } // Save R4,R5,R7 on stack - save LR as well for function call return
3a107a :45d5 E? : CMP SP, H2 // Check on all funcs ... probably some heap overflow check
3a107c :da01 ?. : BGE 3a1082 //
3a107e :f00af863: BL 3ab148 (Routine (11 calls)) //
3a1082 :1c07 .. : MOV R7, R0 // R7 = R0 (1st parameter, let's call it Parm1), so R7 = Parm1
3a1084 :b083 ?? : ADD SP, #-000c // Reserve 12 bytes on the stack for function usage
3a1086 :482c H, : LDR R0, #003f8060 // Load a structure pointer into R0, let's call it Ptr1
3a1088 :7cc0 |? : LDRB R0, [R0, #13] // R0 = *((char *)Ptr1 + 13) , let's call it Ptr1->Byte1
3a108a :ab02 ?. : ADD R3, SP, #0008 // R3 points on the 9th char of the 12 we reserved on stack (let's call this LocByte1), so R3 = &LocByte1
3a108c :7018 p. : STRB R0, [R3, #0] // LocByte1 = R0 = Ptr1->Byte1
3a108e :207f : MOV R0, #7f // R0 = #7f
3a1090 :03c0 .? : LSL R0, R0, #.15 // R0 = R0<<15 = #7f0000, let's cal it PtrByte2 (a special reserver part of the memory ? Why is it computed like this ?)
3a1092 :7800 x. : LDRB R0, [R0, #0] // R0 = PtrByte2[0]
3a1094 :2501 %. : MOV R5, #1 // R5 = 1
3a1096 :2800 (. : CMP R0, #0 // if (R0 == 0)
3a1098 :d004 ?. : BEQ 3a10a4 // Goto Branch1
3a109a :1c38 .8 : MOV R0, R7 // R0 = Parm1 (R0 is used as 1st parm for function calls)
3a109c :f6b7fba4: BL 2587e8 (Routine (4 calls)) // R0 = Routine1(Parm1)
3a10a0 :2800 (. : CMP R0, #0 // if (R0 == 0)
3a10a2 :d001 ?. : BEQ 3a10a8 // Goto Branch2
Branch1
3a10a4 :1c28 .( : MOV R0, R5 // R0 = R5 = 1
3a10a6 :e044 ?D : B 3a1132 // goto Branch8 (return (1))
Branch2
3a10a8 :2101 !. : MOV R1, #1 // R1 = 1
3a10aa :a802 ?. : ADD R0, SP, #0008 // R0 = &LocByte1, LocByte1 = Ptr1->Byte1
3a10ac :f000fc37: BL 3a191e (Routine (11 calls)) // DecryptData(&LocByte1, 1) (call using a reference, not a direct value)
3a10b0 :2400 $. : MOV R4, #0 // R4 = 0
3a10b2 :a802 ?. : ADD R0, SP, #0008 // R0 = &LocByte1 (modified)
3a10b4 :7800 x. : LDRB R0, [R0, #0] // R0 = LocByte1
3a10b6 :2800 (. : CMP R0, #0 // if (LocByte1 <= 0)
3a10b8 :dd3a ?: : BLE 3a1130 // goto Branch7 (return(0))
Branch6
3a10ba :0060 .` : LSL R0, R4, #.1 // R0 = R4 << 1 = 0 ??? I don't understand ...
3a10bc :1900 .. : ADD R0, R0, R4 // R0 += R4
3a10be :0040 .@ : LSL R0, R0, #.1 // R0 = R0 << 1 = 0 ???
3a10c0 :4b1e K. : LDR R3, #003f8074 // R3 = Ptr2
3a10c2 :18c1 .? : ADD R1, R0, R3 // R1 = &Ptr2->Data1
3a10c4 :4668 Fh : MOV R0, SP // R0 = stack pointer = LocString2 (points on the 1st char of the 12 we reserved on stack)
3a10c6 :2206 ". : MOV R2, #6 // R2 = 6
3a10c8 :f005fa2c: BL 3a6524 (Routine (13 calls)) // BATTMgrResumeCharging(LocString2 , &Ptr2->Data1, 6)
3a10cc :4668 Fh : MOV R0, SP // R0 = stack pointer = LocString2
3a10ce :2106 !. : MOV R1, #6 // R1 = 6
3a10d0 :f000fc25: BL 3a191e (Routine (11 calls)) // DecryptData(LocString2 , 6)
3a10d4 :a800 ?. : ADD R0, SP, #0000 // R0 = LocString2
3a10d6 :7800 x. : LDRB R0, [R0, #0] // R0 = LocString2[0] (modified by DecryptData)
3a10d8 :7839 x9 : LDRB R1, [R7, #0] // R1 = Parm1[0]
3a10da :4288 B? : CMP R0, R1 // if (LocString2[0] != Parm1[0])
3a10dc :d121 ?! : BNE 3a1122 // goto Branch3
3a10de :a800 ?. : ADD R0, SP, #0000 // R0 = LocString2
3a10e0 :7840 x@ : LDRB R0, [R0, #1] // R0 = LocString2[1]
3a10e2 :7879 xy : LDRB R1, [R7, #1] // R1 = Parm1[1]
3a10e4 :4288 B? : CMP R0, R1 // if (LocString2[1] != Parm1[1])
3a10e6 :d11c ?. : BNE 3a1122 // goto Branch3
3a10e8 :a800 ?. : ADD R0, SP, #0000 // R0 = LocString2
3a10ea :7880 x? : LDRB R0, [R0, #2] // R0 = LocString2[2]
3a10ec :78b9 x? : LDRB R1, [R7, #2] // R1 = Parm1[2]
3a10ee :4288 B? : CMP R0, R1 // if (LocString2[1] != Parm1[1])
3a10f0 :d117 ?. : BNE 3a1122 // goto Branch3
3a10f2 :a800 ?. : ADD R0, SP, #0000 //
3a10f4 :78c0 x? : LDRB R0, [R0, #3] //
3a10f6 :78f9 x? : LDRB R1, [R7, #3] //
3a10f8 :4288 B? : CMP R0, R1 // if (LocString2[3] != Parm1[3])
3a10fa :d112 ?. : BNE 3a1122 // goto Branch3
3a10fc :a801 ?. : ADD R0, SP, #0004 //
3a10fe :7800 x. : LDRB R0, [R0, #0] //
3a1100 :7939 y9 : LDRB R1, [R7, #4] //
3a1102 :4288 B? : CMP R0, R1 // if (LocString2[4] != Parm1[4])
3a1104 :d10d ?. : BNE 3a1122 // goto Branch3
3a1106 :a801 ?. : ADD R0, SP, #0004
3a1108 :78402800: : x@(. // ????? - probably a problem with the disassembler ...
3a110c :d0ca ?? : BEQ 3a10a4
3a110e :a801 ?. : ADD R0, SP, #0004
3a1110 :7840 x@ : LDRB R0, [R0, #1]
3a1112 :7979 yy : LDRB R1, [R7, #5]
3a1114 :4288 B? : CMP R0, R1 // if (LocString2[5] != Parm1[5])
3a1116 :d101 ?. : BNE 3a111c // goto Branch4
3a1118 :2001 . : MOV R0, #1 // R0 = 1
3a111a :e000 ?. : B 3a111e // goto Branch5
Branch4
3a111c :2000 . : MOV R0, #0 // R0 = 0
Branch5
3a111e :2800 (. : CMP R0, #0 // if (R0 != 0)
3a1120 :d1c0 ?? : BNE 3a10a4 // goto Branch1 (return(1))
Branch3
3a1122 :1c60 .` : ADD R0, R4, #1 // RO = R4 + 1
3a1124 :06040e24: AND R4, R0, #000000ff // R4 = R0 & #ff
3a1128 :a802 ?. : ADD R0, SP, #0008 // R0 = &LocByte1
3a112a :7800 x. : LDRB R0, [R0, #0] // R0 = LocByte1
3a112c :4284 B? : CMP R4, R0 // if(R4 == R0)
3a112e :dbc4 ?? : BLT 3a10ba // goto Branch6
Branch7
3a1130 :2000 . : MOV R0, #0 // return(0)
Branch8
3a1132 :b003 ?. : ADD SP, #000c // Liberate the 12 bytes on the stack
3a1134 :bdb0 ?? : POP { R4,R5,R7, PC } // Restore registers and return
-----------------------------------------^ end routine
I'm sure I missed something vital which is needed to help fix the code. Please post with any additional info you may need and I'll look it up.
Again, thanks for your time!