Skip to content

DerekSelander/dyldplus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dyldplus

This codebase attempts to load a mach-o from memory and registers it into the dyld codebase so one can inject code without having to recompile the program. It also exposes the primary API, void* dlopen_register_memory(void *mmap_mem) This can be useful for debugging with lldb and symbol referencing, dlclose, and dlsym functions.

This is a deviates from https://blog.xpnsec.com/restoring-dyld-memory-loading/ which many of the ideas appear to be no longer usable and primarily for the macOS.

This has been tested on:

  • iOS 16.7
  • iOS 17.something
  • iOS 18.1
  • iOS 26b1

Howto

Make sure your computer and your iOS device is on the same network. Navigate to the Settings on the iOS device, find the network and your devices IP address.

Compile a basic test iOS file like so:

#include <Foundation/Foundation.h>

@interface HHIUHIHIHI: NSObject
@end
@implementation HHIUHIHIHI
+ (void)load {
    NSLog(@"%s:%d: objc +load command called", __PRETTY_FUNCTION__, __LINE__);
}
@end

__attribute__((constructor)) static void oninit(void) {
    NSLog(@"%s:%d: constructor called", __PRETTY_FUNCTION__, __LINE__);
}

__attribute__((destructor)) static void ondeinit(void) {
    NSLog(@"%s:%d: destructor called", __PRETTY_FUNCTION__, __LINE__);
}

Compile:

> xcrun -sdk iphoneos clang -fobjc-arc -fmodules /tmp/yo.m -shared -o /tmp/yo.dylib -g   -mios-version-min=15.0

Optionally codesign (see below):

>codesigning -f -s ${YOUR_ID_HERE} /tmp/yo.dylib

Turn on device log monitoring for the dlopenPOC process:

> idevicesyslog -p dlopenPOC

Upload the dylib to the device, while keeping an eye on the logs:

nc 192.168.86.222 3501  < /tmp/yo.dylib
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: Connected!
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: Got a connection.
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: Sending reply...
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: Receiving command...
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: bulk image update start! ***********************
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: 1063a0000 [MEMORY]/0x1092d0000//tmp/yo.dylib
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: bulk image update end ***************************
Jun 18 23:37:22 dlopenPOC(yo.dylib)[3195] <Notice>: +[HHIUHIHIHI load]:7: objc +load command called
Jun 18 23:37:22 dlopenPOC(yo.dylib)[3195] <Notice>: void oninit(void):12: constructor called
Jun 18 23:37:22 dlopenPOC[3195] <Notice>: dlopen success! handle: 0x8223a890

Example done on iOS 26b1 ^

In addition, the UI will reflect all loaded dylibs that dyld recognizes as loaded into the process

dyld loaded images

Limitations

ios 26

Although it works for all these versions, there are limitations especially for iOS 26b1 (and maybe the future). Even when a process has get-task-allow and is being debugged, it is not allowed to patch it's own memory nor is it allowed to create it's own RX memory. As a result, a breakpoint is created and the debugserver must actually patch the memory. The debugging command to write to RX memory is the following for this project:

br set -n lldb_callout -G1 -C "script e = lldb.SBError(); content = lldb.process.ReadMemory(`$arg2`, `$arg3`, e); lldb.process.WriteMemory(`$arg1`, content, e) ; e"

In the iOS Xcode project, a shared symbolic breakpoint is created so you don't have to do anything. If however, you delete all GUI Xcode breakpoints, the functionality will be lost and you'll have to recreate the symbolic breakpoint, or execucte the above command before memory patching occurs

codesigning

For all other iOS versions, if you are running the iOS application, dlopenPOC, under the debugger great, you don't need to worry about anything. However, if you are running it without a debugger, you'll need to worry about codesigning. Code validation doesn't happen when your process is being debugged. If you attempt to load a mach-o that isn't codesigned with the same signature that created the dlopenPOC executable without being debugged, the code will refuse to load and crash. Here's an example of looking at the build product and figuring out how to properly sign an executable

After building dlopenPOC in Xcode, select Products, Show Build Folder in Finder, then in Terminal...

> cd cd /Users/feet/Library/Developer/Xcode/DerivedData/dyldplus-frdkvakfgvrcdjajztsfrvspwobt/Build/Products/Debug-iphoneos/dlopenPOC.app
> codesign -d --verbose=10 dlopenPOC 2>&1  | grep Authority
Authority=Apple Development: im Apple (9AABCDCA9F)
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA

# you can find all your valid identities with this command
> security find-identity
Policy: X.509 Basic
  Matching identities
  1) 0000000000000000000000000000000000000000 "Apple Development: im Apple (9AABCDCA9F)"
     1 identities found

  Valid identities only
  1) 0000000000000000000000000000000000000000 "Apple Development: im Apple(9AABCDCA9F)"
     1 valid identities found

# now codesign a newly built shared library with the same signature
codesigning -f -s "Tim Apple (9AABCDCA9F)" /tmp/some_executable.dylib

About

file free dlopen

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors