2024-11-14 11:15:18 +01:00
|
|
|
#import "Utils.h"
|
2026-08-03 09:46:46 -04:00
|
|
|
|
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;
|
2026-08-03 09:46:46 -04:00
|
|
|
}
|
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];
|
|
|
|
|
});
|
|
|
|
|
}
|