Search code examples
c++macosmemoryprocessdyld

Getting SizeOfImage and EntryPoint of dylib module


I'm writing a cross-platform memory analysis library and one of the functions I provide is GetProcessModules. On windows I use EnumProcessModules to get a list of all modules loaded in a process along with GetModuleInformation to retrieve the Address, SizeOfImage and EntryPoint of the module.

Translating this to OSX I found this and other sources which helped me implement this function. I've been able to use the dyld_image_info struct to get the name of the module and the loaded address but how do I go about getting the SizeOfImage and EntryPoint values?


Solution

  • SizeOfImage and EntryPoint are the field names in the Windows MODULEINFO structure. Naturally, the don't exist in the OS X context.

    The dynamic libraries used by an OS X task are object files of the Mach-O format, which has the following basic structure:

    Mach-O file format basic structure

    (From Apple: Mach-O File Format Reference)

    I will assume that the SizeOfImage value you are after is the number of bytes the whole object file consumes as currently loaded into memory. The way to do this is to sum the size of the Header, Load Commands and the data Segments. Something along the lines of:

    size_t size_of_image(struct mach_header *header) {
        size_t sz = sizeof(*header); // Size of the header
        sz += header->sizeofcmds;    // Size of the load commands
    
        struct load_command *lc = (struct load_command *) (header + 1);
        for (uint32_t i = 0; i < header->ncmds; i++) {
            if (lc->cmd == LC_SEGMENT) {
                sz += ((struct segment_command *) lc)->vmsize; // Size of segments
            }
            lc = (struct load_command *) ((char *) lc + lc->cmdsize);
        }
        return sz;
    }
    

    Next, the entry point is a little different. My guess is that you want the address of the initializer function of the dynamic library (ref here). This is found in the __mod_init_func section of the __DATA segment. To retrieve this section, we can use getsectbynamefromheader. This function returns a pointer to a "struct section", which contains a pointer to the virtual memory location of the section.

    #include <mach-o/getsect.h>
    
    uint32_t mod_init_addr(struct mach_header *header) {
        struct section *sec;
        if (sec = getsectbynamefromheader(header, "__DATA", "__mod_init_func")) {
            return sec->addr;
        }
        return 0;
    }
    

    The returned value is the virtual memory address of the __mod_init_func section, which contains "pointers to module initialization functions".

    NOTE: These structures and functions have analogous 64-bit implementations, suffixed by _64, such as struct mach_header_64, getsectbynamefromheader_64 etc. For 64-bit objects, these functions must be employed instead.

    Disclaimer: All code untested - coded in browser