1.安装ldid
ldid用来专门签名iOS可执行文件的工具,用以在越狱iOS中取代Xcode自带的codesign。如果不安装,那么产生的deb文件就安装不到手机上
brew install ldid
2.Theos安装
官方建议把Theos安装在/opt/theos目录下
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
然后把/opt/theos的权限改为自己所拥有
sudo chown $(id -u):$(id -g) /opt/theos
3.环境变量
编辑配置文件:vim ~/.bash_profile
export THEOS=/opt/theos
export PATH=/opt/theos/bin/:$PATH
- 更新立即生效
source ~/.bash_profile
- 查看是否生效:
echo $THEOS
,echo $PATH
- 如果关闭命令端,再打开就失效是因为采用了
zsh
代替bash
,而zsh
加载的是~/.zshrc
文件,而.zshrc
文件中并没有定义任务环境变量。解决办法在~/.zshrc
文件最后,增加一行:source ~/.bash_profile
然后立即生效source ~/.zshrc
- 测试安装是否成功
在任意路径下输入nic.pl
nic.pl
NIC 2.0 - New Instance Creator
------------------------------
[1.] iphone/activator_event
[2.] iphone/application_modern
[3.] iphone/application_swift
[4.] iphone/flipswitch_switch
[5.] iphone/framework
[6.] iphone/library
[7.] iphone/preference_bundle_modern
[8.] iphone/tool
[9.] iphone/tool_swift
[10.] iphone/tweak
[11.] iphone/xpc_service
Choose a Template (required):
Tweak项目创建
1. 输入nic.pl后,选择模板输入10
Choose a Template (required): 10
2.输入tweak的工程名
Project Name (required): readerTweak
3.输入deb包名(格式类似bundle Identifier)
Package Name [com.yourcompany.readertweak]: com.lb.readertweak
4. 输入作者或维护人名字
Author/Maintainer Name [mac]: Lucky Blue
5. 输入tweak作用的对象,就是需要需要HOOK的APP的bundle Identifier
[iphone/tweak] MobileSubstrate Bundle filter [com.apple.springboard]: com.tencent.ied.app.comic
6.输入tweak安装完成后需要重启的应用,以进程名表示,比如系统的桌面:
[iphone/tweak] List of applications to terminate upon installation (space-separated, '-' for none) [SpringBoard]: SpringBoard
成功终端就会显示
Instantiating iphone/tweak in readertweak/...
Done.
完整步骤
成功后会生成下面四个文件
Tweak项目编写
在Makefile文件最上面加入下面两行代码
THEOS_DEVICE_IP:本机IP
THEOS_DEVICE_PORT:本机与iPhone通信的端口
export THEOS_DEVICE_IP=127.0.0.1
export THEOS_DEVICE_PORT=5757
删除所有Tweak.x
文件里默认的注释,然后输入如下
Logos官方文档
%hook ComicHomeViewController //%hook 类名
-(void)viewWillAppear:(BOOL)animated{
%orig;// %orig是Logos语法,先调用上一层的代码,跟oc的 [super xxxx]差不多的意思
//创建UIAlertView
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"注意"
message:@"这是第一个tweak项目"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil];
[alert show];
}
%end
编译,打包和安装
make clean && make && make package && make install
编译打包安装成功
Cydia可以看到已安装
因为按键精灵ios手机版需要购买vip才能使用,于是…
原理是修改用户模块的变量
- 用户模块的变量被我强制改成
arg1.UserName = @"用户名";//写你注册d 名字
arg1.IsActivated = [NSNumber numberWithInt:1];
arg1.IsVIP = [NSNumber numberWithInt:1];
arg1.VIPExpTime = @"2099-12-31";
注入方式是用theos编写tweak生成deb包。
@interface MAUser : NSObject
@property(copy, nonatomic) NSString *UserName; // @synthesize
@property(copy, nonatomic) NSNumber *IsActivated; // @synthesize
@property(copy, nonatomic) NSString *VIPExpTime; // @synthesize
@property(copy, nonatomic) NSNumber *IsVIP; // @synthesize
@end
%hook MAMineHeaderView
- (void)updateWithUser:(MAUser *)arg1 {
arg1.UserName = @"修改注入的名字!";
arg1.IsActivated = [NSNumber numberWithInt:1];
arg1.IsVIP = [NSNumber numberWithInt:1];
arg1.VIPExpTime = @"2022-06-15";
%orig;
}
%end
- 生成tweak模板的时候bundle ID 指定为:com.cyjh.MobileAnjian
Cycript调试VIP内容
adv-cmds
先通过SSH登录到服务器(iPhone
)
ps 命令
- 列出所有进程
ps -A
(当前手机打开了腾讯动漫)
- 可以从上图找到
11095
是腾讯动漫的进程id(pid
), ComicReader
是腾讯动漫的进程名称- 搜索进程:
ps –A | grep 关键词
i-57:~ root# ps -A | grep ComicReader
11095 ?? 0:05.50 /var/containers/Bundle/Application/015C9AB9-4440-492F-911B-6DEC6915FBFC/ComicReader.app/ComicReader
11121 ttys000 0:00.01 grep ComicReader
i-57:~ root#
附加App直接调试 cycript -p 进程名称/进程的编号
cycript -p 11095
或者
cycript -p ComicReader
cy#
启动和退出
启动:cycript -p 进程名称
退出:control + d
清屏:command + r
Cycript 常用语法
UIApp = UIApplication.sharedApplication()
cy# UIApp
#"<UIApplication: 0x104f04470>"
用内存地址获取对象:#内存地址
cy# #0x104f04470
#"<UIApplication: 0x104f04470>"
查看对象的所有成员变量:*对象
cy# *UIApp
{isa:UIApplication,_responderFlags:@error,_delegate:#"<TencentXGPushAppDelegate: 0x280e46cc0>",_remoteControlEventObservers:0,_topLevelNibObjects:null,_networkResourcesCurrentlyLoadingCount:0,_hideNetworkActivityIndicatorTimer:null,_statusBar:null,_statusBarRequestedStyle:0,_statusBarWindow:null,_observerBlocks:@[],_postCommitActions:@[],_postCommitActionsNeedToSynchronize:false,_mainStoryboardName:null,_idleModeController:null,_displayLayoutMonitor:null,_systemUserInterfaceStyle:0,_eventFetcher:#"<UIEventFetcher: 0x282264540>",_eventDispatcher:#"<UIEventDispatcher: 0x281569620>",_applicationFlags:@error,_keyCommandToken:#"<BSSimpleAssertion: 0x281445110; identifier: com.apple.backboard.hid.delivery; reason: 2-keycmds; valid: YES>",_physicalKeyCommandMap:@{},_physicalKeycodeMap:[NSOrderedSet orderedSetWithArray:@[]]],_alwaysHitTestsForMainScreen:false,_backgroundHitTestWindow:null,_appInfo:#"<_UIApplicationInfoParser: 0x2830656c0>",_actionsPendingInitialization:null,_idleTimerDisabledReasons:[NSSet setWithArray:@[]]],_keyRepeatAction:null,_currentTimestampWhenFirstTouchCameDown:0,_currentLocationWhereFirstTouchCameDown:{x:0,y:0},_saveStateRestorationArchiveWithFileProtectionCompleteUntilFirstUserAuthentication:false,_fenceTaskAssertion:null,_cachedSystemAnimationFence:null,_systemNavigationAction:null,_activityContinuationManager:#"<UIActivityContinuationManager: 0x28156e310>",__gestureEnvironment:#"<UIGestureEnvironment: 0x283061d50>",_forceStageObservable:null,_HIDGameControllerEventObserver:null,_HIDGameControllerEventQueue:null,_motionNotificationGenerator:null,_appState:#"<UISApplicationState: 0x281b633c0>",_applicationPushRegistry:#"<PKPushRegistry: 0x2838401e0>",_storyboardInitialMenu:null,_endpointMonitor:#"<BSServiceConnectionEndpointMonitor: 0x283861ef0; service: com.apple.frontboard.open; active>",optOutOfRTL:false,_isDisplayingActivityContinuationUI:false,_applicationWantsGESEvents:false,_shortcutService:null,___queuedOrientationChange:null,__expectedViewOrientation:1}
递归打印view的所有子控件:view.recursiveDescription().toString()
UIApp.keyWindow.recursiveDescription().toString()
定义变量:var 变量名 = 变量值
cy# var window = UIApp.keyWindow
#"<UIWindow: 0x104f1be40; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x281552d30>; layer = <UIWindowLayer: 0x281b753e0>>"
定义函数:function 函数名(...) { ... }
cy# function sum(a, b) {return a+b;}
cy# sum(2,3)
5
筛选出某种类型的对象:choose(类型)
cy# choose(UIViewController)
[#"<UISystemInputAssistantViewController: 0x106468630>",#"<UIEditingOverlayViewController: 0x10649e1d0>",#"<ComicHomeViewController: 0x105843000>",#"<ComicNavgationController: 0x105849000>",#"<VPlaygoundViewController: 0x10584e200>",#"<ComicNavgationController: 0x105850200>",#"<WaitHomeViewController: 0x105853a00>",#"<BookShelfViewController: 0x10585aa00>",#"<ComicNavgationController: 0x10585b000>",#"<MyViewController: 0x10585b600>",#"<ComicNavgationController: 0x10585bc00>",#"<ComicNavgationController: 0x105867400>",#"<UpdateChannelViewController: 0x105883a00>",#"<UpdateChannelSubViewController: 0x1058ee400>",#"<UpdateChannelSubViewController: 0x1058f5000>",#"<UIInputWindowController: 0x10595b000>",#"<ADWebViewController: 0x105972a00>",#"<ComicTabBarController: 0x105040400>",#"<ADWebViewController: 0x105137000>",#"<GenderSelectionViewController: 0x1051e8000>"]
对.cy文件的应用
.cy文件是对Cycript的封装,方便提供一些比较常用的函数。
(function(exports) {
var invalidParamStr = 'Invalid parameter';
var missingParamStr = 'Missing parameter';
// app id
LBAppId = [NSBundle mainBundle].bundleIdentifier;
// mainBundlePath
LBAppPath = [NSBundle mainBundle].bundlePath;
// document path
LBDocPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
// caches path
LBCachesPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
// 加载系统动态库
LBLoadFramework = function(name) {
var head = "/System/Library/";
var foot = "Frameworks/" + name + ".framework";
var bundle = [NSBundle bundleWithPath:head + foot] || [NSBundle bundleWithPath:head + "Private" + foot];
[bundle load];
return bundle;
};
// keyWindow
LBKeyWin = function() {
return UIApp.keyWindow;
};
// 根控制器
LBRootVc = function() {
return UIApp.keyWindow.rootViewController;
};
// 找到显示在最前面的控制器
var _LBFrontVc = function(vc) {
if (vc.presentedViewController) {
return _LBFrontVc(vc.presentedViewController);
}else if ([vc isKindOfClass:[UITabBarController class]]) {
return _LBFrontVc(vc.selectedViewController);
} else if ([vc isKindOfClass:[UINavigationController class]]) {
return _LBFrontVc(vc.visibleViewController);
} else {
var count = vc.childViewControllers.count;
for (var i = count - 1; i >= 0; i--) {
var childVc = vc.childViewControllers[i];
if (childVc && childVc.view.window) {
vc = _LBFrontVc(childVc);
break;
}
}
return vc;
}
};
LBFrontVc = function() {
return _LBFrontVc(UIApp.keyWindow.rootViewController);
};
// 递归打印UIViewController view的层级结构
LBVcSubviews = function(vc) {
if (![vc isKindOfClass:[UIViewController class]]) throw new Error(invalidParamStr);
return vc.view.recursiveDescription().toString();
};
// 递归打印最上层UIViewController view的层级结构
LBFrontVcSubViews = function() {
return LBVcSubviews(_LBFrontVc(UIApp.keyWindow.rootViewController));
};
// 获取按钮绑定的所有TouchUpInside事件的方法名
LBBtnTouchUpEvent = function(btn) {
var events = [];
var allTargets = btn.allTargets().allObjects()
var count = allTargets.count;
for (var i = count - 1; i >= 0; i--) {
if (btn != allTargets[i]) {
var e = [btn actionsForTarget:allTargets[i] forControlEvent:UIControlEventTouchUpInside];
events.push(e);
}
}
return events;
};
// CG函数
LBPointMake = function(x, y) {
return {0 : x, 1 : y};
};
LBSizeMake = function(w, h) {
return {0 : w, 1 : h};
};
LBRectMake = function(x, y, w, h) {
return {0 : LBPointMake(x, y), 1 : LBSizeMake(w, h)};
};
// 递归打印controller的层级结构
LBChildVcs = function(vc) {
if (![vc isKindOfClass:[UIViewController class]]) throw new Error(invalidParamStr);
return [vc _printHierarchy].toString();
};
// 递归打印view的层级结构
LBSubviews = function(view) {
if (![view isKindOfClass:[UIView class]]) throw new Error(invalidParamStr);
return view.recursiveDescription().toString();
};
// 判断是否为字符串 "str" @"str"
LBIsString = function(str) {
return typeof str == 'string' || str instanceof String;
};
// 判断是否为数组 []、@[]
LBIsArray = function(arr) {
return arr instanceof Array;
};
// 判断是否为数字 666 @666
LBIsNumber = function(num) {
return typeof num == 'number' || num instanceof Number;
};
var _LBClass = function(className) {
if (!className) throw new Error(missingParamStr);
if (LBIsString(className)) {
return NSClassFromString(className);
}
if (!className) throw new Error(invalidParamStr);
// 对象或者类
return className.class();
};
// 打印所有的子类
LBSubclasses = function(className, reg) {
className = _LBClass(className);
return [c for each (c in ObjectiveC.classes)
if (c != className
&& class_getSuperclass(c)
&& [c isSubclassOfClass:className]
&& (!reg || reg.test(c)))
];
};
// 打印所有的方法
var _LBGetMethods = function(className, reg, clazz) {
className = _LBClass(className);
var count = new new Type('I');
var classObj = clazz ? className.constructor : className;
var methodList = class_copyMethodList(classObj, count);
var methodsArray = [];
var methodNamesArray = [];
for(var i = 0; i < *count; i++) {
var method = methodList[i];
var selector = method_getName(method);
var name = sel_getName(selector);
if (reg && !reg.test(name)) continue;
methodsArray.push({
selector : selector,
type : method_getTypeEncoding(method)
});
methodNamesArray.push(name);
}
free(methodList);
return [methodsArray, methodNamesArray];
};
var _LBMethods = function(className, reg, clazz) {
return _LBGetMethods(className, reg, clazz)[0];
};
// 打印所有的方法名字
var _LBMethodNames = function(className, reg, clazz) {
return _LBGetMethods(className, reg, clazz)[1];
};
// 打印所有的对象方法
LBInstanceMethods = function(className, reg) {
return _LBMethods(className, reg);
};
// 打印所有的对象方法名字
LBInstanceMethodNames = function(className, reg) {
return _LBMethodNames(className, reg);
};
// 打印所有的类方法
LBClassMethods = function(className, reg) {
return _LBMethods(className, reg, true);
};
// 打印所有的类方法名字
LBClassMethodNames = function(className, reg) {
return _LBMethodNames(className, reg, true);
};
// 打印所有的成员变量
LBIvars = function(obj, reg){
if (!obj) throw new Error(missingParamStr);
var x = {};
for(var i in *obj) {
try {
var value = (*obj)[i];
if (reg && !reg.test(i) && !reg.test(value)) continue;
x[i] = value;
} catch(e){}
}
return x;
};
// 打印所有的成员变量名字
LBIvarNames = function(obj, reg) {
if (!obj) throw new Error(missingParamStr);
var array = [];
for(var name in *obj) {
if (reg && !reg.test(name)) continue;
array.push(name);
}
return array;
};
})(exports);
将lbtool.cy文件拷贝到iPhone的/usr/lib/cycript0.9目录下
scp /Users/mac/Desktop/lbtool.cy root@192.168.2.6:/usr/lib/cycript0.9
lbtool.cy 100% 6178 760.8KB/s 00:00
lbtool.cy文件用法
用@import + 文件名导入文件
i-57:~ root# cycript -p 11424
cy# @import lbtool
{}
- 获取当前显示的控制器
cy# LBFrontVc()
#"<ACReaderViewController: 0x1048ae600>"
获取view的层级结构
cy# LBSubviews(LBFrontVc().view)
`<UIView: 0x117c54a40; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x283adab00>>
| <ACReaderEngineView: 0x117c4b850; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x283483720>; layer = <CALayer: 0x283acd3c0>>
| | <ACZoomScrollView: 0x105b15600; baseClass = UIScrollView; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x2834be790>; layer = <CALayer: 0x283acd660>; contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}>
| | | <UICollectionView: 0x105b19600; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x283491920>; layer = <CALayer: 0x283acdbe0>; contentOffset: {0, 10}; contentSize: {375, 2130}; adjustedContentInset: {0, 0, 0, 0}; layout: <UICollectionViewFlowLayout: 0x11bf46e50>; dataSource: <ACReaderEngineView: 0x117c4b850; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x283483720>; layer = <CALayer: 0x283acd3c0>>>
最后小试牛刀把腾讯动漫底部充值view隐藏
- 隐藏前
cy# #0x11bfeb950.hidden = YES
true
© 版权声明
THE END
暂无评论内容