(→Weak Classdump (Cycript based class-dump): adding syntax highlighting block) |
Nosskirneh (talk | contribs) |
||
(15 intermediate revisions by 9 users not shown) | |||
Line 1: | Line 1: | ||
== | == Getting objects == | ||
=== Objective-C objects using choose() === | |||
The function <tt>choose()</tt>, introduced in version 0.9.502<sup>[citation needed]</sup> and documented [http://www.cycript.org/manual/#7061c058-5485-4c00-be7e-b67accc55796 here], allows us to get an array of existing objects of a certain class. | |||
=== Objective-C objects from addresses === | |||
Use <tt>#0xdeadbabe</tt>. | |||
<source lang="javascript"> | |||
cy# var p = #0x8614390 | |||
cy# p | |||
["<SKPaymentTransaction: 0x8613d80>"] | |||
</source> | |||
=== Javascript variables === | |||
''Requires testing.'' | |||
<source lang="javascript"> | |||
cy# typedef int a; | |||
cy# for (x in this) if (x == 'a') system.print('yay'); | |||
</source> | |||
== Getting ivars == | |||
Often just typing <tt>*varName</tt> works: | Often just typing <tt>*varName</tt> works: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
Line 6: | Line 32: | ||
cy# | cy# | ||
</source> | </source> | ||
Sometimes it does not... | Sometimes it does not... | ||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# *UIApp | cy# *UIApp | ||
{message:"hasProperty callback returned true for a property that doesn't exist.",name:"ReferenceError"} | {message:"hasProperty callback returned true for a property that doesn't exist.",name:"ReferenceError"} | ||
</source> | </source> | ||
Then you can do: | |||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# [i for (i in *UIApp)] | cy# [i for (i in *UIApp)] | ||
Line 17: | Line 47: | ||
</source> | </source> | ||
You may use this function to get as much ivar values as possible: | |||
<source lang="javascript"> | <source lang="javascript"> | ||
function tryPrintIvars(a){ var x={}; for(i in *a){ try{ x[i] = (*a)[i]; } catch(e){} } return x; } | function tryPrintIvars(a){ var x={}; for(i in *a){ try{ x[i] = (*a)[i]; } catch(e){} } return x; } | ||
</source> | </source> | ||
To use: | To use: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# *a | cy# *a | ||
Line 31: | Line 62: | ||
</source> | </source> | ||
== Getting bundle identifier == | |||
<source lang="javascript"> | |||
NSBundle.mainBundle.bundleIdentifier | |||
</source> | |||
== Getting methods == | |||
Function to get the methods: | Function to get the methods: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
function printMethods(className) { | function printMethods(className, isa) { | ||
var count = new new Type("I"); | var count = new new Type("I"); | ||
var | var classObj = (isa != undefined) ? objc_getClass(className).constructor : objc_getClass(className); | ||
var methods = class_copyMethodList(classObj, count); | |||
var methodsArray = []; | var methodsArray = []; | ||
for(var i = 0; i < *count; i++) { | for(var i = 0; i < *count; i++) { | ||
Line 45: | Line 82: | ||
} | } | ||
free(methods); | free(methods); | ||
return methodsArray; | return methodsArray; | ||
} | } | ||
Line 51: | Line 87: | ||
Usage: | Usage: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# printMethods("MailboxPrefsTableCell") | cy# printMethods("MailboxPrefsTableCell") | ||
Line 56: | Line 93: | ||
cy# | cy# | ||
</source> | </source> | ||
You can also just look at the | |||
UIApp.keyWindow.rootViewController.isa. | You can also just look at the prototype property of the isa, e.g. to get rootViewControllers methods: | ||
<tt>UIApp.keyWindow.rootViewController.isa.prototype</tt> | |||
=== Get methods matching particular RegExp === | === Get methods matching particular RegExp === | ||
<source lang="javascript"> | <source lang="javascript"> | ||
function methodsMatching(cls, regexp) { return [[new Selector(m).type(cls), m] for (m in cls. | function methodsMatching(cls, regexp) { return [[new Selector(m).type(cls), m] for (m in cls.prototype) if (!regexp || regexp.test(m))]; } | ||
</source> | </source> | ||
Usage: | Usage: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# methodsMatching(NSRunLoop, /forKey:$/) | cy# methodsMatching(NSRunLoop, /forKey:$/) | ||
Line 69: | Line 110: | ||
</source> | </source> | ||
== Getting | === Getting class methods === | ||
''class''<tt>.prototype</tt> only contains instance methods. To hook class methods, you need to get to its ''metaclass''. A simple way would be | |||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# | cy# NSRunLoop.constructor.prototype['currentRunLoop'] = ... | ||
[ | |||
</source> | </source> | ||
Alternatively, set the optional second parameter in <tt>printMethods()</tt> to <tt>true</tt>, e.g. <tt>printMethods("NSRunLoop", true)</tt> | |||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# printMethods("NSRunLoop", true) | |||
[{selector:@selector(currentRunLoop),implementation:&(extern "C" id 674681217(id, SEL, ...))}... | |||
} | |||
</source> | </source> | ||
== Replacing existing Objective-C methods == | === Replacing existing Objective-C methods === | ||
You can simulate MSHookMessage by replacing contents in the <tt> | |||
You can simulate MSHookMessage by replacing contents in the <tt>prototype</tt> array, e.g. | |||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# original_NSRunLoop_description = NSRunLoop. | cy# original_NSRunLoop_description = NSRunLoop.prototype['description']; | ||
(extern "C" id ":description"(id, SEL)) | |||
cy# NSRunLoop. | cy# NSRunLoop.prototype['description'] = function() { return original_NSRunLoop_description.call(this).toString().substr(0, 80)+", etc."; } | ||
{} | function (){var e;e=this;return original_NSRunLoop_description.call(e).toString().substr(0,80)+", etc."} | ||
cy# [NSRunLoop currentRunLoop] | cy# [NSRunLoop currentRunLoop] | ||
"<CFRunLoop | #"<CFRunLoop 0x13750a630 [0x1a103e150]>{wakeup port = 0x1003, stopped = false, ign, etc." | ||
</source> | </source> | ||
Note the <tt>func.call(this)</tt> construct. This binds the <tt>this</tt> in the original function to the user-specified one. If more than one variable is needed, use <tt>function(arg1, arg2, arg3, ...) {...func.call(self, arg1, arg2, arg3, ...);}</tt>, e.g. | Note the <tt>func.call(this)</tt> construct. This binds the <tt>this</tt> in the original function to the user-specified one. If more than one variable is needed, use <tt>function(arg1, arg2, arg3, ...) {...func.call(self, arg1, arg2, arg3, ...);}</tt>, e.g. | ||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# original_SpringBoard_menuButtonDown = SpringBoard. | cy# original_SpringBoard_menuButtonDown = SpringBoard.prototype['menuButtonDown:'] | ||
0x17dbab1 | 0x17dbab1 | ||
cy# SpringBoard. | cy# SpringBoard.prototype['menuButtonDown:'] = function(arg1) {original_SpringBoard_menuButtonDown.call(this, arg1);} | ||
function (e) {var e;var $cy0=this;original_SpringBoard_menuButtonDown.call($cy0,e);} | function (e) {var e;var $cy0=this;original_SpringBoard_menuButtonDown.call($cy0,e);} | ||
</source> | </source> | ||
Line 106: | Line 149: | ||
Note that the subsequent arguments will not be automatically mapped to the corresponding Objective-C types, so instead of "foo" you will need to use <tt>[NSString stringWithString:"foo"]</tt>. | Note that the subsequent arguments will not be automatically mapped to the corresponding Objective-C types, so instead of "foo" you will need to use <tt>[NSString stringWithString:"foo"]</tt>. | ||
== | == List all subclasses == | ||
[c for each (c in ObjectiveC.classes) if (class_getSuperclass(c) && [c isSubclassOfClass:UIView])] | |||
(The <tt>class_getSuperclass</tt> is needed to prevent crash due to the "Object" class not inheriting from NSObject) | |||
== Load frameworks == | |||
<source lang="javascript"> | <source lang="javascript"> | ||
function loadFramework(fw) { | |||
var h="/System/Library/",t="Frameworks/"+fw+".framework"; | |||
[[NSBundle bundleWithPath:h+t]||[NSBundle bundleWithPath:h+"Private"+t] load]; | |||
} | |||
</source> | </source> | ||
== Include other Cycript files == | == Include other Cycript files == | ||
As of 0.9.274-1, there isn't a native file import feature. If cycript will be hooked into another process, since the data will be retained there, you can first load the other .cy file with this: | As of 0.9.274-1, there isn't a native file import feature. If cycript will be hooked into another process, since the data will be retained there, you can first load the other .cy file with this: | ||
<source lang="bash"> | <source lang="bash"> | ||
localhost:~ mobile$ cycript -p SpringBoard main.cy | localhost:~ mobile$ cycript -p SpringBoard main.cy | ||
Line 122: | Line 176: | ||
If cycript is launched standalone, inclusion can still be faked with a combination of cycript compiler and Javascript's <tt>eval</tt> function: | If cycript is launched standalone, inclusion can still be faked with a combination of cycript compiler and Javascript's <tt>eval</tt> function: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
// include other .cy files | // include other .cy files | ||
Line 131: | Line 186: | ||
} | } | ||
</source> | </source> | ||
As of version 0.9.502<sup>[citation needed]</sup>, there is. See [http://www.cycript.org/manual/#754b6781-f13f-4a0a-ba2f-594d5778e97f @import's documentation]. | |||
== Using NSLog == | == Using NSLog == | ||
In recent versions of cycript, NSLog should just work. If not, using the following: | |||
Type in the console: | Type in the console: | ||
NSLog_ = dlsym(RTLD_DEFAULT, "NSLog") | NSLog_ = dlsym(RTLD_DEFAULT, "NSLog") | ||
Line 149: | Line 209: | ||
== Using CGGeometry functions == | == Using CGGeometry functions == | ||
CGPoint, CGSize, and CGRect are structures of numbers (floats or doubles), and can be represented in Cycript with simple arrays: | |||
<source lang=javascript> | |||
cy# view.frame = [[10, 10], [100, 100]]; | |||
[[10,10],[100,100]] | |||
</source> | |||
If you’d prefer to use the CG…Make() functions, you can construct them yourself: | |||
<source lang=javascript> | |||
function CGPointMake(x, y) { return [x, y]; } | |||
function CGSizeMake(w, h) { return [w, h]; } | |||
function CGRectMake(x, y, w, h) { return [[x, y], [w, h]]; } | |||
</source> | |||
== Using NSError == | |||
<source lang= | <source lang="objc"> | ||
cy# var error = new @encode(NSError *) | |||
&null | |||
cy# var thing; [[NSFileManager defaultManager] copyItemAtPath:@"aaadsdsds" toPath:@"bbbdsdsdsds" error:error]; thing = *error | |||
</source> | cy# thing | ||
#'Error Domain=NSCocoaErrorDomain Code=260 "The file \xe2\x80\x9caaadsdsds\xe2\x80\x9d couldn\xe2\x80\x99t be opened because there is no such file." UserInfo=0x100310af0 {NSFilePath=aaadsdsds, NSUnderlyingError=0x1003108e0 "The operation couldn\xe2\x80\x99t be completed. No such file or directory"}' | |||
</source> | |||
== Writing Cycript output to file == | == Writing Cycript output to file == | ||
Line 173: | Line 250: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
cy# UIApp.keyWindow.recursiveDescription().toString() | |||
cy# UIApp.keyWindow.recursiveDescription | |||
"<UIWindow: 0x13a900; frame = (0 0; 320 480); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x13a9d0>> | "<UIWindow: 0x13a900; frame = (0 0; 320 480); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x13a9d0>> | ||
<UITextField: 0x13abf0; frame = (20 40; 280 31); text = ''; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x13ad10>> | <UITextField: 0x13abf0; frame = (20 40; 280 31); text = ''; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x13ad10>> | ||
Line 193: | Line 268: | ||
<UILabel: 0x13aaf0; frame = (9 8; 266 15); text = 'Test'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1399f0>>" | <UILabel: 0x13aaf0; frame = (9 8; 266 15); text = 'Test'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1399f0>>" | ||
</source> | </source> | ||
== Cycript scripts == | == Cycript scripts == | ||
Line 208: | Line 280: | ||
<blockquote>'''Warning:''' If you run this command multiple times against a process, the scripts will be loaded into the script multiple times. This could potentially have unexpected consequences depending on the scripts you are loading. It is not a proper way of doing this and saurik recommends against it.</blockquote> | <blockquote>'''Warning:''' If you run this command multiple times against a process, the scripts will be loaded into the script multiple times. This could potentially have unexpected consequences depending on the scripts you are loading. It is not a proper way of doing this and saurik recommends against it.</blockquote> | ||
=== Weak Classdump (Cycript based class-dump) === | |||
Link: https://github.com/limneos/weak_classdump | Link: https://github.com/limneos/weak_classdump | ||
Usage: | Usage: | ||
<source lang=javascript> | <source lang=javascript> | ||
root# cycript -p Skype weak_classdump.cy; cycript -p Skype | root# cycript -p Skype weak_classdump.cy; cycript -p Skype | ||
Line 234: | Line 306: | ||
"Dumping bundle... Check syslog. Will play lock sound when done." | "Dumping bundle... Check syslog. Will play lock sound when done." | ||
</source> | </source> | ||
=== Utils === | |||
Link: https://github.com/Tyilo/cycript-utils |
Latest revision as of 16:44, 13 February 2018
Getting objects
Objective-C objects using choose()
The function choose(), introduced in version 0.9.502[citation needed] and documented here, allows us to get an array of existing objects of a certain class.
Objective-C objects from addresses
Use #0xdeadbabe.
cy# var p = #0x8614390
cy# p
["<SKPaymentTransaction: 0x8613d80>"]
Javascript variables
Requires testing.
cy# typedef int a;
cy# for (x in this) if (x == 'a') system.print('yay');
Getting ivars
Often just typing *varName works:
cy# *controller
{isa:"PrefsRootController",_contentView:"<UIView: 0x10bd70; frame = (0 0; 320 460); autoresize = W+H; layer = <CALayer: 0x150120>>",_navBar:...
cy#
Sometimes it does not...
cy# *UIApp
{message:"hasProperty callback returned true for a property that doesn't exist.",name:"ReferenceError"}
Then you can do:
cy# [i for (i in *UIApp)]
["isa","_delegate","_touchMap","_exclusiveTouchWindows","_event",...
You may use this function to get as much ivar values as possible:
function tryPrintIvars(a){ var x={}; for(i in *a){ try{ x[i] = (*a)[i]; } catch(e){} } return x; }
To use:
cy# *a
{message:"hasProperty callback returned true for a property that doesn't exist.",name:"ReferenceError"}
cy# tryPrintIvars(a)
{isa:"SBWaveView",_layer:"<CALayer: 0x2a5160>",_tapInfo:null,_gestureInfo:null,_gestureRecognizers:...
Getting bundle identifier
NSBundle.mainBundle.bundleIdentifier
Getting methods
Function to get the methods:
function printMethods(className, isa) {
var count = new new Type("I");
var classObj = (isa != undefined) ? objc_getClass(className).constructor : objc_getClass(className);
var methods = class_copyMethodList(classObj, count);
var methodsArray = [];
for(var i = 0; i < *count; i++) {
var method = methods[i];
methodsArray.push({selector:method_getName(method), implementation:method_getImplementation(method)});
}
free(methods);
return methodsArray;
}
Usage:
cy# printMethods("MailboxPrefsTableCell")
[{selector:@selector(layoutSubviews),implementation:0x302bf2e9},{selector:@selector(setCurrentMailbox:),implementation:0x302bee0d},...
cy#
You can also just look at the prototype property of the isa, e.g. to get rootViewControllers methods: UIApp.keyWindow.rootViewController.isa.prototype
Get methods matching particular RegExp
function methodsMatching(cls, regexp) { return [[new Selector(m).type(cls), m] for (m in cls.prototype) if (!regexp || regexp.test(m))]; }
Usage:
cy# methodsMatching(NSRunLoop, /forKey:$/)
[["v20@0:4I8@12@16","didChange:valuesAtIndexes:forKey:"],["v20@0:4I8@12@16","willChange:valuesAtIndexes:forKey:"],["v16@0:4@8@12","setValue:forKey:"]]
Getting class methods
class.prototype only contains instance methods. To hook class methods, you need to get to its metaclass. A simple way would be
cy# NSRunLoop.constructor.prototype['currentRunLoop'] = ...
Alternatively, set the optional second parameter in printMethods() to true, e.g. printMethods("NSRunLoop", true)
cy# printMethods("NSRunLoop", true)
[{selector:@selector(currentRunLoop),implementation:&(extern "C" id 674681217(id, SEL, ...))}...
Replacing existing Objective-C methods
You can simulate MSHookMessage by replacing contents in the prototype array, e.g.
cy# original_NSRunLoop_description = NSRunLoop.prototype['description'];
(extern "C" id ":description"(id, SEL))
cy# NSRunLoop.prototype['description'] = function() { return original_NSRunLoop_description.call(this).toString().substr(0, 80)+", etc."; }
function (){var e;e=this;return original_NSRunLoop_description.call(e).toString().substr(0,80)+", etc."}
cy# [NSRunLoop currentRunLoop]
#"<CFRunLoop 0x13750a630 [0x1a103e150]>{wakeup port = 0x1003, stopped = false, ign, etc."
Note the func.call(this) construct. This binds the this in the original function to the user-specified one. If more than one variable is needed, use function(arg1, arg2, arg3, ...) {...func.call(self, arg1, arg2, arg3, ...);}, e.g.
cy# original_SpringBoard_menuButtonDown = SpringBoard.prototype['menuButtonDown:']
0x17dbab1
cy# SpringBoard.prototype['menuButtonDown:'] = function(arg1) {original_SpringBoard_menuButtonDown.call(this, arg1);}
function (e) {var e;var $cy0=this;original_SpringBoard_menuButtonDown.call($cy0,e);}
Note that the subsequent arguments will not be automatically mapped to the corresponding Objective-C types, so instead of "foo" you will need to use [NSString stringWithString:"foo"].
List all subclasses
[c for each (c in ObjectiveC.classes) if (class_getSuperclass(c) && [c isSubclassOfClass:UIView])]
(The class_getSuperclass is needed to prevent crash due to the "Object" class not inheriting from NSObject)
Load frameworks
function loadFramework(fw) {
var h="/System/Library/",t="Frameworks/"+fw+".framework";
[[NSBundle bundleWithPath:h+t]||[NSBundle bundleWithPath:h+"Private"+t] load];
}
Include other Cycript files
As of 0.9.274-1, there isn't a native file import feature. If cycript will be hooked into another process, since the data will be retained there, you can first load the other .cy file with this:
localhost:~ mobile$ cycript -p SpringBoard main.cy
0x12345678
localhost:~ mobile$ cycript -p SpringBoard
cy# ...
If cycript is launched standalone, inclusion can still be faked with a combination of cycript compiler and Javascript's eval function:
// include other .cy files
function include(fn) {
var t = [new NSTask init]; [t setLaunchPath:@"/usr/bin/cycript"]; [t setArguments:["-c", fn]];
var p = [NSPipe pipe]; [t setStandardOutput:p]; [t launch]; [t waitUntilExit];
var s = [new NSString initWithData:[[p fileHandleForReading] readDataToEndOfFile] encoding:4];
return this.eval(s.toString());
}
As of version 0.9.502[citation needed], there is. See @import's documentation.
Using NSLog
In recent versions of cycript, NSLog should just work. If not, using the following:
Type in the console:
NSLog_ = dlsym(RTLD_DEFAULT, "NSLog") NSLog = function() { var types = 'v', args = [], count = arguments.length; for (var i = 0; i != count; ++i) { types += '@'; args.push(arguments[i]); } new Functor(NSLog_, types).apply(null, args); }
And then you can use NSLog as usual:
cy# NSLog_ = dlsym(RTLD_DEFAULT, "NSLog") 0x31451329 cy# NSLog = function() { var types = 'v', args = [], count = arguments.length; for (var i = 0; i != count; ++i) { types += '@'; args.push(arguments[i]); } new Functor(NSLog_, types).apply(null, args); } {} cy# NSLog("w ivars: %@", tryPrintIvars(w))
If you are attached to a process, the output is going to be in the syslog:
Nov 17 20:26:01 iPhone3GS Foobar[551]: w ivars: {\n contentView = <UIView: 0x233ea0; ....}
Using CGGeometry functions
CGPoint, CGSize, and CGRect are structures of numbers (floats or doubles), and can be represented in Cycript with simple arrays:
cy# view.frame = [[10, 10], [100, 100]];
[[10,10],[100,100]]
If you’d prefer to use the CG…Make() functions, you can construct them yourself:
function CGPointMake(x, y) { return [x, y]; }
function CGSizeMake(w, h) { return [w, h]; }
function CGRectMake(x, y, w, h) { return [[x, y], [w, h]]; }
Using NSError
cy# var error = new @encode(NSError *)
&null
cy# var thing; [[NSFileManager defaultManager] copyItemAtPath:@"aaadsdsds" toPath:@"bbbdsdsdsds" error:error]; thing = *error
cy# thing
#'Error Domain=NSCocoaErrorDomain Code=260 "The file \xe2\x80\x9caaadsdsds\xe2\x80\x9d couldn\xe2\x80\x99t be opened because there is no such file." UserInfo=0x100310af0 {NSFilePath=aaadsdsds, NSUnderlyingError=0x1003108e0 "The operation couldn\xe2\x80\x99t be completed. No such file or directory"}'
Writing Cycript output to file
Cycript output is an NSString, so it is possible to call writeToFile and save it somewhere. Example:
[[someObject someFunction] writeToFile:"/var/mobile/cycriptoutput.txt" atomically:NO encoding:4 error:NULL]
You can use this, for example, to get a dump of SpringBoard's view tree.
iPhone:~$ cycript -p SpringBoard
cy# [[UIApp->_uiController.window recursiveDescription] writeToFile:"/var/mobile/viewdump.txt" atomically:NO encoding:4 error:NULL]
Printing view hierarchy
cy# UIApp.keyWindow.recursiveDescription().toString()
"<UIWindow: 0x13a900; frame = (0 0; 320 480); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x13a9d0>>
<UITextField: 0x13abf0; frame = (20 40; 280 31); text = ''; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x13ad10>>
<UITextFieldRoundedRectBackgroundView: 0x143d10; frame = (0 0; 280 31); userInteractionEnabled = NO; layer = <CALayer: 0x143dc0>>
<UIImageView: 0x144030; frame = (0 0; 8 15); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1440b0>>
<UIImageView: 0x144400; frame = (8 0; 264 15); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x144430>>
<UIImageView: 0x144460; frame = (272 0; 8 15); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x144490>>
<UIImageView: 0x1444c0; frame = (8 0; 0 15); userInteractionEnabled = NO; layer = <CALayer: 0x1444f0>>
<UIImageView: 0x144520; frame = (0 15; 8 1); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x144550>>
<UIImageView: 0x144580; frame = (8 15; 264 1); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1445b0>>
<UIImageView: 0x1445e0; frame = (272 15; 8 1); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x144610>>
<UIImageView: 0x144640; frame = (8 15; 0 1); userInteractionEnabled = NO; layer = <CALayer: 0x144670>>
<UIImageView: 0x1446a0; frame = (0 16; 8 15); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1446d0>>
<UIImageView: 0x144700; frame = (8 16; 264 15); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x144730>>
<UIImageView: 0x144760; frame = (272 16; 8 15); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x144790>>
<UIImageView: 0x1447c0; frame = (8 16; 0 15); userInteractionEnabled = NO; layer = <CALayer: 0x1447f0>>
<UILabel: 0x13aaf0; frame = (9 8; 266 15); text = 'Test'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1399f0>>"
Cycript scripts
Custom shell function that loads a cycript file:
cyc () { cycript -p $1 /var/root/common.cy > /dev/null; cycript -p $1; }
Usage: cyc ProcessName
Add this to /etc/profile.d/cycript.sh to make it available in all sessions.
Warning: If you run this command multiple times against a process, the scripts will be loaded into the script multiple times. This could potentially have unexpected consequences depending on the scripts you are loading. It is not a proper way of doing this and saurik recommends against it.
Weak Classdump (Cycript based class-dump)
Link: https://github.com/limneos/weak_classdump
Usage:
root# cycript -p Skype weak_classdump.cy; cycript -p Skype
'Added weak_classdump to "Skype" (1685)'
cy# UIApp
"<HellcatApplication: 0x1734e0>"
cy# weak_classdump(HellcatApplication);
"Wrote file to /tmp/HellcatApplication.h"
cy# UIApp.delegate
"<SkypeAppDelegate: 0x194db0>"
cy# weak_classdump(SkypeAppDelegate,"/someDirWithWriteAccess/");
"Wrote file to /someDirWithWriteAccess/SkypeAppDelegate.h"
root# cycript -p iapd weak_classdump.cy; cycript -p iapd
'Added weak_classdump to "iapd" (1127)'
cy# weak_classdump(IAPPortManager)
"Wrote file to /tmp/IAPPortManager.h"
root# cycript -p MobilePhone weak_classdump.cy; cycript -p MobilePhone
'Added weak_classdump to "MobilePhone" (385)'
#cy weak_classdump_bundle([NSBundle mainBundle],"/tmp/MobilePhone")
"Dumping bundle... Check syslog. Will play lock sound when done."