mirror of
https://github.com/khanhduytran0/coruna.git
synced 2026-07-12 06:56:38 +02:00
tmp
This commit is contained in:
Binary file not shown.
+7260
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
.theos/
|
||||
packages/
|
||||
.DS_Store
|
||||
@@ -0,0 +1,21 @@
|
||||
TARGET := iphone:clang:latest:15.0
|
||||
ARCHS = arm64 arm64e
|
||||
FINALPACKAGE = 1
|
||||
STRIP = 0
|
||||
GO_EASY_ON_ME = 1
|
||||
|
||||
include $(THEOS)/makefiles/common.mk
|
||||
|
||||
SUBPROJECTS += SpringBoardTweak
|
||||
include $(THEOS_MAKE_PATH)/aggregate.mk
|
||||
|
||||
LIBRARY_NAME = TweakLoader
|
||||
TweakLoader_FILES = TweakLoader.m lv_bypass.c
|
||||
TweakLoader_CFLAGS = -fno-objc-arc
|
||||
TweakLoader_LDFLAGS = -sectcreate __TEXT __SBTweak $(THEOS_OBJ_DIR)/SpringBoardTweak.dylib
|
||||
TweakLoader_INSTALL_PATH = /usr/local/lib
|
||||
|
||||
$(THEOS_OBJ_DIR)/TweakLoader.dylib: \
|
||||
$(THEOS_OBJ_DIR)/SpringBoardTweak.dylib
|
||||
|
||||
include $(THEOS_MAKE_PATH)/library.mk
|
||||
@@ -0,0 +1,16 @@
|
||||
TARGET := iphone:clang:latest:15.0
|
||||
ARCHS = arm64 arm64e
|
||||
FINALPACKAGE = 1
|
||||
STRIP = 0
|
||||
GO_EASY_ON_ME = 1
|
||||
|
||||
include $(THEOS)/makefiles/common.mk
|
||||
|
||||
LIBRARY_NAME = SpringBoardTweak
|
||||
|
||||
SpringBoardTweak_FILES = SpringBoardTweak.m
|
||||
SpringBoardTweak_CFLAGS = -fobjc-arc
|
||||
SpringBoardTweak_LDFLAGS = -undefined dynamic_lookup
|
||||
SpringBoardTweak_INSTALL_PATH = /usr/local/lib
|
||||
|
||||
include $(THEOS_MAKE_PATH)/library.mk
|
||||
@@ -0,0 +1,8 @@
|
||||
@import UIKit;
|
||||
|
||||
static void showAlert(NSString *title, NSString *message);
|
||||
|
||||
@interface SpringBoard : UIApplication
|
||||
+ (SpringBoard *)sharedApplication;
|
||||
- (UIView *)statusBarForEmbeddedDisplay;
|
||||
@end
|
||||
@@ -0,0 +1,259 @@
|
||||
@import UIKit;
|
||||
@import UniformTypeIdentifiers;
|
||||
#import "SpringBoardTweak.h"
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/message.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <spawn.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#pragma mark - Status Bar Clock Tweak
|
||||
|
||||
static void (*orig_applyStyleAttributes)(id self, SEL _cmd, id arg1);
|
||||
static void (*orig_setText)(id self, SEL _cmd, NSString *text);
|
||||
|
||||
static void hook_applyStyleAttributes(id self, SEL _cmd, id arg1) {
|
||||
UILabel *label = (UILabel *)self;
|
||||
if (!(label.text != nil && [label.text containsString:@":"])) {
|
||||
orig_applyStyleAttributes(self, _cmd, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
static void hook_setText(id self, SEL _cmd, NSString *text) {
|
||||
if ([text containsString:@":"]) {
|
||||
UILabel *label = (UILabel *)self;
|
||||
@autoreleasepool {
|
||||
NSMutableAttributedString *finalString = [[NSMutableAttributedString alloc] init];
|
||||
|
||||
NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
|
||||
[formatter1 setDateFormat:@"HH:mm"];
|
||||
UIFont *font1 = [UIFont systemFontOfSize:15.0 weight:UIFontWeightSemibold];
|
||||
NSAttributedString *attrString1 = [[NSAttributedString alloc] initWithString:[formatter1 stringFromDate:[NSDate date]]
|
||||
attributes:@{NSFontAttributeName: font1}];
|
||||
|
||||
NSLocale *currentLocale = [NSLocale autoupdatingCurrentLocale];
|
||||
NSDateFormatter *formatter2 = [[NSDateFormatter alloc] init];
|
||||
[formatter2 setDateFormat:@"E dd/MM/yyyy"];
|
||||
[formatter2 setLocale:currentLocale];
|
||||
UIFont *font2 = [UIFont systemFontOfSize:8.0 weight:UIFontWeightRegular];
|
||||
NSAttributedString *attrString2 = [[NSAttributedString alloc] initWithString:[formatter2 stringFromDate:[NSDate date]]
|
||||
attributes:@{NSFontAttributeName: font2}];
|
||||
|
||||
[finalString appendAttributedString:attrString1];
|
||||
[finalString appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]];
|
||||
[finalString appendAttributedString:attrString2];
|
||||
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.numberOfLines = 2;
|
||||
label.attributedText = finalString;
|
||||
}
|
||||
} else {
|
||||
orig_setText(self, _cmd, text);
|
||||
}
|
||||
}
|
||||
|
||||
static void hookStatusBarClass(Class cls) {
|
||||
if (!cls) return;
|
||||
|
||||
Method m1 = class_getInstanceMethod(cls, @selector(applyStyleAttributes:));
|
||||
if (m1) {
|
||||
orig_applyStyleAttributes = (void *)method_getImplementation(m1);
|
||||
method_setImplementation(m1, (IMP)hook_applyStyleAttributes);
|
||||
}
|
||||
|
||||
Method m2 = class_getInstanceMethod(cls, @selector(setText:));
|
||||
if (m2) {
|
||||
orig_setText = (void *)method_getImplementation(m2);
|
||||
method_setImplementation(m2, (IMP)hook_setText);
|
||||
}
|
||||
}
|
||||
|
||||
static void initStatusBarTweak(void) {
|
||||
// iOS 17+: STUIStatusBarStringView (StatusBarUI framework)
|
||||
Class cls17 = objc_getClass("STUIStatusBarStringView");
|
||||
// iOS 16: _UIStatusBarStringView (UIKit private)
|
||||
Class cls16 = objc_getClass("_UIStatusBarStringView");
|
||||
|
||||
if (cls17) hookStatusBarClass(cls17);
|
||||
if (cls16) hookStatusBarClass(cls16);
|
||||
}
|
||||
|
||||
#pragma mark - Status Bar gesture
|
||||
|
||||
@implementation SpringBoard(Hook)
|
||||
+ (SpringBoard *)sharedApplication {
|
||||
return (id)UIApplication.sharedApplication;
|
||||
}
|
||||
- (void)initStatusBarGesture {
|
||||
[self.statusBarForEmbeddedDisplay addGestureRecognizer:[[UILongPressGestureRecognizer alloc]
|
||||
initWithTarget:self action:@selector(statusBarLongPressed:)
|
||||
]];
|
||||
}
|
||||
|
||||
- (void)showInjectedAlert {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Coruna"
|
||||
message:@"SpringBoard is pwned. Long-press on the status bar to activate this menu." preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Install TrollStore helper to Tips"
|
||||
style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
NSString *hp = @"/tmp/PersistenceHelper_Embedded";
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:hp]) {
|
||||
showAlert(@"Ready", @"PersistenceHelper is at /tmp/.\nNow open Tips app - it will launch PersistenceHelper instead!");
|
||||
} else {
|
||||
showAlert(@"Downloading...", @"PersistenceHelper is being downloaded. Wait a moment and try again.");
|
||||
}
|
||||
}]];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Enable Status Bar Tweak"
|
||||
style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
initStatusBarTweak();
|
||||
showAlert(@"Done", @"Status bar tweak enabled!\nLock and unlock your device for it to take effect.");
|
||||
}]];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Load .dylib tweak"
|
||||
style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
UIDocumentPickerViewController *documentPickerVC = [[UIDocumentPickerViewController alloc]
|
||||
initForOpeningContentTypes:@[[UTType typeWithFilenameExtension:@"dylib" conformingToType:UTTypeData]]
|
||||
asCopy:NO];
|
||||
documentPickerVC.allowsMultipleSelection = YES;
|
||||
documentPickerVC.delegate = (id<UIDocumentPickerDelegate>)self;
|
||||
[SpringBoard.viewControllerToPresent presentViewController:documentPickerVC animated:YES completion:nil];
|
||||
}]];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Activate FLEX"
|
||||
style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
Class flexManagerClass = NSClassFromString(@"FLEXManager");
|
||||
if (flexManagerClass) {
|
||||
id sharedManager = [flexManagerClass valueForKey:@"sharedManager"];
|
||||
[sharedManager performSelector:@selector(showExplorer)];
|
||||
} else {
|
||||
showAlert(@"Error", @"FLEXManager not found. Please load libFLEX.dylib first");
|
||||
}
|
||||
}]];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Respring (will remove inject)"
|
||||
style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {
|
||||
exit(0);
|
||||
}]];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel handler:nil]];
|
||||
|
||||
[SpringBoard.viewControllerToPresent presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
// Document picker delegate
|
||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {
|
||||
if (urls.count <= 0) return;
|
||||
NSString *log = @"";
|
||||
for (NSURL *url in urls) {
|
||||
NSString *path = url.path;
|
||||
log = [log stringByAppendingFormat:@"Load %@:", path.lastPathComponent];
|
||||
//if (![[NSFileManager defaultManager] fileExistsAtPath:path]) return;
|
||||
void *handle = dlopen(path.UTF8String, RTLD_NOW);
|
||||
if (handle) {
|
||||
log = [log stringByAppendingString:@" Success!\n"];
|
||||
} else {
|
||||
log = [log stringByAppendingFormat:@" Failed: %s\n", dlerror()];
|
||||
}
|
||||
}
|
||||
showAlert(@"Result", log);
|
||||
}
|
||||
|
||||
- (void)statusBarLongPressed:(UILongPressGestureRecognizer *)gesture {
|
||||
if (gesture.state == UIGestureRecognizerStateBegan) {
|
||||
[self showInjectedAlert];
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIViewController *)viewControllerToPresent {
|
||||
UIViewController *root = UIApplication.sharedApplication.keyWindow.rootViewController;
|
||||
while (root.presentedViewController) root = root.presentedViewController;
|
||||
return root;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - FrontBoard Trust Bypass (AppSync-like)
|
||||
|
||||
static IMP orig_trustStateForApplication = NULL;
|
||||
static NSUInteger hook_trustStateForApplication(id self, SEL _cmd, id application) {
|
||||
return 8; // Always trusted (iOS 14+)
|
||||
}
|
||||
|
||||
static void initFrontBoardBypass(void) {
|
||||
Class cls = objc_getClass("FBSSignatureValidationService");
|
||||
if (cls) {
|
||||
Method m = class_getInstanceMethod(cls, @selector(trustStateForApplication:));
|
||||
if (m) {
|
||||
orig_trustStateForApplication = method_getImplementation(m);
|
||||
method_setImplementation(m, (IMP)hook_trustStateForApplication);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - RBSLaunchContext Hook (Tips -> PersistenceHelper)
|
||||
|
||||
@interface RBSLaunchContext : NSObject
|
||||
@property (nonatomic, copy, readonly) NSString *bundleIdentifier;
|
||||
@end
|
||||
@implementation RBSLaunchContext(Hook)
|
||||
- (NSString *)_overrideExecutablePath {
|
||||
if([self.bundleIdentifier isEqualToString:@"com.apple.tips"]) {
|
||||
return @"/tmp/PersistenceHelper_Embedded";
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
void showAlert(NSString *title, NSString *message) {
|
||||
UIAlertController *a = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
|
||||
[a addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
||||
[SpringBoard.viewControllerToPresent presentViewController:a animated:YES completion:nil];
|
||||
}
|
||||
|
||||
static NSData *downloadFile(NSString *urlString) {
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
|
||||
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
|
||||
timeoutInterval:60];
|
||||
__block NSData *downloadedData = nil;
|
||||
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
|
||||
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
downloadedData = data;
|
||||
dispatch_semaphore_signal(sem);
|
||||
}];
|
||||
[task resume];
|
||||
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
|
||||
return downloadedData;
|
||||
}
|
||||
|
||||
#pragma mark - Constructor
|
||||
|
||||
__attribute__((constructor)) static void init() {
|
||||
initFrontBoardBypass();
|
||||
// Auto-enable status bar tweak on load (works on both iOS 16 and 17)
|
||||
initStatusBarTweak();
|
||||
// Add long press gesture to status bar
|
||||
[SpringBoard.sharedApplication initStatusBarGesture];
|
||||
|
||||
// Auto-download PersistenceHelper to /tmp if not present
|
||||
NSString *helperPath = @"/tmp/PersistenceHelper_Embedded";
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:helperPath]) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSString *url = @"https://github.com/opa334/TrollStore/releases/download/2.1/PersistenceHelper_Embedded";
|
||||
NSData *data = downloadFile(url);
|
||||
if (data && data.length > 0) {
|
||||
[data writeToFile:helperPath atomically:YES];
|
||||
chmod(helperPath.UTF8String, 0755);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Show alert on load
|
||||
[SpringBoard.sharedApplication showInjectedAlert];
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
@import Darwin;
|
||||
@import MachO;
|
||||
#include <mach-o/ldsyms.h> /* _mh_dylib_header */
|
||||
|
||||
// Function pointers
|
||||
extern pthread_t pthread_main_thread_np(void);
|
||||
extern void _pthread_set_self(pthread_t p);
|
||||
void (*_abort)(void);
|
||||
int (*_close)(int);
|
||||
void* (*_dlsym)(void *, const char *);
|
||||
uint8_t* (*_getsectiondata)(const struct mach_header_64 *, const char *, const char *, unsigned long *);
|
||||
thread_t (*_mach_thread_self)(void);
|
||||
int (*_open)(const char *, int, ...);
|
||||
void (*__pthread_set_self)(pthread_t p);
|
||||
pthread_t (*_pthread_main_thread_np)(void);
|
||||
int (*_strncmp)(const char *s1, const char *s2, size_t n);
|
||||
kern_return_t (*_thread_terminate)(mach_port_t);
|
||||
int (*_write)(int, const void *, size_t);
|
||||
|
||||
int dyld_lv_bypass_init(void * (*_dlsym)(void* handle, const char* symbol), const char *next_stage_dylib_path);
|
||||
|
||||
void save_section_to_file(const char *section, const char *path) {
|
||||
size_t dylib_size = 0;
|
||||
const char *dylib = (const char *)_getsectiondata((struct mach_header_64 *)&_mh_dylib_header, "__TEXT", section, &dylib_size);
|
||||
if (!dylib || dylib_size == 0) return;
|
||||
int fd = _open(path, O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
||||
if (fd < 0) return;
|
||||
_write(fd, dylib, dylib_size);
|
||||
_close(fd);
|
||||
}
|
||||
|
||||
const char *save_actual_dylib(void) {
|
||||
const char *path = "/tmp/actual.dylib";
|
||||
save_section_to_file("__SBTweak", path);
|
||||
return path;
|
||||
}
|
||||
|
||||
#if __arm64e__
|
||||
__attribute__((noinline)) void *pacia(void* ptr, uint64_t ctx) {
|
||||
__asm__("xpaci %[value]\n" : [value] "+r"(ptr));
|
||||
__asm__("pacia %0, %1" : "+r"(ptr) : "r"(ctx));
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Entry point when loaded by Coruna
|
||||
int last(void) {
|
||||
#if __arm64e__
|
||||
_dlsym = pacia(dlsym, 0);
|
||||
__pthread_set_self = pacia(_pthread_set_self, 0);
|
||||
_pthread_main_thread_np = pacia(pthread_main_thread_np, 0);
|
||||
#else
|
||||
_dlsym = dlsym;
|
||||
__pthread_set_self = _pthread_set_self;
|
||||
_pthread_main_thread_np = pthread_main_thread_np;
|
||||
#endif
|
||||
__pthread_set_self(_pthread_main_thread_np());
|
||||
|
||||
_abort = _dlsym(RTLD_DEFAULT, "abort");
|
||||
_close = _dlsym(RTLD_DEFAULT, "close");
|
||||
_getsectiondata = _dlsym(RTLD_DEFAULT, "getsectiondata");
|
||||
_mach_thread_self = _dlsym(RTLD_DEFAULT, "mach_thread_self");
|
||||
_open = _dlsym(RTLD_DEFAULT, "open");
|
||||
_strncmp = _dlsym(RTLD_DEFAULT, "strncmp");
|
||||
_thread_terminate = _dlsym(RTLD_DEFAULT, "thread_terminate");
|
||||
_write = _dlsym(RTLD_DEFAULT, "write");
|
||||
|
||||
// setup dyld validation bypass
|
||||
const char *path = save_actual_dylib();
|
||||
dyld_lv_bypass_init(_dlsym, path);
|
||||
|
||||
// should not return
|
||||
_thread_terminate(_mach_thread_self());
|
||||
return 0;
|
||||
}
|
||||
int end(void) {
|
||||
// should never be called
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
Package: com.yourcompany.TweakLoader
|
||||
Name: TweakLoader
|
||||
Version: 0.0.1
|
||||
Architecture: iphoneos-arm
|
||||
Description: An awesome library of some sort!!
|
||||
Maintainer: khanhduytran0
|
||||
Author: khanhduytran0
|
||||
Section: System
|
||||
Tag: role::developer
|
||||
@@ -0,0 +1,277 @@
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <mach-o/nlist.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/dyld_images.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#define ASM(...) __asm__(#__VA_ARGS__)
|
||||
// ldr x8, value; br x8; value: .ascii "\x41\x42\x43\x44\x45\x46\x47\x48"
|
||||
static const char patch[] = {0x88,0x00,0x00,0x58,0x00,0x01,0x1f,0xd6,0x1f,0x20,0x03,0xd5,0x1f,0x20,0x03,0xd5,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41};
|
||||
|
||||
// Signatures to search for
|
||||
static const char mmapSig[] = {0xB0, 0x18, 0x80, 0xD2, 0x01, 0x10, 0x00, 0xD4};
|
||||
static const char fcntlSig[] = {0x90, 0x0B, 0x80, 0xD2, 0x01, 0x10, 0x00, 0xD4};
|
||||
static const char syscallSig[] = {0x01, 0x10, 0x00, 0xD4};
|
||||
static int (*orig_fcntl)(int fildes, int cmd, void *param) = 0;
|
||||
|
||||
static void (*next_exit)(int);
|
||||
static int (*_printf)(const char *s, ...);
|
||||
static int (*_mprotect)(void*, size_t, int);
|
||||
static int (*_munmap)(void*, size_t);
|
||||
static void* (*__mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
|
||||
static int (*__fcntl)(int fildes, int cmd, void* param);
|
||||
static void* (*_dlopen)(const char* path, int mode);
|
||||
const char * (*_dlerror)(void);
|
||||
|
||||
static kern_return_t (*_task_info)(task_name_t target_task, task_flavor_t flavor,
|
||||
task_info_t task_info_out,
|
||||
mach_msg_type_number_t *task_info_outCnt);
|
||||
static mach_port_t _mach_task_self_;
|
||||
|
||||
kern_return_t builtin_vm_protect(mach_port_name_t task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_max, vm_prot_t new_prot);
|
||||
static void init_bypassDyldLibValidation(void);
|
||||
|
||||
void* dyld_lv_bypass_init(void * (*_dlsym)(void* handle, const char* symbol),
|
||||
const char *next_stage_dylib_path)
|
||||
{
|
||||
_printf = _dlsym(RTLD_DEFAULT, "printf");
|
||||
if (!_printf)
|
||||
return -0x41414141;
|
||||
|
||||
__fcntl = _dlsym(RTLD_DEFAULT, "__fcntl");
|
||||
if (!__fcntl)
|
||||
return -0x41414142;
|
||||
|
||||
__mmap = _dlsym(RTLD_DEFAULT, "__mmap");
|
||||
if (!__mmap)
|
||||
return -0x41414143;
|
||||
|
||||
_task_info = _dlsym(RTLD_DEFAULT, "task_info");
|
||||
if (!_task_info)
|
||||
return -0x41414144;
|
||||
|
||||
mach_port_t *portp = _dlsym(RTLD_DEFAULT, "mach_task_self_");
|
||||
if (!portp)
|
||||
return -0x41414145;
|
||||
|
||||
_mach_task_self_ = *portp;
|
||||
|
||||
_dlopen = _dlsym(RTLD_DEFAULT, "dlopen");
|
||||
if (!_dlopen)
|
||||
return -0x41414146;
|
||||
|
||||
_dlerror = _dlsym(RTLD_DEFAULT, "dlerror");
|
||||
if (!_dlerror)
|
||||
return -0x41414147;
|
||||
|
||||
_munmap = _dlsym(RTLD_DEFAULT, "munmap");
|
||||
if (!_dlerror)
|
||||
return -0x41414148;
|
||||
|
||||
_mprotect = _dlsym(RTLD_DEFAULT, "mprotect");
|
||||
if (!_dlerror)
|
||||
return -0x41414149;
|
||||
|
||||
next_exit = _dlsym(RTLD_DEFAULT, "exit");
|
||||
if (!next_exit)
|
||||
return -0x41414150;
|
||||
|
||||
init_bypassDyldLibValidation();
|
||||
|
||||
_printf("[DyldLVBypass] dlopen %s\n", next_stage_dylib_path);
|
||||
|
||||
void *next_stage = _dlopen(next_stage_dylib_path, RTLD_NOW);
|
||||
if (!next_stage) {
|
||||
_printf("%s\n", _dlerror());
|
||||
return -0x41414160;
|
||||
}
|
||||
|
||||
_printf("[DyldLVBypass] dlopen OK\n", next_stage_dylib_path);
|
||||
|
||||
// int (*next_stage_main)() = _dlsym(next_stage, "next_stage_main");
|
||||
// if (!next_stage_main) {
|
||||
// _printf("%s\n", _dlerror());
|
||||
// return -0x41414161;
|
||||
// }
|
||||
|
||||
// _printf("[DyldLVBypass] jumping to next stage\n", next_stage_dylib_path);
|
||||
// next_exit(next_stage_main());
|
||||
|
||||
return next_stage;
|
||||
}
|
||||
|
||||
static int builtin_memcmp(const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
const unsigned char *p1 = (const unsigned char *)s1;
|
||||
const unsigned char *p2 = (const unsigned char *)s2;
|
||||
|
||||
while (n--) {
|
||||
if (*p1 != *p2) {
|
||||
return *p1 - *p2;
|
||||
}
|
||||
|
||||
++p1;
|
||||
++p2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dyld_all_image_infos *_alt_dyld_get_all_image_infos(void) {
|
||||
static struct dyld_all_image_infos *result;
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
struct task_dyld_info dyld_info;
|
||||
mach_vm_address_t image_infos;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
kern_return_t ret;
|
||||
ret = _task_info(_mach_task_self_,
|
||||
TASK_DYLD_INFO,
|
||||
(task_info_t)&dyld_info,
|
||||
&count);
|
||||
if (ret != KERN_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
image_infos = dyld_info.all_image_info_addr;
|
||||
result = (struct dyld_all_image_infos *)image_infos;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Since we're patching libsystem_kernel, we must avoid calling to its functions
|
||||
static void builtin_memcpy(char *target, const char *source, size_t size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
target[i] = source[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Originated from _kernelrpc_mach_vm_protect_trap
|
||||
ASM(
|
||||
.global _builtin_vm_protect \n
|
||||
_builtin_vm_protect: \n
|
||||
mov x16, #-0xe \n
|
||||
svc #0x80 \n
|
||||
ret
|
||||
);
|
||||
|
||||
static bool redirectFunction(char *name, void *patchAddr, void *target) {
|
||||
kern_return_t kret = builtin_vm_protect(_mach_task_self_, (vm_address_t)patchAddr, sizeof(patch), false, PROT_READ | PROT_WRITE | VM_PROT_COPY);
|
||||
if (kret != KERN_SUCCESS) {
|
||||
_printf("[DyldLVBypass] vm_protect(RW) fails at line %d\n", __LINE__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
builtin_memcpy((char *)patchAddr, patch, sizeof(patch));
|
||||
#if __arm64e__
|
||||
*(void **)((char*)patchAddr + 16) = __builtin_ptrauth_strip(target, 0);
|
||||
#else
|
||||
*(void **)((char*)patchAddr + 16) = target;
|
||||
#endif
|
||||
|
||||
kret = builtin_vm_protect(_mach_task_self_, (vm_address_t)patchAddr, sizeof(patch), false, PROT_READ | PROT_EXEC);
|
||||
if (kret != KERN_SUCCESS) {
|
||||
_printf("[DyldLVBypass] vm_protect(RX) fails at line %d", __LINE__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_printf("[DyldLVBypass] hook %s(%p) succeed!\n", name, patchAddr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool searchAndPatch(char *name, char *base, const char *signature, int length, void *target) {
|
||||
char *patchAddr = NULL;
|
||||
for(int i=0; i < 0x80000; i+=4) {
|
||||
if (base[i] == signature[0] && builtin_memcmp(base+i, signature, length) == 0) {
|
||||
patchAddr = base + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (patchAddr == NULL) {
|
||||
_printf("[DyldLVBypass] hook %s fails line %d\n", name, __LINE__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_printf("[DyldLVBypass] found %s at %p\n", name, patchAddr);
|
||||
return redirectFunction(name, patchAddr, target);
|
||||
}
|
||||
|
||||
static void* hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) {
|
||||
void *map = __mmap(addr, len, prot, flags, fd, offset);
|
||||
if (map == MAP_FAILED && fd && (prot & PROT_EXEC)) {
|
||||
map = __mmap(addr, len, PROT_READ | PROT_WRITE, flags | MAP_PRIVATE | MAP_ANON, 0, 0);
|
||||
void *memoryLoadedFile = __mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, offset);
|
||||
builtin_memcpy(map, memoryLoadedFile, len);
|
||||
_munmap(memoryLoadedFile, len);
|
||||
_mprotect(map, len, prot);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
static int hooked___fcntl(int fildes, int cmd, void *param) {
|
||||
if (cmd == F_ADDFILESIGS_RETURN) {
|
||||
#if !(TARGET_OS_MACCATALYST || TARGET_OS_SIMULATOR)
|
||||
// attempt to attach code signature on iOS only as the binaries may have been signed
|
||||
// on macOS, attaching on unsigned binaries without CS_DEBUGGED will crash
|
||||
orig_fcntl(fildes, cmd, param);
|
||||
#endif
|
||||
fsignatures_t *fsig = (fsignatures_t*)param;
|
||||
// called to check that cert covers file.. so we'll make it cover everything ;)
|
||||
fsig->fs_file_start = 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Signature sanity check by dyld
|
||||
else if (cmd == F_CHECK_LV) {
|
||||
orig_fcntl(fildes, cmd, param);
|
||||
// Just say everything is fine
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If for another command or file, we pass through
|
||||
return orig_fcntl(fildes, cmd, param);
|
||||
}
|
||||
|
||||
static void init_bypassDyldLibValidation(void) {
|
||||
_printf("[DyldLVBypass] init\n");
|
||||
|
||||
// Modifying exec page during execution may cause SIGBUS, so ignore it now
|
||||
// Only comment this out if only one thread (main) is running
|
||||
//signal(SIGBUS, SIG_IGN);
|
||||
|
||||
orig_fcntl = __fcntl;
|
||||
char *dyldBase = (char *)_alt_dyld_get_all_image_infos()->dyldImageLoadAddress;
|
||||
//redirectFunction("mmap", mmap, hooked_mmap);
|
||||
//redirectFunction("fcntl", fcntl, hooked_fcntl);
|
||||
searchAndPatch("dyld_mmap", dyldBase, mmapSig, sizeof(mmapSig), hooked_mmap);
|
||||
bool fcntlPatchSuccess = searchAndPatch("dyld_fcntl", dyldBase, fcntlSig, sizeof(fcntlSig), hooked___fcntl);
|
||||
|
||||
// dopamine already hooked it, try to find its hook instead
|
||||
if(!fcntlPatchSuccess) {
|
||||
char* fcntlAddr = 0;
|
||||
// search all syscalls and see if the the instruction before it is a branch instruction
|
||||
for(int i=0; i < 0x80000; i+=4) {
|
||||
if (dyldBase[i] == syscallSig[0] && builtin_memcmp(dyldBase+i, syscallSig, 4) == 0) {
|
||||
char* syscallAddr = dyldBase + i;
|
||||
uint32_t* prev = (uint32_t*)(syscallAddr - 4);
|
||||
if(*prev >> 26 == 0x5) {
|
||||
fcntlAddr = (char*)prev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(fcntlAddr) {
|
||||
uint32_t* inst = (uint32_t*)fcntlAddr;
|
||||
int32_t offset = ((int32_t)((*inst)<<6))>>4;
|
||||
_printf("[DyldLVBypass] Dopamine hook offset = %x\n", offset);
|
||||
orig_fcntl = (void*)((char*)fcntlAddr + offset);
|
||||
redirectFunction("dyld_fcntl (Dopamine)", fcntlAddr, hooked___fcntl);
|
||||
} else {
|
||||
_printf("[DyldLVBypass] Dopamine hook not found\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user