I'm wondering how the info stored in the chained fixups in the Mach-O file is used to resolve binding and rebases?
My question originated from wanting to parse all the Objective-C classes inside a Mach-O and parse their respective objc_class
and get a list of selectors.
In-order to achieve that I started by parsing the Mach-O segments to get to the section __objc_classlist
and read the pointers that should point to struct of type objc_class
.
What I don't understand is how to use the stored information there to fix these pointers for example. Taking as a ref point I have a binary that the first pointer on disk (0x00231D8
) in the __objc_classlist
section points to 0x0025EED0
which is its related objc_class
struct (validated using Ghidra). When I read from 0x00231D8
I get 0x801000000000022a
which is not a valid pointer, pointing to the mapped file.
After seeing that the pointers are invalid I was noted that I should parse and use the information stored in the chained fixups load command to fix the pointers.
So I parsed the chained fixups but I'm not sure how to use the parsed binds/rebases structs in-order to fix the pointers for example at the __objc_classlist
.
Taking the ref point I'm working on to validate my work, I use Ghidra to see what symbol the first pointer in the __objc_classlist
actually is and I look for any binding info related to that symbol in my parsed result to find the following both in the fixups of the __DATA_CONST
and the __DATA
segments:
BIND ordinal: 554 addend: 0 reserved: 0 (_OBJC_METACLASS_$_XYZ)
I understand that the ordinal is the index into the symbol table pointer to by the dyld_chained_fixups_header
imports_offset
which I also printed to validate the ordinal is correct:
[553] lib_ordinal: 15 weak_import: 0 name_offset: 13346 (ABC)
[554] lib_ordinal: 0 weak_import: 0 name_offset: 13380 (_OBJC_CLASS_$_XYZ)
[555] lib_ordinal: 0 weak_import: 0 name_offset: 13429 (_OBJC_CLASS_$_DEF)
Now I'm not sure if what I should be looking for in the chained fixups in-order to fix these class pointers is rebase/bind information. I know rebase is used for ASLR when loading other libs so if the objective-c class list is the binary owned class list there's no reason for rebases at least for these pointers, on the other hand even though I find related binding information to my class I don't see why do we need this information if it's a data owned by the binary and not some other dylib, why do we need to bind it in runtime?
Even so, how do I even use this information in-order to fix the pointer for example at 0x00231D8
in the __objc_classlist
? All I have is the binding information which gives an ordinal to the chained fixups imports as-well as addend
field which seems to always be 0 and I have no idea what it is used for.
The only logical jump I could've make is that if I look for the same import by its symbol name in the symbol table pointed by the symbol table command and take the n_value
of the symbol I get that elusive 0x0025EED0
pointer value.
But that still doesn't answer on how this symbol value should be the pointer in the first address of the __objc_classlist
section 0x00231D8
, what BINDs them together?
Continuing on, even if I read the value from disk in address 0x0025EED0
which should be the objc_class
struct of that symbol that resides in __DATA.__objc_data
, I get 80 10 00 00 00 00 03 c7
and by looking at the valid data in Ghidra I see f8 ee 25 00 00 00 00 00
, so clearly another discrepancy and maybe this data also need rebase/binding?
So I tried to take the address of the struct 0x0025EED0
and see if I can find rebase information (didn't look for binding information since it's not a symbol just a struct data?) on it from the chained fixups but couldn't find any so I'm not sure what needs to be done to fix it?