revenge-tweak/Sources/Utils.m

76 lines
2.8 KiB
Mathematica
Raw Permalink Normal View History

2024-11-14 11:15:18 +01:00
#import "Utils.h"
fix: replace speculative Bridgeless hook with RainTweak's verified approach The RCTInstance/-_loadScriptFromSource: + fake-RCTSource hook from the previous commit was a plausible guess from RN's public source, but codeberg.org/raincord/RainTweak - an actively-shipping loader for a sibling Revenge/Bunny fork - proves both the Bridgeless diagnosis correct (its %ctor refuses to run below Discord v332, i.e. pre-Bridgeless) and shows a cleaner, verified mechanism: hook RCTHost/-instance:didInitializeRuntime:, let Discord's own bundle load untouched via %orig, then evaluate Revenge's scripts directly against the live JSI runtime instead of faking another bundle load. - Add Headers/JSI.h + Sources/JSI.mm (ported from RainTweak's JSI.mm): evaluates NSData as JS or Hermes bytecode directly against a facebook::jsi::Runtime. - Add Headers/RCTHost.h declaring the hook target's signature (RN ships no public header for this internal class). - Vendor Headers/jsi/{jsi.h,jsi-inl.h,instrumentation.h} - Meta's MIT-licensed JSI headers, which Theos doesn't provide; RainTweak vendors the same files. - Rewrite Tweak.x -> Tweak.xm (needs C++ for jsi::Runtime&): runRevengeInjection now takes a plain data/async execute callback, driven by either the new RCTHost+JSI hook or the legacy RCTCxxBridge hook (kept as a no-cost fallback), guarded by a didInject flag so only one path actually injects. - Makefile: build .xm/.mm sources, add -std=c++17 CCFLAGS matching RainTweak. Still unverified against a real device, but the mechanism itself is no longer a guess - it's the one running in a comparable, currently-shipping mod.
2026-08-03 10:10:32 -04:00
BOOL isHermesBytecode(NSData *data) {
if (!data || data.length < 4) return NO;
const uint8_t *bytes = (const uint8_t *)data.bytes;
// Hermes bytecode magic: "Herm"
return bytes[0] == 0x48 && bytes[1] == 0x65 && bytes[2] == 0x72 && bytes[3] == 0x6d;
}
2024-11-14 11:15:18 +01:00
NSURL *getPyoncordDirectory(void) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentDirectoryURL = [[fileManager URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
NSURL *pyoncordFolderURL = [documentDirectoryURL URLByAppendingPathComponent:@"pyoncord"];
if (![fileManager fileExistsAtPath:pyoncordFolderURL.path]) {
[fileManager createDirectoryAtURL:pyoncordFolderURL
withIntermediateDirectories:YES
attributes:nil
error:nil];
}
return pyoncordFolderURL;
}
UIColor *hexToUIColor(NSString *hex) {
if (![hex hasPrefix:@"#"]) {
return nil;
}
NSString *hexColor = [hex substringFromIndex:1];
if (hexColor.length == 6) {
hexColor = [hexColor stringByAppendingString:@"ff"];
}
if (hexColor.length == 8) {
unsigned int hexNumber;
NSScanner *scanner = [NSScanner scannerWithString:hexColor];
if ([scanner scanHexInt:&hexNumber]) {
CGFloat r = ((hexNumber & 0xFF000000) >> 24) / 255.0;
CGFloat g = ((hexNumber & 0x00FF0000) >> 16) / 255.0;
CGFloat b = ((hexNumber & 0x0000FF00) >> 8) / 255.0;
CGFloat a = (hexNumber & 0x000000FF) / 255.0;
return [UIColor colorWithRed:r green:g blue:b alpha:a];
}
}
return nil;
}
void showErrorAlert(NSString *title, NSString *message) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleDefault
handler:nil];
[alert addAction:okAction];
UIWindow *window = nil;
NSArray *windows = [[UIApplication sharedApplication] windows];
for (UIWindow *w in windows) {
if (w.isKeyWindow) {
window = w;
break;
}
}
[window.rootViewController presentViewController:alert animated:YES completion:nil];
});
}