ios-hooks/AppRunMan/server/XSHackIos.m
2025-09-05 18:48:22 +08:00

1491 lines
53 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// XSHackIos.m
// nochange
//
// Created by mac on 2024/10/15.
//
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#include <ftw.h>
#include <spawn.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#import <objc/runtime.h>
#include <dlfcn.h>
#include <SpringBoard/SBWindow.h>
#import "XSHelper.h"
#import "XSHackIos.h"
#import "XSPhoneConfig.h"
#import "XSPhoneInfo.h"
/**
获取当前应用
*/
SBApplication* XSGetFrontMostApplication(void)
{
//TODO: might cause problem here. Both _accessibilityFrontMostApplication failed or front most application springboard will cause app be nil.
__block id app = nil;
NSLog(@"XS- getFrontMostApplication");
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_sync(dispatch_get_main_queue(), ^{
@try{
SpringBoard *springboard = (SpringBoard *)[UIApplication sharedApplication];
//SpringBoard *springboard = (SpringBoard*)[%c(SpringBoard) sharedApplication];
if ([springboard respondsToSelector:@selector(_accessibilityFrontMostApplication)]) {
app = [springboard performSelector:@selector(_accessibilityFrontMostApplication)];
NSLog(@"XS- Simulated home button press, %@", app);
}
// app = [springboard _accessibilityFrontMostApplication];
//NSLog(@"com.zjx.springboard: app: %@, id: %@", app, [app displayIdentifier]);
}
@catch (NSException *exception) {
NSLog(@"XS-: Debug: %@", exception.reason);
}
dispatch_semaphore_signal(semaphore);
});
// 设置超时时间为5秒
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC);
// 等待信号量最多等待5秒
long result = dispatch_semaphore_wait(semaphore, timeout);
if (result == 0) {
// 在超时之前收到了信号
NSLog(@"XSGetFrontMostApplication end");
} else {
// 超时
NSLog(@"XSGetFrontMostApplication 等待超时");
}
return app;
}
NSString* XSFrontMostAppId(void) {
SBApplication* sbapp = XSGetFrontMostApplication();
if (sbapp == nil || [sbapp isEqual:[NSNull null]]) {
return @"";
}
return sbapp.bundleIdentifier;
}
extern char **environ;
//执行系统命令
int XSRuncmd(char *args[])
{
printf("XSRuncmd: args ");
for (int i = 0; args[i] != NULL; i++) {
printf("%s ", args[i]);
}
printf("\n");
posix_spawnattr_t attr;
posix_spawn_file_actions_t fact;
pid_t pid;
posix_spawnattr_init(&attr);
posix_spawn_file_actions_init(&fact);
posix_spawn(&pid,args[0], NULL, NULL,args,environ);
perror("posix_spawn");
NSLog(@"XS- pid=%d,child pid = %d\n",getpid(),pid);
int stat=0;
waitpid(pid,&stat,0);
NSLog(@"XS- stat is %d\n",stat);
return pid;
}
int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf){
int rv = remove(fpath);
if (rv)
perror(fpath);
return rv;
}
void XSSystem(const char *cmd) {
int stat = nftw(cmd, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
NSLog(@"nftw res: %d", stat);
}
NSString* XSGetAppExecutable(NSString *pkgName) {
//获取应用程序列表
Class cls = NSClassFromString(@"LSApplicationWorkspace");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id s = [(id)cls performSelector:NSSelectorFromString(@"defaultWorkspace")];
NSArray *array = [s performSelector:NSSelectorFromString(@"allApplications")];
#pragma clang diagnostic pop
Class LSApplicationProxy_class = NSClassFromString(@"LSApplicationProxy");
for (LSApplicationProxy_class in array) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
NSString *res = [LSApplicationProxy_class performSelector:@selector(applicationIdentifier)];
//NSString *strBundleID = [LSApplicationProxy_class performSelector:@selector(bundleIdentifier)];
#pragma clang diagnostic pop
// localizedName
if ([res isEqualToString:pkgName]) {
NSURL * bundleFullURL = [LSApplicationProxy_class performSelector:@selector(bundleURL)];
NSString * s_bundleURL = [bundleFullURL absoluteString];
NSString *prefix = @"file://";
NSRange needleRange = NSMakeRange(prefix.length,
s_bundleURL.length - prefix.length );
NSString *needle = [s_bundleURL substringWithRange:needleRange];
NSBundle *bundle = [NSBundle bundleWithPath:needle];
NSString* executable = [[bundle infoDictionary] valueForKeyPath:@"CFBundleExecutable"];
return executable;
}
}
return nil;
}
int XSReboot(void) {
char *argv[] = {
"/usr/sbin/reboot",
NULL
};
int r = XSRuncmd(argv);
return r;
}
int XSKillApp(NSString *appexe) {
if(appexe) {
const char* app = [appexe UTF8String];
char *appStr = strdup(app);
char *argv[] = {
"/usr/bin/killall",
"-9",
appStr,
NULL
};
int r = XSRuncmd(argv);
free(appStr);
return r;
}
return 0;
}
int kill2(NSString *appexe) {
NSString *cmd = [NSString stringWithFormat:@"/usr/bin/killall -9 %@", appexe];
const char* app = [cmd UTF8String];
char *appStr = strdup(app);
int r = system2(appStr, NULL, NULL);
free(appStr);
return r;
}
int XSKillAppByName(NSString *pkgName){
NSString* appexe = XSGetAppExecutable(pkgName);
return kill2(appexe);
}
int (*_XSOpenApp)(CFStringRef, Boolean);
int XSBringAppForeground(NSString *appIdentifier)
{
void* sbServices = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY);
CFStringRef appBundleName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), appIdentifier);
//[NSString stringWithFormat:@"%s", eventData];
NSLog(@"XS-: Switch to application: %@", appBundleName);
if (!_XSOpenApp) {
_XSOpenApp = (int(*)(CFStringRef, Boolean))dlsym(sbServices,"SBSLaunchApplicationWithIdentifier");
}
return _XSOpenApp(appBundleName, false);
}
void bringAppToForeground(NSString *bundleID) {
@autoreleasepool {
Class FBSSystemServiceClass = NSClassFromString(@"FBSSystemService");
if (FBSSystemServiceClass) {
id service = [FBSSystemServiceClass sharedService];
NSDictionary *options = @{
@"BSLaunchOrigin": @"SpringBoard",
@"BSSuspended": @NO,
};
[service openApplication:bundleID
options:options
clientPort:0
withResult:^(NSError *error) {
if (error) {
NSLog(@"Failed to bring app to foreground: %@", error);
}
}];
}
}
}
void activateApp(NSString *bundleID){
// 这个方法不行
Class SBApplicationControllerClass = NSClassFromString(@"SBApplicationController");
if (SBApplicationControllerClass) {
id controller = [SBApplicationControllerClass sharedInstance];
id app = [controller applicationWithBundleIdentifier:bundleID];
if ([app respondsToSelector:@selector(activate)]) {
[app activate];
}
}
}
void XSRemoteUnlock(void) {
// 获取 SBLockScreenManager 的共享实例
// 获取 SBUIController 实例
@autoreleasepool {
Class sbUIControllerClass = objc_getClass("SBUIController");
id sbUIController = [sbUIControllerClass performSelector:@selector(sharedInstance)];
// 检查设备是否在锁屏状态
if ([sbUIController respondsToSelector:@selector(isOnLockScreen)]) {
BOOL isLocked = [sbUIController performSelector:@selector(isOnLockScreen)];
if (isLocked) {
// 模拟滑动解锁(对于没有密码的设备)
CGPoint startPoint = CGPointMake(50, CGRectGetMidY([UIScreen mainScreen].bounds));
CGPoint endPoint = CGPointMake(CGRectGetMaxX([UIScreen mainScreen].bounds) - 50, CGRectGetMidY([UIScreen mainScreen].bounds));
UITouch *touch = [[UITouch alloc] init];
[touch setValue:[NSValue valueWithCGPoint:startPoint] forKey:@"_locationInWindow"];
UIEvent *event = [[UIEvent alloc] init];
[event setValue:@(UIEventTypeTouches) forKey:@"_type"];
[event setValue:[NSSet setWithObject:touch] forKey:@"_touches"];
[[UIApplication sharedApplication] sendEvent:event];
[touch setValue:[NSValue valueWithCGPoint:endPoint] forKey:@"_locationInWindow"];
[[UIApplication sharedApplication] sendEvent:event];
// 对于有密码的设备,还需要模拟输入密码
// 这部分代码会更复杂,需要模拟点击数字键盘
NSLog(@"Simulated unlock gesture");
} else {
NSLog(@"Device is not locked");
}
} else {
NSLog(@"Unable to determine lock state");
}
// 模拟按下 Home 键
SpringBoard *springboard = (SpringBoard *)[UIApplication sharedApplication];
if ([springboard respondsToSelector:@selector(_simulateHomeButtonPress)]) {
[springboard performSelector:@selector(_simulateHomeButtonPress)];
NSLog(@"Simulated home button press");
}
}
/*
Class lockScreenManagerClass = objc_getClass("SBLockScreenManager");
if (lockScreenManagerClass) {
id lockScreenManager = [lockScreenManagerClass performSelector:@selector(sharedInstance)];
// 获取 SBUserAgent 的共享实例
Class userAgentClass = objc_getClass("SBUserAgent");
id userAgent = [userAgentClass performSelector:@selector(sharedUserAgent)];
if (lockScreenManager && userAgent) {
// 调用解锁方法
if ([lockScreenManager performSelector:@selector(isUILocked)]) {
[lockScreenManager performSelector:@selector(unlockUIFromSource:withOptions:)
withObject:@(1)
withObject:nil];
// 尝试唤醒屏幕
[userAgent performSelector:@selector(undimScreen)];
// 尝试解锁设备
[userAgent performSelector:@selector(unlockDevice)];
NSLog(@"-ad -log- Unlock command sent");
}else {
NSLog(@"-ad log- No lock");
}
} else {
NSLog(@"Unable to get LockScreenManager");
}
} else {
NSLog(@"-ad log- NO SBLockScreenManager");
}
*/
}
NSString* getDeviceName(void)
{
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine
encoding:NSUTF8StringEncoding];
}
/*
round up number by multiple of another number
*/
int roundUp(int numToRound, int multiple)
{
if (multiple == 0)
return numToRound;
int remainder = numToRound % multiple;
if (remainder == 0)
return numToRound;
return numToRound + multiple - remainder;
}
CGImageRef createScreenShotCGImageRef(void)
{
Boolean isiPad8orUp = false;
CGFloat scale = [UIScreen mainScreen].scale;
CGSize screenSize = [UIScreen mainScreen].bounds.size;
int height = (int)(screenSize.height * scale);
int width = (int)(screenSize.width * scale);
// check whether it is ipad8 or later
NSString *searchText = getDeviceName();
NSRange range = [searchText rangeOfString:@"^iPad[8-9]|iPad[1-9][0-9]+" options:NSRegularExpressionSearch];
if (range.location != NSNotFound) { // ipad pro (3rd) or later
isiPad8orUp = true;
}
if (isiPad8orUp)
{
if (width < height)
{
int temp = width;
width = height;
height = temp;
}
}
else
{
if (width > height)
{
int temp = width;
width = height;
height = temp;
}
}
int bytesPerElement = 4;
int bytesPerRow = roundUp(bytesPerElement * width, 32);
NSNumber *IOSurfaceBytesPerElement = [NSNumber numberWithInteger:bytesPerElement];
NSNumber *IOSurfaceBytesPerRow = [NSNumber numberWithInteger:bytesPerRow]; // don't know why but it should be a multiple of 32
NSNumber *IOSurfaceAllocSize = [NSNumber numberWithInteger:bytesPerRow * height];
NSNumber *nheight = [NSNumber numberWithInteger:height];
NSNumber *nwidth = [NSNumber numberWithInteger:width];
NSNumber *IOSurfacePixelFormat = [NSNumber numberWithInteger:1111970369];
NSNumber *IOSurfaceIsGlobal = [NSNumber numberWithInteger:1];
NSDictionary *properties = [[NSDictionary alloc] initWithObjectsAndKeys:IOSurfaceAllocSize, @"IOSurfaceAllocSize"
, IOSurfaceBytesPerElement, @"IOSurfaceBytesPerElement", IOSurfaceBytesPerRow, @"IOSurfaceBytesPerRow", nheight, @"IOSurfaceHeight",
IOSurfaceIsGlobal, @"IOSurfaceIsGlobal", IOSurfacePixelFormat, @"IOSurfacePixelFormat", nwidth, @"IOSurfaceWidth", nil];
IOSurfaceRef screenSurface = IOSurfaceCreate((__bridge CFDictionaryRef)(properties));
properties = nil;
IOSurfaceLock(screenSurface, 0, NULL);
CARenderServerRenderDisplay(0, CFSTR("LCD"), screenSurface, 0, 0);
CGImageRef cgImageRef = nil;
if (screenSurface) {
cgImageRef = UICreateCGImageFromIOSurface(screenSurface);
int targetWidth = CGImageGetWidth(cgImageRef);
int targetHeight = CGImageGetHeight(cgImageRef);
if (isiPad8orUp) // rotate 90 degrees counterclockwise
{
CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(cgImageRef);
CGContextRef bitmap;
//if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(cgImageRef), CGImageGetBytesPerRow(cgImageRef), colorSpaceInfo, kCGImageAlphaPremultipliedFirst);
//} else {
//bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(cgImageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
//}
CGFloat degrees = -90.f;
CGFloat radians = degrees * (M_PI / 180.f);
CGContextTranslateCTM (bitmap, 0.5*targetHeight, 0.5*targetWidth);
CGContextRotateCTM (bitmap, radians);
CGContextTranslateCTM (bitmap, -0.5*targetWidth, -0.5*targetHeight);
CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), cgImageRef);
CGImageRelease(cgImageRef);
cgImageRef = CGBitmapContextCreateImage(bitmap);
CGColorSpaceRelease(colorSpaceInfo);
CGContextRelease(bitmap);
}
}
IOSurfaceUnlock(screenSurface, 0, NULL);
CFRelease(screenSurface);
screenSurface = nil;
return cgImageRef;
}
UIImage* XSCcaptureScreen2(void) {
CGImageRef cgImage = createScreenShotCGImageRef();
UIImage *uiImage = [UIImage imageWithCGImage:cgImage];
NSLog(@"img2:%@", uiImage);
CFRelease(cgImage);
return uiImage;
}
UIImage* XSCaptureScreen(void) {
NSLog(@"captureScreen");
UIImage* res = _UICreateScreenUIImage();
NSLog(@"img1:%@", res);
if (res && res != nil && ![res isEqual:[NSNull null]]) {
return res;
}
return XSCcaptureScreen2();
}
UIImage* defaultIconWithSize (CGSize size, NSString *appName) {
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
// 使用随机颜色填充矩形
CGFloat hue = (CGFloat)arc4random() / UINT32_MAX;
UIColor *color = [UIColor colorWithHue:hue saturation:0.5 brightness:0.8 alpha:1.0];
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
// 可选:添加应用名称的首字母
NSString *initial = [[appName substringToIndex:1] uppercaseString];
UIColor *textColor = [UIColor whiteColor];
NSDictionary *attributes = @{
NSFontAttributeName: [UIFont boldSystemFontOfSize:size.width * 0.6],
NSForegroundColorAttributeName: textColor
};
CGSize textSize = [initial sizeWithAttributes:attributes];
CGPoint textPoint = CGPointMake((size.width - textSize.width) / 2,
(size.height - textSize.height) / 2);
[initial drawAtPoint:textPoint withAttributes:attributes];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
NSArray* XSGetApps(void){
NSMutableArray *appInfoArray = [NSMutableArray array];
//获取应用程序列表
Class cls = NSClassFromString(@"LSApplicationWorkspace");
id s = [(id)cls performSelector:NSSelectorFromString(@"defaultWorkspace")];
NSArray *array = [s performSelector:NSSelectorFromString(@"allApplications")];
Class LSApplicationProxy_class = NSClassFromString(@"LSApplicationProxy");
for (LSApplicationProxy_class in array){
NSString * applicationIdentifier = [LSApplicationProxy_class performSelector:@selector(applicationIdentifier)];
NSString *strBundleID = [LSApplicationProxy_class performSelector:@selector(bundleIdentifier)];
NSString *localizedName = [LSApplicationProxy_class performSelector:@selector(localizedName)];
// localizedName
//获取应用的相关信息
NSString *strVersion = [LSApplicationProxy_class performSelector:@selector(bundleVersion)];
NSString *strShortVersion = [LSApplicationProxy_class performSelector:@selector(shortVersionString)];
NSURL * bundleFullURL = [LSApplicationProxy_class performSelector:@selector(bundleURL)];
NSString * s_bundleURL = [bundleFullURL absoluteString];
NSURL *strContainerURL = [LSApplicationProxy_class performSelector:@selector(containerURL)];
NSString *strContainerDataPath = [strContainerURL path];
if ([s_bundleURL hasPrefix:@"file:///private/"]){
NSString *prefix = @"file://";
NSRange needleRange = NSMakeRange(prefix.length,
s_bundleURL.length - prefix.length );
NSString *needle = [s_bundleURL substringWithRange:needleRange];
NSBundle *bundle = [NSBundle bundleWithPath:needle];
NSString* executable = [[bundle infoDictionary] valueForKeyPath:@"CFBundleExecutable"];
}
UIImage *icon = nil;
// 方法1: 尝试从bundle中获取图标
NSBundle *appBundle = [NSBundle bundleWithIdentifier:applicationIdentifier];
if (appBundle) {
NSString *iconPath = [appBundle pathForResource:@"AppIcon60x60" ofType:@"png"];
if (iconPath) {
icon = [UIImage imageWithContentsOfFile:iconPath];
}
}
// 方法2: 如果方法1失败尝试使用UIApplication的私有API
if (!icon) {
UIApplication *application = [UIApplication sharedApplication];
if ([application respondsToSelector:@selector(_iconDataForBundleIdentifier:)]) {
NSData *iconData = [application performSelector:@selector(_iconDataForBundleIdentifier:) withObject:applicationIdentifier];
if (iconData) {
icon = [UIImage imageWithData:iconData];
}
}
}
// 尝试使用_applicationIconImageForBundleIdentifier:获取图标
if ([UIImage respondsToSelector:@selector(_applicationIconImageForBundleIdentifier:format:scale:)]) {
icon = [UIImage _applicationIconImageForBundleIdentifier:applicationIdentifier format:10 scale:[UIScreen mainScreen].scale];
}
if (!icon) {
// 使用默认图标
icon = defaultIconWithSize(CGSizeMake(60, 60), localizedName);
}
NSString *logInfo = [NSString stringWithFormat:@"bundleId:%@,name:%@,containerPath:%@,version:%@,shortVersion:%@,icon:%@", strBundleID, localizedName, strContainerDataPath, strVersion, strShortVersion, icon];
NSLog(@"%@", logInfo);
NSDictionary *dic = @{
@"bundleId": applicationIdentifier ?: @"",
@"name": localizedName ?: @"",
@"containerPath": strContainerDataPath ?: @"",
@"version": strVersion ?: @"",
@"shortVersion": strShortVersion ?: @"",
@"icon": icon ?: [NSNull null]
};
[appInfoArray addObject:dic];
}
return [appInfoArray copy];
}
void XSCleanSafariHistory(void) {
NSString *historyPath = @"/var/mobile/Library/Safari/History.db";
sqlite3 *database;
if (sqlite3_open([historyPath UTF8String], &database) == SQLITE_OK) {
char *errMsg;
const char *sql = "DELETE FROM history_items; DELETE FROM history_visits; VACUUM;";
if (sqlite3_exec(database, sql, NULL, NULL, &errMsg) != SQLITE_OK) {
NSLog(@"Error cleaning Safari history: %s", errMsg);
sqlite3_free(errMsg);
} else {
NSLog(@"Safari history cleaned successfully");
}
sqlite3_close(database);
} else {
NSLog(@"Unable to open database");
}
}
/**
清楚safari数据
*/
void XSCleanSafari(void) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
// 清理 Safari 缓存
NSString *safariCachePath = @"/var/mobile/Library/Caches/com.apple.mobilesafari";
[XSHelper rmFiles:safariCachePath];
NSString *safariSafePath = @"/var/mobile/Library/Caches/com.apple.Safari.SafeBrowsing";
[XSHelper rmFiles:safariSafePath];
// 清理 Safari 的 WebKit 缓存
NSString *webKitCachePath = @"/var/mobile/Library/WebKit/com.apple.mobilesafari";
[XSHelper rmFiles:webKitCachePath];
// 清理 Safari 历史记录
// cleanSafariHistory();
/*
NSString *historyPath = @"/var/mobile/Library/Safari/History.db";
[fileManager removeItemAtPath:historyPath error:&error];
if (error) {
NSLog(@"Error clearing Safari history: %@", error.localizedDescription);
}
*/
NSString *historyPath = @"/var/mobile/Library/Safari";
[XSHelper rmFiles:historyPath];
// 清理 Safari Cookies
NSString *cookiesPath = @"/var/mobile/Library/Cookies/Cookies.binarycookies";
[XSHelper rmFiles:cookiesPath];
NSLog(@"Safari data cleared successfully");
NSFileManager *man = [NSFileManager defaultManager];
// 清理cookie
NSString *cookiepath = @"/var/mobile/Library/Cookies";
[XSHelper rmFiles:cookiepath];
cookiepath = @"/private/var/root/Library/Cookies";
[XSHelper rmFiles:cookiepath];
// 获取safari的沙盒路径
NSString* safaricontainer = nil;
NSString* installplist = @"/var/mobile/Library/Caches/com.apple.mobile.installation.plist";
if ([man fileExistsAtPath:installplist]) {
NSDictionary* plist = [NSDictionary dictionaryWithContentsOfFile:installplist];
id obj = plist[@"User"][@"com.apple.mobilesafari"];
if (obj == nil) {
obj = plist[@"System"][@"com.apple.mobilesafari"];
}
if (obj != nil) {
safaricontainer = obj[@"Container"];
}
} else {
Class LSApplicationProxy_cls = objc_getClass("LSApplicationProxy");
id obj = [LSApplicationProxy_cls performSelector:@selector(applicationProxyForIdentifier:) withObject:@"com.apple.mobilesafari"];
if (obj != nil && [obj respondsToSelector:@selector(dataContainerURL)]) {
safaricontainer = [[obj performSelector:@selector(dataContainerURL)] path];
}
}
if(safaricontainer) {
// 清理library
NSString* libpath = [safaricontainer stringByAppendingPathComponent:@"Library"];
NSString* libcachepath = [libpath stringByAppendingPathComponent:@"Caches"];
[XSHelper rmFiles:libcachepath];
}
}
void XSCleanKeychain(void) {
NSFileManager* man = [NSFileManager defaultManager];
if ([man fileExistsAtPath:@"/var/Keychains/keychain-2.db"]) {
/*
char *cpCmd = "/usr/bin/cp";
if ([man fileExistsAtPath:@"/bin/cp"]) {
cpCmd = "/bin/cp";
}
char *cmds[] = {
cpCmd,
"/var/Keychains/keychain-2.db",
"/tmp/",
NULL
};
*/
// XSRuncmd(cmds);
XSSystem("cp /var/Keychains/keychain-2.db /tmp/");
sqlite3* ppDb;
char cmd[256];
if (0 == sqlite3_open("/tmp/keychain-2.db", &ppDb)) {
strcpy(cmd, "DELETE FROM cert WHERE agrp<>'apple' and agrp not like '%apple%' and agrp <> 'ichat' and agrp <>'lockdown-identities'");
sqlite3_exec(ppDb, cmd, 0, 0, 0);
strcpy(cmd, "DELETE FROM keys WHERE agrp<>'apple' and agrp not like '%apple%' and agrp <> 'ichat' and agrp <>'lockdown-identities'");
sqlite3_exec(ppDb, cmd, 0, 0, 0);
strcpy(cmd, "DELETE FROM inet WHERE agrp<>'apple' and agrp not like '%apple%' and agrp <> 'ichat' and agrp <>'lockdown-identities'");
sqlite3_exec(ppDb, cmd, 0, 0, 0);
/*
char *cmds1[] = {
cpCmd,
"/tmp/keychain-2.*",
"/var/Keychains/",
NULL
};
*/
//XSRuncmd(cmds1);
XSSystem("cp /tmp/keychain-2.* /var/Keychains/");
}
//free(cpCmd);
}
}
void XSCleanPastboard(void) {
UIPasteboard* pb = [UIPasteboard generalPasteboard];
if (pb != nil) {
NSArray* items = [pb items];
if (items != nil) {
items = [NSArray array];
}
[pb setItems:items];
}
NSFileManager* man = [NSFileManager defaultManager];
NSProcessInfo* proc = [NSProcessInfo processInfo];
BOOL isbe8 = FALSE;
NSOperatingSystemVersion ver;
ver.majorVersion = 8;
ver.minorVersion = 0;
ver.patchVersion = 0;
if ([proc respondsToSelector:@selector(isOperatingSystemAtLeastVersion:)]) {
isbe8 = [proc isOperatingSystemAtLeastVersion:ver];
}
NSString* pbplist = nil;
if ([man fileExistsAtPath:@"/System/Library/LaunchDaemons/com.apple.UIKit.pasteboardd.plist"]) {
pbplist = @"/System/Library/LaunchDaemons/com.apple.UIKit.pasteboardd.plist";
//pbbundle = @"com.apple.UIKit.pasteboardd";
}
else if ([man fileExistsAtPath:@"/Library/LaunchDaemons/com.apple.UIKit.pasteboardd.plist"]) {
pbplist = @"/Library/LaunchDaemons/com.apple.UIKit.pasteboardd.plist";
//pbbundle = @"com.apple.UIKit.pasteboardd";
}
else if ([man fileExistsAtPath:@"/System/Library/LaunchDaemons/com.apple.pasteboard.pasted.plist"]) {
pbplist = @"/System/Library/LaunchDaemons/com.apple.pasteboard.pasted.plist";
//pbbundle = @"com.apple.pasteboard.pasted";
}
// BOOL pbdbexist = [man fileExistsAtPath:@"/var/mobile/Library/Caches/com.apple.UIKit.pboard/pasteboardDB"];
NSString* pbcontainer = nil;
if ([man fileExistsAtPath:@"/var/mobile/Library/Caches/com.apple.UIKit.pboard"]) {
pbcontainer = @"/var/mobile/Library/Caches/com.apple.UIKit.pboard";
} else if ([man fileExistsAtPath:@"/var/mobile/Library/Caches/com.apple.Pasteboard"]) {
pbcontainer = @"/var/mobile/Library/Caches/com.apple.Pasteboard";
}
if (!isbe8 && [man fileExistsAtPath:pbplist]) {
XSSystem("launchctl unload -w");
}
if (pbcontainer != nil && [man fileExistsAtPath:pbcontainer]) {
NSString* cmd = [NSString stringWithFormat:@"rm -rf %@/*", pbcontainer];
XSSystem([cmd UTF8String]);
}
}
NSString* getAppExecutable(NSString *pkgName){
//获取应用程序列表
Class cls = NSClassFromString(@"LSApplicationWorkspace");
id s = [(id)cls performSelector:NSSelectorFromString(@"defaultWorkspace")];
NSArray *array = [s performSelector:NSSelectorFromString(@"allApplications")];
Class LSApplicationProxy_class = NSClassFromString(@"LSApplicationProxy");
for (LSApplicationProxy_class in array){
NSString * res = [LSApplicationProxy_class performSelector:@selector(applicationIdentifier)];
NSString *strBundleID = [LSApplicationProxy_class performSelector:@selector(bundleIdentifier)];
// localizedName
if ([res isEqualToString:pkgName]) {
NSURL * bundleFullURL = [LSApplicationProxy_class performSelector:@selector(bundleURL)];
NSString * s_bundleURL = [bundleFullURL absoluteString];
if ([s_bundleURL hasPrefix:@"file:///private/"]){
NSString *prefix = @"file://";
NSRange needleRange = NSMakeRange(prefix.length,
s_bundleURL.length - prefix.length );
NSString *needle = [s_bundleURL substringWithRange:needleRange];
NSBundle *bundle = [NSBundle bundleWithPath:needle];
NSString* executable = [[bundle infoDictionary] valueForKeyPath:@"CFBundleExecutable"];
return executable;
}}
}
return nil;
}
NSString* getAppSandboxPath(NSString *app){
//获取应用程序列表
Class cls = NSClassFromString(@"LSApplicationWorkspace");
id s = [(id)cls performSelector:NSSelectorFromString(@"defaultWorkspace")];
NSArray *array = [s performSelector:NSSelectorFromString(@"allApplications")];
Class LSApplicationProxy_class = NSClassFromString(@"LSApplicationProxy");
for (LSApplicationProxy_class in array){
NSString *strBundleID = [LSApplicationProxy_class performSelector:@selector(bundleIdentifier)];
//获取应用的相关信息
NSString *strVersion = [LSApplicationProxy_class performSelector:@selector(bundleVersion)];
NSString *strShortVersion = [LSApplicationProxy_class performSelector:@selector(shortVersionString)];
NSURL *strContainerURL = [LSApplicationProxy_class performSelector:@selector(containerURL)];
NSString *strContainerDataPath = [strContainerURL path];
//NSLog(@"bundleID%@ localizedName: %@", strBundleID, strLocalizedName);
if ([strBundleID isEqualToString:app]) {
return strContainerDataPath;
}
}
return nil;
}
NSString* XSGetAppInfoPath(NSString *app) {
NSString *appDataPath = getAppSandboxPath(app);
if (appDataPath) {
//判断目录,只有这两个目录才能清除,如果是其他的目录,比如/var/mobile/Documents/ 千万不能清除,
//否则可能需要重新激活或产生其他的问题
if ([appDataPath hasPrefix:@"/private/var/mobile/Containers/Data/Application/"] ||
[appDataPath hasPrefix:@"/var/mobile/Containers/Data/Application/"]) {
NSString *strLibraryPath = [appDataPath stringByAppendingPathComponent:@"Library"];
NSString *strPreferencesPath = [strLibraryPath stringByAppendingPathComponent:@"Preferences"];
NSString *appInfoPlist = [strPreferencesPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.plist", app]];
NSLog(@"app info path:%@", appInfoPlist);
return appInfoPlist;
}
}
return nil;
}
NSDictionary* XSGetAppInfo(NSString *appInfoPlist) {
if (appInfoPlist) {
NSDictionary *appInfo = [[NSDictionary alloc] initWithContentsOfFile:appInfoPlist];
return appInfo;
}
return nil;
}
void XSSaveAppInfo(NSDictionary *dic, NSString *appInfoPath) {
NSMutableDictionary *saveDic = [[NSMutableDictionary alloc] init];
if (dic) {
id kzzhDeviceInfo = dic[@"kzzhDeviceInfo"];
if (kzzhDeviceInfo) {
[saveDic setValue:kzzhDeviceInfo forKey:@"kzzhDeviceInfo"];
}
id appInfo = dic[@"appInfo"];
if (appInfo) {
[saveDic setValue:appInfo forKey:@"appInfo"];
}
id applovinInfo = dic[@"applovinInfo"];
if (applovinInfo) {
[saveDic setValue:applovinInfo forKey:@"applovinInfo"];
}
id kNilOptions = dic[@"kNilOptions"];
if (kNilOptions) {
[saveDic setValue:kNilOptions forKey:@"kNilOptions"];
}
id bfaceDictKey = dic[@"bfaceDictKey"];
XSPhoneConfig *config = [XSPhoneConfig sharedInstance];
NSString *deviceId = config.DeviceId;
NSString *loclIp = [[XSPhoneInfo sharedInstance] IPAddress];
if (bfaceDictKey) {
NSMutableDictionary *tempDic = [NSMutableDictionary dictionaryWithDictionary:bfaceDictKey];
[tempDic setValue:deviceId forKey:@"adbrush_deviceid"];
[tempDic setValue:loclIp forKey:@"adbrush_localip"];
[saveDic setValue:tempDic forKey:@"bfaceDictKey"];
} else {
NSDictionary *tempDic = @{@"adbrush_deviceid": deviceId, @"adbrush_localip": loclIp};
[saveDic setValue:tempDic forKey:@"bfaceDictKey"];
}
/*
NSDictionary *strAttrib = [NSDictionary dictionaryWithObjectsAndKeys:
@"mobile",NSFileGroupOwnerAccountName,
@"mobile",NSFileOwnerAccountName,
nil];
*/
[saveDic writeToFile:appInfoPath atomically:YES];
}
}
void cleanBundleContainer(NSString *appDataPath) {
//判断目录,只有这两个目录才能清除,如果是其他的目录,比如/var/mobile/Documents/ 千万不能清除,
//否则可能需要重新激活或产生其他的问题
if ([appDataPath hasPrefix:@"/private/var/mobile/Containers/Data/Application/"] ||
[appDataPath hasPrefix:@"/var/mobile/Containers/Data/Application/"]) {
NSFileManager *fm = [NSFileManager defaultManager];
NSString *strDocumentsPath = [appDataPath stringByAppendingPathComponent:@"Documents"];
[fm removeItemAtPath:strDocumentsPath error:nil];
NSString *strLibraryPath = [appDataPath stringByAppendingPathComponent:@"Library"];
NSString *strCachesPath = [strLibraryPath stringByAppendingPathComponent:@"Caches"];
NSString *strPreferencesPath = [strLibraryPath stringByAppendingPathComponent:@"Preferences"];
[fm removeItemAtPath:strLibraryPath error:nil];
NSString *strTmpPath = [appDataPath stringByAppendingPathComponent:@"tmp"];
[fm removeItemAtPath:strTmpPath error:nil];
NSString *strStoreKitPath = [appDataPath stringByAppendingPathComponent:@"StoreKit"];
[fm removeItemAtPath:strStoreKitPath error:nil];
//删除沙盒目录之后要以mobile身份创建相应的目录否则可能会因为权限问题使再次安装的应用
//不能写入应用沙盒目录
NSDictionary *strAttrib = [NSDictionary dictionaryWithObjectsAndKeys:
@"mobile",NSFileGroupOwnerAccountName,
@"mobile",NSFileOwnerAccountName,
nil];
[fm createDirectoryAtPath:appDataPath withIntermediateDirectories:NO
attributes:strAttrib error:nil];
[fm createDirectoryAtPath:strDocumentsPath withIntermediateDirectories:NO
attributes:strAttrib error:nil];
[fm createDirectoryAtPath:strLibraryPath withIntermediateDirectories:NO
attributes:strAttrib error:nil];
[fm createDirectoryAtPath:strCachesPath withIntermediateDirectories:NO
attributes:strAttrib error:nil];
[fm createDirectoryAtPath:strPreferencesPath withIntermediateDirectories:NO
attributes:strAttrib error:nil];
[fm createDirectoryAtPath:strTmpPath withIntermediateDirectories:NO
attributes:strAttrib error:nil];
}
}
void clearAppStringInfo(NSString* appPath) {
NSFileManager *fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:appPath]) {
return;
}
if ([appPath hasPrefix:@"/private/var/containers/Bundle/Application"] ||
[appPath hasPrefix:@"/var/containers/Bundle/Application"] ||
[appPath hasPrefix:@"/private/var/mobile/Containers/Data/Application"] ||
[appPath hasPrefix:@"/var/mobile/Containers/Data/Application"]) {
NSString *itunesPath = [appPath stringByDeletingLastPathComponent];
NSLog(@"itunes path: %@", itunesPath);
NSString *file1 = [NSString stringWithFormat:@"%@/iTunesMetadata.plist", itunesPath];
NSString *file2 = [NSString stringWithFormat:@"%@/iTunesArtwork", itunesPath];
NSString *file3 = [NSString stringWithFormat:@"%@/BundleMetadata.plist", itunesPath];
[fm removeItemAtPath:file1 error:nil];
[fm removeItemAtPath:file2 error:nil];
[fm removeItemAtPath:file3 error:nil];
}
}
void XSClearAppData(NSString *app) {
NSString *appPath = getAppSandboxPath(app);
if (appPath) {
cleanBundleContainer(appPath);
clearAppStringInfo(appPath);
}
}
BOOL screenIsLocked(void) {
Class sbUIControllerClass = objc_getClass("SBUIController");
id sbUIController = [sbUIControllerClass performSelector:@selector(sharedInstance)];
// 检查设备是否在锁屏状态
if ([sbUIController respondsToSelector:@selector(isOnLockScreen)]) {
BOOL isLocked = [sbUIController performSelector:@selector(isOnLockScreen)];
return isLocked;
}
return YES;
}
void XSClearAll(NSString *appId) {
XSCleanSafari();
XSCleanKeychain();
XSCleanPastboard();
XSClearAppData(appId);
}
double getCPUTemperature(void) {
double temperature = 0.0;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMC"));
if (platformExpert) {
CFMutableDictionaryRef propertyDict = NULL;
kern_return_t result = IORegistryEntryCreateCFProperties(platformExpert, &propertyDict, kCFAllocatorDefault, 0);
if (result == kIOReturnSuccess) {
CFDataRef data = CFDictionaryGetValue(propertyDict, CFSTR("TC0P"));
if (data) {
const UInt8 *bytes = CFDataGetBytePtr(data);
temperature = (double)bytes[0];
}
CFRelease(propertyDict);
}
IOObjectRelease(platformExpert);
}
return temperature;
}
// 注入网络权限
void injectNetworkPermissions(void) {
// 创建授权选项
SecTaskRef task = SecTaskCreateFromSelf(NULL);
if (!task) return;
CFErrorRef error = NULL;
CFTypeRef entitled = SecTaskCopyValueForEntitlement(task,
CFSTR("com.apple.private.network.client"),
&error);
if (!entitled) {
// 添加网络客户端权限
CFDictionaryRef entitlements = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue((CFMutableDictionaryRef)entitlements,
CFSTR("com.apple.private.network.client"),
kCFBooleanTrue);
static void *security = NULL;
static SecTaskSetEntitlementsPtr SetEntitlements = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
security = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY);
if (security) {
SetEntitlements = (SecTaskSetEntitlementsPtr)dlsym(security, "SecTaskSetEntitlements");
}
});
if (!security || !SetEntitlements) {
NSLog(@"XS- no SecTaskSetEntitlements");
return;
}
// 应用权限
SetEntitlements(task, entitlements);
CFRelease(entitlements);
}
if (entitled) CFRelease(entitled);
CFRelease(task);
}
BOOL injectEntitlementsWithOptions(NSDictionary *options, NSError **error) {
static void *security = NULL;
static SecTaskSetEntitlementsPtr SetEntitlements = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
security = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY);
if (security) {
SetEntitlements = (SecTaskSetEntitlementsPtr)dlsym(security, "SecTaskSetEntitlements");
}
});
if (!security || !SetEntitlements) {
if (error) {
*error = [NSError errorWithDomain:@"EntitlementsInjectorErrorDomain"
code:-1
userInfo:@{NSLocalizedDescriptionKey: @"无法加载必要的系统函数"}];
}
return NO;
}
SecTaskRef task = SecTaskCreateFromSelf(NULL);
if (!task) {
if (error) {
*error = [NSError errorWithDomain:@"EntitlementsInjectorErrorDomain"
code:-2
userInfo:@{NSLocalizedDescriptionKey: @"无法创建任务引用"}];
}
return NO;
}
// 转换权限字典
NSMutableDictionary *entitlements = [NSMutableDictionary dictionary];
// 基本网络权限
entitlements[@"com.apple.developer.networking.HotspotConfiguration"] = @YES;
entitlements[@"com.apple.developer.networking.networkextension"] = @YES;
entitlements[@"com.apple.developer.networking.wifi-info"] = @YES;
// 添加用户自定义权限
[entitlements addEntriesFromDictionary:options];
// 注入权限
CFErrorRef cfError = NULL;
Boolean success = SetEntitlements(task, (__bridge CFDictionaryRef)entitlements);
CFRelease(task);
if (!success) {
if (error) {
*error = (__bridge NSError *)cfError;
}
if (cfError) CFRelease(cfError);
return NO;
}
return YES;
}
// 验证权限是否注入成功
BOOL verifyEntitlement(NSString *entitlementName) {
SecTaskRef task = SecTaskCreateFromSelf(NULL);
if (!task) return NO;
CFErrorRef error = NULL;
CFTypeRef value = SecTaskCopyValueForEntitlement(task,
(__bridge CFStringRef)entitlementName,
&error);
CFRelease(task);
if (error) {
CFRelease(error);
return NO;
}
BOOL hasEntitlement = (value != NULL);
if (value) CFRelease(value);
return hasEntitlement;
}
pid_t system2(const char * command, int * infp, int * outfp)
{
int p_stdin[2];
int p_stdout[2];
pid_t pid;
if (pipe(p_stdin) == -1)
return -1;
if (pipe(p_stdout) == -1) {
close(p_stdin[0]);
close(p_stdin[1]);
return -1;
}
pid = fork();
if (pid < 0) {
close(p_stdin[0]);
close(p_stdin[1]);
close(p_stdout[0]);
close(p_stdout[1]);
return pid;
} else if (pid == 0) {
close(p_stdin[1]);
dup2(p_stdin[0], 0);
close(p_stdout[0]);
dup2(p_stdout[1], 1);
dup2(open("/dev/null", O_RDONLY), 2);
/// Close all other descriptors for the safety sake.
for (int i = 3; i < 4096; ++i)
close(i);
setsid();
execl("/bin/sh", "sh", "-c", command, NULL);
_exit(1);
}
close(p_stdin[0]);
close(p_stdout[1]);
if (infp == NULL) {
close(p_stdin[1]);
} else {
*infp = p_stdin[1];
}
if (outfp == NULL) {
close(p_stdout[0]);
} else {
*outfp = p_stdout[0];
}
if (pid > 0)
{
waitpid(pid, NULL, 0);
}
return pid;
}
void printInfo(id object) {
if (!object) {
NSLog(@"Object is nil");
return;
}
// 获取类名
NSLog(@"\nClass: %@", NSStringFromClass([object class]));
// 1. 获取所有属性
unsigned int propertyCount;
objc_property_t *properties = class_copyPropertyList([object class], &propertyCount);
NSLog(@"\n=== Properties ===");
for (unsigned int i = 0; i < propertyCount; i++) {
objc_property_t property = properties[i];
// 属性名
const char *propertyName = property_getName(property);
// 属性特性
const char *attributes = property_getAttributes(property);
NSLog(@"Property: %s, Attributes: %s", propertyName, attributes);
// 尝试获取属性值
@try {
NSString *name = [NSString stringWithUTF8String:propertyName];
id value = [object valueForKey:name];
NSLog(@"Value: %@", value);
} @catch (NSException *exception) {
NSLog(@"Cannot access value");
}
}
free(properties);
// 2. 获取所有实例方法
unsigned int methodCount;
Method *methods = class_copyMethodList([object class], &methodCount);
NSLog(@"\n=== Methods ===");
for (unsigned int i = 0; i < methodCount; i++) {
Method method = methods[i];
SEL selector = method_getName(method);
NSString *methodName = NSStringFromSelector(selector);
// 获取参数个数
int arguments = method_getNumberOfArguments(method);
struct objc_method_description *desc = method_getDescription(method);
NSLog(@"args:%s", desc->types);
// 获取返回值类型
char *returnType = method_copyReturnType(method);
NSLog(@"Method: %@, Args: %d, ReturnType: %s", methodName, arguments, returnType);
free(returnType);
}
free(methods);
// 3. 获取所有实例变量
unsigned int ivarCount;
Ivar *ivars = class_copyIvarList([object class], &ivarCount);
NSLog(@"\n=== Instance Variables ===");
for (unsigned int i = 0; i < ivarCount; i++) {
Ivar ivar = ivars[i];
const char *ivarName = ivar_getName(ivar);
const char *ivarType = ivar_getTypeEncoding(ivar);
NSLog(@"Ivar: %s, Type: %s", ivarName, ivarType);
}
free(ivars);
// 4. 获取遵循的协议
unsigned int protocolCount;
Protocol * __unsafe_unretained *protocols = class_copyProtocolList([object class], &protocolCount);
NSLog(@"\n=== Protocols ===");
for (unsigned int i = 0; i < protocolCount; i++) {
Protocol *protocol = protocols[i];
const char *protocolName = protocol_getName(protocol);
NSLog(@"Protocol: %s", protocolName);
}
free(protocols);
}
// 递归获取父类信息
void printClassHierarchy(Class cls) {
NSLog(@"\n=== Class Hierarchy ===");
while (cls) {
NSLog(@"Class: %@", NSStringFromClass(cls));
cls = class_getSuperclass(cls);
}
}
// 获取方法的详细信息
void printMethodInfo(Method method) {
SEL selector = method_getName(method);
NSString *methodName = NSStringFromSelector(selector);
// 获取参数类型
unsigned int argCount = method_getNumberOfArguments(method);
NSMutableArray *argTypes = [NSMutableArray array];
for (unsigned int i = 0; i < argCount; i++) {
char *argType = method_copyArgumentType(method, i);
if (argType) {
[argTypes addObject:[NSString stringWithUTF8String:argType]];
free(argType);
}
}
// 获取返回值类型
char *returnType = method_copyReturnType(method);
NSString *returnTypeString = returnType ? [NSString stringWithUTF8String:returnType] : @"?";
free(returnType);
NSLog(@"Method: %@\nReturn Type: %@\nArgument Types: %@",
methodName, returnTypeString, argTypes);
}
// 获取属性的详细信息
void printPropertyInfo(objc_property_t property) {
const char *name = property_getName(property);
const char *attributes = property_getAttributes(property);
unsigned int attrCount;
objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
NSMutableArray *attributeDetails = [NSMutableArray array];
for (unsigned int i = 0; i < attrCount; i++) {
NSString *attrName = @(attrs[i].name);
NSString *attrValue = attrs[i].value ? @(attrs[i].value) : @"";
[attributeDetails addObject:[NSString stringWithFormat:@"%@=%@", attrName, attrValue]];
}
free(attrs);
NSLog(@"Property: %s\nAttributes: %s\nDetailed Attributes: %@",
name, attributes, attributeDetails);
}
// 属性特性解析工具
NSDictionary* parsePropertyAttributes(const char *attributes) {
NSString *attributeString = @(attributes);
NSArray *components = [attributeString componentsSeparatedByString:@","];
NSMutableDictionary *result = [NSMutableDictionary dictionary];
for (NSString *component in components) {
if ([component hasPrefix:@"T"]) {
result[@"type"] = [component substringFromIndex:1];
} else if ([component isEqualToString:@"R"]) {
result[@"readonly"] = @YES;
} else if ([component isEqualToString:@"C"]) {
result[@"copy"] = @YES;
} else if ([component isEqualToString:@"&"]) {
result[@"strong"] = @YES;
} else if ([component isEqualToString:@"W"]) {
result[@"weak"] = @YES;
} else if ([component isEqualToString:@"N"]) {
result[@"nonatomic"] = @YES;
}
}
return result;
}
// 获取前台应用
void getFrontAppWindows(void) {
SpringBoard *springBoard = (SpringBoard *)[UIApplication sharedApplication];
UIApplication *frontApp = [springBoard _accessibilityFrontMostApplication];
printInfo(frontApp);
// 获取SBWindowManager类
Class SBWindowManagerClass = NSClassFromString(@"SBWindowManager");
id windowManager = [SBWindowManagerClass sharedInstance];
NSLog(@"SBWindowManager");
printInfo(windowManager);
UIWindow *win = [[NSClassFromString(@"SBUIController") sharedInstance] window];
printInfo(win);
// 尝试获取windows
if ([windowManager respondsToSelector:@selector(windows)]) {
NSArray *windows = [windowManager windows];
NSLog(@"windows: %@", windows);
}
}
void findButtonsInView(UIView *view) {
NSLog(@"findButtonsInView:%@",view);
// 如果是按钮
if ([view isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)view;
CGRect frameInWindow = [button convertRect:button.bounds toView:nil];
NSString *title = [button titleForState:UIControlStateNormal];
NSLog(@"Button: %@, Position: %@", title, NSStringFromCGRect(frameInWindow));
}
// 遍历子视图
for (UIView *subview in view.subviews) {
findButtonsInView(subview);
}
}
UIWindow* getKeyWindow(void) {
NSLog(@"getKeyWindow");
getFrontAppWindows();
UIWindow *keyWindow = nil;
// iOS 13及以上版本
if (@available(iOS 13.0, *)) {
NSSet *connectedScenes = [[UIApplication sharedApplication] connectedScenes];
for (UIScene *scene in connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
for (UIWindow *window in windowScene.windows) {
NSLog(@"getKeyWindow: %@", window);
findButtonsInView(window);
if (window.isKeyWindow) {
keyWindow = window;
//break;
}
}
}
}
} else {
// iOS 13以下版本
keyWindow = [[UIApplication sharedApplication] keyWindow];
}
return keyWindow;
}
void getAllButtons(void) {
dispatch_sync(dispatch_get_main_queue(),^{
// 获取当前窗口
//FBScene *scene = getForegroundAppScene();
//findButtonsInView(scene.window);
UIWindow *keyWindow = getKeyWindow();
// 递归查找按钮
findButtonsInView(keyWindow);
});
}