Cycript
是由Cydia創(chuàng)始人Saurik推出的一款腳本語(yǔ)言饿序,Cycript混合了OC、JavaScript
語(yǔ)法的解釋器羹蚣,這意味著我們能夠在一個(gè)命令中使用OC或者JavaScript原探,甚至兩者并用。它能夠掛鉤正在運(yùn)行的進(jìn)程,能夠在運(yùn)行時(shí)修改很多東西咽弦。
安裝
- 下載
Cycript
徒蟆,官方文檔 - 下載完成之后,為了方便使用型型,可以將其拷貝至/opt目錄下段审。
cp ./cycript_0.9.594 /opt/cycript_0.9.594
- 配置環(huán)境變量,在
~/.bash_profile
或者~/.zshrc
文件中添加以下配置
#Cycript配置
export CYCRIPT_PATH=/opt/cycript_0.9.594
使用
附加進(jìn)程
Monkey
中集成了Cycript
闹蒜,使用MonkeyDev
重簽名應(yīng)用寺枉,會(huì)自動(dòng)注入libcycript.dylib
相關(guān)文件。
當(dāng)設(shè)備啟動(dòng)注入了Cycript
的目標(biāo)應(yīng)用绷落,應(yīng)用進(jìn)程會(huì)調(diào)用Cycript
的方法姥闪,打開(kāi)端口供第三方監(jiān)聽(tīng),如下:
CYListenServer(6666);
當(dāng)設(shè)備啟用監(jiān)聽(tīng)時(shí)砌烁,第三方可以通過(guò)端口附加進(jìn)程筐喳,進(jìn)入cy環(huán)境,從而查看當(dāng)前進(jìn)程中的內(nèi)存數(shù)據(jù)函喉。假設(shè)端口IP為:172.20.10.14避归,則終端
附加方式如下:
cycript -r 172.20.10.14:6666
cy#
注意:進(jìn)程運(yùn)行的設(shè)備
和附加進(jìn)程的終端
必須在同一網(wǎng)絡(luò)環(huán)境
。
常用指令
- 獲取
keyWindow
cy# UIWindow.keyWindow()
#"<iConsoleWindow: 0x14ea6fee0; baseClass = UIWindow; frame = (0 0; 375 812); gestureRecognizers = <NSArray: 0x282279260>; layer = <UIWindowLayer: 0x282db4080>>"
- 獲取
UIApplication
cy# UIApp
#"<UIApplication: 0x14ea28e00>"
- 定義
變量并賦值
cy# var keyWd = UIWindow.keyWindow()
#"<iConsoleWindow: 0x14ea6fee0; baseClass = UIWindow; frame = (0 0; 375 812); gestureRecognizers = <NSArray: 0x282279260>; layer = <UIWindowLayer: 0x282db4080>>"
cy# keyWd.rootViewController
#"<MMUINavigationController: 0x14f11f800> ChildViewControllers:(\n \"<WCAccountLoginFirstViewController: 0x14f0fa600>\"\n)"
cy#
注意:當(dāng)程序的進(jìn)程結(jié)束了管呵,定義的所有變量也會(huì)釋放掉梳毙。
- 獲取
對(duì)象
//通過(guò)(#對(duì)象地址)獲取對(duì)象
cy# #0x14f11f800
#"<MMUINavigationController: 0x14f11f800> ChildViewControllers:(\n \"<WCAccountLoginFirstViewController: 0x14f0fa600>\"\n)"
//通過(guò)(*定義的變量)獲取對(duì)象
cy# *keyWd
{isa:iConsoleWindow,_responderFlags:@error,_constraintsExceptingSubviewAutoresizingConstraints:null...
查看當(dāng)前視圖結(jié)構(gòu)
cy# keyWd.recursiveDescription()
@"<iConsoleWindow: 0x14ea6fee0; baseClass = UIWindow; frame = (0 0; 375 812); gestureRecognizers = <NSArray: 0x282279260>; layer = <UIWindowLayer: 0x282db4080>>\n | <UITransitionView: 0x14ea65650; frame = (0 0; 375 812);...
cy# keyWd.recursiveDescription().toString()
`<iConsoleWindow: 0x14ea6fee0; baseClass = UIWindow; frame = (0 0; 375 812); gestureRecognizers = <NSArray: 0x282279260>; layer = <UIWindowLayer: 0x282db4080>>
| <UITransitionView: 0x14ea65650; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x282db5460>>
| | <UIDropShadowView: 0x14ea74650; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x282db5580>>
| | | <UILayoutContainerView: 0x14ea2e280; frame = (0 0; 375 812); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x28227a040>; layer = <CALayer: 0x282db47c0>>
| | | | <UINavigationTransitionView: 0x14ea724f0; frame = (0 0; 375 812); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x282db4800>>
查詢當(dāng)前進(jìn)程中該類(lèi)型的對(duì)象
cy# choose(UIButton)
[#"<FixTitleColorButton: 0x14ef05d40; baseClass = UIButton; frame = (20 18; 157.5 47); clipsToBounds = YES; opaque = NO; autoresize = RM; layer = <CALayer: 0x282d3d200>>",#"<FixTitleColorButton: 0x14ea2cfb0; baseClass = UIButton; frame = (197.5 18; 157.5 47); clipsToBounds = YES; opaque = NO; autoresize = LM; layer = <CALayer: 0x282dead20>>"]
-
修改內(nèi)存中的數(shù)據(jù)
修改當(dāng)前應(yīng)用圖標(biāo)的通知?dú)馀輸?shù)目為999,假設(shè)當(dāng)前使用Monkey安裝并運(yùn)行微信(WeChat8.0.2.ipa)
撇寞。
cy# [UIApp setApplicationBadgeString:@"999"]
修改結(jié)果如下:修改控件屬性
假設(shè)當(dāng)前處于微信的登陸界面,打印keyWindow
下所有視圖
UIWindow.keyWindow().recursiveDescription().toString()
從當(dāng)前界面中可以看到堂氯,有個(gè)+86
的view蔑担,因此可以直接在打印的所有視圖中查找+86
所在的控件
<WCUITextField: 0x116387c00; baseClass = UITextField; frame = (20 0; 73 44); text = '+86'; opaque = NO; autoresize = W+H; tintColor = UIExtendedSRGBColorSpace 0.027451 0.756863 0.376471 1; gestureRecognizers = <NSArray: 0x2817946f0>; borderStyle = None; background = <_UITextFieldNoBackgroundProvider: 0x2819310a0: textfield=<WCUITextField 0x116387c00>>; layer = <CALayer: 0x281b76700>>
修改WCUITextField文本框的text屬性,即:修改該控件的顯示咽白,將+86
修改成+95
#0x116387c00.text = @"+95"
擴(kuò)展指令
MonkeyDev
對(duì)一些常用方法進(jìn)行了封裝啤握,提供給開(kāi)發(fā)者使用,封裝方法的實(shí)現(xiàn)在Mokey
項(xiàng)目的Config
目錄下晶框,找到MDConfig.plist
文件
- 查看所有視圖
cy# pviews()
`<iConsoleWindow: 0x115c4f020; baseClass = UIWindow; frame = (0 0; 375 812); gestureRecognizers = <NSArray: 0x283ab8720>; layer = <UIWindowLayer: 0x283517b80>>
| <UITransitionView: 0x115866000; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x283517da0>>
| | <UIDropShadowView: 0x115851d10; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x283517900>>
pviews
等價(jià)如下指令:
cy# pviews
function (){return UIApp.keyWindow.recursiveDescription().toString()}
獲取當(dāng)前控制器
cy# pvcs()
"<MMUINavigationController 0x116068000>, state: appeared, view: <UILayoutContainerView 0x115876ee0>\n | <WCAccountLoginFirstViewController 0x1160c2a00>, state: appeared, view: <UIView 0x1158941a0>"
pvcs
等價(jià)如下指令
cy# pvcs
function (){return UIWindow.keyWindow().rootViewController._printHierarchy().toString()}
cy文件
Cycript
是一門(mén)腳本語(yǔ)言排抬,它可以加載封裝好的\*.cy
文件,因此授段,我們可以將常用的Cycript
功能封裝至\*.cy
文件蹲蒲,在調(diào)試的時(shí)候可以直接使用\*.cy
文件中封裝的指令。
在以上的擴(kuò)展示例中侵贵,MonkeyDev也對(duì)常用的指令進(jìn)行了封裝届搁。接下來(lái)我們來(lái)嘗試封裝自己的\*.cy文件
。
示例1
- 創(chuàng)建
test.cy
文件 - 將
test.cy
文件添加至MonkeyDemo
項(xiàng)目中。 -
test.cy
文件中先添加簡(jiǎn)單的方法
sum = function(a,b){
return a + b;
}
- 在
MokeyDemo
項(xiàng)目中卡睦,使用Copy Files
添加test.cy
宴胧,注意:test.cy
是腳本文件,不是MachO表锻,因此不需要勾選簽名恕齐。
- 運(yùn)行
MokeyDemo
項(xiàng)目 - 在終端對(duì)
MokeyDemo
項(xiàng)目進(jìn)行附加
cycript -r 172.20.10.14:6666
- 導(dǎo)入
test.cy
腳本
@import test
- 調(diào)用sum方法
sum(10,20)
30
示例2
- 創(chuàng)建
test.cy
文件 - 將
test.cy
文件添加至MonkeyDemo
項(xiàng)目中。 -
test.cy
文件中先添加簡(jiǎn)單的方法
(function(exports){
APPID = [NSBundle mainBundle].bundleIdentifier,
APPPATH = [NSBundle mainBundle].bundlePath,
APPHOME = NSHomeDirectory(),
rootVC = function(){
return UIApp.keyWindow.rootViewController;
};
keyWindow = function(){
return UIApp.keyWindow;
};
getCurrentVC = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = getCurrentVC(rootVC.selectedViewController);
}
else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = getCurrentVC(rootVC.visibleViewController);
}
else{
currentVC = rootVC;
}
return currentVC;
};
currentVC = function(){
return getCurrentVC(rootVC());
};
})(exports);
- 在
MokeyDemo
項(xiàng)目中瞬逊,使用Copy Files
添加test.cy
显歧,注意:test.cy
是腳本文件,不是MachO码耐,因此不需要勾選簽名追迟。
- 運(yùn)行
MokeyDemo
項(xiàng)目 - 在終端對(duì)
MokeyDemo
項(xiàng)目進(jìn)行附加
cycript -r 172.20.10.14:6666
- 導(dǎo)入
test.cy
腳本
@import test
- 獲取
APPID
APPID
@"com.hq.MokeyDemo"
- 獲取
APPPATH
APPPATH
@"/private/var/containers/Bundle/Application/D620C178-5030-48E4-9276-981150FF7299/MokeyDemo.app"
- 獲取
APPHOME
APPHOME
@"/var/mobile/Containers/Data/Application/C2ED1E99-47C4-4C29-8AE6-9C5C136CEE04"
- 調(diào)用
currentVC
方法
currentVC()
#"<WCAccountLoginFirstViewController: 0x14b0b4200>"
總結(jié)
Cycipt
是一種腳本語(yǔ)言,混合了多種語(yǔ)法(混合多種語(yǔ)法的解釋器)骚腥,所以可以兼容敦间。Cycipt
可以附加到進(jìn)程,用來(lái)動(dòng)態(tài)調(diào)試束铭。可以將常用的功能封裝成
\*.cy文件
廓块,當(dāng)附加進(jìn)程后,導(dǎo)致\*.cy文件
契沫,即可使用封裝的功能带猴。