preface
How do we dynamically analyze and debug other people’s applications and then inject scripts for our own purposes? We have all heard of Hook, so what is its principle and what kinds of Hook technology are there? The so-called knife does not mistakenly cut wood, the following several problems listed Hook principle and dynamic debugging, as a note for reference and learning only.
1.0 Hook principle
I have a HOOK. In iOS reverse is the technique of changing the flow of a program. Hook can let other people’s programs to execute their own code, we focus on understanding its principle, so that malicious code can be effectively protected. The following several hook technology analysis.
1.1 MethodSwizzle
This is the more familiar Hook method, callOC system apis
, using OC’sRuntime
Properties, dynamic changeSEL (method number) and IMP
(method implementation), to achieve the purpose of OC method call process change. It is mainly used forOC method
. In OC, the relationship between SEL and IMP is like that of a book"Directory"
. SEL is method number"Title"
The same. IMP is the real address of the method implementation, like the “page number.” They are one-to-one correspondence, as shown in the figure below, we achieve the purpose of hook by changing this correspondence.
Use case
The following takes hook wechat login event as an example. When the login button is clicked, the input password is obtained without affecting the original login logic.
- referenceReverse with shell smashingArticle, create a demo project, put the smashed wechat IPA package into the APP folder,
Pre-run project
Install the demo on your phone - with
appSign.sh
The scriptRe-sign wechat
And install it on your phone. Note that the appsign.sh script is not deletedmacho
Cannot be signed inWatch, the plugin
Folders, the latest version of wechat 8.0.16 also need to be deletedcom.apple.WatchPlaceholder
Folder, as follows
Xcode
Run re-signed wechat,lldb
Additional debugging wechat login interface
- Click the login button to see the login message sent
id
forWCAccountMainLoginViewController
.SEL
foronNext
We also need to know which UITextField the password control is,Class-dump
Wechat header file, static analysisWCAccountMainLoginViewController.h
The header file looks like this
No UI component associated with the password was found, but there is a property named_mainPageView
Open the fileWCAccountLoginMainPageView.h
Files looking for passwords related to the UI
Seems to have found a very password-related property_passwordTextItem
, open the fileWCRedesignTextItem.h
fileWCRedesignTextItem.h
There is an attribute in_textFiled
Open,WCUITextField.h
file
WCUITextField inherits from UITextField, so far we have located the password component, and the keyValue relationship is: WCAccountMainLoginViewController – > _mainPageView – > _passwordTextItem – > _textField.
onNext
Method found, password component also found, you can hook code, a new demowgy.framework
, write hook code as follows
I got the password, but[self newnext]
callThe original logic collapsed
The breakpoint is at line 23, print the id and sel at this point, id isWCAccountMainLoginViewController
, selnewNext
, butWCAccountMainLoginViewController
And in theThere is no newNext method
, so you need to add this method to the class and change it to the following
+ (void)load{
Method oldmethod=class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
const char * typeencode= method_getTypeEncoding(oldmethod);
class_addMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(newNext),method_getImplementation(class_getInstanceMethod(self, @selector(newNext))), typeencode);
method_exchangeImplementations(oldmethod, class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(newNext))); } - (void)newNext{
UITextField* password=[[[self valueForKey:@"_mainPageView"] valueForKey:@"_passwordTextItem"] valueForKey:@"_textField"];
NSLog(@"% @",password.text);
[self newNext];
}
Copy the code
Method_exchangeImplementations although methods can be exchanged, but if you don’t pay attention to calling the original method, you can use class_replaceMethod instead
+ (void)load{
Method oldmethod=class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext));
const char * typeencode= method_getTypeEncoding(oldmethod);
oldimp= class_replaceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext), newNext, typeencode);
}
IMP (*oldimp)(id self,SEL _cmd);
void newNext(id self,SEL _cmd){
UITextField* password=[[[self valueForKey:@"_mainPageView"] valueForKey:@"_passwordTextItem"] valueForKey:@"_textField"];
NSLog(@"% @",password.text);
oldimp(self,_cmd);
}
Copy the code
IMP= (*oldimp)(id self,SEL _cmd); oldimp =(oldimp)(id self,SEL _cmd) Class_replaceMethod is a bit simpler, but many third-party hook frameworks use the setImp and getImp apis to implement hooks, such as the Monkey framework. I also feel that setImp and getImp are more logical
+ (void)load{
oldimp=method_getImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)));
method_setImplementation(class_getInstanceMethod(objc_getClass("WCAccountMainLoginViewController"), @selector(onNext)), newNext);
}
IMP (*oldimp)(id self,SEL _cmd);
void newNext(id self,SEL _cmd){
UITextField* password=[[[self valueForKey:@"_mainPageView"] valueForKey:@"_passwordTextItem"] valueForKey:@"_textField"];
NSLog(@"% @",password.text);
oldimp(self,_cmd);
}
Copy the code
- So once you’ve written the logical code, this is the last thing you need to do
FrameWork
Injected into theMacho LoadCommands
In the paragraph, this involvesdyld
Loading principle, useyololibTool changeMachO
.yololib
Download it and copy it into the project directoryappSign.sh
Add the following script at the bottom and re-run the APP to inject successfully
yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/wgyFramework.framework/wgyFramework"
Copy the code
MethodSwizzle is mainly used forHook OC
Method, often using the following API
method_exchangeImplementations
: Exchange two API, use should be careful, to avoid the problem of calling the original method crashclass_replaceMethod
: Replace the IMP of the original method, saveAddress of the primitive function pointer
.method_getImplementation
,method_setImplementation
SetImp sets the address of the pointer to the new function.It is recommended to use
.
1.2 FishHook
FaceBook provides a tool, using MachO file loading principle, by dynamically changing the pointer address of lazy and non-lazy two tables to achieve the purpose of Hook C function. Note that the C function here refers to the system’s own C functions, such as MethodSwizzle function, NSLog function and other system shared cache C functions, can not Hook their own C functions. Let’s see how it works, and then how it works, okay
Use case
So let’s take the Hook SYSTEM API “method_exchangeImplementations” C function, and we can sort of feel the inverse protection, so we’ll replace the method_exchangeImplementations system function with something we defined ourselves, So that’s invalidated when someone uses the system method method_exchangeImplementations to attack your APP. Complete the following steps
- new
fishhookdemo
Project, the main interface defines a UIButton, click the button to trigger the eventonNext
, pop-up prompt “Welcome you”, the purpose is to demonstrate protection. - Created in the Demo project
protected.framework
For protection,Pay attention to
Fenced code generally uses the Framework becauseThe FrameWork loads before the MachO main process
And theSelf-written frameworks load before others inject frameworks
So we need to execute our protection code as much as possible first - downloadFishHook source fileCopy,
Fishhook. C and fishhook. H
File in protected. Framework and create a new protected fileSaveProtect. H and saveProtect. M
- SaveProtect protection code is written as follows, note
annotation
The use of functions in
@interface saveProtect : NSObject
// The original function address is exposed for its own use
CF_EXPORT void (*old_exchange)(Method m1,Method m2);
@end
@implementation saveProtect
+ (void)load{
struct rebinding rebind;
rebind.name="method_exchangeImplementations";
rebind.replacement=new_exchangeImp;
rebind.replaced=(void*)&old_exchange;
struct rebinding rebs[]={rebind};
rebind_symbols(rebs, 1);
}
// The original function pointer can be placed in a header file to expose its own project use
void (*old_exchange)(Method m1,Method m2);
/ / the new function
void new_exchangeImp(Method m1,Method m2){
NSLog(@"Hook detected");
}
@end
Copy the code
- packaging
fishhookdemo.ipa
- Create a new demo project to crack fishhookDemo. ipa, write
MethodSwizzle
Code HookonNext
methods
+ (void)load{
class_addMethod(objc_getClass("ViewController"), @selector(newNext), newNext, "v@:");
method_exchangeImplementations(class_getInstanceMethod(objc_getClass("ViewController"), @selector(onNext)), class_getInstanceMethod(objc_getClass("ViewController"), @selector(newNext)));
}
void newNext(id self,SEL _cmd){
NSLog(@"Hook to the");
}
Copy the code
So if method_exchangeImplementations Hook succeeds, hitting the Button should print “Hook is up”, and the fact is that there is still a “welcome” prompt that says method_exchangeImplementations is invalid, Successful defense.
FishHook principle
Ios has a special location for the system dynamic library, known as the dynamic shared cache, and FishHook uses PIC technology to dynamically change the value of pointer addresses when rebinding.
- Due to the
External function
The memory location cannot be determined at compile time. - Apple USES
PIC
Technology (location-independent code). inmacho
fileData
Create two tables,Lazy loading and non-lazy loading tables
.Holds a pointer to an external function
For the first time
callLazy loading function
, will go toThe pile of code
Execution, the first execution will be executedbinder
functionThe binding
FishHook
usingStringtable -> Symbols > Indirect SYbols -> Lazy load symbol table
The corresponding relationship betweenHeavy binding
Modifies the value of a pointer
1.3 InlineHook
The so-called inlineHook is to directly modify the header code of the target function to make it jump to our self-defined function to execute our code, so as to achieve the purpose of Hook. This Hook technology is generally used in static language hooks, such as custom C function, or C function of swift language. This fixes FishHook’s inability to Hook C functions. Dobby’s best framework is at home, so it’s as easy as using FishHook.
Compile the Dobby
git clone https://github.com/jmpews/Dobby.git --depth=1
“, download the Dobby source locally, depth specifiedThe depth of cloning
If the value is 1, only the latest COMMIT is cloned- Due to the
Dobby
It’s cross-platform, so you need toCompile into Xcode project
. Run the following command to create onebuild_for_ios_arm64
Folder put compiledThe Xcode project
cd Dobby && mkdir build_for_ios_arm64 && cd build_for_ios_arm64
cmake .. -G Xcode \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=cmake/ios.toolchain.cmake \
-DPLATFORM=OS64 \
-DARCHS=arm64 \
-DENABLE_BITCODE=0 \
-DENABLE_ARC=0 \
-DENABLE_VISIBILITY=1 \
-DDEPLOYMENT_TARGET=9.3 \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DDynamicBinaryInstrument=ON -DNearBranchTrampoline=ON \
-DPlugin.FindSymbol=ON -DPlugin.HideLibrary=ON -DPlugin.ObjectiveC=ON
Copy the code
- After compiling
build_for_ios_arm64
The Xcode project in the folder is as follows. Then compile the Xcode project to generateDobbyX.framework
Use case
- new
demo
engineering - copy
DobbyX.framework
There are two possible errors when running the Demo projectBitcode error
: Either set bitcode support when compiling dobbyx.framework, or bitcode=NO in demodyld: Library not loaded
: @ rpath/DobbyX framework/DobbyX Reason: image not found error: framework for the first time into the project, Xcode will not help us to copy into the Macho, so you need toCopy it manually
, as shown below
3. Add test functions on the main interfacesum()
.Dobby
hooksum()
The function is replaced byNew_sum (
), tap the screen to invokesum()
Function, code as follows
@implementation ViewController
int sum(int a,int b){
return a+b;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Argument 1: address of the function that needs hook
// Parameter 2: address of the new function
// Parameter 3: preserves the address of the pointer to the original function
DobbyHook(sum, new_sum, (void*)&originsum);
}
// Save the original function pointer address for subsequent calls
int (*originsum)(int a,int b);
int new_sum(int a,int b){
NSLog(@"Original result: % I",originsum(a,b));
returna*b; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@Result: % I,sum(10.20));
}
Copy the code
Click on the screen console and the output is as follows:
We’ve obviously hooked the sum() function and executed our own. C function assembly, look at how Dobby, broken lives the sum () function, hook before and after the hook assembly below
After hook, only the first three lines are different, and there is no stretch stack space, jump into BR x17, look at X17
Dobby inserted the new function, new_sum(), directly in the header of the original function sum(), so inlineHook modified the target function header code directly. New_sum (), x8, x8, x8, x8
To follow upblr x8
Look at the assembly
If the original function is called, stretch the stack space and br x17 executes back to the original function. Inlinehook can hook custom C functions, so can hook system functions? Try Hook NSLog() as shown below
Dobby was mighty,External system functions can also Hook
“At that point, it seemed possible to get Dobby done instead of FishHook.
The principle of summary
inlineHook
I’m going to modify it directlyHeader code for the target function
.- If the original function is called in the new function, the stack space is stretched and the original function is called otherwise the original function is not executed.
inlinehook
Is in theDynamic head insertion
The new function,__text
Segments are read-only.
Address substitution function
After all, the release package is unsigned. We usually get the offset address of the function by analyzing Macho, and then get the first address of Macho ASLR. The offset address +ASLR is the real address of the function. Sum () = LLDB () = LLDB () = LLDB () = LLDB () = LLDB () = LLDB ()
As shown in the figure, the offset of the sum() function is:0x104119e18-0x1041114000=0x5e18
.macho
See the0x5e18
The offsetcontrastlldb
Sum assembler and Macho assembler, this should besum()
Function, we know that the offset of sum() is0x5e18
Do the whole thing, package the demo project, create a new sample project and re-sign it as abovedemo
Project, as shown below
Analysis:
-
Sum () = pageZero; sum() = pageZero; sum() = pageZero; sum() = pageZero
-
After dragging dobbyx. framework into the main project, remember to link dobbyx. framework in wgyFramework, otherwise the dynamic library will not be found by compilation
- It also needs to be there
wgyFramework
Set in theFramework search path
Reference path, otherwise import header file can not find the header file error. (Library Search Paths
Is that this is.a
The path)
1.4 Monkey
Logos Tweak, CaptainHook Tweak, command-line Tool, Monke4App is a powerful Tool for jailbreak and non-jailbreak developers that integrates four modules, Logos Tweak, CaptainHook Tweak, command-line Tool, Monke4App, and more. Monkey Hook: getImp and setImp: Monkey Hook: getImp and setImp: Monkey hook: getImp and setImp: setImp: Monkey hook: getImp and setImp: setImp
- Install thoes
//1. Install the latest theOS recursively
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
//2. Install lDID signature tool, jailbreak plug-in signature tool, coDesign is official signature tool,
brew install ldid
Copy the code
- Xcode installs the plug-in
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)
Copy the code
- After the installation is successful,
/opt
You’ll find it in your directoryTheos, MonkeyDev, frida-ios-dump
Folder, and the Xcode new project will appearMonkeyApp
options
remind
If any error occurs during the installation, refer to the following two articles- www.jianshu.com/p/208906289…
- www.jianshu.com/p/767304005…
– error # libstdc++ not found
- Modify the
/opt/MonkeyDev/Tools/pack.sh
File, add deletecom.apple.WatchPlaceholder
Otherwise, the latest wechat cannot be re-signed
Use case
Or in theHook wechat login
For example, if you click the login button, you can obtain the entered password without affecting the original login logic.Xcode
Select a new Demo projectMonkeyApp
,Smash the shell of wechat. Ipa
Package copy intoTargetApp
folder
inLogos
Folder to prepare Hook code as follows, run the program can be very simple HookonNext
Methods.
Logos grammar
The simple example above is a Hook code written through the Logos syntax, so it is important to understand the syntax of Logos. According to the Logos syntax on the website, there are three sections. Memorizing them is useless.
Conclusion:
%hook,%end
: Hooks a class%group,%end
: grouping, each group needs to be constructed by the %ctor() function, initialized by %init(group name)%log
Output method details (caller, method name, method parameters)%orig
Calling the original method, you can pass parameters and receive return values%c
Similar to getClass, get a class object%new
Add a method- It is often used in practical applications
MSHookIvar
To obtainAttributes of a class
, such as MSHookIvar<UITableView*>(self, “_tableView”), to get the _tableView property of the self class - It is often used in actual development
In response to the chain
Find specific classes, such as[tableview.nextResponder.nextResponder isKindofClass:%c(WeiXinViewController)]
, the tableView response chain is used to determine whether the TableView belongs to the class WeiXinViewController
2.0 Dynamic Debugging
Reverse is no source code, so can not set breakpoints in the source code, followed by debugging others on the shelf of the application is off the symbol, can not directly give a symbol under the breakpoint, only dynamic debugging to find memory address, and then give a specific memory address under the breakpoint. So it is necessary to master the method of dynamic debugging, and then with static analysis can be very easy to play reverse. Let’s take a look at the dynamic debugging tools LLDB, Cycript and Reveal.
2.1 LLDB
Dynamic debugging tools built into Xcode by default. The standard LLDB provides an extensive set of commands designed to be compatible with older versions of GDB commands. In addition to using standard configurations, you can easily customize the LLDB to suit your needs.
Common instructions are as follows:
Normal breakpoints
To set breakpoints
:breakpoint set -n xxx
If it is a method of a class, use double quotation marks, such as “-[viewController Touchbegin :]”.breakpoint set -r xxx
, block all places that contain “XXX”.Breakpoint - a address
To set a breakpoint on the address. (B-n XXX, short for XXX)- View all breakpoints:
breakpoint list
- Delete breakpoint:
breakpoint delete
- Disable/enable breakpoints:
breakpoint disable/breakpoint enable
- To continue:
c
(the continue abbreviated) - To execute a single function as a whole in one step:
n
(next abbreviation) - Run in a single step, if it encounters a subfunction, it will enter:
s
Function call stack type
- View the function call stack:
bt
- Select to enter the concrete stack:
frame select 12
, and enter the stack number 12, but enter the stack, the data will not change - Walk through the current method and return to the upper layer
The call stack frame
:finish
View the id and method parameters of the current function stack
:frame variable
It’s easy to use.- Function call stack rollback:
up/down
- Rollback function stack:
thread return
Up /down, which affects the result of execution
Memory breakpoint
- Listen for changes in memory values and enter breakpoints when changes occur:
watchpoint set variable p1->name
Or,Watchpoint set expression Memory address
- Memory breakpoint removal:
whatch delete
, Disable, etc., similar to BreakPoint - Global breakpoint listening:
Target stop-hook add -o "frame variable"
“Stop-hook” is used to display the frame variable whenever a breakpoint occurs
other
- Execution code:
p
Po stands for calling the discraption method of an object. - View instructions:
help breakpoint
- View the mirror list:
image list
- Register read and write:
register read/write x0
- Read memory value:
Memory read 或者 x
Just memorizing is useless, must refer to the practice, more instructions please refer to the LLDB official website. Using these instructions can be tedious and often requires several instructions to locate your view, so we need to use tools that encapsulate the LLDB API.
chisel
LLDB API wrapped by Facebook, using tools called by Python. First download and install Chisel, refer to this website for specific installation steps, configure. Lldbinit and then you can use it.
Common convenience instruction
pviews
: Prints the view level, pview-u, prints the upper view levelpvc
: Displays the current controllerPactions Indicates the address of the pointer
: Prints the page on which the button is located and its click event methodPresponder pointer address
: Gets the response chain for the buttonPclass pointer address
: Prints the controller inheritance relationshipPmethods pointer address
: Prints all methodsPinternals Pointer address
: Prints all member attributesFvc-v pointer address
: Locate the controller to which it belongsFv UI name
: Displays how many such views the current controller has, for example, fV WCUITextFiledFlicker pointer address
: Locate the control will flicker, this is very useful ohVs pointer address
: Enters a specific control and can be debugged. Q exits debugging. This is handy for finding components.(w)
Move to superView(s)
Move to first subview(a)
Move to previous Sibling(d)
Move to next Sibling(p)
Print the Hierarchy
Here is an example of locating the login button in the wechat login interface. First, pViews prints all the views, randomly find a component address, flicker locates the component, and when it is located, it will blink. Then vs component address goes into the component for debugging, using w, S, A, D, P instructions to locate the login button, as shown in the picture below.
DerekSelander
This LLDB tool is more convenient to use in conjunction with Chisel, so it is common to install both tools together. First download DerekSelander to the local directory, then unzip to the specified directory, such as /opt, edit.lldbinit to specify dslldy.py, as shown in the following image.
Common convenience instruction
search UIView
: Global search viewMethods pointer address
: Print all methods (and method addresses, breakpoints can be set to address)sbt
: Prints the call stack. Note that the stack isRestore partial method symbols
The bt command prints without symbols.
See DerekSelander for more instructions, here with chisel to see what methods are available on the home screen.
2.2 cycript
Cycript is a scripting language developed by Saurik, the founder of Cydia. Cycript mixes OC with the interpreter for JavaScript syntax, which means that we can use OC or JavaScript, or both, in a single command. It can hook up to running processes and modify a lot of things at run time. Unlike LLDB, cycript does not block processes, so it is convenient to debug applications dynamically, which is also a tool often used in reverse, whereas LLDB add-on processes are blocked. The installation steps are as follows
- Website: www.cycript.org/
- Once downloaded, use the executable file Cycript
- For convenience, we can put it
/ opt/cycript_0. 9.594
(the opt directory is optional), and also configure the environment variables in ~/.bash_profile (the path of the execution file).
Special reminder: MonkeyDev/bin contains the executable file, so it is highly recommended to install and configure the environment variables as follows: This allows the console to directly use tools in MonkeyDev/bin such as class-dump, dump.py, and cycript.
Non-jailbreak debugging
The Monkey project automatically packages the Cycript static library into your APP, so you can only dynamically debug this APP instead of other apps. The default Monkey port number for cycript injected into your phone is 6666. The Cycript tool on your Mac uses this port number to connect to cycript in your APP.
The cycript command in the Mac connection APP is as follows:
cycript -r 192.1681.98.:6666
Copy the code
- here
192.168.2.2
Cell phone isip
The address,6666
Is the cycript port number in the APP on your phonecycript
Command encapsulation asA shell script
However, it is not recommended here, after all, once the wireless network changes the IP will change, so it is easier to package USB connection. - inJailbreak and shell smashingWe wrote one in the article
usbConnect.sh
Script, encapsulatedSSH via USB
Link cell phones. Here again, two shell scripts are encapsulated, onecyusbConnect.sh
Do USB port mapping, onecyLogin.sh
Make a cycript connection to the APP. Sh and cyusbconnect. sh are two port mapping scripts combined together. If you know, please leave a message to me.
Common commands
- It is strongly recommended that
UIApp, UIApp. KeyWindow. RootViewController
And so on commonly used command encapsulationCustom cy
The cy file is then imported into the phone for use. It is very convenient to customize cy files in both jailbroken and non-jailbroken environments, such as the following customizationGY.cy
.
//IIFE anonymous function self-executing expression
(function(exports){
APPID = [NSBundle mainBundle].bundleIdentifier,
APPPATH = [NSBundle mainBundle].bundlePath,
// If there is a change, use function to define it.
GYRootVc = function(){
return UIApp.keyWindow.rootViewController;
};
GYKeyWindow = function(){
return UIApp.keyWindow;
};
GYGetFrontVcFromRootVc = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = GYGetFrontVcFromRootVc(rootVC.selectedViewController);
}else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = GYGetFrontVcFromRootVc(rootVC.visibleViewController);
}else{
currentVC = rootVC;
}
return currentVC;
};
// The controller currently being displayed
GYFrontVc = function(){
return GYGetFrontVcFromRootVc(GYRootVc());
};
GYVcViews=function(vc){
if(! [vc isKindOfClass:[UIViewControllerclass]]) throw new Error(invalidParamStr);
return vc.view.recursiveDescription().toString();
}
// The UI level currently being displayed
GYFrontViews = function(){
var currentVC=GYGetFrontVcFromRootVc(GYRootVc());
return GYVcViews(currentVC);
};
// Gets the method names of all TouchUpInside events bound to the button
GYTouchUpEvent = 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]) {vare = [btn actionsForTarget:allTargets[i] forControlEvent:UIControlEventTouchUpInside]; events.push(e); }}return events;
};
// Print the view hierarchy recursively
GYSubviews = function(view) {
if(! [view isKindOfClass:[UIViewclass]]) throw new Error(invalidParamStr);
return view.recursiveDescription().toString();
};
var _GYClass = function(className) {
if(! className)throw new Error(missingParamStr);
if (MJIsString(className)) {
return NSClassFromString(className);
}
if(! className)throw new Error(invalidParamStr);
// Object or class
return className.class();
};
// Prints all subclasses
GYSubclasses = function(className, reg) {
className = GYClass(className);
return [c for each (c in ObjectiveC.classes)
if(c ! = className && class_getSuperclass(c) && [c isSubclassOfClass:className] && (! reg || reg.test(c))) ]; };var _GYGetMethods = function(className, reg, clazz) {
className = GYClass(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 _GYMethods = function(className, reg, clazz) {
return GYGetMethods(className, reg, clazz)[0];
};
var _GYMethodNames = function(className, reg, clazz) {
return GYGetMethods(className, reg, clazz)[1];
};
// Prints all object methods
GYInstanceMethods = function(className, reg) {
return _GYMethods(className, reg);
};
// Prints all object method names
GYInstanceMethodNames = function(className, reg) {
return _GYMethodNames(className, reg);
};
// Prints all class methods
GYClassMethods = function(className, reg) {
return _GYMethods(className, reg, true);
};
// Prints all class method names
GYClassMethodNames = function(className, reg) {
return _GYMethodNames(className, reg, true);
};
// Prints all member variables
GYIvars = 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;
};
// Prints all member variable names
GYIvarNames = 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);
}
returnarray; }; }) (exports);
Copy the code
Xcode
Open the Monkey project and importGY.cy
The file looks like this, Xcode reruns the project,GY.cy
It’s packaged into your APP, and when YOU use your custom cy file,Need @ the import
Monkey
The project will download it for us automaticallymd.cy
andMS.cy
File and package into APP, mD.cy provides some convenient instructions such asPviews (), PVCS (), RP (), pactions()
Ms. Cy provides dynamic code insertion. Note these two CY filesDon't need @ import
The import.
However, these two files can not be downloaded due to network problems, so it is necessary to change the git source address and replace these two URLS withRaw.fastgit.org/AloneMonkey… 和 Raw.fastgit.org/AloneMonkey…
The demo is as follows:
Prison break debugging
The cycript plugin can be downloaded from the jailbreak store Cydia. Once the plugin is downloaded, SSH can connect to the phone to attach the Cycript process.
The cycript plugin folder is shown in the picture above. Although you can attach apps on your phone, some shortcut commands such as APPID and PVCS () are not available, so we need to import our custom Gy. cy and mD. cy downloaded from Git. SCP copy the cy file to /usr/lib/cycript0.9/com/, create a gy folder in com, as shown below
When used@import
Import it and you can happily use the shortcut command, the additional genuine wechat demo is as follows
Analysis:Cycript -p Process ID/appID
Append process. It is possible to import custom Gy. cy, but it is not possible to import MD. cy. I am not sure about this, and some friends who know this can leave me a message.
2.3 pass Reveal
Reveal is a tool that allows you to dynamically debug your APP UI. Compared to xcode’s built-in View Debugger, it does not block the APP process and can dynamically debug the UI. Here’s how to use Reveal in a jailbreak environment.
- Jailbreak cell phone in
Cydia store
In the installationReveal Loader
SSH Connection to a Mobile Phone
CD Library directorymkdir RHRevealLoader
Folder.Mac
Computer installationPass Reveal tools
Here is a recommendationCracking tool download platform- Ma computer
Copy RevealServer
Executable program into the mobile phoneRHRevealLoader folder
. Open the Reveal program,Help
–>Show Reveal Library in Finder
–>iOS Library
–>RevealServer.framework
–>RevealServer
. SCP copied RevealServer into the phone and renamed it tolibReveal.dylib
Restart the phone
- Mobile phone into
Settings -->Reveal--> Open the APP you want to debug
- If you want to use the Reveal tool again, you should be able to debug the UI dynamically.