├── ShadowTrackerExtra ├── icon.png ├── Target.plist ├── Scripts │ └── quick-resign.sh ├── Config │ └── MDConfig.plist └── Info.plist ├── LatestBuild ├── ShadowTrackerExtraDylib ├── BBURLProtocol.h ├── ShadowTrackerExtraDylib-Prefix.pch ├── XYPlayMusicViewController.h ├── XYMetalRenderHelper.h ├── Config │ ├── MDMethodTrace.h │ ├── MDConfigManager.h │ ├── MDCycriptManager.h │ ├── ANYMethodLog.h │ ├── MDConfigManager.m │ ├── MDMethodTrace.m │ ├── MDCycriptManager.m │ └── ANYMethodLog.m ├── Tools │ ├── LLDBTools.h │ └── LLDBTools.mm ├── ShadowTrackerExtraDylib.h ├── BSBacktraceLogger.h ├── XYPlayMusicManager.h ├── XYSliderView.h ├── XYMetalRenderHelper.m ├── ShadowTrackerExtraDylib.m ├── fishhook │ ├── fishhook.h │ └── fishhook.c ├── AntiAntiDebug │ └── AntiAntiDebug.m ├── BBURLProtocol.m ├── XYPlayMusicManager.m ├── XYPlayMusicViewController.m ├── XYSuspensionMenu.h ├── XYSliderView.m ├── BSBacktraceLogger.m └── Logos │ └── ShadowTrackerExtraDylib.xm ├── ShadowTrackerExtra.xcodeproj └── project.xcworkspace │ └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings ├── README.md └── .gitignore /ShadowTrackerExtra/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tuxi/ShadowTrackerExtra/HEAD/ShadowTrackerExtra/icon.png -------------------------------------------------------------------------------- /ShadowTrackerExtra/Target.plist: -------------------------------------------------------------------------------- 1 | /Users/swae/Documents/Github/ShadowTrackerExtra/ShadowTrackerExtra/TargetApp/PUBGM.app/Info.plist -------------------------------------------------------------------------------- /LatestBuild: -------------------------------------------------------------------------------- 1 | /Users/swae/Library/Developer/Xcode/DerivedData/ShadowTrackerExtra-byzwkahalgwvevdvwzezgjwswkhy/Build/Products/Release-iphoneos -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/BBURLProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // BBURLProtocol.h 3 | // Boobuz 4 | // 5 | // Created by xiaoyuan on 2018/4/2. 6 | // Copyright © 2018年 erlinyou.com. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BBURLProtocol : NSURLProtocol 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/ShadowTrackerExtraDylib-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ShadowTrackerExtraDylib' target in the 'ShadowTrackerExtraDylib' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import "/opt/theos/Prefix.pch" //path/to/theos/Prefix.pch 8 | #endif 9 | -------------------------------------------------------------------------------- /ShadowTrackerExtra.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ShadowTrackerExtra.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ShadowTrackerExtra 2 | ## Requirements/Notes 3 | - [MonkeyDev](https://github.com/AloneMonkey/MonkeyDev) 4 | 5 | ## Build Release & Run 6 | - ipa或者app包,从xx助手下载越狱版的全军出击,将ipa或者app包放到/Users/ShadowTrackerExtra/ShadowTrackerExtra/TargetApp目录中 7 | - 使用xcode打开ShadowTrackerExtra.xcodeproj,选择你的iOS设备,点击run或者command+r 8 | 9 | ## TODO 10 | 经测试 刺激战场会封号请勿用,全军出击暂时没有问题 11 | 全军出击1.0.15被检测封号,暂时无解。 12 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYPlayMusicViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // XYPlayMusicViewController.h 3 | // ShadowTrackerExtraDylib 4 | // 5 | // Created by swae on 2018/10/17. 6 | // Copyright © 2018 xiaoyuan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface XYPlayMusicViewController : UIViewController 14 | 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYMetalRenderHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // XYMetalRenderHelper.h 3 | // ShadowTrackerExtraDylib 4 | // 5 | // Created by xiaoyuan on 2018/5/23. 6 | // Copyright © 2018年 xiaoyuan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XYMetalRenderHelper : NSObject 12 | 13 | @property (nonatomic, assign, class) NSUInteger instanceCount; 14 | @property (nonatomic, assign, class) BOOL weedOutWeeds; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ShadowTrackerExtra/Scripts/quick-resign.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage 4 | # Must be an absolute path 5 | 6 | # ./quick-resign.sh [insert] "origin.ipa path" "resign.ipa path" 7 | 8 | INSERT_DYLIB=NO 9 | INPUT_PATH=$1 10 | OUTPUT_PATH=$2 11 | 12 | if [[ $1 == "insert" ]];then 13 | INSERT_DYLIB=YES 14 | INPUT_PATH=$2 15 | OUTPUT_PATH=$3 16 | fi 17 | 18 | if [[ ! $OUTPUT_PATH ]];then 19 | OUTPUT_PATH=$PWD 20 | fi 21 | 22 | cp -rf $INPUT_PATH ../TargetApp/ 23 | cd ../../ 24 | xcodebuild MONKEYDEV_INSERT_DYLIB=$INSERT_DYLIB | xcpretty 25 | cd LatestBuild 26 | ./createIPA.command 27 | cp -rf Target.ipa $OUTPUT_PATH 28 | exit 0 -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/MDMethodTrace.h: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // MDMethodTrace.h 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2017/9/7. 8 | // Copyright © 2017年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #ifndef MethodTrace_h 12 | #define MethodTrace_h 13 | 14 | #import 15 | 16 | @interface MDMethodTrace : NSObject 17 | 18 | + (void)addClassTrace:(NSString*) className; 19 | 20 | + (void)addClassTrace:(NSString *)className methodName:(NSString*) methodName; 21 | 22 | + (void)addClassTrace:(NSString *)className methodList:(NSArray*) methodList; 23 | 24 | @end 25 | 26 | #endif /* MethodTrace_h */ 27 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Tools/LLDBTools.h: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // LLDBTools.h 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2018/3/8. 8 | // Copyright © 2018年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #import 12 | #import 13 | 14 | //(lldb) po pviews() 15 | 16 | NSString* pvc(void); 17 | 18 | NSString* pviews(void); 19 | 20 | NSString* pactions(vm_address_t address); 21 | 22 | NSString* pblock(vm_address_t address); 23 | 24 | NSString* methods(const char * classname); 25 | 26 | NSString* ivars(vm_address_t address); 27 | 28 | NSString* choose(const char* classname); 29 | 30 | NSString* vmmap(); 31 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/ShadowTrackerExtraDylib.h: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // ShadowTrackerExtraDylib.h 5 | // ShadowTrackerExtraDylib 6 | // 7 | // Created by xiaoyuan on 2018/5/21. 8 | // Copyright (c) 2018年 xiaoyuan. All rights reserved. 9 | // 10 | 11 | #import 12 | 13 | #define INSERT_SUCCESS_WELCOME @"\n 🎉!!!congratulations!!!🎉\n👍----------------insert dylib success----------------👍" 14 | 15 | @interface CustomViewController 16 | 17 | @property (nonatomic, copy) NSString* newProperty; 18 | 19 | + (void)classMethod; 20 | 21 | - (NSString*)getMyName; 22 | 23 | - (void)newMethod:(NSString*) output; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/BSBacktraceLogger.h: -------------------------------------------------------------------------------- 1 | // 2 | // BSBacktraceLogger.h 3 | // BSBacktraceLogger 4 | // 5 | // Created by 张星宇 on 16/8/27. 6 | // Copyright © 2016年 bestswifter. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define BSLOG NSLog(@"%@",[BSBacktraceLogger bs_backtraceOfCurrentThread]); 12 | #define BSLOG_MAIN NSLog(@"%@",[BSBacktraceLogger bs_backtraceOfMainThread]); 13 | #define BSLOG_ALL NSLog(@"%@",[BSBacktraceLogger bs_backtraceOfAllThread]); 14 | 15 | @interface BSBacktraceLogger : NSObject 16 | 17 | + (NSString *)bs_backtraceOfAllThread; 18 | + (NSString *)bs_backtraceOfCurrentThread; 19 | + (NSString *)bs_backtraceOfMainThread; 20 | + (NSString *)bs_backtraceOfNSThread:(NSThread *)thread; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/MDConfigManager.h: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // MDConfigManager.h 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2018/4/24. 8 | // Copyright © 2018年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #import 12 | 13 | #define MDCONFIG_CYCRIPT_KEY @"Cycript" 14 | #define MDCONFIG_TRACE_KEY @"MethodTrace" 15 | #define MDCONFIG_ENABLE_KEY @"ENABLE" 16 | #define MDCONFIG_CLASS_LIST @"CLASS_LIST" 17 | #define MDCONFIG_LOADATLAUNCH_KEY @"LoadAtLaunch" 18 | 19 | @interface MDConfigManager : NSObject 20 | 21 | + (instancetype)sharedInstance; 22 | 23 | - (NSDictionary*)readConfigByKey:(NSString*) key; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYPlayMusicManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // XYPlayMusicManager.h 3 | // ShadowTrackerExtraDylib 4 | // 5 | // Created by swae on 2018/10/17. 6 | // Copyright © 2018 xiaoyuan. All rights reserved. 7 | // 8 | 9 | #import 10 | @import AVFoundation; 11 | @import MediaPlayer; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface XYPlayMusicManager : NSObject 16 | @property (strong, nonatomic, nullable) AVAudioPlayer *audioPlayer; 17 | @property (nonatomic, strong, class) XYPlayMusicManager *manager; 18 | @property (nonatomic, strong, nullable) NSNumber *volumeNum; 19 | - (void)play; 20 | - (void)pause; 21 | /// 顺序播放多首歌曲,从trackNumber开始播放到最后一首歌 22 | - (void)playWithItems:(NSArray *)items trackNumber:(NSInteger)trackNumber; 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/MDCycriptManager.h: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // MDCycriptManager.h 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2018/3/8. 8 | // Copyright © 2018年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #ifndef __OPTIMIZE__ 12 | 13 | #import 14 | 15 | #define PORT 6666 16 | 17 | @interface MDCycriptManager : NSObject 18 | 19 | + (instancetype)sharedInstance; 20 | 21 | 22 | /** 23 | Download script by config.plist 24 | 25 | @param update Force update of all scripts 26 | */ 27 | -(void)loadCycript:(BOOL) update; 28 | 29 | /** 30 | eval javascript by cycript 31 | 32 | @param cycript javascript string 33 | @param error error happened 34 | @return eval result 35 | */ 36 | -(NSString*)evaluateCycript:(NSString*) cycript error:(NSError **) error; 37 | 38 | @end 39 | 40 | #endif -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYSliderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // XYSliderView.h 3 | // SliderDemo 4 | // 5 | // Created by xiaoyuan on 2018/6/4. 6 | // Copyright © 2018年 xiaoyuan. All rights reserved. 7 | // 8 | 9 | #import "XYSuspensionMenu.h" 10 | 11 | @interface XYSliderView : SuspensionView 12 | 13 | @property(nonatomic) float value; // default 0.0. this value will be pinned to min/max 14 | @property(nonatomic) float minimumValue; // default 0.0. the current value may change if outside new min value 15 | @property(nonatomic) float maximumValue; // default 1.0. the current value may change if outside new max value 16 | @property(nonatomic,getter=isContinuous) BOOL continuous; // if set, value change events are generated any time the value changes due to dragging. default = YES 17 | 18 | @property (nonatomic, copy) void (^ valueChangeBlock)(float value); 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/ANYMethodLog.h: -------------------------------------------------------------------------------- 1 | // 2 | // ANYMethodLog.h 3 | // ANYMethodLog 4 | // 5 | // Created by qiuhaodong on 2017/1/14. 6 | // Copyright © 2017年 qiuhaodong. All rights reserved. 7 | // 8 | // https://github.com/qhd/ANYMethodLog.git 9 | // 10 | 11 | #import 12 | 13 | typedef BOOL (^ConditionBlock)(SEL sel); 14 | typedef void (^BeforeBlock)(id target, SEL sel, NSArray *args, int deep); 15 | typedef void (^AfterBlock)(id target, SEL sel, NSArray *args, NSTimeInterval interval, int deep, id retValue); 16 | 17 | @interface ANYMethodLog : NSObject 18 | 19 | /** 20 | 打印对象的方法调用 21 | 22 | @param aClass 要打印的类 23 | @param condition 根据此 block 来决定是否追踪方法(sel 是方法名) 24 | @param before 方法调用前会调用该 block(target 是检测的对象,sel 是方法名,args 是参数列表) 25 | @param after 方法调用后会调用该 block(interval 是执行方法的耗时) 26 | */ 27 | + (void)logMethodWithClass:(Class)aClass 28 | condition:(ConditionBlock) condition 29 | before:(BeforeBlock) before 30 | after:(AfterBlock) after; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYMetalRenderHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // XYMetalRenderHelper.m 3 | // ShadowTrackerExtraDylib 4 | // 5 | // Created by xiaoyuan on 2018/5/23. 6 | // Copyright © 2018年 xiaoyuan. All rights reserved. 7 | // 8 | /** 9 | AGXA11FamilyRenderContext 10 | */ 11 | #import "XYMetalRenderHelper.h" 12 | 13 | @implementation XYMetalRenderHelper 14 | 15 | static BOOL _weedOutWeeds = NO; 16 | 17 | + (void)setInstanceCount:(NSUInteger)instanceCount { 18 | [[NSUserDefaults standardUserDefaults] setInteger:instanceCount forKey:NSStringFromSelector(@selector(instanceCount))]; 19 | [[NSUserDefaults standardUserDefaults] synchronize]; 20 | } 21 | 22 | + (NSUInteger)instanceCount { 23 | NSNumber *n = [[NSUserDefaults standardUserDefaults] objectForKey:NSStringFromSelector(@selector(instanceCount))]; 24 | if (n == nil) { 25 | return 1; 26 | } 27 | return n.integerValue; 28 | } 29 | 30 | + (BOOL)weedOutWeeds { 31 | return _weedOutWeeds; 32 | } 33 | 34 | + (void)setWeedOutWeeds:(BOOL)weedOutWeeds { 35 | _weedOutWeeds = weedOutWeeds; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/MDConfigManager.m: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // MDConfigManager.m 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2018/4/24. 8 | // Copyright © 2018年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #define CONFIG_FILE_NAME @"MDConfig" 12 | 13 | #import "MDConfigManager.h" 14 | 15 | @implementation MDConfigManager{ 16 | NSString* _filepath; 17 | } 18 | 19 | + (instancetype)sharedInstance{ 20 | static MDConfigManager *sharedInstance = nil; 21 | if (!sharedInstance){ 22 | sharedInstance = [[MDConfigManager alloc] init]; 23 | } 24 | return sharedInstance; 25 | } 26 | 27 | - (BOOL)isActive{ 28 | _filepath = [[NSBundle mainBundle] pathForResource:CONFIG_FILE_NAME ofType:@"plist"]; 29 | if(_filepath == nil){ 30 | return NO; 31 | } 32 | return YES; 33 | } 34 | 35 | - (NSDictionary*) readConfigByKey:(NSString*) key{ 36 | if([self isActive]){ 37 | NSDictionary* contentDict = [NSDictionary dictionaryWithContentsOfFile:_filepath]; 38 | if([contentDict.allKeys containsObject:key]){ 39 | return contentDict[key]; 40 | }else{ 41 | return nil; 42 | } 43 | }else{ 44 | return nil; 45 | } 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | *.app 12 | ShadowTrackerExtra/TargetApp 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | .build/ 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots 69 | fastlane/test_output 70 | ShadowTrackerExtra/PUBGM_Headers/ 71 | ShadowTrackerExtra/ShadowTrackerExtra_Headers -------------------------------------------------------------------------------- /ShadowTrackerExtra/Config/MDConfig.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MethodTrace 6 | 7 | ENABLE 8 | 9 | CLASS_LIST 10 | 11 | BaseMsgContentViewController 12 | 13 | CMessageMgr 14 | 15 | AsyncOnAddMsg:MsgWrap: 16 | onRevokeMsg: 17 | 18 | 19 | 20 | Cycript 21 | 22 | nslog 23 | 24 | LoadAtLaunch 25 | 26 | priority 27 | 0 28 | content 29 | NSLog = function() { var types = 'v', args = [], count = arguments.length; for (var i = 0; i != count; ++i) { types += '@'; args.push(arguments[i]); } new Functor(dlsym(RTLD_DEFAULT, "NSLog"), types).apply(null, args); } 30 | 31 | ms 32 | 33 | LoadAtLaunch 34 | 35 | priority 36 | 1 37 | url 38 | https://raw.githubusercontent.com/AloneMonkey/MDCycript/master/MS.cy 39 | 40 | hook 41 | 42 | LoadAtLaunch 43 | 44 | priority 45 | 2 46 | content 47 | try{ 48 | var oldm = {}; 49 | HookMessage(CustomViewController, @selector(showChangeLog:), function(log) { 50 | NSLog("hooked by cycript!!!"); 51 | return oldm->call(this,log); 52 | }, oldm); 53 | }catch(err){ 54 | NSLog(err.toString()) 55 | } 56 | 57 | md 58 | 59 | LoadAtLaunch 60 | 61 | priority 62 | 3 63 | url 64 | https://raw.githubusercontent.com/AloneMonkey/MDCycript/master/md.cy 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/ShadowTrackerExtraDylib.m: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // ShadowTrackerExtraDylib.m 5 | // ShadowTrackerExtraDylib 6 | // 7 | // Created by xiaoyuan on 2018/5/21. 8 | // Copyright (c) 2018年 xiaoyuan. All rights reserved. 9 | // 10 | 11 | #import "ShadowTrackerExtraDylib.h" 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import "BBURLProtocol.h" 17 | #import 18 | 19 | CHConstructor{ 20 | NSLog(INSERT_SUCCESS_WELCOME); 21 | 22 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { 23 | // [NSURLProtocol registerClass:NSClassFromString(@"BBURLProtocol")]; 24 | #ifndef __OPTIMIZE__ 25 | CYListenServer(6666); 26 | 27 | MDCycriptManager* manager = [MDCycriptManager sharedInstance]; 28 | [manager loadCycript:NO]; 29 | 30 | NSError* error; 31 | NSString* result = [manager evaluateCycript:@"UIApp" error:&error]; 32 | NSLog(@"result: %@", result); 33 | 34 | if(error.code != 0){ 35 | NSLog(@"error: %@", error.localizedDescription); 36 | } 37 | #endif 38 | 39 | }]; 40 | 41 | } 42 | 43 | CHDeclareClass(CustomViewController) 44 | 45 | #pragma clang diagnostic push 46 | #pragma clang diagnostic ignored "-Wstrict-prototypes" 47 | 48 | //add new method 49 | CHDeclareMethod1(void, CustomViewController, newMethod, NSString*, output){ 50 | NSLog(@"This is a new method : %@", output); 51 | } 52 | 53 | #pragma clang diagnostic pop 54 | 55 | CHOptimizedClassMethod0(self, void, CustomViewController, classMethod){ 56 | NSLog(@"hook class method"); 57 | CHSuper0(CustomViewController, classMethod); 58 | } 59 | 60 | CHOptimizedMethod0(self, NSString*, CustomViewController, getMyName){ 61 | //get origin value 62 | NSString* originName = CHSuper(0, CustomViewController, getMyName); 63 | 64 | NSLog(@"origin name is:%@",originName); 65 | 66 | //get property 67 | NSString* password = CHIvar(self,_password,__strong NSString*); 68 | 69 | NSLog(@"password is %@",password); 70 | 71 | [self newMethod:@"output"]; 72 | 73 | //set new property 74 | self.newProperty = @"newProperty"; 75 | 76 | NSLog(@"newProperty : %@", self.newProperty); 77 | 78 | //change the value 79 | return @"xiaoyuan"; 80 | 81 | } 82 | 83 | //add new property 84 | CHPropertyRetainNonatomic(CustomViewController, NSString*, newProperty, setNewProperty); 85 | 86 | CHConstructor{ 87 | CHLoadLateClass(CustomViewController); 88 | CHClassHook0(CustomViewController, getMyName); 89 | CHClassHook0(CustomViewController, classMethod); 90 | 91 | CHHook0(CustomViewController, newProperty); 92 | CHHook1(CustomViewController, setNewProperty); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/fishhook/fishhook.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #ifndef fishhook_h 25 | #define fishhook_h 26 | 27 | #include 28 | #include 29 | 30 | #if !defined(FISHHOOK_EXPORT) 31 | #define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) 32 | #else 33 | #define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) 34 | #endif 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif //__cplusplus 39 | 40 | /* 41 | * A structure representing a particular intended rebinding from a symbol 42 | * name to its replacement 43 | */ 44 | struct rebinding { 45 | const char *name; 46 | void *replacement; 47 | void **replaced; 48 | }; 49 | 50 | /* 51 | * For each rebinding in rebindings, rebinds references to external, indirect 52 | * symbols with the specified name to instead point at replacement for each 53 | * image in the calling process as well as for all future images that are loaded 54 | * by the process. If rebind_functions is called more than once, the symbols to 55 | * rebind are added to the existing list of rebindings, and if a given symbol 56 | * is rebound more than once, the later rebinding will take precedence. 57 | */ 58 | FISHHOOK_VISIBILITY 59 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); 60 | 61 | /* 62 | * Rebinds as above, but only in the specified image. The header should point 63 | * to the mach-o header, the slide should be the slide offset. Others as above. 64 | */ 65 | FISHHOOK_VISIBILITY 66 | int rebind_symbols_image(void *header, 67 | intptr_t slide, 68 | struct rebinding rebindings[], 69 | size_t rebindings_nel); 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif //__cplusplus 74 | 75 | #endif //fishhook_h 76 | 77 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/MDMethodTrace.m: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // MDMethodTrace.m 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2017/9/6. 8 | // Copyright © 2017年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #import "ANYMethodLog.h" 12 | #import "MDMethodTrace.h" 13 | #import 14 | #import 15 | #import "MDConfigManager.h" 16 | 17 | #define MDLog(fmt, ...) NSLog((@"[MethodTrace] " fmt), ##__VA_ARGS__) 18 | 19 | @implementation MDMethodTrace : NSObject 20 | 21 | +(void)addClassTrace:(NSString *)className{ 22 | [self addClassTrace:className methodList:nil]; 23 | } 24 | 25 | +(void)addClassTrace:(NSString *)className methodName:(NSString *)methodName{ 26 | [self addClassTrace:className methodList:@[methodName]]; 27 | } 28 | 29 | +(void)addClassTrace:(NSString *)className methodList:(NSArray *)methodList{ 30 | Class targetClass = objc_getClass([className UTF8String]); 31 | if(targetClass != nil){ 32 | [ANYMethodLog logMethodWithClass:NSClassFromString(className) condition:^BOOL(SEL sel) { 33 | return (methodList == nil || methodList.count == 0) ? YES : [methodList containsObject:NSStringFromSelector(sel)]; 34 | } before:^(id target, SEL sel, NSArray *args, int deep) { 35 | NSString *selector = NSStringFromSelector(sel); 36 | NSMutableString *selectorString = [NSMutableString new]; 37 | if([selector containsString:@":"]){ 38 | NSArray *selectorArrary = [selector componentsSeparatedByString:@":"]; 39 | selectorArrary = [selectorArrary filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"length > 0"]]; 40 | for (int i = 0; i < selectorArrary.count; i++) { 41 | [selectorString appendFormat:@"%@:%@ ", selectorArrary[i], args[i]]; 42 | } 43 | }else{ 44 | [selectorString appendString:selector]; 45 | } 46 | 47 | NSMutableString *deepString = [NSMutableString new]; 48 | for (int i = 0; i < deep; i++) { 49 | [deepString appendString:@"-"]; 50 | } 51 | NSLog(@"%@[%@ %@]", deepString , target, selectorString); 52 | } after:^(id target, SEL sel, NSArray *args, NSTimeInterval interval,int deep, id retValue) { 53 | NSMutableString *deepString = [NSMutableString new]; 54 | for (int i = 0; i < deep; i++) { 55 | [deepString appendString:@"-"]; 56 | } 57 | NSLog(@"%@ret:%@", deepString, retValue); 58 | }]; 59 | }else{ 60 | MDLog(@"canot find class %@", className); 61 | } 62 | } 63 | 64 | @end 65 | 66 | static __attribute__((constructor)) void entry(){ 67 | MDConfigManager * configManager = [MDConfigManager sharedInstance]; 68 | NSDictionary* content = [configManager readConfigByKey:MDCONFIG_TRACE_KEY]; 69 | 70 | if(content && [content valueForKey:MDCONFIG_ENABLE_KEY] && [content[MDCONFIG_ENABLE_KEY] boolValue]){ 71 | NSDictionary* classListDictionary = [content valueForKey:MDCONFIG_CLASS_LIST]; 72 | if(classListDictionary && classListDictionary.count > 0){ 73 | for (NSString* className in classListDictionary.allKeys) { 74 | Class targetClass = objc_getClass([className UTF8String]); 75 | if(targetClass != nil){ 76 | id methodList = [classListDictionary valueForKey:className]; 77 | if([methodList isKindOfClass:[NSArray class]]){ 78 | [MDMethodTrace addClassTrace:className methodList:methodList]; 79 | }else{ 80 | [MDMethodTrace addClassTrace:className]; 81 | } 82 | }else{ 83 | MDLog(@"Canot find class %@", className); 84 | } 85 | } 86 | } 87 | }else{ 88 | MDLog(@"Method Trace is disabled"); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/AntiAntiDebug/AntiAntiDebug.m: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // AntiAntiDebug.m 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2016/12/10. 8 | // Copyright © 2017年 MonkeyDev. All rights reserved. 9 | // 10 | 11 | #if TARGET_OS_SIMULATOR 12 | #error Do not support the simulator, please use the real iPhone Device. 13 | #endif 14 | 15 | #import "fishhook.h" 16 | #import 17 | #import 18 | 19 | typedef int (*ptrace_ptr_t)(int _request,pid_t _pid, caddr_t _addr,int _data); 20 | typedef void* (*dlsym_ptr_t)(void * __handle, const char* __symbol); 21 | typedef int (*syscall_ptr_t)(int, ...); 22 | typedef int (*sysctl_ptr_t)(int *,u_int, void*, size_t*,void*, size_t); 23 | 24 | 25 | static ptrace_ptr_t orig_ptrace = NULL; 26 | static dlsym_ptr_t orig_dlsym = NULL; 27 | static sysctl_ptr_t orig_sysctl = NULL; 28 | static syscall_ptr_t orig_syscall = NULL; 29 | 30 | int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data); 31 | void* my_dlsym(void* __handle, const char* __symbol); 32 | int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize); 33 | int my_syscall(int code, va_list args); 34 | 35 | int my_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data){ 36 | if(_request != 31){ 37 | return orig_ptrace(_request,_pid,_addr,_data); 38 | } 39 | 40 | NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH"); 41 | 42 | return 0; 43 | } 44 | 45 | void* my_dlsym(void* __handle, const char* __symbol){ 46 | if(strcmp(__symbol, "ptrace") != 0){ 47 | return orig_dlsym(__handle, __symbol); 48 | } 49 | 50 | NSLog(@"[AntiAntiDebug] - dlsym get ptrace symbol"); 51 | 52 | return my_ptrace; 53 | } 54 | 55 | typedef struct kinfo_proc _kinfo_proc; 56 | 57 | int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){ 58 | if(namelen == 4 && name[0] == CTL_KERN && name[1] == KERN_PROC && name[2] == KERN_PROC_PID && info && infosize && ((int)*infosize == sizeof(_kinfo_proc))){ 59 | int ret = orig_sysctl(name, namelen, info, infosize, newinfo, newinfosize); 60 | struct kinfo_proc *info_ptr = (struct kinfo_proc *)info; 61 | if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){ 62 | NSLog(@"[AntiAntiDebug] - sysctl query trace status."); 63 | info_ptr->kp_proc.p_flag ^= P_TRACED; 64 | if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){ 65 | NSLog(@"trace status reomve success!"); 66 | } 67 | } 68 | return ret; 69 | } 70 | return orig_sysctl(name, namelen, info, infosize, newinfo, newinfosize); 71 | } 72 | 73 | int my_syscall(int code, va_list args){ 74 | int request; 75 | va_list newArgs; 76 | va_copy(newArgs, args); 77 | if(code == 26){ 78 | #ifdef __LP64__ 79 | __asm__( 80 | "ldr %w[result], [fp, #0x10]\n" 81 | : [result] "=r" (request) 82 | : 83 | : 84 | ); 85 | #else 86 | request = va_arg(args, int); 87 | #endif 88 | if(request == 31){ 89 | NSLog(@"[AntiAntiDebug] - syscall call ptrace, and request is PT_DENY_ATTACH"); 90 | return 0; 91 | } 92 | } 93 | return orig_syscall(code, newArgs); 94 | } 95 | 96 | __attribute__((constructor)) static void entry(){ 97 | NSLog(@"[AntiAntiDebug Init]"); 98 | 99 | rebind_symbols((struct rebinding[1]){{"ptrace", my_ptrace, (void*)&orig_ptrace}},1); 100 | 101 | rebind_symbols((struct rebinding[1]){{"dlsym", my_dlsym, (void*)&orig_dlsym}},1); 102 | 103 | //some app will crash with _dyld_debugger_notification 104 | // rebind_symbols((struct rebinding[1]){{"sysctl", my_sysctl, (void*)&orig_sysctl}},1); 105 | 106 | rebind_symbols((struct rebinding[1]){{"syscall", my_syscall, (void*)&orig_syscall}},1); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/BBURLProtocol.m: -------------------------------------------------------------------------------- 1 | // 2 | // BBURLProtocol.m 3 | // Boobuz 4 | // 5 | // Created by xiaoyuan on 2018/4/2. 6 | // Copyright © 2018年 erlinyou.com. All rights reserved. 7 | // 8 | 9 | #import "BBURLProtocol.h" 10 | #import 11 | 12 | #ifdef SD_WEBP 13 | #import "UIImage+WebP.h" 14 | #endif 15 | 16 | static NSString* const BBProtocolKey = @"BBURLProtocol"; 17 | 18 | 19 | @interface BBURLProtocol () 20 | @property (strong, nonatomic) NSURLConnection *connection; 21 | @property (strong, nonatomic) NSMutableData *recData; 22 | @end 23 | 24 | @implementation BBURLProtocol 25 | -(void)dealloc 26 | { 27 | self.recData = nil; 28 | 29 | } 30 | 31 | + (BOOL)canInitWithRequest:(NSURLRequest *)request { 32 | 33 | if ([request.URL.scheme isEqualToString:@"http"] || [request.URL.scheme isEqualToString:@"https"]) { 34 | if ([NSURLProtocol propertyForKey:BBProtocolKey inRequest:request] == nil) { 35 | return YES; 36 | } 37 | } 38 | return NO; 39 | } 40 | 41 | + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 42 | NSMutableURLRequest *mutableReqeust = [request mutableCopy]; 43 | //这边可用干你想干的事情。。更改地址,提取里面的请求内容,或者设置里面的请求头。。 44 | return mutableReqeust; 45 | } 46 | 47 | - (void)stopLoading 48 | { 49 | 50 | if (self.connection) { 51 | [self.connection cancel]; 52 | } 53 | self.connection = nil; 54 | } 55 | 56 | - (void)startLoading { 57 | NSMutableURLRequest *newRequest = [self cloneRequest:self.request]; 58 | NSString *urlString = newRequest.URL.absoluteString; 59 | [NSURLProtocol setProperty:@YES forKey:BBProtocolKey inRequest:newRequest]; 60 | 61 | [self sendRequest:newRequest]; 62 | } 63 | 64 | 65 | //复制Request对象 66 | - (NSMutableURLRequest *)cloneRequest:(NSURLRequest *)request 67 | { 68 | NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:request.URL cachePolicy:request.cachePolicy timeoutInterval:request.timeoutInterval]; 69 | 70 | newRequest.allHTTPHeaderFields = request.allHTTPHeaderFields; 71 | 72 | if (request.HTTPMethod) { 73 | newRequest.HTTPMethod = request.HTTPMethod; 74 | } 75 | 76 | if (request.HTTPBodyStream) { 77 | newRequest.HTTPBodyStream = request.HTTPBodyStream; 78 | } 79 | 80 | if (request.HTTPBody) { 81 | newRequest.HTTPBody = request.HTTPBody; 82 | } 83 | 84 | newRequest.HTTPShouldUsePipelining = request.HTTPShouldUsePipelining; 85 | newRequest.mainDocumentURL = request.mainDocumentURL; 86 | newRequest.networkServiceType = request.networkServiceType; 87 | 88 | return newRequest; 89 | } 90 | 91 | 92 | 93 | //////////////////////////////////////////////////////////////////////// 94 | #pragma mark - 网络请求 95 | //////////////////////////////////////////////////////////////////////// 96 | 97 | - (void)sendRequest:(NSURLRequest *)request { 98 | self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 99 | } 100 | 101 | #pragma mark - 102 | #pragma mark - NSURLConnectionDataDelegate 103 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 104 | { 105 | /** 106 | * 收到服务器响应 107 | */ 108 | self.recData = [NSMutableData new]; 109 | NSURLResponse *returnResponse = response; 110 | [self.client URLProtocol:self didReceiveResponse:returnResponse cacheStoragePolicy:NSURLCacheStorageAllowed]; 111 | } 112 | 113 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 114 | { 115 | /** 116 | * 接收数据 117 | */ 118 | // if (!self.recData) { 119 | // self.recData = [NSMutableData new]; 120 | // } 121 | if (data) { 122 | [self.recData appendData:data]; 123 | } 124 | [self.client URLProtocol:self didLoadData:data]; 125 | } 126 | 127 | - (nullable NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response 128 | { 129 | // 请求重定向 130 | if (response) { 131 | [self.client URLProtocol:self wasRedirectedToRequest:request redirectResponse:response]; 132 | } 133 | return request; 134 | } 135 | 136 | 137 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection 138 | { 139 | // 加载完毕 140 | NSData *data = self.recData; 141 | NSError *error = nil; 142 | @try { 143 | id response = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; 144 | NSLog(@"%@", response); 145 | } 146 | @catch (NSException *exp) { 147 | NSLog(@"%@\n%@", exp.reason, exp.callStackSymbols); 148 | } 149 | [self.client URLProtocol:self didLoadData:data]; 150 | [self.client URLProtocolDidFinishLoading:self]; 151 | 152 | } 153 | 154 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 155 | { 156 | // 加载失败 157 | [self.client URLProtocol:self didFailWithError:error]; 158 | } 159 | 160 | @end 161 | 162 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYPlayMusicManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // XYPlayMusicManager.m 3 | // ShadowTrackerExtraDylib 4 | // 5 | // Created by swae on 2018/10/17. 6 | // Copyright © 2018 xiaoyuan. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "XYPlayMusicManager.h" 11 | 12 | @interface XYPlayMusicManager () 13 | 14 | @property (nonatomic, assign) BOOL isUserPause; 15 | /// 当前播放的歌曲序号, 只适应AVAudioPlayer的本地歌曲 16 | @property (nonatomic, assign) NSInteger currentTrackNumber; 17 | @property (nonatomic, strong) NSArray *localItems; 18 | 19 | @end 20 | 21 | @implementation XYPlayMusicManager 22 | 23 | @dynamic manager; 24 | @synthesize volumeNum = _volumeNum; 25 | 26 | + (XYPlayMusicManager *)manager { 27 | static XYPlayMusicManager *instance = nil; 28 | static dispatch_once_t onceToken; 29 | dispatch_once(&onceToken, ^{ 30 | instance = [XYPlayMusicManager new]; 31 | }); 32 | return instance; 33 | } 34 | 35 | - (instancetype)init 36 | { 37 | self = [super init]; 38 | if (self) { 39 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { 40 | if (self.isUserPause == NO) { 41 | [self.audioPlayer play]; 42 | } 43 | }]; 44 | 45 | [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { 46 | if (self.audioPlayer.isPlaying == YES) { 47 | self.isUserPause = NO; 48 | } 49 | [self.audioPlayer pause]; 50 | }]; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)play { 56 | self.isUserPause = NO; 57 | if (!_audioPlayer.isPlaying) { 58 | // // AVAudioSessionCategoryAmbient 不会中止其他app的后台播放音频 59 | // NSLog(@"Current Category:%@", [AVAudioSession sharedInstance].category); 60 | // NSError *error = nil; 61 | // [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]; 62 | // if (nil != error) { 63 | // NSLog(@"set Category error %@", error.localizedDescription); 64 | // } 65 | // NSLog(@"Current Category:%@", [AVAudioSession sharedInstance].category); 66 | // AVAudioSessionCategoryOptions options = [[AVAudioSession sharedInstance] categoryOptions]; 67 | // NSLog(@"Category[%@] has %lu options", [AVAudioSession sharedInstance].category, options); 68 | // // 减弱后台播放音频的声音AVAudioSessionCategoryOptionDuckOthers 69 | // // 和当前app的音频混音 AVAudioSessionCategoryOptionMixWithOthers 70 | // [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error]; 71 | // if (nil != error) { 72 | // NSLog(@"set Option error %@", error.localizedDescription); 73 | // } 74 | // options = [[AVAudioSession sharedInstance] categoryOptions]; 75 | // NSLog(@"Category[%@] has %lu options", [AVAudioSession sharedInstance].category, options); 76 | 77 | if (nil != _audioPlayer ) { 78 | _audioPlayer.delegate = self; 79 | _audioPlayer.enableRate = YES; 80 | _audioPlayer.meteringEnabled = YES; 81 | [_audioPlayer play]; 82 | } 83 | else { 84 | [[[UIAlertView alloc] initWithTitle:@"无效音乐" message:nil delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil, nil] show]; 85 | } 86 | } 87 | 88 | } 89 | /// 顺序播放多首歌曲,从trackNumber开始播放到最后一首歌 90 | - (void)playWithItems:(NSArray *)items trackNumber:(NSInteger)trackNumber { 91 | trackNumber = MIN(items.count - 1, MAX(0, trackNumber)); 92 | self.localItems = items; 93 | self.currentTrackNumber = trackNumber; 94 | [self.audioPlayer stop]; 95 | self.audioPlayer = nil; 96 | NSURL *musicURL = nil; 97 | MPMediaItem *musicItem = items[self.currentTrackNumber]; 98 | musicURL = [musicItem valueForKey:MPMediaItemPropertyAssetURL]; 99 | if (musicURL) { 100 | NSError *error = nil; 101 | self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:&error]; 102 | [self.audioPlayer play]; 103 | self.audioPlayer.delegate = self; 104 | self.audioPlayer.enableRate = YES; 105 | self.audioPlayer.meteringEnabled = YES; 106 | self.audioPlayer.volume = self.volumeNum.doubleValue; 107 | } 108 | else { 109 | [self playNextMusic]; 110 | } 111 | } 112 | 113 | /// 播放下一曲本地歌曲,如果本地歌曲的MPMediaItemPropertyAssetURL==nil,则播放下一曲 114 | - (void)playNextMusic { 115 | while (self.currentTrackNumber < [self.localItems count] - 1) { 116 | self.currentTrackNumber ++; 117 | if (_audioPlayer) { 118 | [_audioPlayer stop]; 119 | _audioPlayer = nil; 120 | } 121 | MPMediaItem *musicItem = self.localItems[self.currentTrackNumber]; 122 | NSURL *musicURL = [musicItem valueForKey:MPMediaItemPropertyAssetURL]; 123 | /// 如果歌曲是通过mac的itunes同步到iOS设备的,则MPMediaItemPropertyAssetURL有值 124 | /// 如果歌曲是通过apple music下载的,则MPMediaItemPropertyAssetURL为nil 125 | if (musicURL) { 126 | self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:NULL]; 127 | self.audioPlayer.enableRate = YES; 128 | self.audioPlayer.meteringEnabled = YES; 129 | self.audioPlayer.delegate = self; 130 | self.audioPlayer.volume = self.volumeNum.doubleValue; 131 | [self.audioPlayer play]; 132 | break; 133 | } 134 | } 135 | } 136 | 137 | 138 | - (void)pause { 139 | self.isUserPause = YES; 140 | if (nil != _audioPlayer ) { 141 | [_audioPlayer stop]; 142 | } 143 | } 144 | 145 | #pragma mark AVAudioPlayerDelegate 146 | - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { 147 | if (flag) { 148 | [self playNextMusic]; 149 | } 150 | } 151 | 152 | /* if an error occurs while decoding it will be reported to the delegate. */ 153 | - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error { 154 | [self playNextMusic]; 155 | } 156 | 157 | //////////////////////////////////////////////////////////////////////// 158 | #pragma mark - 159 | //////////////////////////////////////////////////////////////////////// 160 | 161 | - (NSNumber *)volumeNum { 162 | if (_volumeNum) { 163 | return _volumeNum; 164 | } 165 | NSNumber *volumeNum = [[NSUserDefaults standardUserDefaults] objectForKey:@"XYAudioVolumeNumKey"]; 166 | if (volumeNum == nil) { 167 | volumeNum = @(0.3); 168 | } 169 | _volumeNum = volumeNum; 170 | return volumeNum; 171 | } 172 | 173 | - (void)setVolumeNum:(NSNumber *)volumeNum { 174 | _volumeNum = volumeNum; 175 | [[NSUserDefaults standardUserDefaults] setObject:volumeNum forKey:@"XYAudioVolumeNumKey"]; 176 | self.audioPlayer.volume = volumeNum.doubleValue; 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYPlayMusicViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // XYPlayMusicViewController.m 3 | // ShadowTrackerExtraDylib 4 | // 5 | // Created by swae on 2018/10/17. 6 | // Copyright © 2018 xiaoyuan. All rights reserved. 7 | // 8 | 9 | #import "XYPlayMusicViewController.h" 10 | #import "XYPlayMusicManager.h" 11 | @import MediaPlayer; 12 | 13 | @interface XYPlayMusicViewController () 14 | 15 | @property (strong, nonatomic) MPMediaPickerController *mpPickerVC; 16 | @property (strong, nonatomic) UISlider * slider; 17 | 18 | @end 19 | 20 | @implementation XYPlayMusicViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | // Do any additional setup after loading the view. 25 | self.view.backgroundColor = [UIColor blackColor]; 26 | self.tabBarItem.title = @"Player"; 27 | _mpPickerVC = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic]; 28 | _mpPickerVC.allowsPickingMultipleItems = NO; 29 | _mpPickerVC.delegate = self; 30 | 31 | UIButton *playBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 32 | [self.view addSubview:playBtn]; 33 | playBtn.translatesAutoresizingMaskIntoConstraints = NO; 34 | [playBtn setTitle:@"播放" forState:UIControlStateNormal]; 35 | [playBtn setTitle:@"暂停" forState:UIControlStateSelected]; 36 | [playBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 37 | [playBtn addTarget:self action:@selector(onPlay:) forControlEvents:UIControlEventTouchUpInside]; 38 | [NSLayoutConstraint constraintWithItem:playBtn attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:-10.0].active = YES; 39 | [NSLayoutConstraint constraintWithItem:playBtn attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0].active = YES; 40 | playBtn.selected = [XYPlayMusicManager manager].audioPlayer.isPlaying; 41 | 42 | UIButton *selectMusicBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 43 | [self.view addSubview:selectMusicBtn]; 44 | selectMusicBtn.translatesAutoresizingMaskIntoConstraints = NO; 45 | selectMusicBtn.backgroundColor = [UIColor redColor]; 46 | [selectMusicBtn setTitle:@"选择音乐" forState:UIControlStateNormal]; 47 | [selectMusicBtn addTarget:self action:@selector(onPickMusic:) forControlEvents:UIControlEventTouchUpInside]; 48 | [NSLayoutConstraint constraintWithItem:selectMusicBtn attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0].active = YES; 49 | [NSLayoutConstraint constraintWithItem:selectMusicBtn attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:10.0].active = YES; 50 | 51 | UIButton *closeBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 52 | [self.view addSubview:closeBtn]; 53 | closeBtn.translatesAutoresizingMaskIntoConstraints = NO; 54 | closeBtn.backgroundColor = [UIColor redColor]; 55 | [closeBtn setTitle:@"关闭" forState:UIControlStateNormal]; 56 | [closeBtn addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside]; 57 | if (@available(iOS 11.0, *)) { 58 | [NSLayoutConstraint constraintWithItem:closeBtn attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view.safeAreaLayoutGuide attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0].active = YES; 59 | [NSLayoutConstraint constraintWithItem:closeBtn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view.safeAreaLayoutGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0].active = YES; 60 | } else { 61 | [NSLayoutConstraint constraintWithItem:closeBtn attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0].active = YES; 62 | [NSLayoutConstraint constraintWithItem:closeBtn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0].active = YES; 63 | } 64 | 65 | UISlider * slider = [[UISlider alloc]initWithFrame:CGRectMake(10 , 100, 300, 50)]; 66 | _slider = slider; 67 | slider.minimumValue = 0.0; 68 | slider.maximumValue = 1.0; 69 | slider.value = [XYPlayMusicManager manager].volumeNum.doubleValue; 70 | [self.view addSubview:slider]; 71 | [slider setContinuous:YES]; 72 | slider.minimumTrackTintColor = [UIColor redColor]; 73 | slider.maximumTrackTintColor = [UIColor blueColor]; 74 | slider.thumbTintColor = [UIColor yellowColor]; 75 | [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; 76 | slider.translatesAutoresizingMaskIntoConstraints = NO; 77 | [NSLayoutConstraint constraintWithItem:slider attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:50.0].active = YES; 78 | [NSLayoutConstraint constraintWithItem:slider attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:10.0].active = YES; 79 | [NSLayoutConstraint constraintWithItem:slider attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:0.5 constant:1.0].active = YES; 80 | 81 | } 82 | 83 | - (void)sliderValueChanged:(UISlider *)slider { 84 | [XYPlayMusicManager manager].volumeNum = @(MIN(1.0, slider.value)); 85 | } 86 | 87 | - (void)close { 88 | [self dismissViewControllerAnimated:YES completion:nil]; 89 | } 90 | 91 | - (void)onPickMusic:(id)sender { 92 | NSLog(@"onPickMusic"); 93 | [self presentViewController: _mpPickerVC animated:YES completion:^{ 94 | NSLog(@"Show Music Picker!"); 95 | }]; 96 | } 97 | 98 | - (void)onPlay:(UIButton *)sender { 99 | NSLog(@"onPlay"); 100 | sender.selected = !sender.isSelected; 101 | [XYPlayMusicManager manager].audioPlayer.volume = MIN(1.0, _slider.value); 102 | if (sender.isSelected) { 103 | [[XYPlayMusicManager manager] play]; 104 | 105 | } else { 106 | [[XYPlayMusicManager manager] pause]; 107 | } 108 | } 109 | 110 | #pragma mark MPMediaPickerControllerDelegate 111 | - (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection { 112 | // NSString *title; 113 | // NSString *artist; 114 | // NSURL *furl = nil; 115 | 116 | NSArray *selectItems = [mediaItemCollection items]; 117 | // for (MPMediaItem * item in selectItems) { 118 | // furl = [item valueForKey:MPMediaItemPropertyAssetURL]; 119 | // if (furl) { 120 | // title = [item valueForKey:MPMediaItemPropertyTitle]; 121 | // artist = [item valueForKey:MPMediaItemPropertyArtist]; 122 | // } 123 | // } 124 | 125 | //获取本地音乐库文件 包含showsCloudItems 126 | MPMediaQuery *mediaQueue = [MPMediaQuery songsQuery]; 127 | NSArray *allItems = [mediaQueue items]; 128 | NSInteger index = [allItems indexOfObject:selectItems.firstObject]; 129 | [[XYPlayMusicManager manager] playWithItems:allItems trackNumber:index]; 130 | [mediaPicker dismissViewControllerAnimated:YES completion:^{ 131 | NSLog(@"Successful pick and return "); 132 | }]; 133 | } 134 | 135 | - (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker { 136 | 137 | [mediaPicker dismissViewControllerAnimated:YES completion:^{ 138 | NSLog(@"User cancel pick and return "); 139 | }]; 140 | } 141 | 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /ShadowTrackerExtra/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildMachineOSBuild 6 | 17D2047 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleDisplayName 10 | 绝地求生 全军出击 11 | CFBundleExecutable 12 | PUBGM 13 | CFBundleIconFiles 14 | 15 | ShadowTrackerExtra/icon.png 16 | 17 | CFBundleIcons 18 | 19 | CFBundlePrimaryIcon 20 | 21 | CFBundleIconFiles 22 | 23 | AppIcon20x20 24 | AppIcon29x29 25 | AppIcon40x40 26 | AppIcon60x60 27 | 28 | CFBundleIconName 29 | AppIcon 30 | 31 | 32 | CFBundleIcons~ipad 33 | 34 | CFBundlePrimaryIcon 35 | 36 | CFBundleIconFiles 37 | 38 | AppIcon20x20 39 | AppIcon29x29 40 | AppIcon40x40 41 | AppIcon60x60 42 | AppIcon76x76 43 | AppIcon83.5x83.5 44 | 45 | CFBundleIconName 46 | AppIcon 47 | 48 | 49 | CFBundleIdentifier 50 | com.tencent.tmgp.pubgm 51 | CFBundleInfoDictionaryVersion 52 | 6.0 53 | CFBundleName 54 | 绝地求生 全军出击 55 | CFBundlePackageType 56 | APPL 57 | CFBundleShortVersionString 58 | 1.0.13 59 | CFBundleSignature 60 | PUBG 61 | CFBundleSupportedPlatforms 62 | 63 | iPhoneOS 64 | 65 | CFBundleURLTypes 66 | 67 | 68 | CFBundleTypeRole 69 | Editor 70 | CFBundleURLName 71 | weixin 72 | CFBundleURLSchemes 73 | 74 | wx13051697527efc45 75 | 76 | NSMicrophoneUsageDescription 77 | 需要您的同意才能读取麦克风. 78 | NSPhotoLibraryUsageDescription 79 | 需要您的同意才能读取媒体资料库 80 | 81 | 82 | CFBundleTypeRole 83 | Editor 84 | CFBundleURLName 85 | tencentopenapi 86 | CFBundleURLSchemes 87 | 88 | tencent1106501964 89 | pubgm1106501964 90 | 91 | NSMicrophoneUsageDescription 92 | 需要您的同意才能读取麦克风. 93 | NSPhotoLibraryUsageDescription 94 | 需要您的同意才能读取媒体资料库 95 | 96 | 97 | CFBundleTypeRole 98 | Editor 99 | CFBundleURLName 100 | QQLaunch 101 | CFBundleURLSchemes 102 | 103 | tencentlaunch1106501964 104 | 105 | NSMicrophoneUsageDescription 106 | 需要您的同意才能读取麦克风. 107 | NSPhotoLibraryUsageDescription 108 | 需要您的同意才能读取媒体资料库 109 | 110 | 111 | CFBundleTypeRole 112 | Editor 113 | CFBundleURLName 114 | QQ 115 | CFBundleURLSchemes 116 | 117 | QQ41F3E14C 118 | 119 | NSMicrophoneUsageDescription 120 | 需要您的同意才能读取麦克风. 121 | NSPhotoLibraryUsageDescription 122 | 需要您的同意才能读取媒体资料库 123 | 124 | 125 | CFBundleVersion 126 | 114758 127 | CHANNEL_DENGTA 128 | 1001 129 | DTCompiler 130 | com.apple.compilers.llvm.clang.1_0 131 | DTPlatformBuild 132 | 15C107 133 | DTPlatformName 134 | iphoneos 135 | DTPlatformVersion 136 | 11.2 137 | DTSDKBuild 138 | 15C107 139 | DTSDKName 140 | iphoneos11.2 141 | DTXcode 142 | 0920 143 | DTXcodeBuild 144 | 9C40b 145 | EnableMSDKLog 146 | 147 | GCloud 148 | 149 | GameId 150 | 680224196 151 | GameKey 152 | e9df2a54434ebaf3a34f8d5a8f78fccf 153 | NSMicrophoneUsageDescription 154 | 需要您的同意才能读取麦克风. 155 | NSPhotoLibraryUsageDescription 156 | 需要您的同意才能读取媒体资料库 157 | 158 | ITSAppUsesNonExemptEncryption 159 | 160 | LSApplicationQueriesSchemes 161 | 162 | mqq 163 | mqqapi 164 | wtloginmqq2 165 | mqqopensdkapiV4 166 | mqqopensdkapiV3 167 | mqqopensdkapiV2 168 | mqqwpa 169 | mqqOpensdkSSoLogin 170 | mqqgamebindinggroup 171 | mqqopensdkfriend 172 | mqzone 173 | weixin 174 | wechat 175 | 176 | LSRequiresIPhoneOS 177 | 178 | MSDKKey 179 | b47e0039e6156b90c6b79ecb3f7e1009 180 | MSDK_ENV 181 | release 182 | MSDK_OfferId 183 | 1450000928 184 | MSDK_PUSH_SWITCH 185 | 186 | MSDK_REAL_NAME_AUTH_SWITCH 187 | 1 188 | MSDK_URL 189 | http://msdk.qq.com 190 | MinimumOSVersion 191 | 9.0 192 | NSAppTransportSecurity 193 | 194 | NSAllowsArbitraryLoads 195 | 196 | 197 | NSAppleMusicUsageDescription 198 | 请求访问音乐库 199 | NSBluetoothPeripheralUsageDescription 200 | App需要您的同意,才能访问蓝牙 201 | NSCameraUsageDescription 202 | App需要您的同意,才能访问相机 203 | NSLocationAlwaysUsageDescription 204 | 此App需要您的同意才能使用定位服务,在游戏中将会使用到您的位置信息来访问身边的好友 205 | NSLocationUsageDescription 206 | 此App需要您的同意才能使用定位服务,在游戏中将会使用到您的位置信息来访问身边的好友 207 | NSLocationWhenInUseUsageDescription 208 | 此App需要您的同意才能在使用期间访问位置,在游戏中将会使用到您的位置信息来访问身边的好友 209 | NSMicrophoneUsageDescription 210 | 麦克风用于游戏内语音聊天 211 | NSPhotoLibraryUsageDescription 212 | App需要您的同意,才能访问相册 213 | NeedNotice 214 | 215 | NoticeTime 216 | 600 217 | QQAppID 218 | 1106501964 219 | QQAppKey 220 | hf8AilLRFPaTaDXR 221 | UIDeviceFamily 222 | 223 | 1 224 | 2 225 | 226 | UILaunchStoryboardName 227 | LaunchScreen 228 | UIRequiredDeviceCapabilities 229 | 230 | arm64 231 | metal 232 | 233 | UIRequiresFullScreen 234 | 235 | UIStatusBarHidden 236 | 237 | UISupportedInterfaceOrientations 238 | 239 | UIInterfaceOrientationLandscapeRight 240 | UIInterfaceOrientationLandscapeLeft 241 | 242 | UIViewControllerBasedStatusBarAppearance 243 | 244 | WXAppID 245 | wx13051697527efc45 246 | 247 | 248 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYSuspensionMenu.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuspensionView.h 3 | // SuspensionView 4 | // 5 | // Created by Ossey on 17/2/25. 6 | // Copyright © 2017年 Ossey All rights reserved. 7 | // 8 | 9 | 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | typedef NS_ENUM(NSUInteger, SuspensionViewLeanEdgeType) { 15 | SuspensionViewLeanEdgeTypeHorizontal = 1, 16 | SuspensionViewLeanEdgeTypeEachSide 17 | }; 18 | 19 | @class SuspensionView, SuspensionMenuView, MenuBarHypotenuseButton, HypotenuseAction; 20 | 21 | #pragma mark *** Protocol *** 22 | 23 | @protocol SuspensionViewDelegate 24 | 25 | @optional 26 | - (void)suspensionViewClickedButton:(SuspensionView *)suspensionView; 27 | - (void)suspensionView:(SuspensionView *)suspensionView locationChange:(UIPanGestureRecognizer *)pan; 28 | - (CGPoint)leanToNewTragetPosionForSuspensionView:(SuspensionView *)suspensionView; 29 | - (void)suspensionView:(SuspensionView *)suspensionView didAutoLeanToTargetPosition:(CGPoint)position; 30 | - (void)suspensionView:(SuspensionView *)suspensionView willAutoLeanToTargetPosition:(CGPoint)position; 31 | 32 | @end 33 | 34 | @protocol SuspensionMenuViewDelegate 35 | 36 | @optional 37 | - (void)suspensionMenuView:(SuspensionMenuView *)suspensionMenuView clickedHypotenuseButtonAtIndex:(NSInteger)buttonIndex; 38 | - (void)suspensionMenuView:(SuspensionMenuView *)suspensionMenuView clickedMoreButtonAtIndex:(NSInteger)buttonIndex fromHypotenuseItem:(HypotenuseAction *)hypotenuseItem; 39 | - (void)suspensionMenuView:(SuspensionMenuView *)suspensionMenuView clickedCenterButton:(SuspensionView *)centerButton; 40 | - (void)suspensionMenuViewDidOpened:(SuspensionMenuView *)suspensionMenuView; 41 | - (void)suspensionMenuViewDidClose:(SuspensionMenuView *)suspensionMenuView; 42 | - (void)suspensionMenuView:(SuspensionMenuView *)suspensionMenuView centerButtonLocationChange:(UIPanGestureRecognizer *)pan; 43 | 44 | 45 | @end 46 | 47 | @protocol XYSuspensionWindowProtocol 48 | - (UIWindow *)xy_window; 49 | - (void)xy_removeWindow; 50 | @end 51 | 52 | #pragma mark *** SuspensionView *** 53 | 54 | @interface SuspensionView : UIButton 55 | 56 | #if ! __has_feature(objc_arc) 57 | @property (nonatomic, assign, nullable) id delegate; 58 | @property (nonatomic, assign, readonly) UIPanGestureRecognizer *panGestureRecognizer; 59 | #else 60 | @property (nonatomic, weak, readonly) UIPanGestureRecognizer *panGestureRecognizer; 61 | @property (nonatomic, weak, nullable) id delegate; 62 | #endif 63 | 64 | @property (nonatomic, assign) SuspensionViewLeanEdgeType leanEdgeType; 65 | @property (nonatomic, assign) UIEdgeInsets leanEdgeInsets; 66 | @property (nonatomic, assign) BOOL invalidHidden; 67 | @property (nonatomic, assign, readonly) BOOL isMoving; 68 | @property (nonatomic, assign) CGFloat usingSpringWithDamping; 69 | @property (nonatomic, assign) CGFloat initialSpringVelocity; 70 | @property (nonatomic, copy, nullable) void (^locationChange)(CGPoint currentPoint); 71 | @property (nonatomic, copy, nullable) void (^ leanFinishCallBack)(CGPoint centerPoint); 72 | @property (nonatomic, assign, getter=isAutoLeanEdge) BOOL autoLeanEdge; 73 | @property (nonatomic, copy, nullable) void (^clickCallBack)(void); 74 | @property (nonatomic, assign) BOOL shouldLeanToPreviousPositionWhenAppStart; 75 | 76 | - (void)moveToDisplayCenter; 77 | - (void)moveToPreviousLeanPosition; 78 | - (void)checkTargetPosition; 79 | 80 | /// 界面方向发生改变,子类可重写此方法,进行布局 81 | - (void)didChangeInterfaceOrientation:(UIInterfaceOrientation)orientation; 82 | 83 | @end 84 | 85 | #pragma mark *** UIResponder (SuspensionView) *** 86 | 87 | @interface UIResponder (SuspensionView) 88 | @property (nonatomic, nonnull) SuspensionView *suspensionView; 89 | - (SuspensionView *)showSuspensionViewWithFrame:(CGRect)frame; 90 | - (void)dismissSuspensionView:(void (^)(void))block; 91 | - (void)setHiddenSuspension:(BOOL)flag; 92 | - (BOOL)isHiddenSuspension; 93 | - (void)setSuspensionTitle:(NSString *)title forState:(UIControlState)state; 94 | - (void)setSuspensionImage:(UIImage *)image forState:(UIControlState)state; 95 | - (void)setSuspensionImageWithImageNamed:(NSString *)name forState:(UIControlState)state; 96 | - (void)setSuspensionBackgroundColor:(UIColor *)color cornerRadius:(CGFloat)cornerRadius; 97 | @end 98 | 99 | #pragma mark *** SuspensionWindow *** 100 | 101 | @interface SuspensionWindow : SuspensionView 102 | 103 | + (instancetype)showWithFrame:(CGRect)frame; 104 | 105 | @end 106 | 107 | #pragma mark *** SuspensionMenuView *** 108 | 109 | @interface SuspensionMenuView : UIView 110 | #if ! __has_feature(objc_arc) 111 | @property (nonatomic, assign, nullable) id delegate; 112 | @property (nonatomic, assign, readonly) UIImageView *backgroundImageView; 113 | @property (nonatomic, assign, readonly) HypotenuseAction *currentResponderItem; 114 | #else 115 | @property (nonatomic, weak, nullable) id delegate; 116 | @property (nonatomic, weak, readonly) UIImageView *backgroundImageView; 117 | @property (nonatomic, weak, readonly) HypotenuseAction *currentResponderItem; 118 | #endif 119 | @property (nonatomic, strong, readonly) SuspensionView *centerButton; 120 | @property (nonatomic, copy) void (^ _Nullable menuBarClickBlock)(NSInteger index); 121 | @property (nonatomic, copy) void (^ _Nullable moreButtonClickBlock)(NSInteger index); 122 | @property (nonatomic, assign) BOOL shouldLeanToScreenCenterWhenOpened; 123 | @property (nonatomic, strong, readonly) NSArray *menuBarItems; 124 | @property (nonatomic, assign) CGFloat usingSpringWithDamping; 125 | @property (nonatomic, assign) CGFloat initialSpringVelocity; 126 | @property (nonatomic, assign) BOOL shouldHiddenCenterButtonWhenOpen; 127 | @property (nonatomic, assign) BOOL shouldCloseWhenDeviceOrientationDidChange; 128 | @property (nonatomic, strong, readonly) UIWindow *xy_window; 129 | 130 | - (instancetype)initWithFrame:(CGRect)frame itemSize:(CGSize)itemSize NS_DESIGNATED_INITIALIZER; 131 | 132 | - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; 133 | 134 | - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER; 135 | 136 | - (void)showWithCompetion:(void (^ _Nullable)(void))competion; 137 | 138 | - (void)addAction:(HypotenuseAction *)action; 139 | 140 | - (void)showViewController:(UIViewController *)viewController animated:(BOOL)animated; 141 | 142 | - (void)open; 143 | - (void)openWithCompetion:(void (^ _Nullable)(BOOL finished))competion; 144 | - (void)close; 145 | - (void)closeWithCompetion:(void (^ _Nullable)(BOOL finished))competion; 146 | @end 147 | 148 | #pragma mark *** SuspensionMenuWindow *** 149 | 150 | @interface SuspensionMenuWindow : SuspensionMenuView 151 | 152 | @property (nonatomic, assign) BOOL shouldOpenWhenViewWillAppear; 153 | 154 | + (instancetype)menuWindowWithFrame:(CGRect)frame itemSize:(CGSize)itemSize; 155 | 156 | @end 157 | 158 | #pragma mark *** HypotenuseAction *** 159 | 160 | @interface HypotenuseAction : NSObject 161 | 162 | @property (nonatomic, strong, readonly) UIButton *hypotenuseButton; 163 | @property (nonatomic, strong, readonly) NSArray *moreHypotenusItems; 164 | @property (nonatomic, assign) CGRect orginRect; 165 | + (instancetype)actionWithType:(UIButtonType)buttonType 166 | handler:(void (^__nullable)(HypotenuseAction *action, SuspensionMenuView *menuView))handler; 167 | - (void)addMoreAction:(HypotenuseAction *)action; 168 | 169 | @end 170 | 171 | #pragma mark *** UIWindow (SuspensionWindow) *** 172 | 173 | @interface UIWindow (SuspensionWindow) 174 | 175 | @property (nonatomic, strong, nullable) SuspensionView *suspensionView; 176 | @property (nonatomic, strong, nullable) SuspensionMenuView *suspensionMenuView; 177 | 178 | @end 179 | 180 | @interface UIApplication (SuspensionWindowExtension) 181 | 182 | - (nullable SuspensionMenuWindow *)xy_suspensionMenuWindow; 183 | 184 | @end 185 | 186 | NS_ASSUME_NONNULL_END 187 | 188 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/fishhook/fishhook.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013, Facebook, Inc. 2 | // All rights reserved. 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are met: 5 | // * Redistributions of source code must retain the above copyright notice, 6 | // this list of conditions and the following disclaimer. 7 | // * Redistributions in binary form must reproduce the above copyright notice, 8 | // this list of conditions and the following disclaimer in the documentation 9 | // and/or other materials provided with the distribution. 10 | // * Neither the name Facebook nor the names of its contributors may be used to 11 | // endorse or promote products derived from this software without specific 12 | // prior written permission. 13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | #import "fishhook.h" 25 | 26 | #import 27 | #import 28 | #import 29 | #import 30 | #import 31 | #import 32 | #import 33 | 34 | #ifdef __LP64__ 35 | typedef struct mach_header_64 mach_header_t; 36 | typedef struct segment_command_64 segment_command_t; 37 | typedef struct section_64 section_t; 38 | typedef struct nlist_64 nlist_t; 39 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 40 | #else 41 | typedef struct mach_header mach_header_t; 42 | typedef struct segment_command segment_command_t; 43 | typedef struct section section_t; 44 | typedef struct nlist nlist_t; 45 | #define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT 46 | #endif 47 | 48 | #ifndef SEG_DATA_CONST 49 | #define SEG_DATA_CONST "__DATA_CONST" 50 | #endif 51 | 52 | struct rebindings_entry { 53 | struct rebinding *rebindings; 54 | size_t rebindings_nel; 55 | struct rebindings_entry *next; 56 | }; 57 | 58 | static struct rebindings_entry *_rebindings_head; 59 | 60 | static int prepend_rebindings(struct rebindings_entry **rebindings_head, 61 | struct rebinding rebindings[], 62 | size_t nel) { 63 | struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); 64 | if (!new_entry) { 65 | return -1; 66 | } 67 | new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); 68 | if (!new_entry->rebindings) { 69 | free(new_entry); 70 | return -1; 71 | } 72 | memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); 73 | new_entry->rebindings_nel = nel; 74 | new_entry->next = *rebindings_head; 75 | *rebindings_head = new_entry; 76 | return 0; 77 | } 78 | 79 | static void perform_rebinding_with_section(struct rebindings_entry *rebindings, 80 | section_t *section, 81 | intptr_t slide, 82 | nlist_t *symtab, 83 | char *strtab, 84 | uint32_t *indirect_symtab) { 85 | uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; 86 | void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); 87 | for (uint i = 0; i < section->size / sizeof(void *); i++) { 88 | uint32_t symtab_index = indirect_symbol_indices[i]; 89 | if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || 90 | symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { 91 | continue; 92 | } 93 | uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; 94 | char *symbol_name = strtab + strtab_offset; 95 | if (strnlen(symbol_name, 2) < 2) { 96 | continue; 97 | } 98 | struct rebindings_entry *cur = rebindings; 99 | while (cur) { 100 | for (uint j = 0; j < cur->rebindings_nel; j++) { 101 | if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { 102 | if (cur->rebindings[j].replaced != NULL && 103 | indirect_symbol_bindings[i] != cur->rebindings[j].replacement) { 104 | *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; 105 | } 106 | indirect_symbol_bindings[i] = cur->rebindings[j].replacement; 107 | goto symbol_loop; 108 | } 109 | } 110 | cur = cur->next; 111 | } 112 | symbol_loop:; 113 | } 114 | } 115 | 116 | static void rebind_symbols_for_image(struct rebindings_entry *rebindings, 117 | const struct mach_header *header, 118 | intptr_t slide) { 119 | Dl_info info; 120 | if (dladdr(header, &info) == 0) { 121 | return; 122 | } 123 | 124 | segment_command_t *cur_seg_cmd; 125 | segment_command_t *linkedit_segment = NULL; 126 | struct symtab_command* symtab_cmd = NULL; 127 | struct dysymtab_command* dysymtab_cmd = NULL; 128 | 129 | uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); 130 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 131 | cur_seg_cmd = (segment_command_t *)cur; 132 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 133 | if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { 134 | linkedit_segment = cur_seg_cmd; 135 | } 136 | } else if (cur_seg_cmd->cmd == LC_SYMTAB) { 137 | symtab_cmd = (struct symtab_command*)cur_seg_cmd; 138 | } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { 139 | dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; 140 | } 141 | } 142 | 143 | if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || 144 | !dysymtab_cmd->nindirectsyms) { 145 | return; 146 | } 147 | 148 | // Find base symbol/string table addresses 149 | uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; 150 | nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); 151 | char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); 152 | 153 | // Get indirect symbol table (array of uint32_t indices into symbol table) 154 | uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); 155 | 156 | cur = (uintptr_t)header + sizeof(mach_header_t); 157 | for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { 158 | cur_seg_cmd = (segment_command_t *)cur; 159 | if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { 160 | if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && 161 | strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { 162 | continue; 163 | } 164 | for (uint j = 0; j < cur_seg_cmd->nsects; j++) { 165 | section_t *sect = 166 | (section_t *)(cur + sizeof(segment_command_t)) + j; 167 | if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { 168 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 169 | } 170 | if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { 171 | perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | 178 | static void _rebind_symbols_for_image(const struct mach_header *header, 179 | intptr_t slide) { 180 | rebind_symbols_for_image(_rebindings_head, header, slide); 181 | } 182 | 183 | int rebind_symbols_image(void *header, 184 | intptr_t slide, 185 | struct rebinding rebindings[], 186 | size_t rebindings_nel) { 187 | struct rebindings_entry *rebindings_head = NULL; 188 | int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); 189 | rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); 190 | free(rebindings_head); 191 | return retval; 192 | } 193 | 194 | int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { 195 | int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); 196 | if (retval < 0) { 197 | return retval; 198 | } 199 | // If this was the first call, register callback for image additions (which is also invoked for 200 | // existing images, otherwise, just run on existing images 201 | if (!_rebindings_head->next) { 202 | _dyld_register_func_for_add_image(_rebind_symbols_for_image); 203 | } else { 204 | uint32_t c = _dyld_image_count(); 205 | for (uint32_t i = 0; i < c; i++) { 206 | _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); 207 | } 208 | } 209 | return retval; 210 | } 211 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/XYSliderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // XYSliderView.m 3 | // SliderDemo 4 | // 5 | // Created by xiaoyuan on 2018/6/4. 6 | // Copyright © 2018年 xiaoyuan. All rights reserved. 7 | // 8 | 9 | #import "XYSliderView.h" 10 | 11 | @interface XYSliderView () 12 | 13 | @property (nonatomic, strong) UIButton *addButton; 14 | @property (nonatomic, strong) UIButton *subButton; 15 | @property (nonatomic, strong) UILabel *valueLabel; 16 | @property (nonatomic, strong) UILongPressGestureRecognizer *longPressGesOfAddButton; 17 | @property (nonatomic, strong) UILongPressGestureRecognizer *longPressGesOfSubButton; 18 | 19 | @end 20 | 21 | @implementation XYSliderView 22 | 23 | - (instancetype)initWithFrame:(CGRect)frame 24 | { 25 | self = [super initWithFrame:frame]; 26 | if (self) { 27 | 28 | self.minimumValue = 0.0; 29 | self.maximumValue = 1.0; 30 | self.backgroundColor = [UIColor clearColor]; 31 | [self addSubview:self.addButton]; 32 | [self addSubview:self.subButton]; 33 | [self addSubview:self.valueLabel]; 34 | [self _addConstraints]; 35 | 36 | [self.addButton addTarget:self action:@selector(sliderValueChange:) forControlEvents:UIControlEventTouchDown]; 37 | [self.subButton addTarget:self action:@selector(sliderValueChange:) forControlEvents:UIControlEventTouchDown]; 38 | 39 | [self hiddenValueLabel]; 40 | self.continuous = YES; 41 | self.leanEdgeInsets = UIEdgeInsetsZero; 42 | self.autoLeanEdge = NO; 43 | } 44 | return self; 45 | } 46 | 47 | - (void)_addConstraints { 48 | [NSLayoutConstraint constraintWithItem:self.addButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0].active = YES; 49 | [NSLayoutConstraint constraintWithItem:self.addButton attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0].active = YES; 50 | [NSLayoutConstraint constraintWithItem:self.addButton attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0].active = YES; 51 | [NSLayoutConstraint constraintWithItem:self.addButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0].active = YES; 52 | [NSLayoutConstraint constraintWithItem:self.addButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.addButton attribute:NSLayoutAttributeWidth multiplier:1.0 constant:20.0].active = YES; 53 | 54 | [NSLayoutConstraint constraintWithItem:self.subButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0].active = YES; 55 | [NSLayoutConstraint constraintWithItem:self.subButton attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0].active = YES; 56 | [NSLayoutConstraint constraintWithItem:self.subButton attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0].active = YES; 57 | [NSLayoutConstraint constraintWithItem:self.subButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.addButton attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0.0].active = YES; 58 | [NSLayoutConstraint constraintWithItem:self.subButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.addButton attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0.0].active = YES; 59 | 60 | [NSLayoutConstraint constraintWithItem:self.valueLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0].active = YES; 61 | [NSLayoutConstraint constraintWithItem:self.valueLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0].active = YES; 62 | [NSLayoutConstraint constraintWithItem:self.valueLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0].active = YES; 63 | 64 | [NSLayoutConstraint constraintWithItem:self.addButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.valueLabel attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0].active = YES; 65 | [NSLayoutConstraint constraintWithItem:self.subButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self.valueLabel attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0].active = YES; 66 | } 67 | 68 | - (void)setContinuous:(BOOL)continuous { 69 | _continuous = continuous; 70 | if (continuous == YES) { 71 | [self _addLongGesture]; 72 | } 73 | else { 74 | [self _removeLongGesture]; 75 | } 76 | } 77 | 78 | - (void)_addLongGesture { 79 | if (self.longPressGesOfAddButton == nil) { 80 | UILongPressGestureRecognizer *longPressGesUp1 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressUp:)]; 81 | longPressGesUp1.minimumPressDuration = 0.3; 82 | [self.addButton addGestureRecognizer:longPressGesUp1]; 83 | self.longPressGesOfAddButton = longPressGesUp1; 84 | } 85 | 86 | if (self.longPressGesOfSubButton == nil) { 87 | UILongPressGestureRecognizer *longPressGesUp2 = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressUp:)]; 88 | longPressGesUp2.minimumPressDuration = 0.3; 89 | [self.subButton addGestureRecognizer:longPressGesUp2]; 90 | self.longPressGesOfSubButton = longPressGesUp2; 91 | } 92 | 93 | } 94 | - (void)_removeLongGesture { 95 | if (self.longPressGesOfAddButton) { 96 | [self.addButton removeGestureRecognizer:self.longPressGesOfAddButton]; 97 | self.longPressGesOfAddButton = nil; 98 | } 99 | if (self.longPressGesOfSubButton) { 100 | [self.subButton removeGestureRecognizer:self.longPressGesOfSubButton]; 101 | self.longPressGesOfSubButton = nil; 102 | } 103 | } 104 | 105 | - (void)longPressUp:(UILongPressGestureRecognizer *)longGesture { 106 | [self sliderValueChange:(id)longGesture.view]; 107 | } 108 | 109 | - (void)sliderValueChange:(UIButton *)btn { 110 | 111 | if (btn.tag == 1001) { 112 | self.value ++; 113 | } 114 | else if (btn.tag == 1002) { 115 | self.value --; 116 | } 117 | [self showValueLabel]; 118 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hiddenValueLabel) object:nil]; 119 | [self performSelector:@selector(hiddenValueLabel) withObject:nil afterDelay:2.0]; 120 | } 121 | 122 | - (void)hiddenValueLabel { 123 | self.valueLabel.alpha = 0.0; 124 | [UIView animateWithDuration:0.1 animations:^{ 125 | [self.valueLabel layoutIfNeeded]; 126 | } completion:^(BOOL finished) { 127 | self.valueLabel.hidden = YES; 128 | }]; 129 | } 130 | 131 | - (void)showValueLabel { 132 | self.valueLabel.alpha = 1.0; 133 | [UIView animateWithDuration:0.1 animations:^{ 134 | [self.valueLabel layoutIfNeeded]; 135 | } completion:^(BOOL finished) { 136 | self.valueLabel.hidden = NO; 137 | }]; 138 | } 139 | 140 | - (void)setMinimumValue:(float)minimumValue { 141 | _minimumValue = minimumValue; 142 | self.value = self.value; 143 | } 144 | 145 | - (void)setMaximumValue:(float)maximumValue { 146 | _maximumValue = maximumValue; 147 | self.value = self.value; 148 | } 149 | 150 | - (void)setValue:(float)value { 151 | NSString *valueKey = NSStringFromSelector(@selector(value)); 152 | [self willChangeValueForKey:valueKey]; 153 | if (value > self.maximumValue) { 154 | value = self.maximumValue; 155 | } 156 | if (value < self.minimumValue) { 157 | value = self.minimumValue; 158 | } 159 | self.valueLabel.text = @(value).stringValue; 160 | if (self.valueChangeBlock) { 161 | self.valueChangeBlock(value); 162 | } 163 | [self didChangeValueForKey:valueKey]; 164 | } 165 | 166 | - (float)value { 167 | return self.valueLabel.text.floatValue; 168 | } 169 | 170 | - (UIButton *)addButton { 171 | if (!_addButton) { 172 | _addButton = [UIButton new]; 173 | _addButton.translatesAutoresizingMaskIntoConstraints = NO; 174 | _addButton.tag = 1001; 175 | [_addButton setTitle:@"+" forState:UIControlStateNormal]; 176 | [_addButton setTitleColor:[[UIColor yellowColor] colorWithAlphaComponent:0.7] forState:UIControlStateNormal]; 177 | _addButton.titleLabel.textAlignment = NSTextAlignmentCenter; 178 | _addButton.contentVerticalAlignment = UIControlContentHorizontalAlignmentCenter; 179 | _addButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; 180 | } 181 | return _addButton; 182 | } 183 | 184 | - (UIButton *)subButton { 185 | if (!_subButton) { 186 | _subButton = [UIButton new]; 187 | _subButton.translatesAutoresizingMaskIntoConstraints = NO; 188 | _subButton.tag = 1002; 189 | [_subButton setTitle:@"-" forState:UIControlStateNormal]; 190 | [_subButton setTitleColor:[[UIColor yellowColor] colorWithAlphaComponent:0.7] forState:UIControlStateNormal]; 191 | _subButton.titleLabel.textAlignment = NSTextAlignmentCenter; 192 | _subButton.contentVerticalAlignment = UIControlContentHorizontalAlignmentCenter; 193 | _subButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; 194 | } 195 | return _subButton; 196 | } 197 | 198 | - (UILabel *)valueLabel { 199 | if (!_valueLabel) { 200 | _valueLabel = [UILabel new]; 201 | _valueLabel.translatesAutoresizingMaskIntoConstraints = NO; 202 | _valueLabel.adjustsFontSizeToFitWidth = YES; 203 | _valueLabel.backgroundColor = [UIColor clearColor]; 204 | _valueLabel.text = @(self.value).stringValue; 205 | _valueLabel.textColor = [[UIColor orangeColor] colorWithAlphaComponent:0.7]; 206 | _valueLabel.textAlignment = NSTextAlignmentCenter; 207 | } 208 | return _valueLabel; 209 | } 210 | 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/MDCycriptManager.m: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // MDCycriptManager.m 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2018/3/8. 8 | // Copyright © 2018年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #ifndef __OPTIMIZE__ 12 | 13 | #import "MDCycriptManager.h" 14 | #import "MDConfigManager.h" 15 | #import 16 | #import 17 | #import 18 | #import 19 | 20 | #define IOS_CELLULAR @"pdp_ip0" 21 | #define IOS_WIFI @"en0" 22 | #define IP_ADDR_IPv4 @"ipv4" 23 | #define IP_ADDR_IPv6 @"ipv6" 24 | #define MDLog(fmt, ...) NSLog((@"[Cycript] " fmt), ##__VA_ARGS__) 25 | 26 | extern JSGlobalContextRef CYGetJSContext(void); 27 | extern void CydgetMemoryParse(const uint16_t **data, size_t *size); 28 | 29 | NSString * const CYErrorLineKey = @"CYErrorLineKey"; 30 | NSString * const CYErrorNameKey = @"CYErrorNameKey"; 31 | NSString * const CYErrorMessageKey = @"CYErrorMessageKey"; 32 | 33 | @interface MDSettingObject : NSObject 34 | 35 | @property (nonatomic, assign) NSInteger priority; 36 | @property (nonatomic, copy) NSString* url; 37 | @property (nonatomic, copy) NSString* content; 38 | @property (nonatomic, assign) BOOL loadAtLaunch; 39 | 40 | -(instancetype)initWithDicationary:(NSDictionary*) dictionary; 41 | 42 | @end 43 | 44 | @implementation MDSettingObject 45 | 46 | -(instancetype)initWithDicationary:(NSDictionary *)dictionary{ 47 | self = [super init]; 48 | if(self){ 49 | self.priority = [dictionary[@"priority"] integerValue]; 50 | self.url = dictionary[@"url"]; 51 | self.content = dictionary[@"content"]; 52 | self.loadAtLaunch = [dictionary objectForKey:MDCONFIG_LOADATLAUNCH_KEY] && [dictionary[MDCONFIG_LOADATLAUNCH_KEY] boolValue]; 53 | } 54 | return self; 55 | } 56 | 57 | @end 58 | 59 | @interface MDCycriptManager() 60 | 61 | @property (nonatomic, strong) NSDictionary* configItem; 62 | @property (nonatomic, copy) NSString* cycriptDirectory; 63 | @property (nonatomic, strong) NSMutableArray* downloading; 64 | @property (nonatomic, strong) NSMutableDictionary* loadAtLaunchModules; 65 | 66 | @end 67 | 68 | @implementation MDCycriptManager 69 | 70 | + (instancetype)sharedInstance{ 71 | static MDCycriptManager *sharedInstance = nil; 72 | if (!sharedInstance){ 73 | sharedInstance = [[MDCycriptManager alloc] init]; 74 | } 75 | return sharedInstance; 76 | } 77 | 78 | - (instancetype)init 79 | { 80 | self = [super init]; 81 | if (self) { 82 | _loadAtLaunchModules = [NSMutableDictionary dictionary]; 83 | _downloading = [NSMutableArray array]; 84 | [self check]; 85 | [self readConfigFile]; 86 | } 87 | return self; 88 | } 89 | 90 | -(void)check{ 91 | NSString* ip = [self getIPAddress]; 92 | if(ip != nil){ 93 | printf("\nDownload cycript(https://cydia.saurik.com/api/latest/3) then run: ./cycript -r %s:%d\n\n", [ip UTF8String], PORT); 94 | }else{ 95 | printf("\nPlease connect wifi before using cycript!\n\n"); 96 | } 97 | 98 | NSFileManager *fileManager = [NSFileManager defaultManager]; 99 | NSString *documentsPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) firstObject]; 100 | _cycriptDirectory = [documentsPath stringByAppendingPathComponent:@"cycript"]; 101 | [fileManager createDirectoryAtPath:_cycriptDirectory withIntermediateDirectories:YES attributes:nil error:nil]; 102 | } 103 | 104 | -(NSArray*)sortedArray:(NSDictionary*) dictionary{ 105 | NSMutableArray* result = [NSMutableArray arrayWithCapacity:10]; 106 | 107 | NSArray* sortedArray = [dictionary.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSNumber* _Nonnull number1, NSNumber* _Nonnull number2) { 108 | if ([number1 integerValue] > [number2 integerValue]) 109 | return NSOrderedDescending; 110 | return NSOrderedAscending; 111 | }]; 112 | 113 | for (NSNumber* item in sortedArray) { 114 | [result addObject:dictionary[item]]; 115 | } 116 | 117 | return [result copy]; 118 | } 119 | 120 | -(void)readConfigFile{ 121 | MDConfigManager * configManager = [MDConfigManager sharedInstance]; 122 | _configItem = [configManager readConfigByKey:MDCONFIG_CYCRIPT_KEY]; 123 | } 124 | 125 | -(void)loadCycript:(BOOL) update{ 126 | NSFileManager *fileManager = [NSFileManager defaultManager]; 127 | 128 | if(_configItem && _configItem.count > 0){ 129 | 130 | BOOL download = NO; 131 | 132 | for (NSString* moduleName in _configItem.allKeys) { 133 | MDSettingObject * item = [[MDSettingObject alloc] initWithDicationary:_configItem[moduleName]]; 134 | NSString *fullPath = [[_cycriptDirectory stringByAppendingPathComponent:moduleName] stringByAppendingPathExtension:@"cy"]; 135 | 136 | if(item.url){ 137 | if(![fileManager fileExistsAtPath:fullPath] || update){ 138 | download = YES; 139 | [self.downloading addObject:moduleName]; 140 | [self downLoadUrl:item.url saveName:moduleName]; 141 | } 142 | } 143 | 144 | if(item.content){ 145 | if(![fileManager fileExistsAtPath:fullPath] || update){ 146 | NSString* writeContent = [NSString stringWithFormat:@"(function(exports) { %@ })(exports);", item.content]; 147 | [writeContent writeToFile:fullPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 148 | } 149 | } 150 | 151 | if(item.loadAtLaunch){ 152 | [_loadAtLaunchModules setObject:fullPath forKey:@(item.priority)]; 153 | } 154 | } 155 | 156 | if(!download){ 157 | [self finishDownload]; 158 | } 159 | } 160 | } 161 | 162 | -(void)finishDownload{ 163 | MDLog(@"Finish download all script!"); 164 | NSArray* sortedArray = [self sortedArray:_loadAtLaunchModules]; 165 | for (NSString* fullPath in sortedArray) { 166 | NSError* error; 167 | [self evaluateCycript:[NSString stringWithFormat:@"require('%@');",fullPath] error:&error]; 168 | if(error.code != 0){ 169 | MDLog(@"%@", error.localizedDescription); 170 | } 171 | } 172 | } 173 | 174 | -(void)downLoadUrl:(NSString*) urlString saveName:(NSString*) filename{ 175 | __weak typeof(self) weakSelf = self; 176 | NSURLSession *session = [NSURLSession sharedSession]; 177 | NSURL *url = [NSURL URLWithString:urlString]; 178 | NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { 179 | 180 | if(error){ 181 | MDLog(@"Failed download script [%@]: %@", filename, error.localizedDescription); 182 | }else{ 183 | NSString *fullPath = [[_cycriptDirectory stringByAppendingPathComponent:filename] stringByAppendingPathExtension:@"cy"]; 184 | [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil]; 185 | 186 | MDLog(@"Successful download script [%@]", filename); 187 | } 188 | 189 | [weakSelf.downloading removeObject:filename]; 190 | 191 | if(!weakSelf.downloading.count){ 192 | [weakSelf finishDownload]; 193 | } 194 | }]; 195 | [downloadTask resume]; 196 | } 197 | 198 | -(NSString *)evaluateCycript:(NSString *)cycript error:(NSError *__autoreleasing *)error{ 199 | JSGlobalContextRef context = CYGetJSContext(); 200 | 201 | size_t length = cycript.length; 202 | unichar *buffer = malloc(length * sizeof(unichar)); 203 | [cycript getCharacters:buffer range:NSMakeRange(0, length)]; 204 | const uint16_t *characters = buffer; 205 | CydgetMemoryParse(&characters, &length); 206 | JSStringRef expression = JSStringCreateWithCharacters(characters, length); 207 | 208 | // Evaluate the Javascript 209 | JSValueRef exception = NULL; 210 | JSValueRef result = JSEvaluateScript(context, expression, NULL, NULL, 0, &exception); 211 | JSStringRelease(expression); 212 | 213 | NSString *resultString = nil; 214 | 215 | // If a result was returned, convert it into an NSString 216 | if (result) { 217 | JSStringRef string = JSValueToStringCopy(context, result, &exception); 218 | if (string) { 219 | resultString = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); 220 | JSStringRelease(string); 221 | } 222 | } 223 | 224 | // If an exception was thrown, convert it into an NSError 225 | if (exception && error) { 226 | JSObjectRef exceptionObject = JSValueToObject(context, exception, NULL); 227 | 228 | NSInteger line = (NSInteger)JSValueToNumber(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("line"), NULL), NULL); 229 | JSStringRef string = JSValueToStringCopy(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("name"), NULL), NULL); 230 | NSString *name = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); 231 | JSStringRelease(string); 232 | string = JSValueToStringCopy(context, JSObjectGetProperty(context, exceptionObject, JSStringCreateWithUTF8CString("message"), NULL), NULL); 233 | NSString *message = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); 234 | JSStringRelease(string); 235 | string = JSValueToStringCopy(context, exception, NULL); 236 | NSString *description = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, string); 237 | JSStringRelease(string); 238 | 239 | NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; 240 | [userInfo setValue:@(line) forKey:CYErrorLineKey]; 241 | [userInfo setValue:name forKey:CYErrorNameKey]; 242 | [userInfo setValue:message forKey:CYErrorMessageKey]; 243 | [userInfo setValue:description forKey:NSLocalizedDescriptionKey]; 244 | *error = [NSError errorWithDomain:@"CYContextDomain" code:0 userInfo:userInfo]; 245 | } 246 | 247 | return resultString; 248 | } 249 | 250 | - (NSString *)getIPAddress{ 251 | 252 | NSDictionary *addresses = [self getIPAddresses]; 253 | 254 | if([addresses.allKeys containsObject:IOS_WIFI @"/" IP_ADDR_IPv4]){ 255 | return addresses[IOS_WIFI @"/" IP_ADDR_IPv4]; 256 | } 257 | 258 | return nil; 259 | } 260 | 261 | - (NSDictionary *)getIPAddresses{ 262 | NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:8]; 263 | 264 | // retrieve the current interfaces - returns 0 on success 265 | struct ifaddrs *interfaces; 266 | if(!getifaddrs(&interfaces)) { 267 | // Loop through linked list of interfaces 268 | struct ifaddrs *interface; 269 | for(interface=interfaces; interface; interface=interface->ifa_next) { 270 | if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) { 271 | continue; // deeply nested code harder to read 272 | } 273 | const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr; 274 | char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ]; 275 | if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) { 276 | NSString *name = [NSString stringWithUTF8String:interface->ifa_name]; 277 | NSString *type; 278 | if(addr->sin_family == AF_INET) { 279 | if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) { 280 | type = IP_ADDR_IPv4; 281 | } 282 | } else { 283 | const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr; 284 | if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) { 285 | type = IP_ADDR_IPv6; 286 | } 287 | } 288 | if(type) { 289 | NSString *key = [NSString stringWithFormat:@"%@/%@", name, type]; 290 | addresses[key] = [NSString stringWithUTF8String:addrBuf]; 291 | } 292 | } 293 | } 294 | // Free memory 295 | freeifaddrs(interfaces); 296 | } 297 | return [addresses count] ? addresses : nil; 298 | } 299 | 300 | @end 301 | 302 | #endif 303 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/BSBacktraceLogger.m: -------------------------------------------------------------------------------- 1 | // 2 | // BSBacktraceLogger.m 3 | // BSBacktraceLogger 4 | // 5 | // Created by 张星宇 on 16/8/27. 6 | // Copyright © 2016年 bestswifter. All rights reserved. 7 | // 8 | 9 | #import "BSBacktraceLogger.h" 10 | #import 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #pragma -mark DEFINE MACRO FOR DIFFERENT CPU ARCHITECTURE 20 | #if defined(__arm64__) 21 | #define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(3UL)) 22 | #define BS_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT 23 | #define BS_THREAD_STATE ARM_THREAD_STATE64 24 | #define BS_FRAME_POINTER __fp 25 | #define BS_STACK_POINTER __sp 26 | #define BS_INSTRUCTION_ADDRESS __pc 27 | 28 | #elif defined(__arm__) 29 | #define DETAG_INSTRUCTION_ADDRESS(A) ((A) & ~(1UL)) 30 | #define BS_THREAD_STATE_COUNT ARM_THREAD_STATE_COUNT 31 | #define BS_THREAD_STATE ARM_THREAD_STATE 32 | #define BS_FRAME_POINTER __r[7] 33 | #define BS_STACK_POINTER __sp 34 | #define BS_INSTRUCTION_ADDRESS __pc 35 | 36 | #elif defined(__x86_64__) 37 | #define DETAG_INSTRUCTION_ADDRESS(A) (A) 38 | #define BS_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT 39 | #define BS_THREAD_STATE x86_THREAD_STATE64 40 | #define BS_FRAME_POINTER __rbp 41 | #define BS_STACK_POINTER __rsp 42 | #define BS_INSTRUCTION_ADDRESS __rip 43 | 44 | #elif defined(__i386__) 45 | #define DETAG_INSTRUCTION_ADDRESS(A) (A) 46 | #define BS_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT 47 | #define BS_THREAD_STATE x86_THREAD_STATE32 48 | #define BS_FRAME_POINTER __ebp 49 | #define BS_STACK_POINTER __esp 50 | #define BS_INSTRUCTION_ADDRESS __eip 51 | 52 | #endif 53 | 54 | #define CALL_INSTRUCTION_FROM_RETURN_ADDRESS(A) (DETAG_INSTRUCTION_ADDRESS((A)) - 1) 55 | 56 | #if defined(__LP64__) 57 | #define TRACE_FMT "%-4d%-31s 0x%016lx %s + %lu" 58 | #define POINTER_FMT "0x%016lx" 59 | #define POINTER_SHORT_FMT "0x%lx" 60 | #define BS_NLIST struct nlist_64 61 | #else 62 | #define TRACE_FMT "%-4d%-31s 0x%08lx %s + %lu" 63 | #define POINTER_FMT "0x%08lx" 64 | #define POINTER_SHORT_FMT "0x%lx" 65 | #define BS_NLIST struct nlist 66 | #endif 67 | 68 | typedef struct BSStackFrameEntry{ 69 | const struct BSStackFrameEntry *const previous; 70 | const uintptr_t return_address; 71 | } BSStackFrameEntry; 72 | 73 | static mach_port_t main_thread_id; 74 | 75 | @implementation BSBacktraceLogger 76 | 77 | + (void)load { 78 | main_thread_id = mach_thread_self(); 79 | } 80 | 81 | #pragma -mark Implementation of interface 82 | + (NSString *)bs_backtraceOfNSThread:(NSThread *)thread { 83 | return _bs_backtraceOfThread(bs_machThreadFromNSThread(thread)); 84 | } 85 | 86 | + (NSString *)bs_backtraceOfCurrentThread { 87 | return [self bs_backtraceOfNSThread:[NSThread currentThread]]; 88 | } 89 | 90 | + (NSString *)bs_backtraceOfMainThread { 91 | return [self bs_backtraceOfNSThread:[NSThread mainThread]]; 92 | } 93 | 94 | + (NSString *)bs_backtraceOfAllThread { 95 | thread_act_array_t threads; 96 | mach_msg_type_number_t thread_count = 0; 97 | const task_t this_task = mach_task_self(); 98 | 99 | kern_return_t kr = task_threads(this_task, &threads, &thread_count); 100 | if(kr != KERN_SUCCESS) { 101 | return @"Fail to get information of all threads"; 102 | } 103 | 104 | NSMutableString *resultString = [NSMutableString stringWithFormat:@"Call Backtrace of %u threads:\n", thread_count]; 105 | for(int i = 0; i < thread_count; i++) { 106 | [resultString appendString:_bs_backtraceOfThread(threads[i])]; 107 | } 108 | return [resultString copy]; 109 | } 110 | 111 | #pragma -mark Get call backtrace of a mach_thread 112 | NSString *_bs_backtraceOfThread(thread_t thread) { 113 | uintptr_t backtraceBuffer[50]; 114 | int i = 0; 115 | NSMutableString *resultString = [[NSMutableString alloc] initWithFormat:@"Backtrace of Thread %u:\n", thread]; 116 | 117 | _STRUCT_MCONTEXT machineContext; 118 | if(!bs_fillThreadStateIntoMachineContext(thread, &machineContext)) { 119 | return [NSString stringWithFormat:@"Fail to get information about thread: %u", thread]; 120 | } 121 | 122 | const uintptr_t instructionAddress = bs_mach_instructionAddress(&machineContext); 123 | backtraceBuffer[i] = instructionAddress; 124 | ++i; 125 | 126 | uintptr_t linkRegister = bs_mach_linkRegister(&machineContext); 127 | if (linkRegister) { 128 | backtraceBuffer[i] = linkRegister; 129 | i++; 130 | } 131 | 132 | if(instructionAddress == 0) { 133 | return @"Fail to get instruction address"; 134 | } 135 | 136 | BSStackFrameEntry frame = {0}; 137 | const uintptr_t framePtr = bs_mach_framePointer(&machineContext); 138 | if(framePtr == 0 || 139 | bs_mach_copyMem((void *)framePtr, &frame, sizeof(frame)) != KERN_SUCCESS) { 140 | return @"Fail to get frame pointer"; 141 | } 142 | 143 | for(; i < 50; i++) { 144 | backtraceBuffer[i] = frame.return_address; 145 | if(backtraceBuffer[i] == 0 || 146 | frame.previous == 0 || 147 | bs_mach_copyMem(frame.previous, &frame, sizeof(frame)) != KERN_SUCCESS) { 148 | break; 149 | } 150 | } 151 | 152 | int backtraceLength = i; 153 | Dl_info symbolicated[backtraceLength]; 154 | bs_symbolicate(backtraceBuffer, symbolicated, backtraceLength, 0); 155 | for (int i = 0; i < backtraceLength; ++i) { 156 | [resultString appendFormat:@"%@", bs_logBacktraceEntry(i, backtraceBuffer[i], &symbolicated[i])]; 157 | } 158 | [resultString appendFormat:@"\n"]; 159 | return [resultString copy]; 160 | } 161 | 162 | #pragma -mark Convert NSThread to Mach thread 163 | thread_t bs_machThreadFromNSThread(NSThread *nsthread) { 164 | char name[256]; 165 | mach_msg_type_number_t count; 166 | thread_act_array_t list; 167 | task_threads(mach_task_self(), &list, &count); 168 | 169 | NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; 170 | NSString *originName = [nsthread name]; 171 | [nsthread setName:[NSString stringWithFormat:@"%f", currentTimestamp]]; 172 | 173 | if ([nsthread isMainThread]) { 174 | return (thread_t)main_thread_id; 175 | } 176 | 177 | for (int i = 0; i < count; ++i) { 178 | pthread_t pt = pthread_from_mach_thread_np(list[i]); 179 | if ([nsthread isMainThread]) { 180 | if (list[i] == main_thread_id) { 181 | return list[i]; 182 | } 183 | } 184 | if (pt) { 185 | name[0] = '\0'; 186 | pthread_getname_np(pt, name, sizeof name); 187 | if (!strcmp(name, [nsthread name].UTF8String)) { 188 | [nsthread setName:originName]; 189 | return list[i]; 190 | } 191 | } 192 | } 193 | 194 | [nsthread setName:originName]; 195 | return mach_thread_self(); 196 | } 197 | 198 | #pragma -mark GenerateBacbsrackEnrty 199 | NSString* bs_logBacktraceEntry(const int entryNum, 200 | const uintptr_t address, 201 | const Dl_info* const dlInfo) { 202 | char faddrBuff[20]; 203 | char saddrBuff[20]; 204 | 205 | const char* fname = bs_lastPathEntry(dlInfo->dli_fname); 206 | if(fname == NULL) { 207 | sprintf(faddrBuff, POINTER_FMT, (uintptr_t)dlInfo->dli_fbase); 208 | fname = faddrBuff; 209 | } 210 | 211 | uintptr_t offset = address - (uintptr_t)dlInfo->dli_saddr; 212 | const char* sname = dlInfo->dli_sname; 213 | if(sname == NULL) { 214 | sprintf(saddrBuff, POINTER_SHORT_FMT, (uintptr_t)dlInfo->dli_fbase); 215 | sname = saddrBuff; 216 | offset = address - (uintptr_t)dlInfo->dli_fbase; 217 | } 218 | return [NSString stringWithFormat:@"%-30s 0x%08" PRIxPTR " %s + %lu\n" ,fname, (uintptr_t)address, sname, offset]; 219 | } 220 | 221 | const char* bs_lastPathEntry(const char* const path) { 222 | if(path == NULL) { 223 | return NULL; 224 | } 225 | 226 | char* lastFile = strrchr(path, '/'); 227 | return lastFile == NULL ? path : lastFile + 1; 228 | } 229 | 230 | #pragma -mark HandleMachineContext 231 | bool bs_fillThreadStateIntoMachineContext(thread_t thread, _STRUCT_MCONTEXT *machineContext) { 232 | mach_msg_type_number_t state_count = BS_THREAD_STATE_COUNT; 233 | kern_return_t kr = thread_get_state(thread, BS_THREAD_STATE, (thread_state_t)&machineContext->__ss, &state_count); 234 | return (kr == KERN_SUCCESS); 235 | } 236 | 237 | uintptr_t bs_mach_framePointer(mcontext_t const machineContext){ 238 | return machineContext->__ss.BS_FRAME_POINTER; 239 | } 240 | 241 | uintptr_t bs_mach_stackPointer(mcontext_t const machineContext){ 242 | return machineContext->__ss.BS_STACK_POINTER; 243 | } 244 | 245 | uintptr_t bs_mach_instructionAddress(mcontext_t const machineContext){ 246 | return machineContext->__ss.BS_INSTRUCTION_ADDRESS; 247 | } 248 | 249 | uintptr_t bs_mach_linkRegister(mcontext_t const machineContext){ 250 | #if defined(__i386__) || defined(__x86_64__) 251 | return 0; 252 | #else 253 | return machineContext->__ss.__lr; 254 | #endif 255 | } 256 | 257 | kern_return_t bs_mach_copyMem(const void *const src, void *const dst, const size_t numBytes){ 258 | vm_size_t bytesCopied = 0; 259 | return vm_read_overwrite(mach_task_self(), (vm_address_t)src, (vm_size_t)numBytes, (vm_address_t)dst, &bytesCopied); 260 | } 261 | 262 | #pragma -mark Symbolicate 263 | void bs_symbolicate(const uintptr_t* const backtraceBuffer, 264 | Dl_info* const symbolsBuffer, 265 | const int numEntries, 266 | const int skippedEntries){ 267 | int i = 0; 268 | 269 | if(!skippedEntries && i < numEntries) { 270 | bs_dladdr(backtraceBuffer[i], &symbolsBuffer[i]); 271 | i++; 272 | } 273 | 274 | for(; i < numEntries; i++) { 275 | bs_dladdr(CALL_INSTRUCTION_FROM_RETURN_ADDRESS(backtraceBuffer[i]), &symbolsBuffer[i]); 276 | } 277 | } 278 | 279 | bool bs_dladdr(const uintptr_t address, Dl_info* const info) { 280 | info->dli_fname = NULL; 281 | info->dli_fbase = NULL; 282 | info->dli_sname = NULL; 283 | info->dli_saddr = NULL; 284 | 285 | const uint32_t idx = bs_imageIndexContainingAddress(address); 286 | if(idx == UINT_MAX) { 287 | return false; 288 | } 289 | const struct mach_header* header = _dyld_get_image_header(idx); 290 | const uintptr_t imageVMAddrSlide = (uintptr_t)_dyld_get_image_vmaddr_slide(idx); 291 | const uintptr_t addressWithSlide = address - imageVMAddrSlide; 292 | const uintptr_t segmentBase = bs_segmentBaseOfImageIndex(idx) + imageVMAddrSlide; 293 | if(segmentBase == 0) { 294 | return false; 295 | } 296 | 297 | info->dli_fname = _dyld_get_image_name(idx); 298 | info->dli_fbase = (void*)header; 299 | 300 | // Find symbol tables and get whichever symbol is closest to the address. 301 | const BS_NLIST* bestMatch = NULL; 302 | uintptr_t bestDistance = ULONG_MAX; 303 | uintptr_t cmdPtr = bs_firstCmdAfterHeader(header); 304 | if(cmdPtr == 0) { 305 | return false; 306 | } 307 | for(uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) { 308 | const struct load_command* loadCmd = (struct load_command*)cmdPtr; 309 | if(loadCmd->cmd == LC_SYMTAB) { 310 | const struct symtab_command* symtabCmd = (struct symtab_command*)cmdPtr; 311 | const BS_NLIST* symbolTable = (BS_NLIST*)(segmentBase + symtabCmd->symoff); 312 | const uintptr_t stringTable = segmentBase + symtabCmd->stroff; 313 | 314 | for(uint32_t iSym = 0; iSym < symtabCmd->nsyms; iSym++) { 315 | // If n_value is 0, the symbol refers to an external object. 316 | if(symbolTable[iSym].n_value != 0) { 317 | uintptr_t symbolBase = symbolTable[iSym].n_value; 318 | uintptr_t currentDistance = addressWithSlide - symbolBase; 319 | if((addressWithSlide >= symbolBase) && 320 | (currentDistance <= bestDistance)) { 321 | bestMatch = symbolTable + iSym; 322 | bestDistance = currentDistance; 323 | } 324 | } 325 | } 326 | if(bestMatch != NULL) { 327 | info->dli_saddr = (void*)(bestMatch->n_value + imageVMAddrSlide); 328 | info->dli_sname = (char*)((intptr_t)stringTable + (intptr_t)bestMatch->n_un.n_strx); 329 | if(*info->dli_sname == '_') { 330 | info->dli_sname++; 331 | } 332 | // This happens if all symbols have been stripped. 333 | if(info->dli_saddr == info->dli_fbase && bestMatch->n_type == 3) { 334 | info->dli_sname = NULL; 335 | } 336 | break; 337 | } 338 | } 339 | cmdPtr += loadCmd->cmdsize; 340 | } 341 | return true; 342 | } 343 | 344 | uintptr_t bs_firstCmdAfterHeader(const struct mach_header* const header) { 345 | switch(header->magic) { 346 | case MH_MAGIC: 347 | case MH_CIGAM: 348 | return (uintptr_t)(header + 1); 349 | case MH_MAGIC_64: 350 | case MH_CIGAM_64: 351 | return (uintptr_t)(((struct mach_header_64*)header) + 1); 352 | default: 353 | return 0; // Header is corrupt 354 | } 355 | } 356 | 357 | uint32_t bs_imageIndexContainingAddress(const uintptr_t address) { 358 | const uint32_t imageCount = _dyld_image_count(); 359 | const struct mach_header* header = 0; 360 | 361 | for(uint32_t iImg = 0; iImg < imageCount; iImg++) { 362 | header = _dyld_get_image_header(iImg); 363 | if(header != NULL) { 364 | // Look for a segment command with this address within its range. 365 | uintptr_t addressWSlide = address - (uintptr_t)_dyld_get_image_vmaddr_slide(iImg); 366 | uintptr_t cmdPtr = bs_firstCmdAfterHeader(header); 367 | if(cmdPtr == 0) { 368 | continue; 369 | } 370 | for(uint32_t iCmd = 0; iCmd < header->ncmds; iCmd++) { 371 | const struct load_command* loadCmd = (struct load_command*)cmdPtr; 372 | if(loadCmd->cmd == LC_SEGMENT) { 373 | const struct segment_command* segCmd = (struct segment_command*)cmdPtr; 374 | if(addressWSlide >= segCmd->vmaddr && 375 | addressWSlide < segCmd->vmaddr + segCmd->vmsize) { 376 | return iImg; 377 | } 378 | } 379 | else if(loadCmd->cmd == LC_SEGMENT_64) { 380 | const struct segment_command_64* segCmd = (struct segment_command_64*)cmdPtr; 381 | if(addressWSlide >= segCmd->vmaddr && 382 | addressWSlide < segCmd->vmaddr + segCmd->vmsize) { 383 | return iImg; 384 | } 385 | } 386 | cmdPtr += loadCmd->cmdsize; 387 | } 388 | } 389 | } 390 | return UINT_MAX; 391 | } 392 | 393 | uintptr_t bs_segmentBaseOfImageIndex(const uint32_t idx) { 394 | const struct mach_header* header = _dyld_get_image_header(idx); 395 | 396 | // Look for a segment command and return the file image address. 397 | uintptr_t cmdPtr = bs_firstCmdAfterHeader(header); 398 | if(cmdPtr == 0) { 399 | return 0; 400 | } 401 | for(uint32_t i = 0;i < header->ncmds; i++) { 402 | const struct load_command* loadCmd = (struct load_command*)cmdPtr; 403 | if(loadCmd->cmd == LC_SEGMENT) { 404 | const struct segment_command* segmentCmd = (struct segment_command*)cmdPtr; 405 | if(strcmp(segmentCmd->segname, SEG_LINKEDIT) == 0) { 406 | return segmentCmd->vmaddr - segmentCmd->fileoff; 407 | } 408 | } 409 | else if(loadCmd->cmd == LC_SEGMENT_64) { 410 | const struct segment_command_64* segmentCmd = (struct segment_command_64*)cmdPtr; 411 | if(strcmp(segmentCmd->segname, SEG_LINKEDIT) == 0) { 412 | return (uintptr_t)(segmentCmd->vmaddr - segmentCmd->fileoff); 413 | } 414 | } 415 | cmdPtr += loadCmd->cmdsize; 416 | } 417 | return 0; 418 | } 419 | 420 | @end 421 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Tools/LLDBTools.mm: -------------------------------------------------------------------------------- 1 | // weibo: http://weibo.com/xiaoqing28 2 | // blog: http://www.alonemonkey.com 3 | // 4 | // LLDBTools.m 5 | // MonkeyDev 6 | // 7 | // Created by AloneMonkey on 2018/3/8. 8 | // Copyright © 2018年 AloneMonkey. All rights reserved. 9 | // 10 | 11 | #pragma GCC diagnostic ignored "-Wundeclared-selector" 12 | 13 | #import "LLDBTools.h" 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | 21 | enum { 22 | BLOCK_HAS_COPY_DISPOSE = (1 << 25), 23 | BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code 24 | BLOCK_IS_GLOBAL = (1 << 28), 25 | BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE 26 | BLOCK_HAS_SIGNATURE = (1 << 30), 27 | }; 28 | 29 | struct Block_literal_1 { 30 | void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock 31 | int flags; 32 | int reserved; 33 | void (*invoke)(void *, ...); 34 | struct Block_descriptor_1 { 35 | unsigned long int reserved; // NULL 36 | unsigned long int size; // sizeof(struct Block_literal_1) 37 | // optional helper functions 38 | void (*copy_helper)(void *dst, void *src); // IFF (1<<25) 39 | void (*dispose_helper)(void *src); // IFF (1<<25) 40 | // required ABI.2010.3.16 41 | const char *signature; // IFF (1<<30) 42 | } *descriptor; 43 | // imported variables 44 | }; 45 | 46 | NSString* decode(NSString* code); 47 | NSArray* choose_inner(const char * classname); 48 | char * protection_bits_to_rwx (vm_prot_t p); 49 | const char * unparse_inheritance (vm_inherit_t i); 50 | char * behavior_to_text (vm_behavior_t b); 51 | 52 | NSString* decode(NSString* code){ 53 | NSDictionary * encodeMap = @{ 54 | @"c": @"char", 55 | @"i": @"int", 56 | @"s": @"short", 57 | @"l": @"long", 58 | @"q": @"long long", 59 | 60 | @"C": @"unsigned char", 61 | @"I": @"unsigned int", 62 | @"S": @"unsigned short", 63 | @"L": @"unsigned long", 64 | @"Q": @"unsigned long long", 65 | 66 | @"f": @"float", 67 | @"d": @"double", 68 | @"B": @"bool", 69 | @"v": @"void", 70 | @"*": @"char *", 71 | @"@": @"id", 72 | @"#": @"Class", 73 | @":": @"SEL" 74 | }; 75 | 76 | if(encodeMap[code]){ 77 | return encodeMap[code]; 78 | }else if([code characterAtIndex:0] == '@'){ 79 | if([code characterAtIndex:1] == '?'){ 80 | return code; 81 | }else if([code characterAtIndex:2] == '<'){ 82 | return [NSString stringWithFormat:@"id%@", [[code substringWithRange:NSMakeRange(2, code.length-3)] stringByReplacingOccurrencesOfString:@"><" withString:@", "]]; 83 | }else{ 84 | return [NSString stringWithFormat:@"%@ *", [code substringWithRange:NSMakeRange(2, code.length-3)]]; 85 | } 86 | }else if([code characterAtIndex:0] == '^'){ 87 | return [NSString stringWithFormat:@"%@ *", decode([code substringFromIndex:1])]; 88 | } 89 | return code; 90 | } 91 | 92 | NSString* pvc(){ 93 | return [[[UIWindow performSelector:@selector(keyWindow)] performSelector:@selector(rootViewController)] performSelector:@selector(_printHierarchy)]; 94 | } 95 | 96 | NSString* pviews(){ 97 | return [[[UIApplication sharedApplication] keyWindow] performSelector:@selector(recursiveDescription)]; 98 | } 99 | 100 | NSString* pactions(vm_address_t address){ 101 | NSMutableString* result = [NSMutableString new]; 102 | UIControl* control = (__bridge UIControl*)(void*)address; 103 | NSArray* targets = [[control allTargets] allObjects]; 104 | for (id item in targets) { 105 | NSArray* actions = [control actionsForTarget:item forControlEvent:0]; 106 | [result appendFormat:@"<%s: 0x%lx>: %@\n", object_getClassName(item), (unsigned long)item, [actions componentsJoinedByString:@","]]; 107 | } 108 | return result; 109 | } 110 | 111 | NSString* pblock(vm_address_t address){ 112 | struct Block_literal_1 real = *((struct Block_literal_1 *)(void*)address); 113 | NSMutableDictionary *dict = (id)[NSMutableDictionary dictionary]; 114 | [dict setObject:(id)[NSNumber numberWithLong:(long)real.invoke] forKey:@"invoke"]; 115 | if (real.flags & BLOCK_HAS_SIGNATURE) { 116 | char *signature; 117 | if (real.flags & BLOCK_HAS_COPY_DISPOSE) { 118 | signature = (char *)(real.descriptor)->signature; 119 | } else { 120 | signature = (char *)(real.descriptor)->copy_helper; 121 | } 122 | 123 | NSMethodSignature *sig = [NSMethodSignature signatureWithObjCTypes:signature]; 124 | NSMutableArray *types = [NSMutableArray array]; 125 | 126 | [types addObject:(id)[NSString stringWithUTF8String:(char *)[sig methodReturnType]]]; 127 | 128 | for (NSUInteger i = 0; i < sig.numberOfArguments; i++) { 129 | char *type = (char *)[sig getArgumentTypeAtIndex:i]; 130 | [types addObject:(id)[NSString stringWithUTF8String:type]]; 131 | } 132 | 133 | [dict setObject:types forKey:@"signature"]; 134 | } 135 | 136 | NSMutableArray* sigArr = dict[@"signature"]; 137 | 138 | if(!sigArr){ 139 | return [NSString stringWithFormat:@"Imp: 0x%lx", (long)dict[@"invoke"]]; 140 | }else{ 141 | NSMutableString* sig = [NSMutableString stringWithFormat:@"%@ ^(", decode(sigArr[0])]; 142 | for (int i = 2; i < sigArr.count; i++) { 143 | if(i == sigArr.count - 1){ 144 | [sig appendFormat:@"%@", decode(sigArr[i])]; 145 | }else{ 146 | [sig appendFormat:@"%@ ,", decode(sigArr[i])]; 147 | } 148 | } 149 | [sig appendString:@");"]; 150 | return [NSString stringWithFormat:@"Imp: 0x%lx Signature: %s", (long)dict[@"invoke"], [sig UTF8String]]; 151 | } 152 | } 153 | 154 | struct CYChoice { 155 | std::set query_; 156 | std::set results_; 157 | }; 158 | 159 | struct CYObjectStruct { 160 | Class isa_; 161 | }; 162 | 163 | static void choose_(task_t task, void *baton, unsigned type, vm_range_t *ranges, unsigned count) { 164 | CYChoice *choice(reinterpret_cast(baton)); 165 | 166 | for (unsigned i(0); i != count; ++i) { 167 | vm_range_t &range(ranges[i]); 168 | void *data(reinterpret_cast(range.address)); 169 | size_t size(range.size); 170 | 171 | if (size < sizeof(CYObjectStruct)) 172 | continue; 173 | 174 | uintptr_t *pointers(reinterpret_cast(data)); 175 | #ifdef __arm64__ 176 | Class isa = (__bridge Class)((void *)(pointers[0] & 0x1fffffff8)); 177 | #else 178 | Class isa =(__bridge Class)(void *)pointers[0]; 179 | #endif 180 | std::set::const_iterator result(choice->query_.find(isa)); 181 | if (result == choice->query_.end()) 182 | continue; 183 | 184 | size_t needed(class_getInstanceSize(*result)); 185 | // XXX: if (size < needed) 186 | 187 | size_t boundary(496); 188 | #ifdef __LP64__ 189 | boundary *= 2; 190 | #endif 191 | if ((needed <= boundary && (needed + 15) / 16 * 16 != size) || (needed > boundary && (needed + 511) / 512 * 512 != size)) 192 | continue; 193 | choice->results_.insert((__bridge id)(data)); 194 | } 195 | } 196 | 197 | static Class *CYCopyClassList(size_t &size) { 198 | size = objc_getClassList(NULL, 0); 199 | Class *data(reinterpret_cast(malloc(sizeof(Class) * size))); 200 | 201 | for (;;) { 202 | size_t writ(objc_getClassList(data, (int)size)); 203 | if (writ <= size) { 204 | size = writ; 205 | return data; 206 | } 207 | 208 | Class *copy(reinterpret_cast(realloc(data, sizeof(Class) * writ))); 209 | if (copy == NULL) { 210 | free(data); 211 | return NULL; 212 | } 213 | 214 | data = copy; 215 | size = writ; 216 | } 217 | } 218 | 219 | static kern_return_t CYReadMemory(task_t task, vm_address_t address, vm_size_t size, void **data) { 220 | *data = reinterpret_cast(address); 221 | return KERN_SUCCESS; 222 | } 223 | 224 | NSArray* choose_inner(const char * classname){ 225 | 226 | Class _class = NSClassFromString([NSString stringWithUTF8String:classname]); 227 | 228 | vm_address_t *zones = NULL; 229 | unsigned size = 0; 230 | //获取所有的zone信息 堆上的区域 231 | kern_return_t error = malloc_get_all_zones(mach_task_self(), &CYReadMemory, &zones, &size); 232 | assert(error == KERN_SUCCESS); 233 | 234 | size_t number; 235 | Class *classes(CYCopyClassList(number)); 236 | assert(classes != NULL); 237 | 238 | CYChoice choice; 239 | 240 | //找到目标Class 241 | for (size_t i(0); i != number; ++i) 242 | for (Class current(classes[i]); current != Nil; current = class_getSuperclass(current)) 243 | if (current == _class) { 244 | choice.query_.insert(classes[i]); 245 | break; 246 | } 247 | 248 | for (unsigned i(0); i != size; ++i) { 249 | const malloc_zone_t *zone(reinterpret_cast(zones[i])); 250 | if (zone == NULL || zone->introspect == NULL) 251 | continue; 252 | 253 | //枚举堆上的对象 254 | zone->introspect->enumerator(mach_task_self(), &choice, MALLOC_PTR_IN_USE_RANGE_TYPE, zones[i], &CYReadMemory, &choose_); 255 | } 256 | NSMutableArray * result = [[NSMutableArray alloc] init]; 257 | 258 | for (auto iter = choice.results_.begin(); iter != choice.results_.end(); iter++) { 259 | [result addObject:(id)*iter]; 260 | } 261 | return result; 262 | } 263 | 264 | NSString* choose(const char* classname){ 265 | NSMutableString* result = [NSMutableString new]; 266 | NSArray* results = choose_inner(classname); 267 | [result appendFormat:@"Find %lu instance objects in memory!\n" , (unsigned long)results.count]; 268 | for (id item in results) { 269 | [result appendFormat:@"<%s: 0x%llx>\n", object_getClassName(item), (long long)item]; 270 | } 271 | return result; 272 | } 273 | 274 | NSString* methods(const char * classname){ 275 | return [objc_getClass(classname) performSelector:@selector(_shortMethodDescription)]; 276 | } 277 | 278 | NSString* ivars(vm_address_t address){ 279 | id target = (__bridge id)(void*)address; 280 | return [target performSelector:@selector(_ivarDescription)]; 281 | } 282 | 283 | char * protection_bits_to_rwx (vm_prot_t p){ 284 | static char returned[4]; 285 | 286 | returned[0] = (p & VM_PROT_READ ? 'r' : '-'); 287 | returned[1] = (p & VM_PROT_WRITE ? 'w' : '-'); 288 | returned[2] = (p & VM_PROT_EXECUTE ? 'x' : '-'); 289 | returned[3] = '\0'; 290 | 291 | // memory leak here. No biggy 292 | return (strdup(returned)); 293 | } 294 | 295 | const char * unparse_inheritance (vm_inherit_t i){ 296 | switch (i){ 297 | case VM_INHERIT_SHARE: 298 | return "share"; 299 | case VM_INHERIT_COPY: 300 | return "copy"; 301 | case VM_INHERIT_NONE: 302 | return "none"; 303 | default: 304 | return "???"; 305 | } 306 | } 307 | 308 | char * behavior_to_text (vm_behavior_t b){ 309 | switch (b){ 310 | case VM_BEHAVIOR_DEFAULT: return((char*)"default"); 311 | case VM_BEHAVIOR_RANDOM: return((char*)"random"); 312 | case VM_BEHAVIOR_SEQUENTIAL: return((char*)"fwd-seq"); 313 | case VM_BEHAVIOR_RSEQNTL: return((char*)"rev-seq"); 314 | case VM_BEHAVIOR_WILLNEED: return((char*)"will-need"); 315 | case VM_BEHAVIOR_DONTNEED: return((char*)"will-need"); 316 | case VM_BEHAVIOR_FREE: return((char*)"free-nowb"); 317 | case VM_BEHAVIOR_ZERO_WIRED_PAGES: return((char*)"zero-wire"); 318 | case VM_BEHAVIOR_REUSABLE: return((char*)"reusable"); 319 | case VM_BEHAVIOR_REUSE: return((char*)"reuse"); 320 | case VM_BEHAVIOR_CAN_REUSE: return((char*)"canreuse"); 321 | default: return ((char*)"?"); 322 | } 323 | } 324 | 325 | __BEGIN_DECLS 326 | 327 | extern kern_return_t mach_vm_region 328 | ( 329 | vm_map_t target_task, 330 | mach_vm_address_t *address, 331 | mach_vm_size_t *size, 332 | vm_region_flavor_t flavor, 333 | vm_region_info_t info, 334 | mach_msg_type_number_t *infoCnt, 335 | mach_port_t *object_name 336 | ); 337 | 338 | __END_DECLS 339 | 340 | NSString* vmmap(){ 341 | vm_region_basic_info_data_t info, prev_info; 342 | mach_vm_address_t address = 1, prev_address; 343 | mach_vm_size_t size, prev_size; 344 | mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; 345 | mach_port_t object_name; 346 | 347 | int nsubregions = 0; 348 | kern_return_t kr = mach_vm_region(mach_task_self(), &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object_name); 349 | 350 | NSMutableString* result = [[NSMutableString alloc] init]; 351 | 352 | if(kr != KERN_SUCCESS){ 353 | [result appendFormat:@"mach_vm_region: Error %d - %s", kr, mach_error_string(kr)]; 354 | return [result copy]; 355 | } 356 | 357 | //保存之前查到的info 358 | memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t)); 359 | prev_address = address; 360 | prev_size = size; 361 | nsubregions = 1; 362 | 363 | while (true) { 364 | int print = 0, done = 0; 365 | 366 | address = prev_address + prev_size; 367 | 368 | if (address == 0){ 369 | print = done = 1; 370 | } 371 | 372 | if (!done){ 373 | kr = mach_vm_region (mach_task_self(), &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object_name); 374 | 375 | if (kr != KERN_SUCCESS){ 376 | [result appendFormat:@"mach_vm_region failed for address %llu - Error: %x\n",address, (kr)]; 377 | print = done = 1; 378 | } 379 | } 380 | 381 | //等于才是连续的内存,不等于才打印 382 | if (address != prev_address + prev_size) 383 | print = 1; 384 | 385 | //或者权限信息改变了也打印 386 | if ((info.protection != prev_info.protection) 387 | || (info.max_protection != prev_info.max_protection) 388 | || (info.inheritance != prev_info.inheritance) 389 | || (info.shared != prev_info.reserved) 390 | || (info.reserved != prev_info.reserved)) 391 | print = 1; 392 | 393 | if (print){ 394 | char *print_size_unit = NULL; 395 | 396 | mach_vm_size_t print_size = prev_size; 397 | if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"K"; } 398 | if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"M"; } 399 | if (print_size > 1024) { print_size /= 1024; print_size_unit = (char*)"G"; } 400 | 401 | [result appendFormat:@" %p-%p [%llu%s](%s/%s; %s, %s, %s) %s", 402 | (void*)(prev_address), 403 | (void*)(prev_address + prev_size), 404 | print_size, 405 | print_size_unit, 406 | protection_bits_to_rwx (prev_info.protection), 407 | protection_bits_to_rwx (prev_info.max_protection), 408 | unparse_inheritance (prev_info.inheritance), 409 | prev_info.shared ? "shared" : "private", 410 | prev_info.reserved ? "reserved" : "not-reserved", 411 | behavior_to_text (prev_info.behavior)]; 412 | 413 | if (nsubregions > 1) 414 | [result appendFormat:@" (%d sub-regions)", nsubregions]; 415 | 416 | [result appendFormat:@"\n"]; 417 | prev_address = address; 418 | prev_size = size; 419 | memcpy (&prev_info, &info, sizeof (vm_region_basic_info_data_t)); 420 | nsubregions = 1; 421 | }else{ 422 | prev_size += size; 423 | nsubregions++; 424 | } 425 | 426 | if (done) 427 | break; 428 | } 429 | return [result copy]; 430 | } 431 | 432 | 433 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Config/ANYMethodLog.m: -------------------------------------------------------------------------------- 1 | // 2 | // ANYMethodLog.m 3 | // ANYMethodLog 4 | // 5 | // Created by qiuhaodong on 2017/1/14. 6 | // Copyright © 2017年 qiuhaodong. All rights reserved. 7 | // 8 | // https://github.com/qhd/ANYMethodLog.git 9 | // 10 | 11 | /*经实践打印出不同类型占的长度,放此以方便调试查看 12 | +---------------------------+------------+------------+--------+ 13 | | type | value(32) | value(64) | comp | 14 | |---------------------------|------------|------------|--------| 15 | | sizeof(char) | 1 | 1 | | 16 | |---------------------------|------------|------------|--------| 17 | | sizeof(int) | 4 | 4 | | 18 | |---------------------------|------------|------------|--------| 19 | | sizeof(short) | 2 | 2 | | 20 | |---------------------------|------------|------------|--------| 21 | | sizeof(long) | 4 | 8 | * | 22 | |---------------------------|------------|------------|--------| 23 | | sizeof(long long) | 8 | 8 | | 24 | |---------------------------|------------|------------|--------| 25 | | sizeof(unsigned char) | 1 | 1 | | 26 | |---------------------------|------------|------------|--------| 27 | | sizeof(unsigned int) | 4 | 4 | | 28 | |---------------------------|------------|------------|--------| 29 | | sizeof(unsigned short) | 2 | 2 | | 30 | |---------------------------|------------|------------|--------| 31 | | sizeof(unsigned long) | 4 | 8 | * | 32 | |---------------------------|------------|------------|--------| 33 | | sizeof(unsigned long long)| 8 | 8 | | 34 | |---------------------------|------------|------------|--------| 35 | | sizeof(float) | 4 | 4 | | 36 | |---------------------------|------------|------------|--------| 37 | | sizeof(double) | 8 | 8 | | 38 | |---------------------------|------------|------------|--------| 39 | | sizeof(BOOL) | 1 | 1 | | 40 | |---------------------------|------------|------------|--------| 41 | | sizeof(void) | 1 | 1 | | 42 | |---------------------------|------------|------------|--------| 43 | | sizeof(char*) | 4 | 8 | * | 44 | |---------------------------|------------|------------|--------| 45 | | sizeof(id) | 4 | 8 | * | 46 | |---------------------------|------------|------------|--------| 47 | | sizeof(Class) | 4 | 8 | * | 48 | |---------------------------|------------|------------|--------| 49 | | sizeof(SEL) | 4 | 8 | * | 50 | +---------------------------+------------+------------+--------+ 51 | */ 52 | 53 | #import "ANYMethodLog.h" 54 | #import 55 | #import 56 | #import 57 | 58 | #pragma mark - deep 59 | 60 | //调用层次 61 | static int deep = -1; 62 | 63 | #pragma mark - Func Define 64 | 65 | BOOL qhd_isInBlackList(NSString *methodName); 66 | NSDictionary *qhd_canHandleTypeDic(void); 67 | BOOL qhd_isCanHandle(NSString *typeEncode); 68 | SEL qhd_createNewSelector(SEL originalSelector); 69 | BOOL qhd_isStructType(const char *argumentType); 70 | NSString *qhd_structName(const char *argumentType); 71 | BOOL isCGRect (const char *type); 72 | BOOL isCGPoint (const char *type); 73 | BOOL isCGSize (const char *type); 74 | BOOL isCGVector (const char *type); 75 | BOOL isUIOffset (const char *type); 76 | BOOL isUIEdgeInsets (const char *type); 77 | BOOL isCGAffineTransform(const char *type); 78 | BOOL qhd_isCanHook(Method method, const char *returnType); 79 | id getReturnValue(NSInvocation *invocation); 80 | NSArray *qhd_method_arguments(NSInvocation *invocation); 81 | void qhd_forwardInvocation(id target, SEL selector, NSInvocation *invocation); 82 | BOOL qhd_replaceMethod(Class cls, SEL originSelector, char *returnType); 83 | void qhd_logMethod(Class aClass, BOOL(^condition)(SEL sel)); 84 | 85 | #pragma mark - AMLBlock 86 | 87 | @interface AMLBlock : NSObject 88 | 89 | @property (strong, nonatomic) NSString *targetClassName; 90 | @property (copy, nonatomic) ConditionBlock condition; 91 | @property (copy, nonatomic) BeforeBlock before; 92 | @property (copy, nonatomic) AfterBlock after; 93 | 94 | @end 95 | 96 | @implementation AMLBlock 97 | 98 | - (BOOL)runCondition:(SEL)sel { 99 | if (self.condition) { 100 | return self.condition(sel); 101 | } else { 102 | return YES; 103 | } 104 | } 105 | 106 | - (void)rundBefore:(id)target sel:(SEL)sel args:(NSArray *)args deep:(int) deep { 107 | if (self.before) { 108 | self.before(target, sel, args, deep); 109 | } 110 | } 111 | 112 | - (void)rundAfter:(id)target sel:(SEL)sel args:(NSArray *)args interval:(NSTimeInterval)interval deep:(int)deep retValue:(id)retValue{ 113 | if (self.after) { 114 | self.after(target, sel, args, interval, deep, retValue); 115 | } 116 | } 117 | 118 | @end 119 | 120 | 121 | #pragma mark - ANYMethodLog private interface 122 | 123 | @interface ANYMethodLog() 124 | 125 | @property (strong, nonatomic) NSMutableDictionary *blockCache; 126 | 127 | + (instancetype)sharedANYMethodLog; 128 | 129 | - (void)setAMLBlock:(AMLBlock *)block forKey:(NSString *)aKey; 130 | 131 | - (AMLBlock *)blockWithTarget:(id)target; 132 | 133 | @end 134 | 135 | 136 | #pragma mark - C function 137 | 138 | #define SHARED_ANYMETHODLOG [ANYMethodLog sharedANYMethodLog] 139 | 140 | //#define OPEN_TARGET_LOG 141 | 142 | #ifdef OPEN_TARGET_LOG 143 | #define TARGET_LOG(format, ...) NSLog(format, ## __VA_ARGS__) 144 | #else 145 | #define TARGET_LOG(format, ...) 146 | #endif 147 | 148 | 149 | //#define OPEN_DEV_LOG 150 | 151 | #ifdef OPEN_DEV_LOG 152 | #define DEV_LOG(format, ...) NSLog(format, ## __VA_ARGS__) 153 | #else 154 | #define DEV_LOG(format, ...) 155 | #endif 156 | 157 | //是否在默认的黑名单中 158 | BOOL qhd_isInBlackList(NSString *methodName) { 159 | static NSArray *defaultBlackList = nil; 160 | static dispatch_once_t onceToken; 161 | dispatch_once(&onceToken, ^{ 162 | defaultBlackList = @[/*UIViewController的:*/@".cxx_destruct", @"dealloc", @"_isDeallocating", @"release", @"autorelease", @"retain", @"Retain", @"_tryRetain", @"copy", /*UIView的:*/ @"nsis_descriptionOfVariable:", /*NSObject的:*/@"respondsToSelector:", @"class", @"methodSignatureForSelector:", @"allowsWeakReference", @"retainWeakReference", @"init", @"forwardInvocation:"]; 163 | }); 164 | return ([defaultBlackList containsObject:methodName]); 165 | } 166 | 167 | /*reference: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1 168 | 经实践发现与文档有差别 169 | 1.在64位时@encode(long)跟@encode(long long)的值一样; 170 | 2.在64位时@encode(unsigned long)跟@encode(unsigned long long)的值一样; 171 | 3.在32位时@encode(BOOL)跟@encode(char)一样。 172 | +--------------------+-----------+-----------+ 173 | | type |code(32bit)|code(64bit)| 174 | |--------------------|-----------|-----------| 175 | | BOOL | c | B | 176 | |--------------------|-----------|-----------| 177 | | char | c | c | 178 | |--------------------|-----------|-----------| 179 | | long | l | q | 180 | |--------------------|-----------|-----------| 181 | | long long | q | q | 182 | |--------------------|-----------|-----------| 183 | | unsigned long | L | Q | 184 | |--------------------|-----------|-----------| 185 | | unsigned long long | Q | Q | 186 | +--------------------+-----------+-----------+ 187 | */ 188 | NSDictionary *qhd_canHandleTypeDic() { 189 | static NSDictionary *dic = nil; 190 | static dispatch_once_t onceToken; 191 | dispatch_once(&onceToken, ^{ 192 | dic = @{[NSString stringWithUTF8String:@encode(char)] : @"(char)", 193 | [NSString stringWithUTF8String:@encode(int)] : @"(int)", 194 | [NSString stringWithUTF8String:@encode(short)] : @"(short)", 195 | [NSString stringWithUTF8String:@encode(long)] : @"(long)", 196 | [NSString stringWithUTF8String:@encode(long long)] : @"(long long)", 197 | [NSString stringWithUTF8String:@encode(unsigned char)] : @"(unsigned char))", 198 | [NSString stringWithUTF8String:@encode(unsigned int)] : @"(unsigned int)", 199 | [NSString stringWithUTF8String:@encode(unsigned short)] : @"(unsigned short)", 200 | [NSString stringWithUTF8String:@encode(unsigned long)] : @"(unsigned long)", 201 | [NSString stringWithUTF8String:@encode(unsigned long long)] : @"(unsigned long long)", 202 | [NSString stringWithUTF8String:@encode(float)] : @"(float)", 203 | [NSString stringWithUTF8String:@encode(double)] : @"(double)", 204 | [NSString stringWithUTF8String:@encode(BOOL)] : @"(BOOL)", 205 | [NSString stringWithUTF8String:@encode(void)] : @"(void)", 206 | [NSString stringWithUTF8String:@encode(char *)] : @"(char *)", 207 | [NSString stringWithUTF8String:@encode(id)] : @"(id)", 208 | [NSString stringWithUTF8String:@encode(Class)] : @"(Class)", 209 | [NSString stringWithUTF8String:@encode(SEL)] : @"(SEL)", 210 | [NSString stringWithUTF8String:@encode(CGRect)] : @"(CGRect)", 211 | [NSString stringWithUTF8String:@encode(CGPoint)] : @"(CGPoint)", 212 | [NSString stringWithUTF8String:@encode(CGSize)] : @"(CGSize)", 213 | [NSString stringWithUTF8String:@encode(CGVector)] : @"(CGVector)", 214 | [NSString stringWithUTF8String:@encode(CGAffineTransform)] : @"(CGAffineTransform)", 215 | [NSString stringWithUTF8String:@encode(UIOffset)] : @"(UIOffset)", 216 | [NSString stringWithUTF8String:@encode(UIEdgeInsets)] : @"(UIEdgeInsets)", 217 | @"@?":@"(block)" // block类型 218 | };//TODO:添加其他类型 219 | }); 220 | return dic; 221 | } 222 | 223 | //根据定义的类型的判断是否能处理 224 | BOOL qhd_isCanHandle(NSString *typeEncode) { 225 | return [qhd_canHandleTypeDic().allKeys containsObject:typeEncode]; 226 | } 227 | 228 | //创建一个新的selector 229 | SEL qhd_createNewSelector(SEL originalSelector) { 230 | NSString *oldSelectorName = NSStringFromSelector(originalSelector); 231 | NSString *newSelectorName = [NSString stringWithFormat:@"qhd_%@", oldSelectorName]; 232 | SEL newSelector = NSSelectorFromString(newSelectorName); 233 | return newSelector; 234 | } 235 | 236 | //是否struct类型 237 | BOOL qhd_isStructType(const char *argumentType) { 238 | NSString *typeString = [NSString stringWithUTF8String:argumentType]; 239 | return ([typeString hasPrefix:@"{"] && [typeString hasSuffix:@"}"]); 240 | } 241 | 242 | //struct类型名 243 | NSString *qhd_structName(const char *argumentType) { 244 | NSString *typeString = [NSString stringWithUTF8String:argumentType]; 245 | NSUInteger start = [typeString rangeOfString:@"{"].location; 246 | NSUInteger end = [typeString rangeOfString:@"="].location; 247 | if (end > start) { 248 | return [typeString substringWithRange:NSMakeRange(start + 1, end - start - 1)]; 249 | } else { 250 | return nil; 251 | } 252 | } 253 | 254 | BOOL isCGRect (const char *type) {return [qhd_structName(type) isEqualToString:@"CGRect"];} 255 | BOOL isCGPoint (const char *type) {return [qhd_structName(type) isEqualToString:@"CGPoint"];} 256 | BOOL isCGSize (const char *type) {return [qhd_structName(type) isEqualToString:@"CGSize"];} 257 | BOOL isCGVector (const char *type) {return [qhd_structName(type) isEqualToString:@"CGVector"];} 258 | BOOL isUIOffset (const char *type) {return [qhd_structName(type) isEqualToString:@"UIOffset"];} 259 | BOOL isUIEdgeInsets (const char *type) {return [qhd_structName(type) isEqualToString:@"UIEdgeInsets"];} 260 | BOOL isCGAffineTransform(const char *type) {return [qhd_structName(type) isEqualToString:@"CGAffineTransform"];} 261 | 262 | //检查是否能处理 263 | BOOL qhd_isCanHook(Method method, const char *returnType) { 264 | 265 | //若在黑名单中则不处理 266 | NSString *selectorName = NSStringFromSelector(method_getName(method)); 267 | if (qhd_isInBlackList(selectorName)) { 268 | return NO; 269 | } 270 | 271 | if ([selectorName rangeOfString:@"qhd_"].location != NSNotFound) { 272 | return NO; 273 | } 274 | 275 | NSString *returnTypeString = [NSString stringWithUTF8String:returnType]; 276 | 277 | BOOL isCanHook = YES; 278 | if (!qhd_isCanHandle(returnTypeString)) { 279 | isCanHook = NO; 280 | } 281 | for(int k = 2 ; k < method_getNumberOfArguments(method); k ++) { 282 | char argument[250]; 283 | memset(argument, 0, sizeof(argument)); 284 | method_getArgumentType(method, k, argument, sizeof(argument)); 285 | NSString *argumentString = [NSString stringWithUTF8String:argument]; 286 | if (!qhd_isCanHandle(argumentString)) { 287 | isCanHook = NO; 288 | break; 289 | } 290 | } 291 | return isCanHook; 292 | } 293 | 294 | //获取方法返回值 295 | id getReturnValue(NSInvocation *invocation){ 296 | const char *returnType = invocation.methodSignature.methodReturnType; 297 | if (returnType[0] == 'r') { 298 | returnType++; 299 | } 300 | #define WRAP_GET_VALUE(type) \ 301 | do { \ 302 | type val = 0; \ 303 | [invocation getReturnValue:&val]; \ 304 | return @(val); \ 305 | } while (0) 306 | if (strcmp(returnType, @encode(id)) == 0 || strcmp(returnType, @encode(Class)) == 0 || strcmp(returnType, @encode(void (^)(void))) == 0) { 307 | __autoreleasing id returnObj; 308 | [invocation getReturnValue:&returnObj]; 309 | return returnObj; 310 | } else if (strcmp(returnType, @encode(char)) == 0) { 311 | WRAP_GET_VALUE(char); 312 | } else if (strcmp(returnType, @encode(int)) == 0) { 313 | WRAP_GET_VALUE(int); 314 | } else if (strcmp(returnType, @encode(short)) == 0) { 315 | WRAP_GET_VALUE(short); 316 | } else if (strcmp(returnType, @encode(long)) == 0) { 317 | WRAP_GET_VALUE(long); 318 | } else if (strcmp(returnType, @encode(long long)) == 0) { 319 | WRAP_GET_VALUE(long long); 320 | } else if (strcmp(returnType, @encode(unsigned char)) == 0) { 321 | WRAP_GET_VALUE(unsigned char); 322 | } else if (strcmp(returnType, @encode(unsigned int)) == 0) { 323 | WRAP_GET_VALUE(unsigned int); 324 | } else if (strcmp(returnType, @encode(unsigned short)) == 0) { 325 | WRAP_GET_VALUE(unsigned short); 326 | } else if (strcmp(returnType, @encode(unsigned long)) == 0) { 327 | WRAP_GET_VALUE(unsigned long); 328 | } else if (strcmp(returnType, @encode(unsigned long long)) == 0) { 329 | WRAP_GET_VALUE(unsigned long long); 330 | } else if (strcmp(returnType, @encode(float)) == 0) { 331 | WRAP_GET_VALUE(float); 332 | } else if (strcmp(returnType, @encode(double)) == 0) { 333 | WRAP_GET_VALUE(double); 334 | } else if (strcmp(returnType, @encode(BOOL)) == 0) { 335 | WRAP_GET_VALUE(BOOL); 336 | } else if (strcmp(returnType, @encode(char *)) == 0) { 337 | WRAP_GET_VALUE(const char *); 338 | } else if (strcmp(returnType, @encode(void)) == 0) { 339 | return @"void"; 340 | } else { 341 | NSUInteger valueSize = 0; 342 | NSGetSizeAndAlignment(returnType, &valueSize, NULL); 343 | unsigned char valueBytes[valueSize]; 344 | [invocation getReturnValue:valueBytes]; 345 | 346 | return [NSValue valueWithBytes:valueBytes objCType:returnType]; 347 | } 348 | return nil; 349 | } 350 | 351 | //获取方法参数 352 | NSArray *qhd_method_arguments(NSInvocation *invocation) { 353 | NSMethodSignature *methodSignature = [invocation methodSignature]; 354 | NSMutableArray *argList = (methodSignature.numberOfArguments > 2 ? [NSMutableArray array] : nil); 355 | for (NSUInteger i = 2; i < methodSignature.numberOfArguments; i++) { 356 | const char *argumentType = [methodSignature getArgumentTypeAtIndex:i]; 357 | id arg = nil; 358 | 359 | if (qhd_isStructType(argumentType)) { 360 | #define GET_STRUCT_ARGUMENT(_type)\ 361 | if (is##_type(argumentType)) {\ 362 | _type arg_temp;\ 363 | [invocation getArgument:&arg_temp atIndex:i];\ 364 | arg = NSStringFrom##_type(arg_temp);\ 365 | } 366 | GET_STRUCT_ARGUMENT(CGRect) 367 | else GET_STRUCT_ARGUMENT(CGPoint) 368 | else GET_STRUCT_ARGUMENT(CGSize) 369 | else GET_STRUCT_ARGUMENT(CGVector) 370 | else GET_STRUCT_ARGUMENT(UIOffset) 371 | else GET_STRUCT_ARGUMENT(UIEdgeInsets) 372 | else GET_STRUCT_ARGUMENT(CGAffineTransform) 373 | 374 | if (arg == nil) { 375 | arg = @"{unknown}"; 376 | } 377 | } 378 | #define GET_ARGUMENT(_type)\ 379 | if (0 == strcmp(argumentType, @encode(_type))) {\ 380 | _type arg_temp;\ 381 | [invocation getArgument:&arg_temp atIndex:i];\ 382 | arg = @(arg_temp);\ 383 | } 384 | else GET_ARGUMENT(char) 385 | else GET_ARGUMENT(int) 386 | else GET_ARGUMENT(short) 387 | else GET_ARGUMENT(long) 388 | else GET_ARGUMENT(long long) 389 | else GET_ARGUMENT(unsigned char) 390 | else GET_ARGUMENT(unsigned int) 391 | else GET_ARGUMENT(unsigned short) 392 | else GET_ARGUMENT(unsigned long) 393 | else GET_ARGUMENT(unsigned long long) 394 | else GET_ARGUMENT(float) 395 | else GET_ARGUMENT(double) 396 | else GET_ARGUMENT(BOOL) 397 | else if (0 == strcmp(argumentType, @encode(id))) { 398 | __unsafe_unretained id arg_temp; 399 | [invocation getArgument:&arg_temp atIndex:i]; 400 | arg = arg_temp; 401 | } 402 | else if (0 == strcmp(argumentType, @encode(SEL))) { 403 | SEL arg_temp; 404 | [invocation getArgument:&arg_temp atIndex:i]; 405 | arg = NSStringFromSelector(arg_temp); 406 | } 407 | else if (0 == strcmp(argumentType, @encode(char *))) { 408 | char *arg_temp; 409 | [invocation getArgument:&arg_temp atIndex:i]; 410 | arg = [NSString stringWithUTF8String:arg_temp]; 411 | } 412 | else if (0 == strcmp(argumentType, @encode(void *))) { 413 | void *arg_temp; 414 | [invocation getArgument:&arg_temp atIndex:i]; 415 | arg = (__bridge id _Nonnull)arg_temp; 416 | } 417 | else if (0 == strcmp(argumentType, @encode(Class))) { 418 | Class arg_temp; 419 | [invocation getArgument:&arg_temp atIndex:i]; 420 | arg = arg_temp; 421 | } 422 | 423 | if (!arg) { 424 | arg = @"unknown"; 425 | } 426 | [argList addObject:arg]; 427 | } 428 | return argList; 429 | } 430 | 431 | //forwardInvocation:方法的新IMP 432 | void qhd_forwardInvocation(id target, SEL selector, NSInvocation *invocation) { 433 | NSArray *argList = qhd_method_arguments(invocation); 434 | 435 | SEL originSelector = invocation.selector; 436 | 437 | NSString *originSelectorString = NSStringFromSelector(originSelector); 438 | 439 | //友盟的UMAOCTools会产生问题 440 | if ([originSelectorString rangeOfString:@"hook_"].location != NSNotFound) { 441 | return; 442 | } 443 | 444 | [invocation setSelector:qhd_createNewSelector(originSelector)]; 445 | [invocation setTarget:target]; 446 | 447 | deep++; 448 | 449 | AMLBlock *block = [SHARED_ANYMETHODLOG blockWithTarget:target]; 450 | [block rundBefore:target sel:originSelector args:argList deep:deep]; 451 | 452 | NSDate *start = [NSDate date]; 453 | 454 | [invocation invoke]; 455 | 456 | NSDate *end = [NSDate date]; 457 | NSTimeInterval interval = [end timeIntervalSinceDate:start]; 458 | 459 | [block rundAfter:target sel:originSelector args:argList interval:interval deep:deep retValue:getReturnValue(invocation)]; 460 | 461 | deep--; 462 | } 463 | 464 | //替换方法 465 | BOOL qhd_replaceMethod(Class cls, SEL originSelector, char *returnType) { 466 | Method originMethod = class_getInstanceMethod(cls, originSelector); 467 | if (originMethod == nil) { 468 | return NO; 469 | } 470 | const char *originTypes = method_getTypeEncoding(originMethod); 471 | IMP msgForwardIMP = _objc_msgForward; 472 | #if !defined(__arm64__) 473 | if (qhd_isStructType(returnType)) { 474 | //Reference JSPatch: 475 | //In some cases that returns struct, we should use the '_stret' API: 476 | //http://sealiesoftware.com/blog/archive/2008/10/30/objc_explain_objc_msgSend_stret.html 477 | //NSMethodSignature knows the detail but has no API to return, we can only get the info from debugDescription. 478 | NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:originTypes]; 479 | if ([methodSignature.debugDescription rangeOfString:@"is special struct return? YES"].location != NSNotFound) { 480 | msgForwardIMP = (IMP)_objc_msgForward_stret; 481 | } 482 | } 483 | #endif 484 | 485 | IMP originIMP = method_getImplementation(originMethod); 486 | 487 | if (originIMP == nil || originIMP == msgForwardIMP) { 488 | return NO; 489 | } 490 | 491 | //把原方法的IMP换成_objc_msgForward,使之触发forwardInvocation方法 492 | class_replaceMethod(cls, originSelector, msgForwardIMP, originTypes); 493 | 494 | //把方法forwardInvocation的IMP换成qhd_forwardInvocation 495 | class_replaceMethod(cls, @selector(forwardInvocation:), (IMP)qhd_forwardInvocation, "v@:@"); 496 | 497 | //创建一个新方法,IMP就是原方法的原来的IMP,那么只要在qhd_forwardInvocation调用新方法即可 498 | SEL newSelecotr = qhd_createNewSelector(originSelector); 499 | BOOL isAdd = class_addMethod(cls, newSelecotr, originIMP, originTypes); 500 | if (!isAdd) { 501 | DEV_LOG(@"class_addMethod fail"); 502 | } 503 | 504 | return YES; 505 | } 506 | 507 | void qhd_logMethod(Class aClass, BOOL(^condition)(SEL sel)) { 508 | unsigned int outCount; 509 | Method *methods = class_copyMethodList(aClass,&outCount); 510 | 511 | for (int i = 0; i < outCount; i ++) { 512 | Method tempMethod = *(methods + i); 513 | SEL selector = method_getName(tempMethod); 514 | char *returnType = method_copyReturnType(tempMethod); 515 | 516 | BOOL isCan = qhd_isCanHook(tempMethod, returnType); 517 | 518 | if (isCan && condition) { 519 | isCan = condition(selector); 520 | } 521 | 522 | if (isCan) { 523 | if (qhd_replaceMethod(aClass, selector, returnType)) { 524 | DEV_LOG(@"success hook method:%@ types:%s", NSStringFromSelector(selector), method_getDescription(tempMethod)->types); 525 | } else { 526 | DEV_LOG(@"fail method:%@ types:%s", NSStringFromSelector(selector), method_getDescription(tempMethod)->types); 527 | } 528 | } else { 529 | DEV_LOG(@"can not hook method:%@ types:%s", NSStringFromSelector(selector), method_getDescription(tempMethod)->types); 530 | } 531 | free(returnType); 532 | } 533 | free(methods); 534 | } 535 | 536 | 537 | #pragma mark - ANYMethodLog implementation 538 | 539 | @implementation ANYMethodLog 540 | 541 | + (void)logMethodWithClass:(Class)aClass 542 | condition:(ConditionBlock) condition 543 | before:(BeforeBlock) before 544 | after:(AfterBlock) after { 545 | #ifndef DEBUG 546 | return; 547 | #endif 548 | 549 | if (aClass) { 550 | AMLBlock *block = [[AMLBlock alloc] init]; 551 | block.targetClassName = NSStringFromClass(aClass); 552 | block.condition = condition; 553 | block.before = before; 554 | block.after = after; 555 | [SHARED_ANYMETHODLOG setAMLBlock:block forKey:block.targetClassName]; 556 | } 557 | 558 | qhd_logMethod(aClass, condition); 559 | 560 | //获取元类,处理类方法。(注意获取元类是用object_getClass,而不是class_getSuperclass) 561 | Class metaClass = object_getClass(aClass); 562 | qhd_logMethod(metaClass, condition); 563 | } 564 | 565 | + (instancetype)sharedANYMethodLog { 566 | static ANYMethodLog *_sharedANYMethodLog = nil; 567 | static dispatch_once_t onceToken; 568 | dispatch_once(&onceToken, ^{ 569 | _sharedANYMethodLog = [[self alloc] init]; 570 | _sharedANYMethodLog.blockCache = [NSMutableDictionary dictionary]; 571 | }); 572 | return _sharedANYMethodLog; 573 | } 574 | 575 | - (void)setAMLBlock:(AMLBlock *)block forKey:(NSString *)aKey { 576 | @synchronized (self) { 577 | [self.blockCache setObject:block forKey:aKey]; 578 | } 579 | } 580 | 581 | - (AMLBlock *)blockWithTarget:(id)target { 582 | Class class = [target class]; 583 | AMLBlock *block = [self.blockCache objectForKey:NSStringFromClass(class)]; 584 | while (block == nil) { 585 | class = [class superclass]; 586 | if (class == nil) { 587 | break; 588 | } 589 | block = [self.blockCache objectForKey:NSStringFromClass(class)]; 590 | } 591 | return block; 592 | } 593 | 594 | @end 595 | -------------------------------------------------------------------------------- /ShadowTrackerExtraDylib/Logos/ShadowTrackerExtraDylib.xm: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import "XYMetalRenderHelper.h" 7 | #import "XYSliderView.h" 8 | #import 9 | #import "XYPlayMusicViewController.h" 10 | 11 | extern void _log_classMethods(Class clas); 12 | extern void _hookAGXFamilyRenderContext(Class clas); 13 | 14 | %group MSRqdDevice 15 | %hook MSRqdDeviceUtil 16 | 17 | + (BOOL)isJailBrokenDevice { 18 | BOOL res = %orig; 19 | NSLog(@"*******_______%@越狱______*******", res ? @"是" : @"不是"); 20 | return NO; 21 | } 22 | 23 | + (id)executableInfo { 24 | id info = %orig; 25 | return info; 26 | } 27 | 28 | + (long long)getParentProcessId { 29 | long long getParentProcessId = %orig; 30 | return getParentProcessId; 31 | } 32 | + (long long)getProcessId { 33 | long long getProcessId = %orig; 34 | return getProcessId; 35 | } 36 | + (id)getParentProcessName { 37 | id getParentProcessName = %orig; 38 | return getParentProcessName; 39 | } 40 | + (id)getProcessName { 41 | id getProcessName = %orig; 42 | return getProcessName; 43 | } 44 | + (BOOL)isReet { 45 | BOOL isReet = %orig; 46 | return isReet; 47 | } 48 | + (float)getFreeSDCard { 49 | float getFreeSDCard = %orig; 50 | return getFreeSDCard; 51 | } 52 | + (float)getCpuUsage { 53 | float getCpuUsage = %orig; 54 | return getCpuUsage; 55 | } 56 | + (id)getCPUArchName { 57 | id getCPUArchName = %orig; 58 | return getCPUArchName; 59 | } 60 | + (long long)getAvailableMemorySize { 61 | long long getAvailableMemorySize = %orig; 62 | return getAvailableMemorySize; 63 | } 64 | + (long long)getTotalMemorySize { 65 | long long getTotalMemorySize = %orig; 66 | return getTotalMemorySize; 67 | } 68 | + (float)getTotalMemory { 69 | float getTotalMemory = %orig; 70 | return getTotalMemory; 71 | } 72 | + (float)getFreeMemory { 73 | float getFreeMemory = %orig; 74 | return getFreeMemory; 75 | } 76 | + (float)getTotalSpace { 77 | float getTotalSpace = %orig; 78 | return getTotalSpace; 79 | } 80 | + (float)getFreeSpace { 81 | float getFreeSpace = %orig; 82 | return getFreeSpace; 83 | } 84 | + (id)getDayTimeStrBy:(double)arg1 { 85 | id getDayTimeStrBy = %orig; 86 | return getDayTimeStrBy; 87 | } 88 | + (id)getDayTimeStr { 89 | id getDayTimeStr = %orig; 90 | return getDayTimeStr; 91 | } 92 | + (id)getFullTimeStrBy:(double)arg1 { 93 | id getFullTimeStrBy = %orig; 94 | return getFullTimeStrBy; 95 | } 96 | + (id)getFullTimeMsStr { 97 | id getFullTimeMsStr = %orig; 98 | return getFullTimeMsStr; 99 | } 100 | + (id)getFullTimeFileStrBy:(double)arg1 { 101 | id getFullTimeFileStrBy = %orig; 102 | return getFullTimeFileStrBy; 103 | } 104 | + (long long)getTimeOfTodayStart { 105 | long long getTimeOfTodayStart = %orig; 106 | return getTimeOfTodayStart; 107 | } 108 | + (id)get_sys_buildver { 109 | id get_sys_buildver = %orig; 110 | return get_sys_buildver; 111 | } 112 | + (id)getOSVersion { 113 | id getOSVersion = %orig; 114 | return getOSVersion; 115 | } 116 | + (float)getOSVerFloat { 117 | float getOSVerFloat = %orig; 118 | return getOSVerFloat; 119 | } 120 | + (id)model { 121 | id model = %orig; 122 | return model; 123 | } 124 | + (id)generateUUID { 125 | id generateUUID = %orig; 126 | // return __uuid; 127 | return generateUUID; 128 | } 129 | 130 | %end 131 | %end 132 | 133 | %group BeaconBundle 134 | %hook BeaconBundleUtil 135 | 136 | + (BOOL)isFirstUsage { 137 | BOOL res = %orig; 138 | return res; 139 | } 140 | + (id)getChannelId { 141 | id res = %orig; 142 | return res; 143 | } 144 | + (id)getBeaconAppKey { 145 | id res = %orig; 146 | return res; 147 | } 148 | + (id)getBundleShortVer { 149 | id res = %orig; 150 | return res; 151 | } 152 | + (id)getBundleVersion { 153 | id res = %orig; 154 | return res; 155 | } 156 | + (id)getBundleId { 157 | id res = %orig; 158 | return res; 159 | } 160 | + (id)getSessionId { 161 | id res = %orig; 162 | return res; 163 | } 164 | + (id)getAnaOpenUdid { 165 | id res = %orig; 166 | return res; 167 | } 168 | + (void)saveOpenUdid:(id)arg1 { 169 | %orig; 170 | } 171 | + (id)createOpenUdid { 172 | id res = %orig; 173 | return res; 174 | } 175 | + (id)getQimei { 176 | id res = %orig; 177 | return res; 178 | } 179 | + (BOOL)saveQimei:(id)arg1 { 180 | BOOL res = %orig; 181 | return res; 182 | } 183 | 184 | %end 185 | %end 186 | 187 | %group isTheAppStoreEnvironment 188 | %hook MSRqdBundleUtil 189 | + (BOOL)isTheAppStoreEnvironment { 190 | BOOL res = %orig; 191 | return YES; 192 | return res; 193 | } 194 | + (BOOL)isATSAllowsArbitraryLoads { 195 | BOOL res = %orig; 196 | return res; 197 | } 198 | + (id)getPasswordForUsername:(id)arg1 andServiceName:(id)arg2 error:(id *)arg3 { 199 | id res = %orig; 200 | return res; 201 | } 202 | 203 | + (id)getBundleExe { 204 | id res = %orig; 205 | return res; 206 | } 207 | + (id)getRDMCIBuildUUID { 208 | id res = %orig; 209 | return res; 210 | } 211 | 212 | + (id)getBundleName { 213 | id res = %orig; 214 | return res; 215 | } 216 | + (id)getBundleId { 217 | id res = %orig; 218 | return res; 219 | } 220 | + (id)createOpenUdid { 221 | id res = %orig; 222 | return res; 223 | } 224 | + (id)getAnaOpenUdid { 225 | id res = %orig; 226 | return res; 227 | } 228 | 229 | %end 230 | %end 231 | 232 | %group MSDKHttpRequest 233 | %hook MSDKHttpRequest 234 | 235 | - (void)reportSata:(int)arg1 retMsg:(id)arg2 { 236 | %orig; 237 | } 238 | - (void)requestFailed:(id)arg1 { 239 | %orig; 240 | } 241 | - (void)requestFinished:(id)arg1 { 242 | %orig; 243 | } 244 | - (void)requestStarted:(id)arg1 { 245 | %orig; 246 | } 247 | - (void)send:(id)arg1 { 248 | %orig; 249 | } 250 | 251 | %end 252 | %end 253 | 254 | 255 | %group MTAAccount 256 | %hook MTAAccountEvent 257 | - (int)getType { 258 | int type = %orig; 259 | return type; 260 | } 261 | %end 262 | %end 263 | 264 | %group AnnoucementNetwork 265 | %hook AnnoucementNetworkModel 266 | 267 | - (void)sendDeviceInfoWithDict:(id)arg1 { 268 | %orig; 269 | } 270 | + (id)getAnnoUrl:(id)arg1 key:(id)arg2 { 271 | id res = %orig; 272 | return res; 273 | } 274 | - (void)cleanExpiredMSGWithCurrentTime:(long long)arg1 { 275 | %orig; 276 | } 277 | - (void)setInvalidMsgDataWithArray:(id)arg1 { 278 | %orig; 279 | } 280 | - (void)setMsgDataWithArray:(id)arg1 andUpdataTime:(id)arg2 andAppid:(id)arg3 { 281 | %orig; 282 | } 283 | - (void)parserMSGDataWithData:(id)arg1 { 284 | %orig; 285 | } 286 | %end 287 | %end 288 | 289 | %group UIApplication 290 | %hook UIApplication 291 | 292 | - (BOOL)canOpenURL:(NSURL *)url { 293 | BOOL res = %orig; 294 | // 绝地求生会尝试打开cydia应用注册的URL scheme判断这个设备是否越狱 295 | if ([url.scheme isEqualToString:@"cydia"] || [url.absoluteString hasPrefix:@"cydia"]) { 296 | NSLog(@"%@", url); 297 | } 298 | return res; 299 | } 300 | %end 301 | 302 | %hook IOSAppDelegate 303 | - (void)applicationDidBecomeActive:(UIApplication *)application { 304 | %orig; 305 | } 306 | 307 | - (void)ToggleSuspend:(_Bool)arg1 { 308 | %orig; 309 | } 310 | - (_Bool)IsRunningOnBattery { 311 | BOOL flag = %orig; 312 | return flag; 313 | } 314 | - (int)GetBatteryLevel { 315 | int flag = %orig; 316 | return flag; 317 | } 318 | - (_Bool)AreHeadphonesPluggedIn { 319 | BOOL flag = %orig; 320 | return flag; 321 | } 322 | - (int)GetAudioVolume { 323 | int flag = %orig; 324 | return flag; 325 | } 326 | - (_Bool)IsBackgroundAudioPlaying { 327 | BOOL flag = %orig; 328 | return flag; 329 | } 330 | - (void)ToggleAudioSession:(_Bool)arg1 { // app进入前台和后台时 中调用 331 | %orig; 332 | } 333 | - (void)InitializeAudioSession { // 初始化音频 334 | %orig; 335 | 336 | } 337 | - (void)AudioInterrupted:(NSNotification *)arg1 { // 收到音频中断的通知AVAudioSessionInterruptionNotification 338 | %orig; 339 | } 340 | - (void)NoUrlCommandLine { 341 | %orig; 342 | } 343 | - (void)EnableIdleTimer:(_Bool)arg1 { 344 | %orig; 345 | } 346 | - (void)DeferredEnableIdleTimer { 347 | %orig; 348 | } 349 | - (void)InitIdleTimerSettings { 350 | %orig; 351 | } 352 | - (void)RecordPeakMemory { 353 | %orig; 354 | } 355 | - (void)timerForSplashScreen { 356 | %orig; 357 | } 358 | - (void)UE4iOSThread:(id)arg1 { 359 | %orig; 360 | } 361 | - (void)MainAppThread:(id)arg1 { 362 | %orig; 363 | } 364 | - (void)ParseCommandLineOverrides { 365 | %orig; 366 | } 367 | %end 368 | /// hook AVAudioSession的目的是为了玩游戏时可以听apple music 369 | %hook AVAudioSession 370 | - (BOOL)setActive:(BOOL)active error:(NSError **)outError { 371 | BOOL res = %orig; 372 | return res; 373 | } 374 | - (BOOL)setActive:(BOOL)active withOptions:(AVAudioSessionSetActiveOptions)options error:(NSError **)outError { 375 | BOOL res = %orig; 376 | return res; 377 | } 378 | - (BOOL)setActive:(BOOL)active withFlags:(NSInteger)flags error:(NSError **)outError { 379 | BOOL res = %orig; 380 | return res; 381 | } 382 | 383 | /* set session category */ 384 | - (BOOL)setCategory:(AVAudioSessionCategory)category error:(NSError **)outError { 385 | // category = AVAudioSessionCategoryAmbient; 386 | BOOL res = %orig; 387 | return res; 388 | } 389 | /* set session category with options */ 390 | - (BOOL)setCategory:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError { 391 | // category = AVAudioSessionCategoryAmbient; 392 | // options = AVAudioSessionCategoryOptionMixWithOthers; 393 | // options = AVAudioSessionCategoryOptionDuckOthers; // 减弱其他app的背景音乐 394 | BOOL res = %orig; // 全军出击app激活时设置的category为AVAudioSessionCategorySoloAmbient会知道apple music的音乐暂停 395 | return res; 396 | } 397 | /* set session category and mode with options */ 398 | - (BOOL)setCategory:(AVAudioSessionCategory)category mode:(AVAudioSessionMode)mode options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError{ 399 | // category = AVAudioSessionCategoryAmbient; 400 | // options = AVAudioSessionCategoryOptionDuckOthers; 401 | BOOL res = %orig; 402 | return res; 403 | } 404 | 405 | /* set session category, mode, routing sharing policy, and options 406 | Use of the long-form route sharing policy is only valid in conjunction with a limited set of category, mode, and option values. 407 | Allowed categories: AVAudioSessionCategoryPlayback 408 | Allowed modes: AVAudioSessionModeDefault, AVAudioSessionModeMoviePlayback, AVAudioSessionModeSpokenAudio 409 | Allowed options: None. Options are allowed when changing the routing policy back to Default, however. */ 410 | - (BOOL)setCategory:(AVAudioSessionCategory)category mode:(AVAudioSessionMode)mode routeSharingPolicy:(AVAudioSessionRouteSharingPolicy)policy options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError { 411 | BOOL res = %orig; 412 | return res; 413 | } 414 | 415 | %end 416 | %end 417 | 418 | %group BeaconDeviceUtil 419 | %hook BeaconDeviceUtil 420 | 421 | + (BOOL)isReet { 422 | BOOL isReet = %orig; 423 | return isReet; 424 | } 425 | + (float)cpuUsage { 426 | float cpuUsage = %orig; 427 | return cpuUsage; 428 | } 429 | + (float)memUsage { 430 | float memUsage = %orig; 431 | return memUsage; 432 | } 433 | + (float)getTotalSpace { 434 | float getTotalSpace = %orig; 435 | return getTotalSpace; 436 | } 437 | + (id)get_sys_buildver { 438 | id get_sys_buildver = %orig; 439 | return get_sys_buildver; 440 | } 441 | + (id)model { 442 | id model = %orig; 443 | return model; 444 | } 445 | %end 446 | %end 447 | 448 | %group MSDKAuth 449 | %hook MSDKAuthService 450 | - (BOOL)switchUser:(BOOL)arg1 { 451 | BOOL res = %orig; 452 | return res; 453 | } 454 | - (int)loadLoginInfo:(struct loginRet_ *)arg1 { 455 | int res = %orig; 456 | return res; 457 | } 458 | 459 | - (void)setPermission:(int)arg1 { 460 | %orig; 461 | } 462 | - (id)getGuestId { 463 | id res = %orig; 464 | return res; 465 | } 466 | - (void)resetGuestId { 467 | %orig; 468 | } 469 | - (void)logout { 470 | %orig; 471 | } 472 | - (void)loginWithLocalInfo:(_Bool)arg1 { 473 | %orig; 474 | } 475 | - (void)qrCodeLogin:(int)arg1 useMSDKLayout:(_Bool)arg2 { 476 | %orig; 477 | } 478 | - (void)login:(int)arg1 { 479 | %orig; 480 | } 481 | 482 | %end 483 | 484 | %hook MSDKAuthModel 485 | + (id)currentPlatformModel { 486 | id res = %orig; 487 | return res; 488 | } 489 | + (id)sharedModel { 490 | id res = %orig; 491 | return res; 492 | } 493 | 494 | - (NSString *)platformType { 495 | NSString *platformType = %orig; 496 | return platformType; 497 | } 498 | 499 | - (int)currentPlatform { 500 | int platformType = %orig; 501 | return platformType; 502 | } 503 | - (void)UploadDeviceInfo:(id)arg1 { 504 | %orig; 505 | } 506 | - (void)setCurrentOpenID:(id)arg1 { 507 | %orig; 508 | } 509 | - (id)guestAuthModel { 510 | id model = %orig; 511 | return model; 512 | } 513 | //- (MSDKGuestAuthModel *)guestAuthModel { 514 | // MSDKGuestAuthModel *model = %orig; 515 | // return model; 516 | //} 517 | %end 518 | 519 | %hook SAUserDefaults 520 | + (id)currentUserDefaults { 521 | id obj = %orig; 522 | return obj; 523 | } 524 | %end 525 | 526 | %hook SAAccountInfo 527 | - (id)avatarURL { 528 | return %orig; 529 | } 530 | %end 531 | 532 | %hook BeaconEventModule 533 | + (id)sharedInstance { 534 | id instance = %orig; 535 | return instance; 536 | } 537 | - (_Bool)isNeedNewQimei { 538 | _Bool res = %orig; 539 | return res; 540 | } 541 | - (_Bool)isCpuReport { 542 | _Bool res = %orig; 543 | return res; 544 | } 545 | - (void)refreshNetInfo { 546 | %orig; 547 | } 548 | - (void)initBeaconProperties { 549 | %orig; 550 | } 551 | - (void)saveAfterFirstUsage { 552 | %orig; 553 | } 554 | - (_Bool)isFirstUsage { 555 | return %orig; 556 | } 557 | - (void)appNetChanged { 558 | %orig; 559 | } 560 | - (void)appEnterBack { 561 | %orig; 562 | } 563 | - (void)appResumed { 564 | %orig; 565 | } 566 | - (void)appStarted { 567 | %orig; 568 | } 569 | - (_Bool)checkRequestQimei { 570 | _Bool res = %orig; 571 | return res; 572 | } 573 | - (_Bool)uploadModuleHistoryData { 574 | _Bool res = %orig; 575 | return res; 576 | } 577 | - (_Bool)isEnabled { 578 | _Bool res = %orig; 579 | return res; 580 | } 581 | - (void)checkPollUp { 582 | %orig; 583 | } 584 | - (void)enableModule { 585 | %orig; 586 | } 587 | - (void)disableModule { 588 | %orig; 589 | } 590 | - (_Bool)checkAndEnable { 591 | _Bool res = %orig; 592 | return res; 593 | } 594 | - (id)getModuleUploadPersistTypes { 595 | id res = %orig; 596 | return res; 597 | } 598 | - (int)moduleKey { 599 | int res = %orig; 600 | return res; 601 | } 602 | %end 603 | 604 | %hook MSDKBugly 605 | + (void)setUserIdentifier:(id)arg1 { 606 | %orig; 607 | } 608 | + (void)startWithAppId:(id)arg1 config:(id)arg2 applicationGroupIdentifier:(id)arg3 { 609 | %orig; 610 | } 611 | - (void)initWithAppId:(id)arg1 config:(id)arg2 appGroups:(id)arg3 { 612 | %orig; 613 | } 614 | + (void)log:(id)arg1 { 615 | %orig; 616 | } 617 | %end 618 | 619 | %hook IOSAppDelegate 620 | - (_Bool)AreHeadphonesPluggedIn { 621 | BOOL res = %orig; 622 | return res; 623 | } 624 | 625 | - (void)ToggleSuspend:(_Bool)arg1 { // app激活或者进入前台时调用,启动或者暂停游戏 626 | %orig; 627 | } 628 | 629 | %end 630 | %end 631 | 632 | %group MetalKit 633 | %hook MTLDebugRenderCommandEncoder 634 | - (void)drawIndexedPrimitives:(MTLPrimitiveType)primitiveType indexCount:(NSUInteger)indexCount indexType:(MTLIndexType)indexType indexBuffer:(id)indexBuffer indexBufferOffset:(NSUInteger)indexBufferOffset instanceCount:(NSUInteger)instanceCount baseVertex:(NSInteger)baseVertex baseInstance:(NSUInteger)baseInstance { 635 | 636 | if(instanceCount > XYMetalRenderHelper.instanceCount && XYMetalRenderHelper.weedOutWeeds) { 637 | return; 638 | } 639 | @try { 640 | %orig; 641 | } 642 | 643 | @catch (NSException *exp) { 644 | NSLog(@"%@\n%@", exp.reason, exp.callStackSymbols); 645 | } 646 | 647 | } 648 | 649 | -(void)drawIndexedPatches:(NSUInteger)numberOfPatchControlPoints patchIndexBuffer:(id )patchIndexBuffer patchIndexBufferOffset:(NSUInteger)patchIndexBufferOffset controlPointIndexBuffer:(id )controlPointIndexBuffer controlPointIndexBufferOffset:(NSUInteger)controlPointIndexBufferOffset indirectBuffer:(id )indirectBuffer indirectBufferOffset:(NSUInteger)indirectBufferOffset { 650 | 651 | %orig; 652 | } 653 | 654 | - (void)setVertexBytes:(const void *)bytes length:(NSUInteger)length atIndex:(NSUInteger)index { 655 | %orig; 656 | } 657 | 658 | /*! 659 | @method setVertexBuffer:offset:atIndex: 660 | @brief Set a global buffer for all vertex shaders at the given bind point index. 661 | */ 662 | - (void)setVertexBuffer:(id )buffer offset:(NSUInteger)offset atIndex:(NSUInteger)index { 663 | %orig; 664 | } 665 | 666 | /*! 667 | @method setVertexBufferOffset:atIndex: 668 | @brief Set the offset within the current global buffer for all vertex shaders at the given bind point index. 669 | */ 670 | - (void)setVertexBufferOffset:(NSUInteger)offset atIndex:(NSUInteger)index { 671 | %orig; 672 | } 673 | 674 | - (NSUInteger)tileWidth { 675 | NSUInteger tileWidth = %orig; 676 | return tileWidth; 677 | } 678 | 679 | - (NSUInteger)tileHeight { 680 | NSUInteger tileHeight = %orig; 681 | return tileHeight; 682 | } 683 | 684 | %end 685 | 686 | %hook MTLToolsRenderCommandEncoder 687 | - (void)drawIndexedPrimitives:(MTLPrimitiveType)primitiveType indexCount:(NSUInteger)indexCount indexType:(MTLIndexType)indexType indexBuffer:(id)indexBuffer indexBufferOffset:(NSUInteger)indexBufferOffset instanceCount:(NSUInteger)instanceCount baseVertex:(NSInteger)baseVertex baseInstance:(NSUInteger)baseInstance { 688 | 689 | %orig; 690 | 691 | } 692 | 693 | %end 694 | 695 | %hook MTLTelemetryRenderCommandEncoder 696 | - (void)drawIndexedPrimitives:(MTLPrimitiveType)primitiveType indexCount:(NSUInteger)indexCount indexType:(MTLIndexType)indexType indexBuffer:(id)indexBuffer indexBufferOffset:(NSUInteger)indexBufferOffset instanceCount:(NSUInteger)instanceCount baseVertex:(NSInteger)baseVertex baseInstance:(NSUInteger)baseInstance { 697 | 698 | %orig; 699 | 700 | } 701 | %end 702 | 703 | %hook _MTLCommandEncoder // AGXA11FamilyRenderContext基类是_MTLCommandEncoder 704 | 705 | - (id)initWithCommandBuffer:(id)arg { 706 | id obj = %orig; 707 | // 获取当前设备的baseObject AGXFamilyRenderContext 708 | if (obj) { 709 | NSString *className = NSStringFromClass([obj class]); 710 | if ([className hasSuffix:@"FamilyRenderContext"] && [className hasPrefix:@"AGX"]) { 711 | _hookAGXFamilyRenderContext([obj class]); 712 | } 713 | } 714 | return obj; 715 | } 716 | %end 717 | 718 | %hook MTLToolsObject 719 | - (id)baseObjectWithClass:(Class)arg1 { 720 | id obj = %orig; 721 | return obj; 722 | } 723 | 724 | - (id)initWithBaseObject:(id)baseObject parent:(id)parent lockingPolicy:(struct ILayerLockingPolicy *)arg3 { 725 | id obj = %orig; 726 | // 获取当前设备的baseObject AGXFamilyRenderContext 727 | // if (baseObject) { 728 | // NSString *className = NSStringFromClass([baseObject class]); 729 | // if ([className hasSuffix:@"FamilyRenderContext"] && [className hasPrefix:@"AGX"]) { 730 | // _hookAGXFamilyRenderContext([baseObject class]); 731 | // } 732 | // } 733 | return obj; 734 | } 735 | - (id)initWithBaseObject:(id)arg1 strongParent:(id)arg2 { 736 | id obj = %orig; 737 | return obj; 738 | } 739 | - (id)initWithBaseObject:(id)arg1 parent:(id)arg2 { 740 | id obj = %orig; 741 | return obj; 742 | } 743 | 744 | - (void)setOriginalObject:(id)arg1 { 745 | %orig; 746 | } 747 | - (id)originalObject { 748 | id obj = %orig; 749 | return obj; 750 | } 751 | 752 | %end 753 | 754 | 755 | %hook FMTLHeap 756 | - (id)newBufferWithLength:(unsigned long long)arg1 options:(unsigned long long)arg2 { 757 | id obj = %orig; 758 | return obj; 759 | } 760 | - (unsigned long long)maxAvailableSizeWithAlignment:(unsigned long long)arg1 { 761 | unsigned long long max = %orig; 762 | return max; 763 | } 764 | %end 765 | %end 766 | 767 | %group AGX 768 | %hook AGXA11FamilyRenderContext 769 | 770 | - (void)drawIndexedPrimitives:(MTLPrimitiveType)primitiveType indexCount:(NSUInteger)indexCount indexType:(MTLIndexType)indexType indexBuffer:(id)indexBuffer indexBufferOffset:(NSUInteger)indexBufferOffset instanceCount:(NSUInteger)instanceCount baseVertex:(NSInteger)baseVertex baseInstance:(NSUInteger)baseInstance { 771 | 772 | 773 | if (instanceCount > XYMetalRenderHelper.instanceCount && XYMetalRenderHelper.weedOutWeeds) { 774 | return; 775 | } 776 | @try { 777 | %orig; 778 | } 779 | 780 | @catch (NSException *exp) { 781 | NSLog(@"%@\n%@", exp.reason, exp.callStackSymbols); 782 | } 783 | 784 | } 785 | 786 | %end 787 | 788 | %hook AGXA10FamilyRenderContext 789 | 790 | - (void)drawIndexedPrimitives:(MTLPrimitiveType)primitiveType indexCount:(NSUInteger)indexCount indexType:(MTLIndexType)indexType indexBuffer:(id)indexBuffer indexBufferOffset:(NSUInteger)indexBufferOffset instanceCount:(NSUInteger)instanceCount baseVertex:(NSInteger)baseVertex baseInstance:(NSUInteger)baseInstance { 791 | 792 | 793 | if (instanceCount > XYMetalRenderHelper.instanceCount && XYMetalRenderHelper.weedOutWeeds) { 794 | return; 795 | } 796 | @try { 797 | %orig; 798 | } 799 | 800 | @catch (NSException *exp) { 801 | NSLog(@"%@\n%@", exp.reason, exp.callStackSymbols); 802 | } 803 | 804 | } 805 | 806 | %end 807 | 808 | %hook AGXA9FamilyRenderContext 809 | 810 | - (void)drawIndexedPrimitives:(MTLPrimitiveType)primitiveType indexCount:(NSUInteger)indexCount indexType:(MTLIndexType)indexType indexBuffer:(id)indexBuffer indexBufferOffset:(NSUInteger)indexBufferOffset instanceCount:(NSUInteger)instanceCount baseVertex:(NSInteger)baseVertex baseInstance:(NSUInteger)baseInstance { 811 | 812 | 813 | if (instanceCount > XYMetalRenderHelper.instanceCount && XYMetalRenderHelper.weedOutWeeds) { 814 | return; 815 | } 816 | @try { 817 | %orig; 818 | } 819 | 820 | @catch (NSException *exp) { 821 | NSLog(@"%@\n%@", exp.reason, exp.callStackSymbols); 822 | } 823 | 824 | } 825 | 826 | %end 827 | %end 828 | 829 | static void * XYSliderViewKey = &XYSliderViewKey; 830 | 831 | @interface FIOSView : UIView 832 | - (void)xy_switchValueChanged:(id)sender; 833 | - (void)onPickMusic; 834 | - (UIImpactFeedbackGenerator *)feedbackGenerator; 835 | @end 836 | 837 | %group FIOSView 838 | %hook FIOSView 839 | - (instancetype)initWithFrame:(CGRect)frame { 840 | self = %orig; 841 | 842 | XYSliderView *slider = [[XYSliderView alloc] init]; 843 | slider.translatesAutoresizingMaskIntoConstraints = NO; 844 | slider.minimumValue = 1; 845 | slider.maximumValue = 100; 846 | slider.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.28]; 847 | slider.layer.cornerRadius = 3.0; 848 | slider.layer.masksToBounds = YES; 849 | slider.value = XYMetalRenderHelper.instanceCount; 850 | [self addSubview:slider]; 851 | objc_setAssociatedObject(self, XYSliderViewKey, slider, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 852 | __weak typeof(self) weakSelf = self; 853 | slider.valueChangeBlock = ^(float value) { 854 | XYMetalRenderHelper.instanceCount = value; 855 | // 触发taptic反馈 856 | #ifdef __IPHONE_10_0 857 | if (value == slider.minimumValue || value == slider.maximumValue) { 858 | return; 859 | } 860 | [weakSelf.feedbackGenerator impactOccurred]; 861 | #endif 862 | }; 863 | [NSLayoutConstraint constraintWithItem:slider attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:0.3 constant:0.0].active = YES; 864 | 865 | [NSLayoutConstraint constraintWithItem:slider attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:30.0].active = YES; 866 | [NSLayoutConstraint constraintWithItem:slider attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:-80.0].active = YES; 867 | [NSLayoutConstraint constraintWithItem:slider attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0].active = YES; 868 | 869 | UISwitch *sw = [[UISwitch alloc] initWithFrame: CGRectZero]; 870 | sw.on = XYMetalRenderHelper.weedOutWeeds; 871 | if (XYMetalRenderHelper.weedOutWeeds == NO) { 872 | slider.hidden = YES; 873 | } 874 | sw.tintColor = [UIColor lightGrayColor]; 875 | sw.onTintColor = [UIColor clearColor]; 876 | sw.thumbTintColor = [[UIColor yellowColor] colorWithAlphaComponent:0.5]; 877 | sw.backgroundColor = [UIColor clearColor]; 878 | sw.translatesAutoresizingMaskIntoConstraints = NO; 879 | [sw addTarget:self action:@selector(xy_switchValueChanged:) forControlEvents:UIControlEventValueChanged]; 880 | [self addSubview:sw]; 881 | if (@available(iOS 11.0, *)) { 882 | [NSLayoutConstraint constraintWithItem:sw attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.safeAreaLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0].active = YES; 883 | } 884 | else { 885 | [NSLayoutConstraint constraintWithItem:sw attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-0.0].active = YES; 886 | } 887 | [NSLayoutConstraint constraintWithItem:sw attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:-15.0].active = YES; 888 | [sw setTransform:CGAffineTransformScale(sw.transform, 0.7, 0.7)]; 889 | 890 | // 播放音乐 891 | UIButton *selectMusicBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 892 | selectMusicBtn.layer.cornerRadius = 7.5; 893 | selectMusicBtn.layer.masksToBounds = YES; 894 | [self addSubview:selectMusicBtn]; 895 | selectMusicBtn.translatesAutoresizingMaskIntoConstraints = NO; 896 | selectMusicBtn.backgroundColor = [UIColor redColor]; 897 | [selectMusicBtn addTarget:self action:@selector(onPickMusic) forControlEvents:UIControlEventTouchUpInside]; 898 | [NSLayoutConstraint constraintWithItem:selectMusicBtn attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:-10.0].active = YES; 899 | [NSLayoutConstraint constraintWithItem:selectMusicBtn attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-50.0].active = YES; 900 | [NSLayoutConstraint constraintWithItem:selectMusicBtn attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:15.0].active = YES; 901 | [NSLayoutConstraint constraintWithItem:selectMusicBtn attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:15.0].active = YES; 902 | return self; 903 | } 904 | 905 | 906 | //#if HAS_METAL 907 | //// Return a drawable object (ie a back buffer texture) for the RHI to render to 908 | - (id)MakeDrawable { 909 | id drawble = %orig; 910 | return drawble; 911 | } 912 | //#endif 913 | 914 | #ifdef __IPHONE_10_0 915 | %new 916 | - (UIImpactFeedbackGenerator *)feedbackGenerator { 917 | UIImpactFeedbackGenerator *feedbackGenerator = objc_getAssociatedObject(self, _cmd); 918 | if (feedbackGenerator == nil) { 919 | feedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; 920 | objc_setAssociatedObject(self, _cmd, feedbackGenerator, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 921 | } 922 | return feedbackGenerator; 923 | } 924 | #endif 925 | 926 | 927 | %new 928 | -(void)xy_switchValueChanged:(id)sender { 929 | UISwitch *sw = (UISwitch *)sender; 930 | XYMetalRenderHelper.weedOutWeeds = sw.isOn; 931 | XYSliderView *slider = objc_getAssociatedObject(self, XYSliderViewKey); 932 | if (sw.isOn == YES) { 933 | slider.hidden = NO; 934 | } 935 | else { 936 | slider.hidden = YES; 937 | } 938 | } 939 | 940 | %new 941 | - (void)onPickMusic { 942 | XYPlayMusicViewController *vc = [XYPlayMusicViewController new]; 943 | [[UIApplication sharedApplication].delegate.window.rootViewController presentViewController:vc animated:YES completion:nil]; 944 | } 945 | %end 946 | %end 947 | 948 | 949 | // 检索一下自己的应用程序是否被链接了异常动态库。 950 | // 动态注入使用了下面这些库 951 | /** 952 | /var/containers/Bundle/Application/347CD938-8A95-4596-9B2A-876BA39FE851/ShadowTrackerExtra.app/Frameworks/libsubstrate.dylib, 953 | /var/containers/Bundle/Application/347CD938-8A95-4596-9B2A-876BA39FE851/ShadowTrackerExtra.app/Frameworks/libcycript.dylib, 954 | /private/var/containers/Bundle/Application/347CD938-8A95-4596-9B2A-876BA39FE851/ShadowTrackerExtra.app/Frameworks/RevealServer.framework/RevealServer, 955 | */ 956 | // 获取所有已链接的动态库: 957 | void _checkDylibs(void) { 958 | uint32_t count = _dyld_image_count(); 959 | NSMutableArray *list = @[].mutableCopy; 960 | for (uint32_t i = 0 ; i < count; ++i) { 961 | NSString *name = [[NSString alloc]initWithUTF8String:_dyld_get_image_name(i)]; 962 | if (name != nil) { 963 | [list addObject:name]; 964 | } 965 | } 966 | NSLog(@"--%@", list); 967 | } 968 | 969 | // 通过检测当前程序运行的环境变量: 970 | void _printEnv(void) { 971 | char *env = getenv("DYLD_INSERT_LIBRARIES"); 972 | NSLog(@"%s", env); 973 | if (env == NULL) { 974 | //未越狱设备返回结果是null 975 | } 976 | } 977 | 978 | 979 | 980 | void _hookAGXFamilyRenderContext(Class clas) { 981 | // Class clas = NULL; 982 | // do { 983 | // clas = objc_getClass("AGXA11FamilyRenderContext"); 984 | // } while (clas == NULL); 985 | 986 | static BOOL isFinished = NO; 987 | if (clas == NULL || isFinished == YES) { 988 | return; 989 | } 990 | isFinished = YES; 991 | %init(AGX); 992 | 993 | _log_classMethods(NSClassFromString(@"AGXA11Device")); 994 | _log_classMethods(clas); 995 | } 996 | void _log_classMethods(Class cls) { 997 | if (cls == NULL) { 998 | return; 999 | } 1000 | unsigned int count; 1001 | NSMutableArray *methodList = @[].mutableCopy; 1002 | while (cls!=[NSObject class] && cls != NULL) { 1003 | Method *methods = class_copyMethodList(cls, &count); 1004 | for (int i=0; i < count; i++) { 1005 | NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding]; 1006 | 1007 | [methodList addObject:methodName?:@""]; 1008 | } 1009 | if (methods) { 1010 | free(methods); 1011 | } 1012 | cls = class_getSuperclass(cls); 1013 | } 1014 | NSLog(@"%@方法名:%@ ",NSStringFromClass(cls), methodList); 1015 | } 1016 | 1017 | 1018 | %ctor { 1019 | _checkDylibs(); 1020 | _printEnv(); 1021 | %init(BeaconDeviceUtil) 1022 | %init(UIApplication) 1023 | %init(MSDKHttpRequest) 1024 | %init(AnnoucementNetwork) 1025 | %init(MTAAccount) 1026 | %init(isTheAppStoreEnvironment) 1027 | %init(MSRqdDevice) 1028 | %init(BeaconBundle) 1029 | %init(MSDKAuth) 1030 | %init(FIOSView) 1031 | %init(MetalKit) 1032 | } 1033 | 1034 | --------------------------------------------------------------------------------