LoadLibraryDlopen - loads a single library using dlopen and resolves all exported symbols using dlsym. This function writes to a temporary file and then loads the file into memory, and unlinks it. This is similar to what NSLinkModule does nowadays.
(name string, image *[]byte)
| 162 | // file and then loads the file into memory, and unlinks it. |
| 163 | // This is similar to what NSLinkModule does nowadays. |
| 164 | func LoadLibraryDlopen(name string, image *[]byte) (*Library, error) { |
| 165 | var ( |
| 166 | dlopenAddr uint64 |
| 167 | dlSymAddr uint64 |
| 168 | dyldAddress uint64 |
| 169 | ) |
| 170 | |
| 171 | machoFile, err := macho.NewFile(bytes.NewReader(*image)) |
| 172 | if err != nil { |
| 173 | return nil, err |
| 174 | } |
| 175 | |
| 176 | // We use the shared library cache to find the libdyld.dylib wrapper loaded into our process. |
| 177 | // Once we have the address of the libdyld.dylib wrapper, we can parse it in memory using debug/macho (thanks Awgh) |
| 178 | // and find the exports we're interested in: dlopen and dlsym. |
| 179 | // This part of the code is a port from the awesome work of usiegl00: https://github.com/usiegl00/metasploit-framework/blob/osx-stage-monterey/external/source/shellcode/osx/stager/main.c#L159-L183 |
| 180 | sharedRegionStart, err := syscallSharedRegionCheckNp() |
| 181 | if err != nil { |
| 182 | return nil, err |
| 183 | } |
| 184 | dyldCacheheader := (*DyldCacheHeader)(unsafe.Pointer(uintptr(sharedRegionStart))) |
| 185 | |
| 186 | imagesCount := dyldCacheheader.ImagesCountOld |
| 187 | if imagesCount == 0 { |
| 188 | imagesCount = dyldCacheheader.ImagesCount |
| 189 | } |
| 190 | imagesOffset := dyldCacheheader.ImagesOffsetOld |
| 191 | if imagesOffset == 0 { |
| 192 | imagesOffset = dyldCacheheader.ImagesOffset |
| 193 | } |
| 194 | sharedFileMapping := (*SharedFileMapping)(unsafe.Pointer(uintptr(sharedRegionStart + uint64(dyldCacheheader.MappingOffset)))) |
| 195 | |
| 196 | dyldCacheImageInfo := (*DyldCacheImageInfo)(unsafe.Pointer(uintptr(sharedRegionStart + uint64(imagesOffset)))) |
| 197 | for i := uint32(0); i < imagesCount; i++ { |
| 198 | pathFileOffset := sharedRegionStart + uint64(dyldCacheImageInfo.PathFileOffset) |
| 199 | dylibPath := readCString(pathFileOffset) |
| 200 | if dylibPath == LIB_DYLD_PATH { |
| 201 | dyldAddress = dyldCacheImageInfo.Address |
| 202 | break |
| 203 | } |
| 204 | dyldCacheImageInfo = (*DyldCacheImageInfo)(unsafe.Pointer(uintptr(sharedRegionStart+uint64(imagesOffset)) + uintptr(i)*unsafe.Sizeof(DyldCacheImageInfo{}))) |
| 205 | } |
| 206 | |
| 207 | offset := sharedRegionStart - sharedFileMapping.Address |
| 208 | dyldAddress += offset |
| 209 | |
| 210 | rawr := rawreader.New(uintptr(dyldAddress), MaxInt) |
| 211 | dyldFile, err := macho.NewFileFromMemory(rawr) |
| 212 | if err != nil { |
| 213 | return nil, err |
| 214 | } |
| 215 | exports := dyldFile.Exports() |
| 216 | |
| 217 | for _, export := range exports { |
| 218 | if export.Name == "_dlopen" { |
| 219 | dlopenAddr = export.VirtualAddress + offset |
| 220 | } |
| 221 | if export.Name == "_dlsym" { |
no test coverage detected
searching dependent graphs…