mirror of
https://github.com/faroukbmiled/RyukGram.git
synced 2026-06-13 02:17:46 +02:00
- Renamed project from SCInsta to RyukGram across all user-facing text,
settings UI, build scripts, workflows, control file, and Makefile
- Added built-in sideload compatibility patch:
keychain access group discovery, SecItem rebinding via fishhook,
NSFileManager app group fallback, Cloud Kit entitlement patches
- Added fishhook library (modules/fishhook/) for C function rebinding
- Updated README with new features, repo links, and credits
- Updated GitHub Actions workflows for RyukGram naming
- Plist renamed from SCInsta.plist to RyukGram.plist
This commit is contained in:
@@ -162,7 +162,7 @@ static void sciShowDebugIvarDump(UIView *cell) {
|
||||
NSLog(@"[SCInsta] Debug: %@", debug);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"SCInsta Debug"
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"RyukGram Debug"
|
||||
message:debug
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Copy & Close" style:UIAlertActionStyleDefault handler:^(UIAlertAction *a) {
|
||||
|
||||
@@ -70,8 +70,8 @@ static char rowStaticRef[] = "row";
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
if (![[[NSUserDefaults standardUserDefaults] objectForKey:@"SCInstaFirstRun"] isEqualToString:SCIVersionString]) {
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"SCInsta Settings Info"
|
||||
message:@"In the future: Hold down on the three lines at the top right of your profile page, to re-open SCInsta settings."
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"RyukGram Settings Info"
|
||||
message:@"In the future: Hold down on the three lines at the top right of your profile page, to re-open RyukGram settings."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"I understand!"
|
||||
|
||||
@@ -233,10 +233,10 @@
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"SCInsta",
|
||||
@"header": @"RyukGram",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Enable tweak settings quick-access" subtitle:@"Allows you to hold on the home tab to open the SCInsta settings" defaultsKey:@"settings_shortcut" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Show tweak settings on app launch" subtitle:@"Automatically opens the SCInsta settings when the app launches" defaultsKey:@"tweak_settings_app_launch"],
|
||||
[SCISetting switchCellWithTitle:@"Enable tweak settings quick-access" subtitle:@"Allows you to hold on the home tab to open the RyukGram settings" defaultsKey:@"settings_shortcut" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Show tweak settings on app launch" subtitle:@"Automatically opens the RyukGram settings when the app launches" defaultsKey:@"tweak_settings_app_launch"],
|
||||
[SCISetting buttonCellWithTitle:@"Reset onboarding completion state"
|
||||
subtitle:@""
|
||||
icon:nil
|
||||
@@ -283,11 +283,11 @@
|
||||
@{
|
||||
@"header": @"Credits",
|
||||
@"rows": @[
|
||||
[SCISetting linkCellWithTitle:@"Developer" subtitle:@"SoCuul" imageUrl:@"https://i.imgur.com/c9CbytZ.png" url:@"https://socuul.dev"],
|
||||
[SCISetting linkCellWithTitle:@"Original Developer" subtitle:@"SoCuul (SCInsta)" imageUrl:@"https://i.imgur.com/c9CbytZ.png" url:@"https://github.com/SoCuul/SCInsta"],
|
||||
[SCISetting linkCellWithTitle:@"Modded by" subtitle:@"Ryuk" imageUrl:@"https://github.com/faroukbmiled.png" url:@"https://github.com/faroukbmiled"],
|
||||
[SCISetting linkCellWithTitle:@"View Repo" subtitle:@"View the tweak's source code on GitHub" imageUrl:@"https://i.imgur.com/BBUNzeP.png" url:@"https://github.com/SoCuul/SCInsta"]
|
||||
[SCISetting linkCellWithTitle:@"View Repo" subtitle:@"View the source code on GitHub" imageUrl:@"https://i.imgur.com/BBUNzeP.png" url:@"https://github.com/faroukbmiled/RyukGram"]
|
||||
],
|
||||
@"footer": [NSString stringWithFormat:@"SCInsta %@\n\nInstagram v%@\n\nModded by Ryuk", SCIVersionString, [SCIUtils IGVersionString]]
|
||||
@"footer": [NSString stringWithFormat:@"RyukGram %@\n\nInstagram v%@\n\nBased on SCInsta by SoCuul", SCIVersionString, [SCIUtils IGVersionString]]
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -300,7 +300,7 @@
|
||||
///
|
||||
|
||||
+ (NSString *)title {
|
||||
return @"SCInsta Settings";
|
||||
return @"RyukGram Settings";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
// Sideload compatibility patch for Instagram.
|
||||
// Fixes keychain, app groups, CloudKit, and container access when sideloaded.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Security/Security.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#import "../../modules/fishhook/fishhook.h"
|
||||
|
||||
static NSString *bundleId = nil;
|
||||
static NSString *accessGroupId = nil;
|
||||
|
||||
static OSStatus (*orig_SecItemAdd)(CFDictionaryRef, CFTypeRef *) = NULL;
|
||||
static OSStatus (*orig_SecItemCopyMatching)(CFDictionaryRef, CFTypeRef *) = NULL;
|
||||
static OSStatus (*orig_SecItemUpdate)(CFDictionaryRef, CFDictionaryRef) = NULL;
|
||||
static OSStatus (*orig_SecItemDelete)(CFDictionaryRef) = NULL;
|
||||
|
||||
static IMP orig_CKEntitlements_initWithEntitlementsDict __attribute__((unused)) = NULL;
|
||||
static IMP orig_CKContainer_setupWithContainerID __attribute__((unused)) = NULL;
|
||||
static IMP orig_CKContainer_initWithContainerIdentifier __attribute__((unused)) = NULL;
|
||||
static IMP orig_NSFileManager_containerURL __attribute__((unused)) = NULL;
|
||||
|
||||
// -- app group path --
|
||||
|
||||
static NSString *_appGroupPath = nil;
|
||||
static dispatch_once_t _appGroupOnce = 0;
|
||||
|
||||
static NSString *getAppGroupPathIfExists(void) {
|
||||
dispatch_once(&_appGroupOnce, ^{
|
||||
Class LSBundleProxy = objc_getClass("LSBundleProxy");
|
||||
if (!LSBundleProxy) return;
|
||||
|
||||
id proxy = ((id(*)(id, SEL))objc_msgSend)(
|
||||
(id)LSBundleProxy, sel_registerName("bundleProxyForCurrentProcess"));
|
||||
if (!proxy) return;
|
||||
|
||||
NSDictionary *ents = ((NSDictionary *(*)(id, SEL))objc_msgSend)(
|
||||
proxy, sel_registerName("entitlements"));
|
||||
if (!ents || ![ents isKindOfClass:[NSDictionary class]]) return;
|
||||
|
||||
NSArray *groups = ents[@"com.apple.security.application-groups"];
|
||||
if (!groups || groups.count == 0) return;
|
||||
|
||||
NSDictionary *urls = ((NSDictionary *(*)(id, SEL))objc_msgSend)(
|
||||
proxy, sel_registerName("groupContainerURLs"));
|
||||
if (!urls || ![urls isKindOfClass:[NSDictionary class]]) return;
|
||||
|
||||
NSURL *url = urls[groups.firstObject];
|
||||
if (url) _appGroupPath = [url path];
|
||||
});
|
||||
return _appGroupPath;
|
||||
}
|
||||
|
||||
static BOOL createDirectoryIfNotExists(NSString *path) {
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
if ([fm fileExistsAtPath:path]) return YES;
|
||||
return [fm createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
|
||||
// -- SecItem replacements: set the correct access group on every call --
|
||||
|
||||
static OSStatus replaced_SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
|
||||
if (attributes && accessGroupId) {
|
||||
NSMutableDictionary *q = [(__bridge NSDictionary *)attributes mutableCopy];
|
||||
q[(__bridge id)kSecAttrAccessGroup] = accessGroupId;
|
||||
return orig_SecItemAdd((__bridge CFDictionaryRef)q, result);
|
||||
}
|
||||
return orig_SecItemAdd(attributes, result);
|
||||
}
|
||||
|
||||
static OSStatus replaced_SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result) {
|
||||
if (query && accessGroupId) {
|
||||
NSMutableDictionary *q = [(__bridge NSDictionary *)query mutableCopy];
|
||||
q[(__bridge id)kSecAttrAccessGroup] = accessGroupId;
|
||||
return orig_SecItemCopyMatching((__bridge CFDictionaryRef)q, result);
|
||||
}
|
||||
return orig_SecItemCopyMatching(query, result);
|
||||
}
|
||||
|
||||
static OSStatus replaced_SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attrs) {
|
||||
if (query && accessGroupId) {
|
||||
NSMutableDictionary *q = [(__bridge NSDictionary *)query mutableCopy];
|
||||
q[(__bridge id)kSecAttrAccessGroup] = accessGroupId;
|
||||
return orig_SecItemUpdate((__bridge CFDictionaryRef)q, attrs);
|
||||
}
|
||||
return orig_SecItemUpdate(query, attrs);
|
||||
}
|
||||
|
||||
static OSStatus replaced_SecItemDelete(CFDictionaryRef query) {
|
||||
if (query && accessGroupId) {
|
||||
NSMutableDictionary *q = [(__bridge NSDictionary *)query mutableCopy];
|
||||
q[(__bridge id)kSecAttrAccessGroup] = accessGroupId;
|
||||
return orig_SecItemDelete((__bridge CFDictionaryRef)q);
|
||||
}
|
||||
return orig_SecItemDelete(query);
|
||||
}
|
||||
|
||||
// -- CloudKit patches: strip iCloud entitlements, disable container init --
|
||||
|
||||
static id replaced_CKEntitlements_init(id self, SEL _cmd, NSDictionary *dict) {
|
||||
NSMutableDictionary *d = [dict mutableCopy];
|
||||
[d removeObjectForKey:@"com.apple.developer.icloud-container-environment"];
|
||||
[d removeObjectForKey:@"com.apple.developer.icloud-services"];
|
||||
return ((id(*)(id, SEL, NSDictionary *))orig_CKEntitlements_initWithEntitlementsDict)(self, _cmd, [d copy]);
|
||||
}
|
||||
|
||||
static id replaced_CKContainer_setup(id self, SEL _cmd, id containerID, id options) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
static id replaced_CKContainer_init(id self, SEL _cmd, id identifier) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// -- NSFileManager: redirect app group container to a local fallback --
|
||||
|
||||
static NSURL *replaced_containerURL(id self, SEL _cmd, NSString *groupId) {
|
||||
NSString *groupPath = getAppGroupPathIfExists();
|
||||
if (!groupPath) {
|
||||
NSString *docs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
|
||||
NSString *fallback = [docs stringByAppendingPathComponent:groupId];
|
||||
createDirectoryIfNotExists(fallback);
|
||||
return [NSURL fileURLWithPath:fallback];
|
||||
}
|
||||
NSURL *url = [[NSURL fileURLWithPath:groupPath] URLByAppendingPathComponent:groupId];
|
||||
createDirectoryIfNotExists([url path]);
|
||||
return url;
|
||||
}
|
||||
|
||||
// -- swizzle helper: walks class hierarchy, handles inherited methods --
|
||||
|
||||
static void swizzleMethod(Class cls, SEL sel, IMP newIMP, IMP *outOrig) {
|
||||
if (!cls) return;
|
||||
Class cur = cls;
|
||||
while (cur) {
|
||||
unsigned int count = 0;
|
||||
Method *list = class_copyMethodList(cur, &count);
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
if (method_getName(list[i]) == sel) {
|
||||
if (cur == cls) {
|
||||
*outOrig = method_setImplementation(list[i], newIMP);
|
||||
} else {
|
||||
*outOrig = method_getImplementation(list[i]);
|
||||
class_addMethod(cls, sel, newIMP, method_getTypeEncoding(list[i]));
|
||||
}
|
||||
free(list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
free(list);
|
||||
cur = class_getSuperclass(cur);
|
||||
}
|
||||
}
|
||||
|
||||
// -- keychain bootstrap: discover the access group assigned to this app --
|
||||
|
||||
static void bootstrapKeychainAccessGroup(void) {
|
||||
NSDictionary *query = @{
|
||||
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
|
||||
(__bridge id)kSecAttrAccount: @"RyukGramSideloadPatch",
|
||||
(__bridge id)kSecAttrService: @"",
|
||||
(__bridge id)kSecReturnAttributes: @YES,
|
||||
};
|
||||
|
||||
CFTypeRef result = NULL;
|
||||
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
|
||||
if (status == errSecItemNotFound)
|
||||
status = SecItemAdd((__bridge CFDictionaryRef)query, &result);
|
||||
|
||||
if (status == errSecSuccess && result) {
|
||||
bundleId = [[NSBundle mainBundle] bundleIdentifier];
|
||||
NSDictionary *attrs = (__bridge NSDictionary *)result;
|
||||
NSString *group = attrs[(__bridge id)kSecAttrAccessGroup];
|
||||
if (group) accessGroupId = [group copy];
|
||||
CFRelease(result);
|
||||
}
|
||||
}
|
||||
|
||||
// -- init --
|
||||
|
||||
%ctor {
|
||||
@autoreleasepool {
|
||||
bootstrapKeychainAccessGroup();
|
||||
|
||||
// rebind SecItem functions so keychain calls use the right access group
|
||||
struct rebinding rebindings[] = {
|
||||
{"SecItemAdd", (void *)replaced_SecItemAdd, (void **)&orig_SecItemAdd},
|
||||
{"SecItemCopyMatching", (void *)replaced_SecItemCopyMatching, (void **)&orig_SecItemCopyMatching},
|
||||
{"SecItemUpdate", (void *)replaced_SecItemUpdate, (void **)&orig_SecItemUpdate},
|
||||
{"SecItemDelete", (void *)replaced_SecItemDelete, (void **)&orig_SecItemDelete},
|
||||
};
|
||||
rebind_symbols(rebindings, 4);
|
||||
|
||||
// patch NSFileManager for app group container fallback
|
||||
Class fm = objc_getClass("NSFileManager");
|
||||
if (fm) swizzleMethod(fm, sel_registerName("containerURLForSecurityApplicationGroupIdentifier:"),
|
||||
(IMP)replaced_containerURL, &orig_NSFileManager_containerURL);
|
||||
|
||||
// patch CloudKit to prevent crashes from missing entitlements
|
||||
Class ckEnt = objc_getClass("CKEntitlements");
|
||||
if (ckEnt) swizzleMethod(ckEnt, sel_registerName("initWithEntitlementsDict:"),
|
||||
(IMP)replaced_CKEntitlements_init, &orig_CKEntitlements_initWithEntitlementsDict);
|
||||
|
||||
Class ckCon = objc_getClass("CKContainer");
|
||||
if (ckCon) {
|
||||
swizzleMethod(ckCon, sel_registerName("_setupWithContainerID:options:"),
|
||||
(IMP)replaced_CKContainer_setup, &orig_CKContainer_setupWithContainerID);
|
||||
swizzleMethod(ckCon, sel_registerName("_initWithContainerIdentifier:"),
|
||||
(IMP)replaced_CKContainer_init, &orig_CKContainer_initWithContainerIdentifier);
|
||||
}
|
||||
|
||||
// NSUserDefaults _initWithSuiteName:container: intentionally not patched —
|
||||
// crashes on current IG versions. the NSFileManager patch covers the
|
||||
// group container redirect which is what actually matters.
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -73,7 +73,7 @@ BOOL dmVisualMsgsViewedButtonEnabled = false;
|
||||
NSLog(@"[SCInsta] First run, initializing");
|
||||
|
||||
// Display settings modal on screen
|
||||
NSLog(@"[SCInsta] Displaying SCInsta first-time settings modal");
|
||||
NSLog(@"[SCInsta] Displaying RyukGram first-time settings modal");
|
||||
[SCIUtils showSettingsVC:[self window]];
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user