larksuite / sdmagichook Goto Github PK
View Code? Open in Web Editor NEWA safe and influence-restricted method hooking for both Objective-C and Swift.
License: MIT License
A safe and influence-restricted method hooking for both Objective-C and Swift.
License: MIT License
aspects和SDMagicHook基本思路都是基于类似kvo的isa替换,但是从api设计以及实现上也有明显的区别,我们通过以下示例简要介绍下:
1.解决了Aspects未能解决的KVO兼容问题,详见 https://mp.weixin.qq.com/s?__biz=MzI1MzYzMjE0MQ==&mid=2247486231&idx=1&sn=1c6584e9dcc3edf71c42cf396bcab051&chksm=e9d0c0f5dea749e34bf23de8259cbc7c868d3c8a6fc56c4366412dfb03eac8f037ee1d8668a1&token=1383088962&lang=zh_CN#rd
2.设计实现了一套更为高效灵活的API,举例如下
假设有这样一个自定义类Test,在其内部定义了一个求和的方法,接收四个int类型的参数。
@implementation Test
- (int)sumWithA:(int)a b:(int)b c:(int)c d:(int)d {
return a + b + c + d;
}
@end
现在要求将四个参数分别平方然后再求和。
使用aspects实现如下:
Test *testObj = [Test new];
[testObj aspect_hookSelector:@selector(sumWithA:b:c:d:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> info, int a, int b, int c, int d) {
int aa = a * a;
int bb = b * b;
int cc = c * c;
int dd = d * d;
[info.originalInvocation setArgument:&aa atIndex:2];
[info.originalInvocation setArgument:&bb atIndex:3];
[info.originalInvocation setArgument:&cc atIndex:4];
[info.originalInvocation setArgument:&dd atIndex:5];
} error:NULL];
int sum = [testObj sumWithA:1 b:2 c:3 d:4];
NSLog(@">>>> %d", sum); // >>>> 30
使用SDMagicHook实现如下:
Test *testObj = [Test new];
[testObj hookMethod:@selector(sumWithA:b:c:d:) impBlock:^(typeof(testObj) this, int a, int b, int c, int d) {
__block int res;
[this callOriginalMethodInBlock:^{
res = [this sumWithA:a * a b:b * b c:c * c d:d * d];
}];
return res;
}];
int sum = [testObj sumWithA:1 b:2 c:3 d:4];
NSLog(@">>>> %d", sum); // >>>> 30
由以上demo可以看出:
1.aspects使用AspectOptions来决定自定义方法和原始方法的执行顺序;SDMagicHook使用callOriginalMethodInBlock来调用原始方法,可以将原始方法放在自定义逻辑的前、中、后任意位置执行,更加灵活方便。
2.aspects将原始方法封装在NSInvocation里面,如果想要修改sumWithA:b:c:d:
的参数值需要调用setArgument:atIndex:方法来实现,api不够简洁友好;SDMagicHook只需在callOriginalMethodInBlock的block参数内部直接调用原始的sumWithA:b:c:d:
方法传参即可,直观简便。
import SDMagicHook
extension AppDelegate {
private func setAutoTracker(){
let imp: @convention(block) (UIViewController, Bool) -> Void = { (vc, flag) in
vc.callOriginalMethod {
vc.viewWillAppear(flag)
}
print(vc.title ?? "" + "viewWillAppear")
}
UIViewController.hookMethod(#selector(UIViewController.viewWillAppear(_:)), impBlock: imp)
}
}
这应该是hook的类方法
报错崩溃
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The Selector viewWillAppear:
may be wrong, please check it!'
最新的iOS15 ,release环境,APP界面卡主了,没有任何提示?怎么解决
看了一下 SDOrderedDict 这个类的实现,是用来保存多个 key 相同的 value 的。而 Ordered 这个单词是表示”有序“的意思,大部分编程语言或者其标准库中都有 OrderedSet、OrderedMap、OrderedDictionary 的概念,表示这个容器内的元素是按 Key 排序的。
这里的 SDOrderedDict 是一个可包含重复 key 的元素的容器,可以参考 C++ STL 的命名,叫做 "MultiDict" 会更合适一些。
能不崩溃吗,我hook方法后,以前的方法不需要执行
///扩大点击响应面积,edge 正数值是缩小面积,扩大是负数
func expandResponseArea(edge:UIEdgeInsets){
let imp: @convention(block) (UIView , CGPoint , UIEvent ) -> Bool = { (v,p,e) in
v.callOriginalMethod {
v.point(inside: p, with: e) //必须调用一次原始方法
}
let r = v.bounds.inset(by: edge)
return r.contains(p)
}
//劫持point(inside:with:
self.hookMethod(#selector(UIButton.point(inside:with:)), impBlock: imp) //Crash Here:Thread 1: EXC_BAD_ACCESS (code=2, address=0x215c5e880)
}
我初次运行该项目时发现 在点击 DemoVC0 CatchIt 按钮后, 在点击方法中 hook 了layer 的setBackgroundColor 方法, 再次返回home, 然后就Crash.
看了代码发现 在SDMagicHook.h第 148行代码, 调用了 SDNewClassManager的hasSetupKVO属性 判定是否添加了 kvo, 如果没有添加KVO 则添加, 查看了整个项目 都没有发现有移出 该KVO 的代码, 所以导致的Crash.
不知道作者设计hasSetupKVO是否有其他的考量,
在SDMagicHook.h第 249行, 同样加入了KVO 监听 依然没有移出监听操作,
上述只是我在学习时发现的.
iOS版本: 14.0
复现情况: 必现
如果这个实例不能你生成的 甚至你都不知道会存在在什么对象里面 你只知道这个对象有那些方法 是不是就无法hook
请检查你是否在hook了
<ButtonDropdown: 0x12a019350; baseClass = UIButton; frame = (20 9.5; 57 20); opaque = NO; layer = <CALayer: 0x2807c1fc0>>的
pointInside:withEvent: 方法之后忘记调用原始方法。
//扩大点击响应面积
private func expandBtn(){
let imp: @convention(block) (UIView , CGPoint , UIEvent ) -> Bool = { (v,p,e) in
v.callOriginalMethod {
v.point(inside: p, with: e) //这里为何一定要调用一次?,不调用就会 请检查你是否在hook了 `pointInside:withEvent:` 方法之后忘记调用原始方法。
}
let r = v.bounds.inset(by: .init(top: 10, left: 10, bottom: 10, right: 30))
return r.contains(p)
}
self.btn_buiding.hookMethod(#selector(UIButton.point(inside:with:)), impBlock: imp)
// self.btn_floor.hookMethod(#selector(UIButton.point(inside:with:)), impBlock: imp)
}
请问hook代码应该写到哪里呢?难道是直接写到程序xcodeproj源代码里吗?
能不能在程序已经编译好的情况下,通过动态库注入的方法,实现hook?
如果通过动态库注入的方法,实现hook,那么能不能hook swift方法?
如果可以注入动态库,那这个动态库能不能直接用swift+sdmagichook编写?
2020-04-02 16:32:15.932354+0800 SDHookDemo[43318:2582823] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x600000353240 of class CALayer was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x6000003480c0> (
<NSKeyValueObservance 0x600000db42d0: Observer: 0x600002737300, Key path: class, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x600000db4210>
)'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff23e3dcce __exceptionPreprocess + 350
1 libobjc.A.dylib 0x00007fff50b3b9b2 objc_exception_throw + 48
2 Foundation 0x00007fff258e2f73 NSKVODeallocate + 569
3 QuartzCore 0x00007fff2b4d1795 _ZN2CA5Layer16free_transactionEPNS_11TransactionE + 623
4 QuartzCore 0x00007fff2b44e514 _ZN2CA11Transaction6commitEv + 942
5 QuartzCore 0x00007fff2b44ed81 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 79
6 CoreFoundation 0x00007fff23da1067 CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 23
7 CoreFoundation 0x00007fff23d9bb1e __CFRunLoopDoObservers + 430
8 CoreFoundation 0x00007fff23d9c06a __CFRunLoopRun + 1226
9 CoreFoundation 0x00007fff23d9b884 CFRunLoopRunSpecific + 404
10 GraphicsServices 0x00007fff38b5ac1a GSEventRunModal + 139
11 UIKitCore 0x00007fff48c19220 UIApplicationMain + 1605
12 SDHookDemo 0x000000010c1db86a main + 122
13 libdyld.dylib 0x00007fff519b910d start + 1
14 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.