• [iOS]使用MonkeyDev完成Hook


    一、确定目标

    先定个小目标,使用七猫举个例,去移除小说阅读页底部广告和章节之间的广告。

    二、HOOK

    1. 创建MonkeyApp项目导入砸壳包

    2. 使用Reveal工具确定“底部广告”和“章末广告”的视图名称

    底部广告

    View Controller:
    Class: QMReader.YYReaderContainer
    Memory Address: 0x107b1d200

    NSObject:
    Class: QMReader.YYReaderBottomBannerView
    Memory Address: 0x11af3f700

     章末广告

    View Controller:
    Class: QMAd.YYReaderInsertAdVC
    Memory Address: 0x108e81600

    3. 使用Hopper Disassembler工具分析Mach-O确定类名

    YYReaderContainer对应的类名为_TtC8QMReader17YYReaderContainer
    YYReaderBottomBannerView对应的类名为_TtC8QMReader24YYReaderBottomBannerView

     YYReaderInsertAdVC对应的类名为_TtC4QMAd18YYReaderInsertAdVC

     

    4. 项目中使用CaptainHook

    (1)CaptainHook 使用方法

    hook函数

    1. /// hook类
    2. CHDeclareClass(<#name#>)
    3. /// hook类方法
    4. CHOptimizedClassMethod0(<#optimization#>, <#return_type#>, <#class_type#>, <#name#>)
    5. /// hook对象方法
    6. /// optimization 当前self或者其他
    7. /// return_type 需要传入什么类型
    8. /// class_type 传入哪一个类
    9. /// name 属性名称
    10. CHOptimizedMethod0(<#optimization#>, <#return_type#>, <#class_type#>, <#name#>)

    新增函数

    1. /// 新增属性
    2. CHPropertyRetainNonatomic(<#class#>, <#type#>, <#getter#>, <#setter#>)
    3. /// 新增类方法
    4. CHDeclareClassMethod0(<#return_type#>, <#class_type#>, <#name#>)
    5. /// 新增对象方法
    6. CHDeclareMethod0(<#return_type#>, <#class_type#>, <#name#>)

    构造函数

    1. /// 构造函数
    2. CHConstructor{
    3. // hook类
    4. CHLoadLateClass(<#name#>);
    5. // hook方法 (CHClassHook0、CHClassHook1... 数字表示有几个参数)
    6. CHClassHook0(<#class#>, <#name#>)
    7. // 添加属性时,需要这样写对应的set,get
    8. CHHook0(<#class#>, <#name#>)
    9. }

    (2)完成hook

    1. #import "MonkeyDevTestDemoDylib.h"
    2. #import
    3. #import
    4. #pragma mark ----申明类可以调用属性和方法----
    5. CHDeclareClass(_TtC8QMReader17YYReaderContainer)
    6. CHDeclareClass(_TtC8QMReader24YYReaderBottomBannerView)
    7. CHDeclareClass(_TtC4QMAd18YYReaderInsertAdVC)
    8. #pragma mark ----实现方法----
    9. /// 隐藏底部广告后,改变阅读区frame。
    10. CHOptimizedMethod1(self, void, _TtC8QMReader17YYReaderContainer, viewDidAppear, BOOL, arg1) {
    11. CHSuper1(_TtC8QMReader17YYReaderContainer, viewDidAppear, arg1);
    12. UIView *view = [(UIViewController *)self view];
    13. NSArray *iArr = view.subviews;
    14. for (int i = 0 ; i < iArr.count ; i ++) {
    15. UIView *iView = iArr[i];
    16. if ([NSStringFromClass([iView class]) isEqualToString:@"UIView"]) {
    17. UIView *tempView = iView;
    18. do {
    19. NSArray *tempArr = tempView.subviews;
    20. for (int j = 0 ; j < tempArr.count ; j ++) {
    21. UIView *subView = tempArr[j];
    22. tempView = subView;
    23. }
    24. } while ([NSStringFromClass([tempView class]) isEqualToString:@"UIView"]);
    25. if ([NSStringFromClass([tempView class]) isEqualToString:@"UIScrollView"]) {
    26. UIScrollView *tempSV = (UIScrollView *)tempView;
    27. NSArray *jArr = tempSV.subviews;
    28. for (int j = 0 ; j < jArr.count ; j ++) {
    29. UIView *jView = jArr[j];
    30. if ([NSStringFromClass([jView class]) isEqualToString:@"UIView"]) {
    31. NSArray *jArr = jView.subviews;
    32. for (int k = 0 ; k < jArr.count ; k ++) {
    33. UIView *kView = jArr[k];
    34. if ([NSStringFromClass([kView class]) isEqualToString:@"UIView"]) {
    35. kView.frame = CGRectMake(0, UIScreen.mainScreen.bounds.size.height, UIScreen.mainScreen.bounds.size.width, 0);
    36. } else if ([NSStringFromClass([kView class]) isEqualToString:@"QMReader.QMContentView"]) {
    37. kView.frame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height);
    38. }
    39. }
    40. }
    41. }
    42. }
    43. }
    44. }
    45. }
    46. /// 例:hook包含多个参数的方法
    47. CHOptimizedMethod3(self, void, _TtC8QMReader17YYReaderContainer, observeValueForKeyPath, id, arg1, ofObject, id, arg2, change, id, arg3) {
    48. }
    49. /// 例:hook类方法
    50. CHOptimizedClassMethod0(self, void, _TtC8QMReader24YYReaderBottomBannerView, load) {
    51. NSObject *obj = (NSObject *)self;
    52. }
    53. /// 隐藏底部广告
    54. CHOptimizedMethod1(self, void, _TtC8QMReader24YYReaderBottomBannerView, initWithFrame, CGRect, arg1) {
    55. CHSuper1(_TtC8QMReader24YYReaderBottomBannerView, initWithFrame, arg1);
    56. printf("nadd3");
    57. UIView *view = (UIView *)self;
    58. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    59. view.alpha = 0;
    60. view.hidden = YES;
    61. view.frame = CGRectMake(0, 0, 0, 0);
    62. [view removeFromSuperview];
    63. });
    64. }
    65. /// 隐藏章末广告
    66. CHOptimizedMethod1(self, void, _TtC4QMAd18YYReaderInsertAdVC, viewDidAppear, BOOL, arg1) {
    67. UIView *view = [(UIViewController *)self view];
    68. view.alpha = 0;
    69. view.hidden = YES;
    70. }
    71. #pragma mark ----构造函数----
    72. CHConstructor{
    73. // hook类
    74. CHLoadLateClass(_TtC8QMReader17YYReaderContainer);
    75. CHLoadLateClass(_TtC8QMReader24YYReaderBottomBannerView);
    76. CHLoadLateClass(_TtC4QMAd18YYReaderInsertAdVC);
    77. // hook方法
    78. CHClassHook3(_TtC8QMReader17YYReaderContainer, observeValueForKeyPath, ofObject, change);
    79. CHClassHook1(_TtC8QMReader17YYReaderContainer, viewDidAppear);
    80. CHClassHook0(_TtC8QMReader24YYReaderBottomBannerView, load);
    81. CHClassHook1(_TtC8QMReader24YYReaderBottomBannerView, initWithFrame);
    82. CHClassHook1(_TtC4QMAd18YYReaderInsertAdVC, viewDidAppear);
    83. }

    最终效果如下:
    demo:https://download.csdn.net/download/u012881779/87148657

    (3)顺便了解一下添加属性和方法

    1. // MonkeyDevTestDemoDylib.h
    2. // MonkeyDevTestDemoDylib
    3. //
    4. // Created by Gamin on 2022/11/19.
    5. // Copyright (c) 2022 ___ORGANIZATIONNAME___. All rights reserved.
    6. //
    7. #import
    8. #import
    9. @interface _TtC8QMReader17YYReaderContainer
    10. @property (nonatomic, strong) UIButton * alertButton;
    11. - (void)tapAlertButton:(UIButton *)sender;
    12. @end
    1. // weibo: http://weibo.com/xiaoqing28
    2. // blog: http://www.alonemonkey.com
    3. //
    4. // MonkeyDevTestDemoDylib.m
    5. // MonkeyDevTestDemoDylib
    6. //
    7. // Created by Gamin on 2022/11/19.
    8. // Copyright (c) 2022 ___ORGANIZATIONNAME___. All rights reserved.
    9. //
    10. #import "MonkeyDevTestDemoDylib.h"
    11. #import
    12. #import
    13. #pragma mark ----申明类可以调用属性和方法----
    14. CHDeclareClass(_TtC8QMReader17YYReaderContainer)
    15. #pragma mark ----实现方法----
    16. /// 隐藏底部广告后,改变阅读区frame。
    17. CHOptimizedMethod1(self, void, _TtC8QMReader17YYReaderContainer, viewDidAppear, BOOL, arg1) {
    18. CHSuper1(_TtC8QMReader17YYReaderContainer, viewDidAppear, arg1);
    19. UIView *view = [(UIViewController *)self view];
    20. // 提示
    21. self.alertButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 40)];
    22. self.alertButton.backgroundColor = UIColor.redColor;
    23. [self.alertButton setTitle:@"提示" forState:UIControlStateNormal];
    24. [self.alertButton addTarget:self action:@selector(tapAlertButton:) forControlEvents:UIControlEventTouchUpInside];
    25. [view addSubview:self.alertButton];
    26. }
    27. /// 添加新属性
    28. CHPropertyRetainNonatomic(_TtC8QMReader17YYReaderContainer, UIButton *, alertButton, setAlertButton);
    29. /// 添加新方法
    30. CHDeclareMethod1(void, _TtC8QMReader17YYReaderContainer, tapAlertButton, UIButton *, sender){
    31. NSLog(@"This is a new method : tapAlertButton");
    32. }
    33. #pragma mark ----构造函数----
    34. CHConstructor{
    35. // hook类
    36. CHLoadLateClass(_TtC8QMReader17YYReaderContainer);
    37. // hook方法
    38. CHClassHook1(_TtC8QMReader17YYReaderContainer, viewDidAppear);
    39. // 新增提示按钮属性
    40. CHHook0(_TtC8QMReader17YYReaderContainer, alertButton);
    41. CHHook1(_TtC8QMReader17YYReaderContainer, setAlertButton);
    42. CHClassHook1(_TtC8QMReader17YYReaderContainer, tapAlertButton);
    43. }

    点击自定义的按钮,控制台输出打印内容。

     

     

  • 相关阅读:
    【openstack】卷迁移导致的虚机热迁移失败问题排查及解决
    灰度级形态学 - 灰度开运算和灰度闭运算
    Spring Security入门
    数据治理的 “独孤九剑”
    中央党校出版社元宇宙图书编委高泽龙在元宇宙100分第24期做分享
    计算机毕业设计ssm+vue基本微信小程序的好物推荐分享系统
    Django JWT验证
    Linux常用命令
    linux 中jenkins启动重启停止命令 改端口
    Cadence IC618使用
  • 原文地址:https://blog.csdn.net/u012881779/article/details/127982988