LoadLibraryImpl - loads a single library to memory, without trying to check or load required imports
(name string, image *[]byte)
| 43 | |
| 44 | // LoadLibraryImpl - loads a single library to memory, without trying to check or load required imports |
| 45 | func LoadLibraryImpl(name string, image *[]byte) (*Library, error) { |
| 46 | // On MacOS Sierra and up, NSLinkModule is just a wrapper around |
| 47 | // dlopen, pwrite and unlink. There's no "in-memory" only method using |
| 48 | // dyld4 APIs, so there's no point in using NSCreateObjectFileImageFromMemory and NSLinkModule anymore. |
| 49 | // We can just write our own version that: |
| 50 | // - writes the binary image to a temporary file |
| 51 | // - calls dlopen on the temporary file |
| 52 | // - unlinks the temporary file |
| 53 | // - uses dlsym to resolve all the symbols |
| 54 | // See https://github.com/apple-oss-distributions/dyld/blob/main/dyld/DyldAPIs.cpp#L2785-L2847 for more details. |
| 55 | if isSierra() { |
| 56 | return LoadLibraryDlopen(name, image) |
| 57 | } |
| 58 | // force input image to be a bundle |
| 59 | // this is not the most efficient method, but it does create the abililty to do more fixups down the road, |
| 60 | // like if we added universal file support |
| 61 | machoFile, err := macho.NewFile(bytes.NewReader(*image)) |
| 62 | if err != nil { |
| 63 | return nil, err |
| 64 | } |
| 65 | machoFile.FileHeader.Type = macho.TypeBundle |
| 66 | newImage, err := machoFile.Bytes() |
| 67 | if err != nil { |
| 68 | return nil, err |
| 69 | } |
| 70 | image = &newImage |
| 71 | |
| 72 | // Find dyld, loop through all the Mach-O images in memory until we find |
| 73 | // one that exports NSCreateObjectFileImageFromMemory and NSLinkModule |
| 74 | var execBase uintptr = uintptr(0x0000000001000000) |
| 75 | ptr := execBase |
| 76 | var createObjectAddr, linkModuleAddr uint64 |
| 77 | |
| 78 | for i := 0; i < 10; i++ { // quit after the first ten images |
| 79 | ptr, err = findMacho(ptr, 0x1000) |
| 80 | if err != nil { |
| 81 | return nil, err |
| 82 | } |
| 83 | fmt.Printf("Found image at 0x%08x\n", ptr) |
| 84 | rawr := rawreader.New(ptr, MaxInt) |
| 85 | machoFile, err := macho.NewFileFromMemory(rawr) |
| 86 | if err != nil { |
| 87 | return nil, err |
| 88 | } |
| 89 | exports := machoFile.Exports() |
| 90 | |
| 91 | foundCreateObj := false |
| 92 | foundLinkModule := false |
| 93 | for _, export := range exports { |
| 94 | if export.Name == "_NSCreateObjectFileImageFromMemory" { |
| 95 | fmt.Println("found NSCreateObjectFileImageFromMemory") |
| 96 | createObjectAddr = export.VirtualAddress |
| 97 | foundCreateObj = true |
| 98 | } |
| 99 | if export.Name == "_NSLinkModule" { |
| 100 | fmt.Println("found NSLinkModule") |
| 101 | linkModuleAddr = export.VirtualAddress |
| 102 | foundLinkModule = true |
nothing calls this directly
no test coverage detected
searching dependent graphs…