[iOS]使用MonkeyDev完成Hook

news2024/12/24 20:46:01

一、确定目标

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

二、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函数

/// hook类
CHDeclareClass(<#name#>)

/// hook类方法
CHOptimizedClassMethod0(<#optimization#>, <#return_type#>, <#class_type#>, <#name#>)

/// hook对象方法
/// optimization 当前self或者其他
/// return_type 需要传入什么类型
/// class_type 传入哪一个类
/// name 属性名称
CHOptimizedMethod0(<#optimization#>, <#return_type#>, <#class_type#>, <#name#>)

新增函数

/// 新增属性
CHPropertyRetainNonatomic(<#class#>, <#type#>, <#getter#>, <#setter#>)

/// 新增类方法
CHDeclareClassMethod0(<#return_type#>, <#class_type#>, <#name#>)

/// 新增对象方法
CHDeclareMethod0(<#return_type#>, <#class_type#>, <#name#>)

构造函数

/// 构造函数
CHConstructor{
	// hook类
	CHLoadLateClass(<#name#>);  

	// hook方法 (CHClassHook0、CHClassHook1... 数字表示有几个参数)     
	CHClassHook0(<#class#>, <#name#>)     

	// 添加属性时,需要这样写对应的set,get
	CHHook0(<#class#>, <#name#>)          
}

(2)完成hook

#import "MonkeyDevTestDemoDylib.h"
#import <CaptainHook/CaptainHook.h>
#import <UIKit/UIKit.h>

#pragma mark ----申明类可以调用属性和方法----

CHDeclareClass(_TtC8QMReader17YYReaderContainer)
CHDeclareClass(_TtC8QMReader24YYReaderBottomBannerView)
CHDeclareClass(_TtC4QMAd18YYReaderInsertAdVC)

#pragma mark ----实现方法----

/// 隐藏底部广告后,改变阅读区frame。
CHOptimizedMethod1(self, void, _TtC8QMReader17YYReaderContainer, viewDidAppear, BOOL, arg1) {
    CHSuper1(_TtC8QMReader17YYReaderContainer, viewDidAppear, arg1);
    UIView *view = [(UIViewController *)self view];
    NSArray *iArr = view.subviews;
    for (int i = 0 ; i < iArr.count ; i ++) {
        UIView *iView = iArr[i];
        if ([NSStringFromClass([iView class]) isEqualToString:@"UIView"]) {
            UIView *tempView = iView;
            do {
                NSArray *tempArr = tempView.subviews;
                for (int j = 0 ; j < tempArr.count ; j ++) {
                    UIView *subView = tempArr[j];
                    tempView = subView;
                }
            } while ([NSStringFromClass([tempView class]) isEqualToString:@"UIView"]);

            if ([NSStringFromClass([tempView class]) isEqualToString:@"UIScrollView"]) {
                UIScrollView *tempSV = (UIScrollView *)tempView;
                NSArray *jArr = tempSV.subviews;
                for (int j = 0 ; j < jArr.count ; j ++) {
                    UIView *jView = jArr[j];
                    if ([NSStringFromClass([jView class]) isEqualToString:@"UIView"]) {
                        NSArray *jArr = jView.subviews;
                        for (int k = 0 ; k < jArr.count ; k ++) {
                            UIView *kView = jArr[k];
                            if ([NSStringFromClass([kView class]) isEqualToString:@"UIView"]) {
                                kView.frame = CGRectMake(0, UIScreen.mainScreen.bounds.size.height, UIScreen.mainScreen.bounds.size.width, 0);
                            } else if ([NSStringFromClass([kView class]) isEqualToString:@"QMReader.QMContentView"]) {
                                kView.frame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height);
                            }
                        }
                    }
                }
            }
        }
    }
        
}

/// 例:hook包含多个参数的方法
CHOptimizedMethod3(self, void, _TtC8QMReader17YYReaderContainer, observeValueForKeyPath, id, arg1, ofObject, id, arg2, change, id, arg3) {
    
}

/// 例:hook类方法
CHOptimizedClassMethod0(self, void, _TtC8QMReader24YYReaderBottomBannerView, load) {
    NSObject *obj = (NSObject *)self;
}

/// 隐藏底部广告
CHOptimizedMethod1(self, void, _TtC8QMReader24YYReaderBottomBannerView, initWithFrame, CGRect, arg1) {
    CHSuper1(_TtC8QMReader24YYReaderBottomBannerView, initWithFrame, arg1);
    printf("nadd3");
    UIView *view = (UIView *)self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        view.alpha = 0;
        view.hidden = YES;
        view.frame = CGRectMake(0, 0, 0, 0);
        [view removeFromSuperview];
    });
}

/// 隐藏章末广告
CHOptimizedMethod1(self, void, _TtC4QMAd18YYReaderInsertAdVC, viewDidAppear, BOOL, arg1) {
    UIView *view = [(UIViewController *)self view];
    view.alpha = 0;
    view.hidden = YES;
}

#pragma mark ----构造函数----

CHConstructor{
    // hook类
    CHLoadLateClass(_TtC8QMReader17YYReaderContainer);
    CHLoadLateClass(_TtC8QMReader24YYReaderBottomBannerView);
    CHLoadLateClass(_TtC4QMAd18YYReaderInsertAdVC);
    // hook方法
    CHClassHook3(_TtC8QMReader17YYReaderContainer, observeValueForKeyPath, ofObject, change);
    CHClassHook1(_TtC8QMReader17YYReaderContainer, viewDidAppear);
    CHClassHook0(_TtC8QMReader24YYReaderBottomBannerView, load);
    CHClassHook1(_TtC8QMReader24YYReaderBottomBannerView, initWithFrame);
    CHClassHook1(_TtC4QMAd18YYReaderInsertAdVC, viewDidAppear);
}

最终效果如下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30619.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Strassen矩阵乘法问题(Java)

Strassen矩阵乘法问题&#xff08;Java&#xff09; 文章目录Strassen矩阵乘法问题&#xff08;Java&#xff09;1、前置介绍3、代码实现4、复杂度分析5、参考资料1、前置介绍 矩阵乘法是线性代数中最常见的问题之一 &#xff0c;它在数值计算中有广泛的应用。 设A和B是2个nXn…

搭建灾情快速分析系统 | Bigemap助力防灾减灾重点工作

Bigemap国产基础软件凭借自身强大的新GIS引擎技术与完善的产品链&#xff0c;为相关部门提供了集"灾情采集-灾情监测-灾害快速评估-应急指挥"于一体的灾害防灾减灾解决方案&#xff0c;搭建了灾情快速分析系统&#xff0c;该系统成为相关部门应对灾情的重要支撑平台。…

虚拟号码认证如何开通?

近年来&#xff0c;经常会接到外卖、房产中介、信用贷款等电话&#xff0c;让顾客不胜其扰。现在电话标记功能使用越来越普遍&#xff0c;可以大概了解电话“来意”&#xff0c;同时也会让误标记、恶意标记很方便。对于开展业务或办公司或企业的人&#xff0c;更加不能让自己的…

排序算法之选择排序

今天来给大家介绍一下排序算法之选择排序 选择排序&#xff1a;&#xff08;Selection sort&#xff09;是一种简单直观的排序算法&#xff0c;也是一种不稳定的排序方法。 选择排序的原理&#xff1a; 一组无序待排数组&#xff0c;做升序排序&#xff0c;我们先假定第一个…

【生成模型】Diffusion Models:概率扩散模型

---前言一、Diffusion Model 基本介绍二、生成模型对比三、直观理解Diffusion model四、形式化解析Diffusion model五、详解 Diffusion Model&#xff08;数学推导&#xff09;1.前向过程(扩散过程)2.逆扩散过程3.逆扩散条件概率推导4.训练损失六、训练、测试伪代码1. 训练2.测…

鲲鹏devkit编译调试工具——《sudoku》作业解析

《sudoku》作业解析 本次实验以sudoku项目为例介绍鲲鹏编译调试插件的基本使用方法 本次实验的步骤主要为 获取源码安装鲲鹏编译调试插件服务器配置进行代码同步配置配置测试任务进行编译调试 接下来我们先获取本次实验所需要的源码 获取源码 sudoku项目已经上传到github使…

stata外部命令大全(包含面板门槛、系统GMM、空间计量、Pvar、中介效应等)

1、数据来源&#xff1a;自主整理 2、时间跨度&#xff1a;无 3、区域范围&#xff1a;无 4、指标说明&#xff1a; 该些外部命令包含面板门槛、系统GMM、空间计量、pvar、中介效应等涵盖全部 以下是部分命令截图&#xff1a; 空间计量&#xff1a; 系统GMM&#xff08;动…

Allure使用手册

一. 简介 Allure是一款支持多语言的测试结果可视化软件&#xff0c;支持Java、Python&#xff0c;搭配Junit、pytest等测试框架食用更香。本文主要讲解搭配Junit4。 二. 下载、安装部署 2.1 下载 百度搜索Allure2&#xff01;&#xff01;&#xff01; 敲重点&#xff1a;…

基于Qlearning强化学习的倒立摆控制系统matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 强化学习通常包括两个实体agent和environment。两个实体的交互如下&#xff0c;在environment的statestst下&#xff0c;agent采取actionatat进而得到rewardrtrt 并进入statest1st1。Q-l…

【头歌实验】五、Python循环结构

文章目录>>>第1关&#xff1a;达依尔的麦子数任务描述案例分析相关知识for循环测试说明参考答案>>>第2关&#xff1a;四级单词查询任务描述案例分析相关知识如何处理文件文件打开文件循环文件关闭遍历文件测试说明第3关&#xff1a;出租车车费计算任务描述案…

Monaco Editor教程(十八):使用api来完成某些键盘操作,格式化,查找,显示右侧菜单等。

背景 在一般的Web IDE中&#xff0c;我们需要将经常用到的一些操作放到顶部操作栏里&#xff0c;类似语雀的文档编辑。 代码编辑器&#xff0c;一般也会放一些查找&#xff0c;格式化&#xff0c;撤销&#xff0c;恢复。有些人喜欢用快捷键来进行这些操作&#xff0c;但由于mo…

Packet Tracer - 配置 OSPF 高级功能

地址分配表 设备 接口 IPv4 地址 子网掩码 默认网关 R1 G0/0 172.16.1.1 255.255.255.0 不适用 S0/0/0 172.16.3.1 255.255.255.252 不适用 S0/0/1 192.168.10.5 255.255.255.252 不适用 R2 G0/0 172.16.2.1 255.255.255.0 不适用 S0/0/0 172.16.3.2 …

论文笔记: 全波形反演的无监督学习: 将 CNN 与偏微分方程做成一个环

摘要: 分享对论文的理解, 原文见 Peng Jin, Xitong Zhang, Yinpeng Chen, Sharon Xiaolei Huang, Zicheng Liu, Youzuo Lin, Unsupervised learning of full-waveform inversion: connecting CNN and partial differential equation in a loop. 论文发表于计算机方面的顶会 ICL…

(续)SSM整合之SSM整合笔记(Spring整合MyBatis)(P179-188)

一 准备工作 1 新建模块ssm com.atguigu.ssm 2 导入依赖 <packaging>war</packaging><properties><spring.version>5.3.1</spring.version> </properties><dependencies><dependency><groupId>org.springframewo…

Linux:进程(二)

文章目录前言一、环境变量1.概念2.常见环境变量3.一个疑问4.通过系统调用获取或设置环境变量二、地址空间1.引入2.分页&进程地址空间1.页表2.写时拷贝3.为什么要有地址空间总结前言 今天我们继续学习进程相关知识。 一、环境变量 1.概念 环境变量(environment variables)…

从理解路由到实现一套Router(路由)

平时在Vue项目中经常用到路由&#xff0c;但是也仅仅处于会用的层面&#xff0c;很多基础知识并不是真正的理解。于是就趁着十一”小长假“查阅了很多资料&#xff0c;总结下路由相关的知识&#xff0c;查缺不漏&#xff0c;加深自己对路由的理解。 路由 在 Web 开发过程中&a…

Redis中最简单的存储类型:String

String类型&#xff0c;也就是字符串类型&#xff0c;是Redis中最简单的存储类型。 其value是字符串&#xff0c;不过根据字符串的格式不同&#xff0c;又可以分为3类&#xff1a; string&#xff1a;普通字符串 int&#xff1a;整数类型&#xff0c;可以做自增、自减操作 f…

CentOS虚拟机装完了,不能粘贴window命令行?不能上网?

文章目录前言关于CentOS安装版本如何实现粘贴命令行CentOS命令行模式下如何联网&#xff1f;结尾前言 最近想系统学习Linux环境下系统运维&#xff0c;所以安装了CentOS 7虚拟机&#xff0c;但是个人笔记本上和工作电脑上无意中下载了不同镜像进行安装&#xff0c;有一台机器无…

Nerf三维重建Pytorch使用Pycharm运行0基础教程

Nerf三维重建Pytorch使用Pycharm运行0基础教程 你好&#xff01; 这里是“出门吃三碗饭”本人&#xff0c;本文章接下来将介绍如何从0运行2020会议Nerf的Pytorch版本&#xff0c;让你自己动手渲染第一个三维模型。视频解说可以关注B站&#xff0c;搜索 出门吃三碗饭 &#xff…

Improving Inductive Link Prediction Using Hyper-Relational Facts

摘要 多年来,知识图(KGs)上的链接预测一直是一个纯粹的转换任务,不允许对看不见的实体进行推理。最近,越来越多的努力被投入到探索半和全归纳场景,使推理能够对不可见的和新兴的实体。然而,所有这些方法都只考虑基于三元组的kg,而它们更丰富的对应,超关系KG(如Wikidata…