CRO0: Difference between revisions

DeltaF1 (talk | contribs)
Link to the definition for segment offsets
Kynex7510 (talk | contribs)
mNo edit summary
 
(4 intermediate revisions by 2 users not shown)
Line 10: Line 10:


For dumping symbols and loading a CRO into IDA, see [https://github.com/plutooo/ctr/] and [https://github.com/wwylele/IDA_plugin_CRO].
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 54: Line 56:
| 0xA0
| 0xA0
| 0x04
| 0x04
| [[Segment offset (4 bytes)|Segment offset]] that is always the same as export symbol "nnroControlObject_". 0xFFFFFFFF in CRS
| [[#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.
| [[#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.
| [[#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.
| [[#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 218: Line 220:
|}
|}


Segment Table entry (12 bytes)
==Segment Table entry (12 bytes)==
{| class="wikitable" border="1"
{| class="wikitable" border="1"
!  Offset
!  Offset
Line 237: 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 249: Line 251:
| 0x4
| 0x4
| 0x4
| 0x4
| [[Segment offset (4 bytes)|Segment offset]] for export
| [[#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 260: Line 262:
| 0x0
| 0x0
| 0x4
| 0x4
| [[Segment offset (4 bytes)|Segment offset]] for export
| [[#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 278: 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 293: 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 301: Line 303:
| 0x0
| 0x0
| 0x4
| 0x4
| [[Segment offset (4 bytes)|Segment offset]] of the export symbol
| [[#Segment offset (4 bytes)|Segment offset]] of the export symbol
|-
|-
| 0x4
| 0x4
Line 308: 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 335: Line 337:
|}
|}


Patch entry (12 bytes)
==Patch entry (12 bytes)==
{| class="wikitable" border="1"
{| class="wikitable" border="1"
!  Offset
!  Offset
Line 343: Line 345:
| 0x0
| 0x0
| 0x4
| 0x4
| [[Segment offset (4 bytes)|Segment offset]] for output.
| [[#Segment offset (4 bytes)|Segment offset]] for output.
|-
|-
| 0x4
| 0x4
| 0x1
| 0x1
| Patch type (0=nothing/ignore, 2=38=write u32 absolute (base+addend), 3=write u32 relative (base+addend-in_ptr), 10=THUMB branch, 28=ARM32 branch, 29=modify ARM32 branch offset, 42=write u32 relative (((signed int)base*2)/2+addend-in_ptr), otherwise err) (This is apparently a subset of relocation type for ARM ELF)
| 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 366: Line 368:
|}
|}


ARM32 branch instruction is constructed as follows:
Relocation code from RO:
  If addend > 0x2000000 or addend < 0xFE000000, then skip.
 
  If (addend&1) == 1 then write "b +4" (nop).
static Result writePatch(u32* out, u32 patchType, u32 addend, u32 base, u32 inputPtr) {
  Else write as normal.
    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
|}