Cycript Tricks: Difference between revisions

From iPhone Development Wiki
 
(17 intermediate revisions by 10 users not shown)
Line 1: Line 1:
== Printing Ivars ==
== 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:
 
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:


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 ==


== Printing 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 methods = class_copyMethodList(objc_getClass(className), count);
   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);
  free(count);
   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 message property of the isa, e.g. to get rootViewControllers methods:
 
UIApp.keyWindow.rootViewController.isa.messages
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.messages) if (!regexp || regexp.test(m))]; }
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 Objective-C Objects from Addresses ==
=== Getting class methods ===
Use <tt>new Instance(0xdeadbabe)</tt>.
 
''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# var p = new Instance(0x8614390)
cy# NSRunLoop.constructor.prototype['currentRunLoop'] = ...
cy# p
["<SKPaymentTransaction: 0x8613d80>"]
</source>
</source>


== Load frameworks ==
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">
function loadFramework(fw) {
cy# printMethods("NSRunLoop", true)
  var h="/System/Library/",t="Frameworks/"+fw+".framework";
[{selector:@selector(currentRunLoop),implementation:&(extern "C" id 674681217(id, SEL, ...))}...
  [[NSBundle bundleWithPath:h+t]||[NSBundle bundleWithPath:h+"Private"+t] load];
}
</source>
</source>


== Replacing existing Objective-C methods ==
=== Replacing existing Objective-C methods ===
You can simulate MSHookMessage by replacing contents in the <tt>messages</tt> array, e.g.
 
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.messages['description'];
cy# original_NSRunLoop_description = NSRunLoop.prototype['description'];
0x339d94c3
(extern "C" id ":description"(id, SEL))
cy# NSRunLoop.messages['description'] = function() { return original_NSRunLoop_description.call(this).toString().substr(0, 80)+", etc."; }
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 0x205ee0 [0x381dbff4]>{locked = false, wait port = 0x1303, stopped = , etc."
#"<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.messages['menuButtonDown:']
cy# original_SpringBoard_menuButtonDown = SpringBoard.prototype['menuButtonDown:']
0x17dbab1
0x17dbab1
cy# SpringBoard.messages['menuButtonDown:'] = function(arg1) {original_SpringBoard_menuButtonDown.call(this, arg1);}
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>.


=== Getting class methods ===
== List all subclasses ==
''class''<tt>.messages</tt> only contains instance methods. To hook class methods, you need to get to its ''metaclass''. A simple way would be
 
[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">
cy# NSRunLoop->isa.messages['currentRunLoop'] = ...
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 ==


In order to use functions from the CGGeometry class, you must type this in the cycript prompt:
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=c>
<source lang=javascript>
function CGPointMake(x, y) { return {x:x, y:y}; }
function CGPointMake(x, y) { return [x, y]; }
function CGSizeMake(w, h) { return {width:w, height:h}; }
function CGSizeMake(w, h) { return [w, h]; }
function CGRectMake(x, y, w, h) { return {origin:CGPointMake(x,y), size:CGSizeMake(w, h)}; }
function CGRectMake(x, y, w, h) { return [[x, y], [w, h]]; }
</source>  
</source>
 
== Using NSError ==
 
<source lang="objc">
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"}'
</source>


== Writing Cycript output to file ==
== Writing Cycript output to file ==
Line 173: Line 250:


<source lang="javascript">
<source lang="javascript">
cy# ?expand
cy# UIApp.keyWindow.recursiveDescription().toString()
expand == true
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>
The <tt>?expand</tt> command toggles between line breaks being displayed as actual line breaks not just /n


== Cycript scripts ==
== Cycript scripts ==


Custom shell function that loads a cycript file:
Custom shell function that loads a cycript file:
  cyc () { cycript -p $1 /var/root/common.cy > /dev/null 2>&1; cycript -p $1; }
  cyc () { cycript -p $1 /var/root/common.cy > /dev/null; cycript -p $1; }


  Usage: cyc ProcessName
  Usage: cyc ProcessName
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) ===


=== 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>
  root# cycript -p Skype weak_classdump.cy; cycript -p Skype
  root# cycript -p Skype weak_classdump.cy; cycript -p Skype
  'Added weak_classdump to "Skype" (1685)'
  'Added weak_classdump to "Skype" (1685)'
Line 232: Line 305:
  #cy weak_classdump_bundle([NSBundle mainBundle],"/tmp/MobilePhone")
  #cy weak_classdump_bundle([NSBundle mainBundle],"/tmp/MobilePhone")
  "Dumping bundle... Check syslog. Will play lock sound when done."
  "Dumping bundle... Check syslog. Will play lock sound when done."
</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."

Utils

Link: https://github.com/Tyilo/cycript-utils