mirror of
https://github.com/NohamR/Tweaks.git
synced 2026-08-26 02:39:42 +00:00
Add CanardDumper tweak
This commit is contained in:
3
CanardDumper/.gitignore
vendored
Normal file
3
CanardDumper/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.theos/
|
||||||
|
packages/
|
||||||
|
.DS_Store
|
||||||
7
CanardDumper/CanardDumper.plist
Normal file
7
CanardDumper/CanardDumper.plist
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
Filter = {
|
||||||
|
Bundles = (
|
||||||
|
"fr.lecanardenchaine.app",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
14
CanardDumper/Makefile
Normal file
14
CanardDumper/Makefile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
TARGET = iphone:latest:15.0
|
||||||
|
ARCHS = arm64 arm64e
|
||||||
|
INSTALL_TARGET_PROCESSES = fr.lecanardenchaine.app
|
||||||
|
|
||||||
|
include $(THEOS)/makefiles/common.mk
|
||||||
|
|
||||||
|
TWEAK_NAME = CanardDumper
|
||||||
|
CanardDumper_FILES = Tweak.x
|
||||||
|
CanardDumper_CFLAGS = -fobjc-arc -Wno-deprecated-declarations -std=c++11 -x objective-c++
|
||||||
|
CanardDumper_CXXFLAGS = -std=c++11
|
||||||
|
CanardDumper_FRAMEWORKS = Foundation UIKit
|
||||||
|
CanardDumper_LDFLAGS = -lstdc++
|
||||||
|
|
||||||
|
include $(THEOS_MAKE_PATH)/tweak.mk
|
||||||
128
CanardDumper/Tweak.x
Normal file
128
CanardDumper/Tweak.x
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#import <substrate.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <dlfcn.h>
|
||||||
|
#import <mach-o/dyld.h>
|
||||||
|
#import <string>
|
||||||
|
|
||||||
|
static UIViewController *CanardTopViewController(UIViewController *viewController) {
|
||||||
|
if (viewController.presentedViewController) {
|
||||||
|
return CanardTopViewController(viewController.presentedViewController);
|
||||||
|
}
|
||||||
|
if ([viewController isKindOfClass:[UINavigationController class]]) {
|
||||||
|
return CanardTopViewController([(UINavigationController *)viewController visibleViewController]);
|
||||||
|
}
|
||||||
|
if ([viewController isKindOfClass:[UITabBarController class]]) {
|
||||||
|
return CanardTopViewController([(UITabBarController *)viewController selectedViewController]);
|
||||||
|
}
|
||||||
|
return viewController;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CanardPresentShareSheet(NSString *filePath) {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
UIApplication *application = [UIApplication sharedApplication];
|
||||||
|
UIWindow *window = application.keyWindow;
|
||||||
|
if (!window) {
|
||||||
|
for (UIWindow *candidate in application.windows) {
|
||||||
|
if (candidate.isKeyWindow) {
|
||||||
|
window = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UIViewController *viewController = CanardTopViewController(window.rootViewController);
|
||||||
|
if (!viewController) {
|
||||||
|
NSLog(@"[CanardDumper] Unable to present file share sheet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
|
||||||
|
UIActivityViewController *shareController = [[UIActivityViewController alloc] initWithActivityItems:@[fileURL] applicationActivities:nil];
|
||||||
|
UIPopoverPresentationController *popover = shareController.popoverPresentationController;
|
||||||
|
popover.sourceView = viewController.view;
|
||||||
|
popover.sourceRect = CGRectMake(CGRectGetMidX(viewController.view.bounds), CGRectGetMidY(viewController.view.bounds), 0, 0);
|
||||||
|
[viewController presentViewController:shareController animated:YES completion:nil];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSString *CanardArchivePassword;
|
||||||
|
static int CanardLastSavedReadSize = -1;
|
||||||
|
|
||||||
|
static NSString *CanardPasswordFileComponent(NSString *password) {
|
||||||
|
if (password.length == 0) {
|
||||||
|
return @"unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
NSCharacterSet *invalidCharacters = [NSCharacterSet characterSetWithCharactersInString:@"/:\\?%*|\"<>\n\r\t"];
|
||||||
|
NSString *safePassword = [[password componentsSeparatedByCharactersInSet:invalidCharacters] componentsJoinedByString:@"_"];
|
||||||
|
return safePassword.length > 0 ? safePassword : @"unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
%hook DlyArchiveReader
|
||||||
|
|
||||||
|
-(BOOL)setUpArchiveError:(id *)error {
|
||||||
|
NSLog(@"[CanardDumper] DlyArchiveReader setUpArchiveError: error=%p", error);
|
||||||
|
return %orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSString *)password {
|
||||||
|
NSString *pwd = %orig;
|
||||||
|
CanardArchivePassword = [pwd copy];
|
||||||
|
NSLog(@"[CanardDumper] DlyArchiveReader password: %@", pwd);
|
||||||
|
return pwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(int)getDocumentSize {
|
||||||
|
int size = %orig;
|
||||||
|
NSLog(@"[CanardDumper] DlyArchiveReader getDocumentSize: %d", size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSData *)readDataAt:(int)offset withSize:(int)size {
|
||||||
|
NSLog(@"[CanardDumper] DlyArchiveReader readDataAt: offset=%d withSize=%d", offset, size);
|
||||||
|
NSArray<NSString *> *callStack = [NSThread callStackSymbols];
|
||||||
|
NSLog(@"[CanardDumper] Backtrace:\n%@", [callStack componentsJoinedByString:@"\n"]);
|
||||||
|
NSData *data = %orig;
|
||||||
|
if (data.length > 0 && size != CanardLastSavedReadSize) {
|
||||||
|
NSFileManager *fm = [NSFileManager defaultManager];
|
||||||
|
NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
||||||
|
NSString *dumpDir = [docsPath stringByAppendingPathComponent:@"CanardDumps"];
|
||||||
|
if (![fm fileExistsAtPath:dumpDir]) {
|
||||||
|
[fm createDirectoryAtPath:dumpDir withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *passwordComponent = CanardPasswordFileComponent(CanardArchivePassword);
|
||||||
|
NSString *fileName = [NSString stringWithFormat:@"file_%@.pdf", passwordComponent];
|
||||||
|
NSString *filePath = [dumpDir stringByAppendingPathComponent:fileName];
|
||||||
|
if ([data writeToFile:filePath atomically:YES]) {
|
||||||
|
CanardLastSavedReadSize = size;
|
||||||
|
NSLog(@"[CanardDumper] Saved readDataAt data to %@ (%lu bytes)", filePath, (unsigned long)data.length);
|
||||||
|
CanardPresentShareSheet(filePath);
|
||||||
|
} else {
|
||||||
|
NSLog(@"[CanardDumper] Failed to save readDataAt data to %@", filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
%end
|
||||||
|
|
||||||
|
%hook DlyCoreArchive
|
||||||
|
|
||||||
|
-(instancetype)initWithArchivePath:(NSString *)path error:(NSError **)error {
|
||||||
|
NSLog(@"[CanardDumper] DlyCoreArchive initWithArchivePath: %@ error=%p", path, error);
|
||||||
|
return %orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
+(instancetype)newWithArchivePath:(NSString *)path error:(NSError **)error {
|
||||||
|
NSLog(@"[CanardDumper] DlyCoreArchive newWithArchivePath: %@ error=%p", path, error);
|
||||||
|
return %orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL)openArchiveWithType:(NSUInteger)type error:(id *)error {
|
||||||
|
NSLog(@"[CanardDumper] DlyCoreArchive openArchiveWithType: %lu error=%p", (unsigned long)type, error);
|
||||||
|
return %orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
%end
|
||||||
9
CanardDumper/control
Normal file
9
CanardDumper/control
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Package: xyz.nohamr.canarddumper
|
||||||
|
Name: CanardDumper
|
||||||
|
Version: 1.0.0
|
||||||
|
Architecture: iphoneos-arm
|
||||||
|
Description: Dumps extracted files from DlyCore DlyArchiveFile::GetFile to Documents/CanardDumps for Le Canard Enchaîné app analysis
|
||||||
|
Maintainer: NohamR
|
||||||
|
Author: NohamR
|
||||||
|
Section: Tweaks
|
||||||
|
Depends: mobilesubstrate (>= 0.9.5000)
|
||||||
0
CanardDumper/index.md
Normal file
0
CanardDumper/index.md
Normal file
Reference in New Issue
Block a user