1251 lines
38 KiB
Plaintext
1251 lines
38 KiB
Plaintext
#import <Foundation/Foundation.h>
|
||
#import <sys/utsname.h>
|
||
#include <sys/sysctl.h>
|
||
#import <mach/mach_time.h>
|
||
#import <UIKit/UIKit.h>
|
||
#import <WebKit/WebKit.h>
|
||
#import <ifaddrs.h> // 获取ip
|
||
#import <arpa/inet.h> // 获取ip
|
||
#import <net/if.h> // 获取ip
|
||
#import <net/if_dl.h>
|
||
#import <SystemConfiguration/CaptiveNetwork.h>
|
||
#import <CoreTelephony/CTCarrier.h>
|
||
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
||
#import <SystemConfiguration/SystemConfiguration.h>
|
||
// #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000
|
||
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
||
// #endif
|
||
#import <SpringBoard/SpringBoard.h>
|
||
#import <CoreMotion/CoreMotion.h>
|
||
#import <objc/runtime.h>
|
||
#import "XSLog.h"
|
||
|
||
void SetupXSLog() {
|
||
XSLogSetupLogWithFilePath(@"/var/mobile/Documents/App.log", 50 * 1024 * 1024);
|
||
XSLogRedirectNSLog();
|
||
}
|
||
|
||
|
||
typedef void (^tryGetValCallback)(id parameter);
|
||
|
||
|
||
// iOS版本检查宏
|
||
#define iOS14_OR_LATER() (@available(iOS 14, *))
|
||
|
||
|
||
@interface SBLockScreenManager : NSObject
|
||
- (BOOL)unlockUIFromSource:(int)source withOptions:(id)options;
|
||
- (void)lockUIFromSource:(int)source withOptions:(id)options;
|
||
@end
|
||
|
||
|
||
|
||
NSDictionary *settings;
|
||
|
||
|
||
|
||
NSUUID* str2uuid(NSString *str) {
|
||
return [[NSUUID alloc] initWithUUIDString:str];
|
||
}
|
||
|
||
NSInteger str2int(NSString *str) {
|
||
return [str integerValue];
|
||
}
|
||
float str2float(NSString *str) {
|
||
return [str floatValue];
|
||
}
|
||
double str2double(NSString *str) {
|
||
return [str doubleValue];
|
||
}
|
||
|
||
unsigned long long str2ull(NSString *str) {
|
||
return [str longLongValue];
|
||
}
|
||
|
||
void tryGetVal(NSString *key, tryGetValCallback block) {
|
||
@try {
|
||
if (!key || !block || !settings) return;
|
||
|
||
id data = settings[key];
|
||
if (data) {
|
||
block(data);
|
||
}
|
||
} @catch (NSException *exception) {
|
||
// NSLog(@"Error in tryGetVal for key %@: %@", key, exception);
|
||
}
|
||
}
|
||
|
||
const char* str2chars(NSString *str) {
|
||
const char *cString = [str UTF8String];
|
||
return cString;
|
||
}
|
||
|
||
|
||
%group ohno
|
||
|
||
// #if __IPHONE_OS_VERSION_MAX_ALLOWED < 140000
|
||
|
||
|
||
// #endif
|
||
|
||
// group ohho start
|
||
|
||
|
||
// #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000
|
||
|
||
%hook ATTrackingManager
|
||
|
||
+ (ATTrackingManagerAuthorizationStatus)trackingAuthorizationStatus {
|
||
__block ATTrackingManagerAuthorizationStatus originalStatus = %orig;
|
||
// NSLog(@"start hook trackingAuthorizationStatus");
|
||
// NSLog(@"[ATTrackingManager Hook] Original trackingAuthorizationStatus: %lu", (unsigned long)originalStatus);
|
||
|
||
// 你可以在这里修改返回值
|
||
// 例如,总是返回已授权状态:
|
||
// return 3; // ATTrackingManagerAuthorizationStatusAuthorized
|
||
tryGetVal(@"trackingStatus", ^(id parameter) {
|
||
// NSLog(@"[ATTrackingManager Hook] API trackingAuthorizationStatus: %@", parameter);
|
||
originalStatus = str2int(parameter);
|
||
});
|
||
|
||
// NSLog(@"[ATTrackingManager Hook] New trackingAuthorizationStatus: %lu", (unsigned long)originalStatus);
|
||
// 或者,你可以直接返回原始值
|
||
return originalStatus;
|
||
|
||
}
|
||
|
||
+ (void)requestTrackingAuthorizationWithCompletionHandler:(void (^)(ATTrackingManagerAuthorizationStatus status))completion {
|
||
// NSLog(@"[ATTrackingManager Hook] requestTrackingAuthorizationWithCompletionHandler called");
|
||
__block ATTrackingManagerAuthorizationStatus attStatus = 3;
|
||
tryGetVal(@"trackingStatus", ^(id parameter) {
|
||
// NSLog(@"[ATTrackingManager Hook] API trackingAuthorizationStatus: %@", parameter);
|
||
attStatus = str2int(parameter);
|
||
});
|
||
// 模拟延迟(真实的授权对话框有延迟)
|
||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||
if (completion) {
|
||
completion(attStatus);
|
||
}
|
||
});
|
||
|
||
// 调用原始方法
|
||
// %orig(completion);
|
||
}
|
||
|
||
%end
|
||
// #endif
|
||
|
||
%hook ASIdentifierManager
|
||
|
||
-(NSUUID*)advertisingIdentifier
|
||
{
|
||
// 修改IDFA
|
||
// NSLog(@"start hook idfa");
|
||
__block NSUUID *idfa = %orig;
|
||
// reloadConfig();
|
||
tryGetVal(@"idfa", ^(id parameter) {
|
||
idfa = str2uuid(parameter);
|
||
});
|
||
// NSLog(@"hook idfa: %@", idfa);
|
||
return idfa;
|
||
}
|
||
-(BOOL) isAdvertisingTrackingEnabled {
|
||
// NSLog(@"[ATTrackingManager Hook] isAdvertisingTrackingEnabled called");
|
||
__block BOOL res = %orig;
|
||
tryGetVal(@"trackingStatus", ^(id parameter) {
|
||
// NSLog(@"[ATTrackingManager Hook] API isAdvertisingTrackingEnabled: %@", parameter);
|
||
NSInteger status = str2int(parameter);
|
||
res = (status >= 3 ? YES : NO);
|
||
});
|
||
return res;
|
||
}
|
||
|
||
%end
|
||
|
||
// static BOOL orientationMonitoringEnabled = NO;
|
||
|
||
%hook UIDevice
|
||
// IDFV
|
||
-(NSUUID*)identifierForVendor{
|
||
// NSLog(@"start hook idfv");
|
||
__block NSUUID *idfv = %orig;
|
||
tryGetVal(@"idfv", ^(id parameter) {
|
||
idfv = str2uuid(parameter);
|
||
});
|
||
// NSLog(@"hook idfv: %@", idfv);
|
||
return idfv;
|
||
}
|
||
|
||
- (NSString *)name{
|
||
// NSLog(@"start hook device name");
|
||
__block NSString *name = %orig;
|
||
tryGetVal(@"deviceName", ^(id parameter) {
|
||
name = parameter;
|
||
});
|
||
// NSLog(@"hook device name: %@", name);
|
||
return name;
|
||
}
|
||
|
||
- (NSString *)model{
|
||
return %orig;
|
||
}
|
||
|
||
- (NSString *)localizedModel{
|
||
return %orig;
|
||
}
|
||
|
||
- (NSString *)systemName{
|
||
return %orig;
|
||
}
|
||
|
||
- (NSString *)systemVersion{
|
||
// NSLog(@"start hook system version");
|
||
__block NSString *systemVersion = %orig;
|
||
tryGetVal(@"osVersion", ^(id parameter) {
|
||
systemVersion = parameter;
|
||
});
|
||
// NSLog(@"hook system version: %@", systemVersion);
|
||
return systemVersion;
|
||
}
|
||
|
||
- (UIDeviceBatteryState)batteryState {
|
||
// NSLog(@"start hook batteryState");
|
||
__block UIDeviceBatteryState res = %orig;
|
||
tryGetVal(@"batteryState", ^(id parameter) {
|
||
NSInteger intVal = str2int(parameter);
|
||
res = (UIDeviceBatteryState)intVal;
|
||
});
|
||
return res;
|
||
}
|
||
|
||
- (float)batteryLevel {
|
||
// 随机电量
|
||
// NSLog(@"start hook batteryLevel");
|
||
__block float res = %orig;
|
||
tryGetVal(@"batteryLevel", ^(id parameter) {
|
||
res = str2float(parameter);
|
||
});
|
||
return res;
|
||
}
|
||
|
||
- (UIDeviceOrientation)orientation {
|
||
return UIDeviceOrientationPortrait;
|
||
}
|
||
|
||
%end
|
||
|
||
%hook NSProcessInfo
|
||
|
||
- (NSTimeInterval) systemUptime {
|
||
// 开机时间
|
||
// NSLog(@"start hook systemUptime");
|
||
__block NSTimeInterval res = %orig;
|
||
tryGetVal(@"systemUptime", ^(id parameter) {
|
||
double v = str2double(parameter);
|
||
if(v > -1.0f) {
|
||
res = v + res;
|
||
}
|
||
});
|
||
return res;
|
||
}
|
||
|
||
- (unsigned long long) physicalMemory {
|
||
// 内存
|
||
// NSLog(@"start hook physicalMemory");
|
||
__block unsigned long long memory = %orig;
|
||
tryGetVal(@"physicalMemory", ^(id parameter) {
|
||
unsigned long long t = str2ull(parameter);
|
||
if(t > 1000) {
|
||
memory = t;
|
||
}
|
||
});
|
||
// NSLog(@"hook physicalMemory: %llu", memory);
|
||
return memory;
|
||
}
|
||
|
||
- (NSUInteger) processorCount {
|
||
// NSLog(@"start hook processorCount");
|
||
__block NSUInteger res = %orig;
|
||
tryGetVal(@"cpuCore", ^(id parameter) {
|
||
NSUInteger t = str2int(parameter);
|
||
if(t > 0) {
|
||
res = t;
|
||
}
|
||
});
|
||
return res;
|
||
}
|
||
|
||
- (NSOperatingSystemVersion)operatingSystemVersion {
|
||
NSOperatingSystemVersion version = %orig;
|
||
__block NSString *versionString = @"";
|
||
tryGetVal(@"osVersion", ^(id parameter) {
|
||
versionString = parameter;
|
||
});
|
||
|
||
if (!versionString || ![versionString length]) {
|
||
return version;
|
||
}
|
||
|
||
NSArray *components = [versionString componentsSeparatedByString:@"."];
|
||
if (components.count == 0 || components.count > 3) {
|
||
return version;
|
||
}
|
||
|
||
// 验证每个组件是否为有效数字
|
||
for (NSString *component in components) {
|
||
if (![[NSScanner scannerWithString:component] scanInteger:NULL]) {
|
||
return version;
|
||
}
|
||
}
|
||
|
||
version.majorVersion = [components[0] integerValue];
|
||
version.minorVersion = components.count > 1 ? [components[1] integerValue] : 0;
|
||
version.patchVersion = components.count > 2 ? [components[2] integerValue] : 0;
|
||
|
||
return version;
|
||
}
|
||
|
||
|
||
%end
|
||
|
||
%hook UIWindow
|
||
- (UIEdgeInsets) safeAreaInsets {
|
||
// NSLog(@"start hook safeAreaInsets");
|
||
__block UIEdgeInsets originalInsets = %orig;
|
||
%log(@"Original safeAreaInsets: %@", NSStringFromUIEdgeInsets(originalInsets));
|
||
|
||
tryGetVal(@"safeAreaInsets", ^(id parameter) {
|
||
NSDictionary *dic = parameter;
|
||
// 修改 safeAreaInsets
|
||
UIEdgeInsets modifiedInsets = UIEdgeInsetsMake(
|
||
originalInsets.top = str2double(dic[@"top"]), // 增加顶部安全区域
|
||
originalInsets.left = 0, // 增加左侧安全区域
|
||
originalInsets.bottom = str2double(dic[@"bottom"]), // 增加底部安全区域
|
||
originalInsets.right = 0 // 增加右侧安全区域
|
||
);
|
||
originalInsets = modifiedInsets;
|
||
});
|
||
|
||
%log(@"Modified safeAreaInsets: %@", NSStringFromUIEdgeInsets(originalInsets));
|
||
return originalInsets;
|
||
}
|
||
%end
|
||
|
||
%hook UIScreen
|
||
- (CGFloat) brightness {
|
||
// 随机亮度
|
||
// NSLog(@"start hook brightness");
|
||
__block CGFloat originalBrightness = %orig;
|
||
tryGetVal(@"screenBrightness", ^(id parameter) {
|
||
double fat = str2double(parameter);
|
||
if(fat > -1.0f) {
|
||
originalBrightness = fat;
|
||
}
|
||
});
|
||
|
||
return originalBrightness;
|
||
}
|
||
- (CGRect)bounds {
|
||
// NSLog(@"start hook bounds");
|
||
__block CGRect originalBounds = %orig;
|
||
tryGetVal(@"screenBounds", ^(id parameter) {
|
||
NSDictionary *dic = parameter;
|
||
double w = str2double(dic[@"x"]);
|
||
double h = str2double(dic[@"y"]);
|
||
CGRect newBounds = {
|
||
.origin = {.x = 0, .y = 0},
|
||
.size = {.width = w, .height = h},
|
||
};
|
||
originalBounds = newBounds;
|
||
});
|
||
return originalBounds;
|
||
}
|
||
- (CGFloat) scale {
|
||
// NSLog(@"start hook scale");
|
||
__block CGFloat originalScale = %orig;
|
||
tryGetVal(@"screenScale", ^(id parameter) {
|
||
double fat = str2double(parameter);
|
||
if(fat > -1.0f) {
|
||
originalScale = fat;
|
||
}
|
||
});
|
||
return originalScale;
|
||
}
|
||
- (CGRect)nativeBounds {
|
||
// NSLog(@"start hook nativeBounds");
|
||
__block CGRect originalBounds = %orig;
|
||
tryGetVal(@"screenBounds", ^(id parameter) {
|
||
NSDictionary *dic = parameter;
|
||
double w = str2double(dic[@"nx"]);
|
||
double h = str2double(dic[@"ny"]);
|
||
CGRect newBounds = {
|
||
.origin = {.x = 0, .y = 0},
|
||
.size = {.width = w, .height = h},
|
||
};
|
||
originalBounds = newBounds;
|
||
});
|
||
return originalBounds;
|
||
}
|
||
|
||
- (BOOL)isCaptured {
|
||
// 总是返回NO,表示屏幕没有被捕获(镜像)
|
||
return NO;
|
||
}
|
||
|
||
- (UIScreen *)mirroredScreen {
|
||
// 总是返回nil,表示没有镜像屏幕
|
||
return nil;
|
||
}
|
||
|
||
%end
|
||
|
||
%hook AVAudioSession
|
||
- (float) outputVolume {
|
||
// 音量
|
||
// NSLog(@"start hook outputVolume");
|
||
__block float originalVolume = %orig;
|
||
tryGetVal(@"outputVolume", ^(id parameter) {
|
||
float fat = str2float(parameter);
|
||
if(fat > -1.0f) {
|
||
originalVolume = fat;
|
||
}
|
||
});
|
||
return originalVolume;
|
||
}
|
||
%end
|
||
|
||
%hook UIScreenMode
|
||
|
||
- (CGSize)size {
|
||
// 修改屏幕大小信息
|
||
// NSLog(@"start hook bounds");
|
||
__block CGSize originalSize = %orig;
|
||
tryGetVal(@"screenBounds", ^(id parameter) {
|
||
NSDictionary *dic = parameter;
|
||
double w = str2double(dic[@"x"]);
|
||
double h = str2double(dic[@"y"]);
|
||
CGSize newBounds = {
|
||
.width = w,
|
||
.height = h
|
||
};
|
||
originalSize = newBounds;
|
||
});
|
||
return originalSize;
|
||
}
|
||
|
||
%end
|
||
|
||
%hook NSFileManager
|
||
- (NSDictionary<NSFileAttributeKey, id> *) attributesOfFileSystemForPath:(NSString *)path error:(NSError **)error {
|
||
// 磁盘信息
|
||
// NSLog(@"start hook disk info");
|
||
NSDictionary<NSFileAttributeKey, id> *res = %orig;
|
||
// int64_t size = [info[NSFileSystemSize] longLongValue]; // 总大小
|
||
// int64_t space = [[info objectForKey:NSFileSystemFreeSize] longLongValue];
|
||
if ([path isEqualToString:NSHomeDirectory()]) {
|
||
NSMutableDictionary *modifiedAttributes = [res mutableCopy];
|
||
// 修改或添加属性
|
||
tryGetVal(@"diskSize", ^(id parameter) {
|
||
int64_t fat = str2ull(parameter);
|
||
if(fat > 0) {
|
||
modifiedAttributes[NSFileSystemSize] = @(fat); // 1 GB
|
||
}
|
||
});
|
||
tryGetVal(@"diskFreeSize", ^(id parameter) {
|
||
int64_t fat = str2ull(parameter);
|
||
if(fat > 0) {
|
||
modifiedAttributes[NSFileSystemFreeSize] = @(fat); // 1 GB
|
||
}
|
||
});
|
||
|
||
return [modifiedAttributes copy];
|
||
}
|
||
|
||
return res;
|
||
}
|
||
// 反越狱检测
|
||
- (BOOL)fileExistsAtPath:(NSString *)event {
|
||
// NSLog(@"start hook fileExistsAtPath");
|
||
NSArray<NSString *> *array = @[@"/Application/Cydia.app",
|
||
@"/Application/Sileo.app",
|
||
@"/usr/lib/TweakInject",
|
||
@"/Library/TweakInject",
|
||
@"/Library/MobileSubstrate/MobileSubstrate.dylib",
|
||
@"/bin/bash",
|
||
@"/usr/sbin/sshd",
|
||
@"/etc/apt",
|
||
@"/usr/bin/ssh",
|
||
@"/private/var/lib/apt",
|
||
@"/private/var/lib/cydia",
|
||
@"/private/var/tmp/cydia.log",
|
||
@"/Applications/WinterBoard.app",
|
||
@"/var/lib/cydia",
|
||
@"/private/etc/dpkg/origins/debian",
|
||
@"/bin.sh",
|
||
@"/private/etc/apt",
|
||
@"/etc/ssh/sshd_config",
|
||
@"/private/etc/ssh/sshd_config",
|
||
@"/Applications/SBSetttings.app",
|
||
@"/private/var/mobileLibrary/SBSettingsThemes/",
|
||
@"/private/var/stash",
|
||
@"/usr/libexec/sftp-server",
|
||
@"/usr/libexec/cydia/",
|
||
@"/usr/sbin/frida-server",
|
||
@"/usr/bin/cycript",
|
||
@"/usr/local/bin/cycript",
|
||
@"/usr/lib/libcycript.dylib",
|
||
@"/System/Library/LaunchDaemons/com.saurik.Cydia.Startup.plist",
|
||
@"/System/Library/LaunchDaemons/com.ikey.bbot.plist",
|
||
@"/Applications/FakeCarrier.app",
|
||
@"/Library/MobileSubstrate/DynamicLibraries/Veency.plist",
|
||
@"/Library/MobileSubstrate/DynamicLibraries/LiveClock.plist",
|
||
@"/usr/libexec/ssh-keysign",
|
||
@"/usr/libexec/sftp-server",
|
||
@"/Applications/blackra1n.app",
|
||
@"/Applications/IntelliScreen.app",
|
||
@"/Applications/Snoop-itConfig.app",
|
||
@"/var/lib/dpkg/info",
|
||
@"/User/Applications"];
|
||
|
||
NSInteger index = [array indexOfObjectPassingTest:^BOOL(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||
BOOL ret = [event hasPrefix:obj];
|
||
if (ret) {
|
||
*stop = YES;
|
||
}
|
||
return ret;
|
||
}];
|
||
if (index != NSNotFound) {
|
||
// NSLog(@"9999999==%@=",event);
|
||
return NO;
|
||
}
|
||
return %orig;
|
||
}
|
||
%end
|
||
|
||
%hook NSLocale
|
||
+ (NSArray *) preferredLanguages {
|
||
// 语言
|
||
// NSLog(@"start hook preferredLanguages");
|
||
return @[@"en-US"];
|
||
}
|
||
+ (NSLocale *)currentLocale {
|
||
// 如果你想修改返回的 locale,可以在这里进行修改
|
||
// 例如,强制返回一个特定的 locale:
|
||
// NSLog(@"start hook currentLocale");
|
||
__block NSLocale *res = %orig;
|
||
tryGetVal(@"locale", ^(id parameter) {
|
||
NSString *loc = parameter;
|
||
res = [[NSLocale alloc] initWithLocaleIdentifier:loc];
|
||
});
|
||
return res;
|
||
}
|
||
+ (NSLocale *)systemLocale {
|
||
// NSLog(@"start hook systemLocale");
|
||
__block NSLocale *res = %orig;
|
||
tryGetVal(@"locale", ^(id parameter) {
|
||
NSString *loc = parameter;
|
||
res = [[NSLocale alloc] initWithLocaleIdentifier:loc];
|
||
});
|
||
return res;
|
||
}
|
||
|
||
%end
|
||
|
||
%hook NSTimeZone
|
||
|
||
|
||
+ (NSTimeZone *)localTimeZone {
|
||
// NSTimeZone *originalTimeZone = %orig;
|
||
// // NSLog(@"[HOOK] Local time zone accessed: %@", [originalTimeZone name]);
|
||
|
||
// 如果你想修改返回的时区,可以在这里进行修改
|
||
// 例如,强制返回一个特定的时区:
|
||
// NSLog(@"start hook localTimeZone");
|
||
__block NSTimeZone *res = %orig;
|
||
tryGetVal(@"timeZone", ^(id parameter) {
|
||
NSString *loc = parameter;
|
||
res = [NSTimeZone timeZoneWithName:loc];
|
||
});
|
||
return res;
|
||
// return originalTimeZone;
|
||
}
|
||
|
||
+ (NSTimeZone *)systemTimeZone {
|
||
// NSLog(@"start hook systemTimeZone");
|
||
__block NSTimeZone *res = %orig;
|
||
tryGetVal(@"timeZone", ^(id parameter) {
|
||
NSString *loc = parameter;
|
||
res = [NSTimeZone timeZoneWithName:loc];
|
||
});
|
||
return res;
|
||
}
|
||
|
||
+ (NSTimeZone *)defaultTimeZone {
|
||
// NSLog(@"start hook defaultTimeZone");
|
||
__block NSTimeZone *res = %orig;
|
||
tryGetVal(@"timeZone", ^(id parameter) {
|
||
NSString *loc = parameter;
|
||
res = [NSTimeZone timeZoneWithName:loc];
|
||
});
|
||
return res;
|
||
}
|
||
|
||
|
||
%end
|
||
|
||
// 状态栏
|
||
%hook UIStatusBarManager
|
||
- (CGRect) statusBarFrame {
|
||
// NSLog(@"start hook statusBarFrame");
|
||
__block CGRect originalFrame = %orig;
|
||
tryGetVal(@"safeAreaInsets", ^(id parameter) {
|
||
NSDictionary *dic = parameter;
|
||
double barHeight = str2double(dic[@"height"]);
|
||
CGSize tempSize = {.width = originalFrame.size.width, .height = barHeight};
|
||
originalFrame.size = tempSize;
|
||
});
|
||
return originalFrame;
|
||
}
|
||
%end
|
||
|
||
%hook NSMutableURLRequest
|
||
// Maybe server side checks the user agent?
|
||
- (instancetype)initWithURL:(NSURL *)URL {
|
||
self = %orig(URL);
|
||
if (self) {
|
||
tryGetVal(@"userAgent", ^(id parameter) {
|
||
[self setValue:parameter forHTTPHeaderField:@"User-Agent"];
|
||
});
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field {
|
||
__block NSString *_userAgent = value;
|
||
if ([field isEqualToString:@"User-Agent"]) {
|
||
// 修改User Agent
|
||
tryGetVal(@"userAgent", ^(id parameter) {
|
||
_userAgent = parameter;
|
||
});
|
||
}
|
||
%orig(_userAgent, field);
|
||
}
|
||
|
||
%end
|
||
|
||
%hook NSURLSession
|
||
|
||
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration {
|
||
// NSLog(@"start hook sessionWithConfiguration");
|
||
//if (configuration.HTTPAdditionalHeaders[@"User-Agent"]) {
|
||
tryGetVal(@"userAgent", ^(id parameter) {
|
||
configuration.HTTPAdditionalHeaders = @{@"User-Agent": parameter};
|
||
});
|
||
//}
|
||
return %orig;
|
||
}
|
||
|
||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
||
completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler {
|
||
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
||
tryGetVal(@"userAgent", ^(id parameter) {
|
||
[mutableRequest setValue:parameter forHTTPHeaderField:@"User-Agent"];
|
||
});
|
||
|
||
return %orig(mutableRequest, completionHandler);
|
||
}
|
||
|
||
%end
|
||
|
||
%hook WKWebView
|
||
|
||
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *error))completionHandler {
|
||
// NSLog(@"start hook evaluateJavaScript");
|
||
%log(@"Evaluating JavaScript: %@", javaScriptString);
|
||
__block NSString *userAgent = nil;
|
||
tryGetVal(@"userAgent", ^(id parameter) {
|
||
userAgent = parameter;
|
||
});
|
||
if(userAgent) {
|
||
[self setCustomUserAgent:userAgent];
|
||
}
|
||
%orig(javaScriptString, completionHandler);
|
||
}
|
||
|
||
- (void)setCustomUserAgent:(NSString *)userAgent {
|
||
__block NSString *_userAgent = userAgent;
|
||
tryGetVal(@"userAgent", ^(id parameter) {
|
||
_userAgent = parameter;
|
||
});
|
||
%orig(_userAgent);
|
||
}
|
||
|
||
- (NSString *)customUserAgent {
|
||
// 获取原来的 User-Agent
|
||
__block NSString *userAgent = %orig;
|
||
|
||
tryGetVal(@"userAgent", ^(id parameter) {
|
||
userAgent = parameter;
|
||
});
|
||
|
||
// 返回修改后的 User-Agent
|
||
return userAgent;
|
||
}
|
||
|
||
%end
|
||
|
||
|
||
|
||
%hook CTTelephonyNetworkInfo
|
||
- (NSDictionary<NSString *, NSString *> *) serviceCurrentRadioAccessTechnology {
|
||
// NSLog(@"start hook serviceCurrentRadioAccessTechnology");
|
||
NSDictionary<NSString *, NSString *> *originalTechnologies = %orig;
|
||
%log(@"Original Radio Access Technologies: %@", originalTechnologies);
|
||
|
||
NSMutableDictionary<NSString *, NSString *> *modifiedProviders = [[NSMutableDictionary alloc] init];
|
||
|
||
tryGetVal(@"simInfo", ^(id parameter) {
|
||
NSDictionary *simInfoDic = parameter;
|
||
for(NSString *service in simInfoDic.allKeys) {
|
||
NSDictionary *dic = simInfoDic[service];
|
||
NSString *wwan = dic[@"wwan"];
|
||
if([wwan isEqual:@"5G"]) {
|
||
[modifiedProviders setValue:@"CTRadioAccessTechnologyNR" forKey:service];
|
||
} else {
|
||
[modifiedProviders setValue:@"CTRadioAccessTechnologyLTE" forKey:service];
|
||
}
|
||
}
|
||
});
|
||
|
||
if([modifiedProviders count] > 0) {
|
||
return [modifiedProviders copy];
|
||
}
|
||
return originalTechnologies;
|
||
}
|
||
- (NSDictionary<NSString *, CTCarrier *> *)serviceSubscriberCellularProviders {
|
||
// NSLog(@"start hook serviceSubscriberCellularProviders");
|
||
NSDictionary<NSString *, CTCarrier *> *originalProviders = %orig;
|
||
%log(@"Original Cellular Providers: %@", originalProviders);
|
||
|
||
NSMutableDictionary<NSString *, CTCarrier *> *modifiedProviders = [[NSMutableDictionary alloc] init];
|
||
|
||
tryGetVal(@"simInfo", ^(id parameter) {
|
||
NSDictionary *simInfoDic = parameter;
|
||
for(NSString *service in simInfoDic.allKeys) {
|
||
NSDictionary *dic = simInfoDic[service];
|
||
if (!dic) {
|
||
continue;
|
||
}
|
||
if (![dic[@"id"] isEqual:[NSNull null]]) {
|
||
[[NSUserDefaults standardUserDefaults] setValue:dic[@"id"] forKey:@"lux-carrier-id"];
|
||
}
|
||
CTCarrier *carrier = [[CTCarrier alloc] init];
|
||
[carrier setValue:dic[@"carrierName"] forKey:@"carrierName"];
|
||
[carrier setValue:dic[@"mobileCountryCode"] forKey:@"mobileCountryCode"];
|
||
[carrier setValue:dic[@"mobileNetworkCode"] forKey:@"mobileNetworkCode"];
|
||
[carrier setValue:dic[@"isoCountryCode"] forKey:@"isoCountryCode"];
|
||
[modifiedProviders setValue:carrier forKey:service];
|
||
}
|
||
});
|
||
|
||
if([modifiedProviders count] > 0) {
|
||
return [modifiedProviders copy];
|
||
}
|
||
return originalProviders;
|
||
}
|
||
%end
|
||
|
||
// 添加随机函数
|
||
static double randomRadiansPerSecond() {
|
||
double randomValue = (double)arc4random() / UINT32_MAX;
|
||
return (randomValue * 20.0) - 10.0;
|
||
}
|
||
// 创建 CMGyroData 的子类
|
||
@interface CustomCMGyroData : CMGyroData
|
||
@property (nonatomic, assign) CMRotationRate customRotationRate;
|
||
@end
|
||
|
||
@implementation CustomCMGyroData
|
||
|
||
- (CMRotationRate)rotationRate {
|
||
return self.customRotationRate;
|
||
}
|
||
|
||
@end
|
||
|
||
|
||
|
||
// 陀螺仪
|
||
%hook CMMotionManager
|
||
|
||
- (void)startGyroUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMGyroHandler)handler {
|
||
if (!queue || !handler) return %orig;
|
||
CMGyroHandler newHandler = ^(CMGyroData *gyroData, NSError *error) {
|
||
|
||
if(gyroData) {
|
||
CMRotationRate originalRate = gyroData.rotationRate;
|
||
|
||
// 在这里,你可以修改或记录 rotationRate
|
||
// NSLog(@"Gyro RotationRate - x: %f, y: %f, z: %f",
|
||
// originalRate.x, originalRate.y, originalRate.z);
|
||
}
|
||
// 设置随机的旋转速率
|
||
CMRotationRate randomRate;
|
||
randomRate.x = randomRadiansPerSecond();
|
||
randomRate.y = randomRadiansPerSecond();
|
||
randomRate.z = randomRadiansPerSecond();
|
||
|
||
// 如果你想修改值,可以这样做:
|
||
// 创建自定义的 CMGyroData 对象
|
||
CustomCMGyroData *customGyroData = (CustomCMGyroData *)[[objc_getClass("CMGyroData") alloc] init];
|
||
// Objective-C 没有直接的方法来修改 CMGyroData 的值,所以这里我们只是记录
|
||
// 设置自定义数据
|
||
customGyroData.customRotationRate = randomRate;
|
||
// 调用原始处理程序,但使用我们的自定义数据
|
||
if (handler) {
|
||
handler((CMGyroData *)customGyroData, error);
|
||
}
|
||
};
|
||
|
||
%orig(queue, newHandler);
|
||
}
|
||
|
||
%end
|
||
|
||
|
||
// int uname(struct utsname *);
|
||
%hookf(int, uname, struct utsname * systemInfo) {
|
||
// NSLog(@"start hook uname");
|
||
int nRet = %orig;
|
||
tryGetVal(@"productStr", ^(id parameter) {
|
||
char str_machine_name[100];
|
||
[parameter getCString:str_machine_name maxLength:100 encoding:NSUTF8StringEncoding];
|
||
strcpy(systemInfo->machine,str_machine_name);
|
||
});
|
||
return nRet; // Call the original implementation of this function
|
||
|
||
}
|
||
|
||
%hookf(int, sysctl, const int *name, u_int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) {
|
||
// NSLog(@"start hook sysctl");
|
||
|
||
if(namelen < 2) {
|
||
return %orig;
|
||
}
|
||
|
||
if (name[0] == CTL_KERN && name[1] == KERN_BOOTTIME) {
|
||
int nRet = %orig;
|
||
if (nRet == 0 && oldp && oldlenp && *oldlenp >= sizeof(struct timeval)) {
|
||
struct timeval *a = (struct timeval*)oldp;
|
||
tryGetVal(@"kernBootTime", ^(id parameter) {
|
||
int kernBootTime = str2int(parameter);
|
||
a->tv_sec = kernBootTime + a->tv_sec;
|
||
});
|
||
}
|
||
return nRet;
|
||
}
|
||
else if(name[0] == CTL_HW && name[1] == HW_MACHINE) {
|
||
__block NSString *modelName = @"iPhone14,2";
|
||
tryGetVal(@"productStr", ^(id parameter) {
|
||
if(parameter) {
|
||
modelName = parameter;
|
||
}
|
||
});
|
||
|
||
const char *spoofedModel = [modelName UTF8String];
|
||
if (!spoofedModel) {
|
||
return %orig;
|
||
}
|
||
|
||
size_t modelLen = strlen(spoofedModel) + 1; // +1 for null terminator
|
||
|
||
// 查询缓冲区大小
|
||
if (!oldp && oldlenp) {
|
||
*oldlenp = modelLen;
|
||
return 0;
|
||
}
|
||
|
||
// 复制数据
|
||
if (oldp && oldlenp) {
|
||
if (*oldlenp < modelLen) {
|
||
// 缓冲区太小,返回错误
|
||
return ENOMEM;
|
||
}
|
||
|
||
// 安全复制字符串
|
||
strlcpy((char*)oldp, spoofedModel, *oldlenp);
|
||
*oldlenp = modelLen;
|
||
// NSLog(@"sysctl model copied: %@", modelName);
|
||
return 0;
|
||
}
|
||
|
||
return EINVAL;
|
||
}
|
||
|
||
// 其他情况调用原函数
|
||
return %orig;
|
||
}
|
||
|
||
// 安全的字符串复制函数
|
||
static BOOL safe_copy_string(void *dst, size_t *dstlen, const char *src) {
|
||
if (!dst || !dstlen || !src) return NO;
|
||
|
||
size_t srclen = strlen(src);
|
||
size_t needed = srclen + 1;
|
||
|
||
if (*dstlen < needed) {
|
||
*dstlen = needed;
|
||
return NO;
|
||
}
|
||
|
||
strlcpy(dst, src, *dstlen);
|
||
*dstlen = srclen;
|
||
return YES;
|
||
}
|
||
|
||
%hookf(int, sysctlbyname, const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
||
// NSLog(@"start hook sysctlbyname");
|
||
if (strcmp(name, "hw.machine") == 0) {
|
||
// NSLog(@"start hook sysctlbyname new machine");
|
||
int ret = %orig;
|
||
__block NSString *machine = nil;
|
||
tryGetVal(@"productStr", ^(id parameter) {
|
||
if (parameter) {
|
||
NSString *temp = parameter;
|
||
machine = [temp copy];
|
||
// NSLog(@"machine,%@", temp);
|
||
}
|
||
});
|
||
if (oldp && machine) {
|
||
// NSLog(@"machine,1");
|
||
// char str_machine_name[100];
|
||
const char *hwMachineCh = [machine UTF8String];
|
||
// [parameter getCString:str_machine_name maxLength:100 encoding:NSUTF8StringEncoding];
|
||
//strcpy((char *)oldp, hwMachineCh);
|
||
if (hwMachineCh) {
|
||
|
||
// NSLog(@"machine,2,%@", machine);
|
||
size_t len = strlen(hwMachineCh);
|
||
if (*oldlenp > len) {
|
||
strlcpy((char *)oldp, hwMachineCh, *oldlenp); // 使用安全的字符串复制
|
||
*oldlenp = len;
|
||
}
|
||
//strncpy((char *)oldp, hwMachineCh, strlen(hwMachineCh));
|
||
}
|
||
}
|
||
return ret;
|
||
} else if (strcmp(name, "hw.model") == 0) {
|
||
// NSLog(@"start hook sysctlbyname new model");
|
||
int ret = %orig;
|
||
__block NSString *modelStr = nil;
|
||
tryGetVal(@"hwModel", ^(id parameter) {
|
||
if (parameter) {
|
||
NSString *temp = parameter;
|
||
modelStr = [temp copy];
|
||
// NSLog(@"model,%@", temp);
|
||
}
|
||
});
|
||
if (oldp && modelStr) {
|
||
// NSLog(@"model,1");
|
||
// char str_machine_name[100];
|
||
const char *modelStrCh = [modelStr UTF8String];
|
||
// [parameter getCString:str_machine_name maxLength:100 encoding:NSUTF8StringEncoding];
|
||
//strcpy((char *)oldp, hwMachineCh);
|
||
if (modelStrCh) {
|
||
// NSLog(@"model,2");
|
||
strncpy((char *)oldp, modelStrCh, strlen(modelStrCh));
|
||
}
|
||
}
|
||
return ret;
|
||
} else {
|
||
// NSLog(@"start hook sysctlbyname old");
|
||
return %orig;
|
||
}
|
||
}
|
||
|
||
// int clock_gettime(clockid_t __clock_id, struct timespec *__tp);
|
||
%hookf(int, clock_gettime, clockid_t __clock_id, struct timespec *__tp) {
|
||
// NSLog(@"start hook clock_gettime");
|
||
int nret = %orig;
|
||
if(__clock_id == CLOCK_MONOTONIC_RAW) {
|
||
// __tp->tv_sec = 20;
|
||
// __tp->tv_nsec = 20;
|
||
}
|
||
return nret;
|
||
}
|
||
|
||
// 修改ip
|
||
|
||
// 辅助函数:创建网络接口
|
||
static struct ifaddrs* createInterface(const char* name, const char* ipv4, const char* ipv6) {
|
||
if (!name || !ipv4 || !ipv6) return NULL;
|
||
|
||
@try {
|
||
// 创建新接口
|
||
struct ifaddrs *new_ifaddr = (struct ifaddrs *)calloc(1, sizeof(struct ifaddrs));
|
||
if (!new_ifaddr) return NULL;
|
||
|
||
// 设置接口名称
|
||
new_ifaddr->ifa_name = strdup(name);
|
||
if (!new_ifaddr->ifa_name) {
|
||
free(new_ifaddr);
|
||
return NULL;
|
||
}
|
||
new_ifaddr->ifa_flags = IFF_UP | IFF_RUNNING;
|
||
|
||
// 创建IPv4地址结构
|
||
struct sockaddr_in *addr_in = (struct sockaddr_in *)calloc(1, sizeof(struct sockaddr_in));
|
||
if (!addr_in) {
|
||
free(new_ifaddr->ifa_name);
|
||
free(new_ifaddr);
|
||
return NULL;
|
||
}
|
||
|
||
// 设置IPv4地址
|
||
addr_in->sin_family = AF_INET;
|
||
if (inet_pton(AF_INET, ipv4, &addr_in->sin_addr) != 1) {
|
||
free(addr_in);
|
||
free(new_ifaddr->ifa_name);
|
||
free(new_ifaddr);
|
||
return NULL;
|
||
}
|
||
new_ifaddr->ifa_addr = (struct sockaddr *)addr_in;
|
||
|
||
// 创建IPv6结构
|
||
struct ifaddrs *next_ifaddr = (struct ifaddrs *)calloc(1, sizeof(struct ifaddrs));
|
||
if (!next_ifaddr) {
|
||
free(addr_in);
|
||
free(new_ifaddr->ifa_name);
|
||
free(new_ifaddr);
|
||
return NULL;
|
||
}
|
||
|
||
// 设置IPv6名称
|
||
next_ifaddr->ifa_name = strdup(name);
|
||
if (!next_ifaddr->ifa_name) {
|
||
free(next_ifaddr);
|
||
free(addr_in);
|
||
free(new_ifaddr->ifa_name);
|
||
free(new_ifaddr);
|
||
return NULL;
|
||
}
|
||
next_ifaddr->ifa_flags = IFF_UP | IFF_RUNNING;
|
||
|
||
// 创建IPv6地址结构
|
||
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)calloc(1, sizeof(struct sockaddr_in6));
|
||
if (!addr_in6) {
|
||
free(next_ifaddr->ifa_name);
|
||
free(next_ifaddr);
|
||
free(addr_in);
|
||
free(new_ifaddr->ifa_name);
|
||
free(new_ifaddr);
|
||
return NULL;
|
||
}
|
||
|
||
// 设置IPv6地址
|
||
addr_in6->sin6_family = AF_INET6;
|
||
if (inet_pton(AF_INET6, ipv6, &addr_in6->sin6_addr) != 1) {
|
||
free(addr_in6);
|
||
free(next_ifaddr->ifa_name);
|
||
free(next_ifaddr);
|
||
free(addr_in);
|
||
free(new_ifaddr->ifa_name);
|
||
free(new_ifaddr);
|
||
return NULL;
|
||
}
|
||
next_ifaddr->ifa_addr = (struct sockaddr *)addr_in6;
|
||
|
||
// 链接接口
|
||
new_ifaddr->ifa_next = next_ifaddr;
|
||
return new_ifaddr;
|
||
} @catch (NSException *exception) {
|
||
// NSLog(@"Error creating interface: %@", exception);
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
// 修改现有接口的IP地址
|
||
static void modifyInterfaceIP(struct ifaddrs *interface, const char *ipv4, const char *ipv6) {
|
||
if (!interface || !ipv4 || !ipv6) return;
|
||
|
||
@try {
|
||
if (interface->ifa_addr) {
|
||
if (((struct sockaddr_in*)interface->ifa_addr)->sin_family == AF_INET) {
|
||
struct sockaddr_in *addr = (struct sockaddr_in*)interface->ifa_addr;
|
||
inet_pton(AF_INET, ipv4, &addr->sin_addr);
|
||
} else if (((struct sockaddr_in*)interface->ifa_addr)->sin_family == AF_INET6) {
|
||
struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)interface->ifa_addr;
|
||
inet_pton(AF_INET6, ipv6, &addr6->sin6_addr);
|
||
}
|
||
}
|
||
} @catch (NSException *exception) {
|
||
// NSLog(@"Error modifying interface IP: %@", exception);
|
||
}
|
||
}
|
||
|
||
%hookf(int, getifaddrs, struct ifaddrs **interfaces) {
|
||
if (!interfaces) return EINVAL;
|
||
|
||
int nRet = %orig;
|
||
if (nRet != 0) return nRet;
|
||
|
||
@try {
|
||
// 获取网络配置
|
||
__block NSDictionary *networkConfig = nil;
|
||
tryGetVal(@"networkInterfacesInfo", ^(id parameter) {
|
||
if ([parameter isKindOfClass:[NSDictionary class]]) {
|
||
networkConfig = parameter;
|
||
}
|
||
});
|
||
|
||
if (!networkConfig) {
|
||
return nRet;
|
||
}
|
||
|
||
// 处理现有接口
|
||
struct ifaddrs *interface;
|
||
bool isHookEn0IpV4 = false;
|
||
|
||
for (interface = *interfaces; interface; interface = interface->ifa_next) {
|
||
if (!interface->ifa_name) continue;
|
||
|
||
NSString *name = @(interface->ifa_name);
|
||
if ([name isEqualToString:@"en0"]) {
|
||
NSDictionary *en0Config = networkConfig[@"en0"];
|
||
if (en0Config) {
|
||
const char *ipv4 = [en0Config[@"ipv4"] UTF8String];
|
||
const char *ipv6 = [en0Config[@"ipv6"] UTF8String];
|
||
if (ipv4 && ipv6) {
|
||
modifyInterfaceIP(interface, ipv4, ipv6);
|
||
isHookEn0IpV4 = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加新接口
|
||
if (!isHookEn0IpV4) {
|
||
NSDictionary *en0Config = networkConfig[@"en0"];
|
||
if (en0Config) {
|
||
const char *ipv4 = [en0Config[@"ipv4"] UTF8String];
|
||
const char *ipv6 = [en0Config[@"ipv6"] UTF8String];
|
||
struct ifaddrs *new_en0 = createInterface("en0", ipv4, ipv6);
|
||
if (new_en0) {
|
||
new_en0->ifa_next->ifa_next = *interfaces;
|
||
*interfaces = new_en0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加pdp_ip0接口
|
||
NSDictionary *pdpConfig = networkConfig[@"pdp_ip0"];
|
||
if (pdpConfig) {
|
||
const char *ipv4 = [pdpConfig[@"ipv4"] UTF8String];
|
||
const char *ipv6 = [pdpConfig[@"ipv6"] UTF8String];
|
||
struct ifaddrs *new_pdp = createInterface("pdp_ip0", ipv4, ipv6);
|
||
if (new_pdp) {
|
||
new_pdp->ifa_next->ifa_next = *interfaces;
|
||
*interfaces = new_pdp;
|
||
}
|
||
}
|
||
|
||
} @catch (NSException *exception) {
|
||
// NSLog(@"Error in getifaddrs hook: %@", exception);
|
||
}
|
||
|
||
return nRet;
|
||
}
|
||
|
||
|
||
|
||
/* Boolean
|
||
SCNetworkReachabilityGetFlags (
|
||
SCNetworkReachabilityRef target,
|
||
SCNetworkReachabilityFlags *flags
|
||
)
|
||
*/
|
||
|
||
%hookf(Boolean, SCNetworkReachabilityGetFlags, SCNetworkReachabilityRef target, SCNetworkReachabilityFlags *flags) {
|
||
// NSLog(@"start hook SCNetworkReachabilityGetFlags");
|
||
Boolean result = %orig(target, flags);
|
||
|
||
if (result && flags != NULL) {
|
||
// 可以在这里修改 flags 的值
|
||
// 例如,总是添加 kSCNetworkReachabilityFlagsReachable 标志
|
||
*flags |= kSCNetworkReachabilityFlagsReachable;
|
||
*flags |= kSCNetworkReachabilityFlagsIsWWAN;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
%hookf(BOOL,UIAccessibilityIsClosedCaptioningEnabled) {
|
||
return YES;
|
||
}
|
||
|
||
|
||
|
||
%hookf(BOOL,UIAccessibilityIsMonoAudioEnabled) {
|
||
return YES;
|
||
}
|
||
|
||
|
||
// group ohho end
|
||
%end
|
||
|
||
|
||
|
||
|
||
%ctor{
|
||
NSLog(@"start hook");
|
||
@try {
|
||
@autoreleasepool {
|
||
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
|
||
//// NSLog(@"print -- %@",bundleIdentifier);
|
||
NSString *jsonPath = @"/var/mobile/Documents/changeapp.json";
|
||
// 创建文件管理器实例
|
||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||
|
||
// 检查文件是否存在
|
||
BOOL fileExists = [fileManager fileExistsAtPath:jsonPath];
|
||
if(fileExists) {
|
||
NSData *jsonData = [NSData dataWithContentsOfFile:jsonPath];
|
||
if (jsonData) {
|
||
NSError *error = nil;
|
||
settings = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
|
||
if (error) {
|
||
NSLog(@"Error parsing JSON: %@", error);
|
||
return;
|
||
}
|
||
}
|
||
NSArray *pkgs = settings[@"apps"];
|
||
|
||
if([pkgs indexOfObject:bundleIdentifier] != NSNotFound){
|
||
NSString *idfa = settings[@"idfa"];
|
||
//
|
||
SetupXSLog();
|
||
NSLog(@"hooks start %@; idfa:%@", bundleIdentifier,idfa);
|
||
// 指定需要运行的执行的分组代码,%init有两种用法,这里只展示一种
|
||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"kLuxSSFaceKey"];
|
||
|
||
%init(ohno);
|
||
}
|
||
}
|
||
}
|
||
} @catch (NSException *exception) {
|
||
// NSLog(@"Error in ctor: %@", exception);
|
||
}
|
||
}
|
||
|
||
static void cleanup() {
|
||
// 清理分配的资源
|
||
if (settings) {
|
||
settings = nil;
|
||
}
|
||
// 其他清理工作
|
||
}
|
||
|
||
%dtor {
|
||
cleanup();
|
||
} |