CRO0: Difference between revisions
Svanheulen (talk | contribs) added new header info |
mNo edit summary |
||
(6 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
[[Category:File formats]] | [[Category:File formats]] | ||
CRO with extension .cro is used for "DLLs". CRS with extension .crs is in the same format of CRO but storing the symbol information of the static module (the main application). The end of the file is aligned to a 0x1000-byte boundary with 0xCC bytes. | |||
The first hash-table entry hashes the 0x100-byte header following the hash-table. The following hash-table entries hash the sections specified in the header. | |||
When the RO module loads the entire CRO into process memory(mapped in the 0x00100000-0x04000000 region), it modifies the mapped CRO data. The magic field is also changed to "FIXD" if fix level is not 0. | |||
Upon loading, the RO module will look for export symbol "nnroAeabiAtexit_" to patch it to its import symbol "__aeabi_atexit". | |||
For dumping symbols and loading a CRO into IDA, see [https://github.com/plutooo/ctr/] and [https://github.com/wwylele/IDA_plugin_CRO]. | |||
= Structure = | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 44: | Line 56: | ||
| 0xA0 | | 0xA0 | ||
| 0x04 | | 0x04 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] that is always the same as export symbol "nnroControlObject_". 0xFFFFFFFF in CRS | ||
|- | |- | ||
| 0xA4 | | 0xA4 | ||
| 0x04 | | 0x04 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] for "OnLoad" function, which will be called when the module is initialized. Set to 0xFFFFFFFF if not exists. | ||
|- | |- | ||
| 0xA8 | | 0xA8 | ||
| 0x04 | | 0x04 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] for "OnExit" function, which will be called when the module is finalized. Set to 0xFFFFFFFF if not exists. | ||
|- | |- | ||
| 0xAC | | 0xAC | ||
| 0x04 | | 0x04 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] for "OnUnresolved" function, which will be called when an unresolved function is called. Set to 0xFFFFFFFF if not exists. | ||
|- | |- | ||
| 0xB0 | | 0xB0 | ||
Line 195: | Line 207: | ||
|} | |} | ||
Segment offset (4 bytes) | ==Segment offset (4 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 208: | Line 220: | ||
|} | |} | ||
Segment Table entry (12 bytes) | ==Segment Table entry (12 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 227: | Line 239: | ||
|} | |} | ||
Named Export Table entry (8 bytes) | ==Named Export Table entry (8 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 239: | Line 251: | ||
| 0x4 | | 0x4 | ||
| 0x4 | | 0x4 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] for export | ||
|} | |} | ||
Indexed Export Table entry (4 bytes) | ==Indexed Export Table entry (4 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 250: | Line 262: | ||
| 0x0 | | 0x0 | ||
| 0x4 | | 0x4 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] for export | ||
|} | |} | ||
Named Import Table entry (8 bytes) | ==Named Import Table entry (8 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 268: | Line 280: | ||
|} | |} | ||
Indexed Import Table entry (8 bytes) | ==Indexed Import Table entry (8 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 283: | Line 295: | ||
|} | |} | ||
Anonymous Import Table entry (8 bytes) | ==Anonymous Import Table entry (8 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 291: | Line 303: | ||
| 0x0 | | 0x0 | ||
| 0x4 | | 0x4 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] of the export symbol | ||
|- | |- | ||
| 0x4 | | 0x4 | ||
Line 298: | Line 310: | ||
|} | |} | ||
Import Module Table entry (20 bytes) | ==Import Module Table entry (20 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 325: | Line 337: | ||
|} | |} | ||
Patch entry (12 bytes) | ==Patch entry (12 bytes)== | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
! Offset | ! Offset | ||
Line 333: | Line 345: | ||
| 0x0 | | 0x0 | ||
| 0x4 | | 0x4 | ||
| | | [[#Segment offset (4 bytes)|Segment offset]] for output. | ||
|- | |- | ||
| 0x4 | | 0x4 | ||
| 0x1 | | 0x1 | ||
| Patch type (0= | | Patch type (R_ARM_NONE = 0, R_ARM_ABS32 = 2, R_ARM_REL32 = 3, R_ARM_THM_PC22 = 10, R_ARM_CALL = 28, R_ARM_JUMP24 = 29, R_ARM_TARGET1 = 38, R_ARM_PREL31 = 42) | ||
|- | |- | ||
| 0x5 | | 0x5 | ||
Line 356: | Line 368: | ||
|} | |} | ||
Relocation code from RO: | |||
---- | static Result writePatch(u32* out, u32 patchType, u32 addend, u32 base, u32 inputPtr) { | ||
const s32 branchOffset = inputPtr - base; | |||
u32 offset = base + addend - inputPtr; | |||
if (patchType == R_ARM_NONE) | |||
return 0; | |||
if (patchType == R_ARM_ABS32 || patchType == R_ARM_TARGET1) { | |||
*out = base + addend; | |||
return 0; | |||
} | |||
if (patchType == R_ARM_REL32) { | |||
*out = offset; | |||
return 0; | |||
} | |||
if (patchType == R_ARM_THM_PC22) { | |||
// +-4MB. | |||
if (branchOffset >= 0x400000 || branchOffset <= -0x400000) | |||
return 0xD9012C23; | |||
if (base & 1) { | |||
*out = (((offset >> 12) | 0xF000) << 16) | ((offset << 4) >> 5) | 0xF800; | |||
} else { | |||
if (offset & 2) | |||
offset += 2; | |||
*out = ((offset >> 12) | 0xF000) << 16 | ((offset << 4) >> 5) | 0xE800; | |||
} | |||
return 0; | |||
} | |||
if (patchType == R_ARM_CALL) { | |||
// +-32MB. | |||
if (branchOffset >= 0x2000000 || branchOffset <= -0x2000000) | |||
return 0xD9012C23; | |||
if (base & 1) { | |||
*out = ((offset << 23) & 0x1000000) | ((offset << 6) >> 8) | 0xFA000000; | |||
} else { | |||
*out = 0xEB000000 | ((offset << 6) >> 8); | |||
} | |||
return 0; | |||
} | |||
if (patchType == R_ARM_JUMP24) { | |||
// +-32MB. | |||
if (branchOffset >= 0x2000000 || branchOffset <= -0x2000000 || (base & 1)) | |||
return 0xD9012C23; | |||
*out = (*out & 0xFF000000) | ((offset << 6) >> 8); | |||
return 0; | |||
} | |||
if (patchType == R_ARM_PREL31) { | |||
*out = addend + ((base << 1) >> 1) - inputPtr; | |||
return 0; | |||
} | |||
return 0xD9012C22; | |||
} | |||
== nnroControlObject == | |||
Signature: | |||
Result nnroControlObject(void* arg, u32 type); | |||
{| class="wikitable" border="1" | |||
! Type | |||
! Description | |||
|- | |||
| 0 | |||
| Write address of "nnroEitNode_" to memory pointed by arg (*(u32*)arg = &nnroEitNode_) | |||
|- | |||
| 1 | |||
| Set global in CRO to arg, where arg is the CRO end (g_CRO_end = (u32)arg) | |||
|- | |||
| 2 | |||
| Write CRO end to memory pointed by arg (*(u32*)arg = g_CRO_end) | |||
|- | |||
| 3 | |||
| Write begin, end of function list (C initializers?) to memory pointed by arg (*(u32*)arg = (u32)listBegin, ((u32*)arg)[1] = (u32)listEnd) | |||
|- | |||
| 4 | |||
| Write begin, end of function list (C++ initializers?) to memory pointed by arg (*(u32*)arg = (u32)listBegin, ((u32*)arg)[1] = (u32)listEnd) | |||
|} | |||
"EitNode" are nodes of a linked list containing informations about the main executable + loaded modules: | |||
{| class="wikitable" border="1" | |||
! Index Word | |||
! Type | |||
! Description | |||
|- | |||
| 0 | |||
| EitNode* | |||
| Pointer to the previous element of the list | |||
|- | |||
| 1 | |||
| EitNode* | |||
| Pointer to the next element of the list | |||
|- | |||
| 2 | |||
| u32 | |||
| Module code start, for the main executable this is .text base, for CROs this is the value at CRO+0xB0 | |||
|- | |||
| 3 | |||
| u32 | |||
| Module code end (start + size), for the main executable the size is the size of all mapped sections, for CROs it's the value at CRO+0xB4 | |||
|- | |||
| 4 | |||
| u32* | |||
| Unknown, seems to be an array of u32, probably holds debugging informations | |||
|- | |||
| 5 | |||
| u32* | |||
| This points at the end of the previous array | |||
|- | |||
| 6 | |||
| ElfNode* (?) | |||
| Unknown, this is only set for the main executable node, and it points to itself | |||
|} |