1

I am trying to extract libraries from the Dyld_shared_cache, and need to fix in external references.

For example, the pointers in the __DATA.__objc_selrefs section usually point to data outside the mach-o file, to fix that I would have to copy the corresponding c-string from the dyld and append it to the __TEXT.__objc_methname section.

Though from my understanding of the Mach-O file format, this extension of the __TEXT.__objc_methname would shift all the sections after it and would force me to fix all the offsets and pointers that reference them. Is there a way to add data to a section without breaking a lot of things?

Thanks!

ArandomDev
  • 125
  • 2
  • 10

2 Answers2

2

Thanks to @Kamil.S for the idea about adding a new load command and section.

One way to achieve adding more data to a section is to create a duplicate segment and section and insert it before the __LINKEDIT segment.

  • Slide the __LINKEDIT segment so we have space to add the new section.
    1. define the slide amount, this must be page-aligned, so I choose 0x4000.
    2. add the slide amount to the relevant load commands, this includes but is not limited to:
      • __LINKEDIT segment (duh)
      • dyld_info_command
      • symtab_command
      • dysymtab_command
      • linkedit_data_commands
    3. physically move the __LINKEDIT in the file.
  • duplicate the section and change the following1
    • size, should be the length of your new data.
    • addr, should be in the free space.
    • offset, should be in the free space.
  • duplicate the segment and change the following1
    • fileoff, should be the start of the free space.
    • vmaddr, should be the start of the free space.
    • filesize, anything as long as it is bigger than your data.
    • vmsize, must be identical to filesize.
    • nsects, change to reflect how many sections your adding.
    • cmdsize, change to reflect the size of the segment command and its section commands.
  • insert the duplicated segment and sections before the __LINKEDIT segment
  • update the mach_header
    • ncmds
    • sizeofcmds
  • physically write the extra data in the file.

  1. you can optionally change the segname and sectname fields, though it isn't necessary. thanks Kamil.S!
ArandomDev
  • 125
  • 2
  • 10
1

UPDATE
After clarifing with OP that extension of __TEXT.__objc_methname would happen during Mach-O post processing of an existing executable I had a fresh look on the problem.

Another take would be to create a new load command LC_SEGMENT_64 with a new __TEXT_EXEC.__objc_methname segment / section entry (normally __TEXT_EXEC is used for some kernel stuff but essentially it's the same thing as __TEXT). Here's a quick POC to ilustrate the concept:

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        printf("%lx",[NSObject new]);
    }
    return 0;
}

Compile like this:

gcc main.m -c -o main.o 
ld main.o -rename_section __TEXT __objc_methname __TEXT_EXEC __objc_methname -lobjc -lc 

Interestingly only ld up to High Sierra 10.14.6 generates __TEXT.__objc_methname, no trace of it on Catalina, it's done differently.

UPDATE2.
Playing around with it, I noticed execution rights for __TEXT segment (and __TEXT_EXEC for that matter) are not required for __objc_methname to work. Even better specific segment & section names are not required:
I could pull off:

__DATA.__objc_methname   
__DATA_CONST.__objc_methname 
__ARBITRARY.__arbitrary 

or in my case last __DATA section
__DATA.__objc_classrefs where the original the data got concatenated by the selector name. It's all fine as long as a proper null terminated C-string with the selector name is there. If I intentionally break the "new\0" in hex editor or MachOView I'll get

"+[NSObject ne]: unrecognized selector sent to instance ..."

upon launching my POC executable so the value is used for sure.

So to sum __TEXT.__objc_methname section itself is likely some debugger hint made by the linker. The app runtime seems to only need selector names as char* anywhere in memory.

Kamil.S
  • 5,205
  • 2
  • 22
  • 51
  • My case is case 2, where I am reconstructing a Mach-O file after compile time. Case 2, alternative A probably won't work (unless I'm misunderstanding you) because for sections like the __TEXT.__objc_methname, it is sandwiched between sections, without any padding. Alternative b might work but would require some time test. – ArandomDev Apr 19 '20 at 20:37
  • I would have to test this, but could this be generalized for other segments like __DATA and __DATA_CONST? – ArandomDev Apr 20 '20 at 13:04
  • I tried to add a whole new load command, with the data at the end of the file, but when trying to load it on my phone, I get the following NSError, `/Library/Frameworks/TestMacho.framework/TestMacho: malformed mach-o image: __LINKEDIT must be last segment`. – ArandomDev Apr 20 '20 at 14:42
  • You'd have to insert the `LC_SEGMENT_64` before `__LINKEDIT`.I was able to squash `__TEXT.__objc_methname` into `__DATA.__objc_classrefs` and it still worked. Why do you need a new section/segment/ load command in the 1st place? – Kamil.S Apr 20 '20 at 15:55
  • Well originally I just wanted to add more data to sections. – ArandomDev Apr 20 '20 at 17:41