1491 lines
53 KiB
Objective-C
1491 lines
53 KiB
Objective-C
//
|
||
// 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);
|
||
});
|
||
}
|
||
|