001--反调试sysctl(代码防护)
// sysctl:检测app进程是否被附加 (防护进程被调试) 《程序员的自我修养》
#import "ViewController.h"
#import
@interface ViewController ()
@end
static dispatch_source_t timer;
@implementation ViewController
// 1秒钟检测一次
void debugCheck(){
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
if (isDebugger()) {
NSLog(@"检测到了!!");
}else{
NSLog(@"正常!!");
}
});
dispatch_resume(timer);
}
// 真机运行 没有DebuggerServer,所以不会检测到调试
// sysctl(int * 控制码, u_int 字节, void * 查询结果, size_t * 结构体, void * 结构体的大小, size_t)
// #define P_TRACED 0x00000800 /* Debugged process being traced: 跟踪调试过程 */
//检测是否被调试
BOOL isDebugger(){
//控制码
int name[4];//里面放字节码.查询信息
name[0] = CTL_KERN; //内核查看
name[1] = KERN_PROC; //查询进程
name[2] = KERN_PROC_PID;//传递的参数是进程的ID(PID) //同:$ ps -A
name[3] = getpid(); //PID的值告诉(进程id)
struct kinfo_proc info; //接受进程查询结果信息的结构体
size_t info_size = sizeof(info);//结构体的大小
//int error = sysctl(name, 4, &info, &info_size, 0, 0);
int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
assert(error == 0);//0就是没有错误,其他就是错误码
//1011 1000 1010 1010 1101 0101 1101 0101
//&
//0000 0000 0000 1000 0000 0000 0000 0000
// == 0 ? 没有、有!!
return ((info.kp_proc.p_flag & P_TRACED) != 0); // P_TRACED: 跟踪调试过程
}
- (void)viewDidLoad {
[super viewDidLoad];
debugCheck();
}
@end
002--破解sysctl(攻击)
创建动态库:injectSysctl
导入fishhook
#import "injectCode.h"
#import "fishhook.h"
#import
@implementation injectCode
//原始函数的地址
int (*sysctl_p)(int *, u_int, void *, size_t *, void *, size_t);
//自定义函数
int mySysctl(int *name, u_int namelen, void *info, size_t *infosize, void *newinfo, size_t newinfosize){
if (namelen == 4
&& name[0] == CTL_KERN
&& name[1] == KERN_PROC
&& name[2] == KERN_PROC_PID
&& info
&& (int)*infosize == sizeof(struct kinfo_proc))
{
int err = sysctl_p(name, namelen, info, infosize, newinfo, newinfosize);
//拿出info做判断
struct kinfo_proc * myInfo = (struct kinfo_proc *)info;
if((myInfo->kp_proc.p_flag & P_TRACED) != 0){ //取与 是否等于零
//使用异或取反
myInfo->kp_proc.p_flag ^= P_TRACED;
}
return err;
}
return sysctl_p(name, namelen, info, infosize, newinfo, newinfosize);
}
+(void)load
{
//交换
rebind_symbols((struct rebinding[1]){{"sysctl",mySysctl,(void *)&sysctl_p}}, 1);
}
@end
003--ptrace&sysctl提前执行 (再防护)
创建动态库:antiDebug
注意:antiDebugCode 防护在前
#import "antiDebugCode.h"
#import "fishhook.h"
#import "MyPtraceHeader.h"
#import
static dispatch_source_t timer;
@implementation antiDebugCode
void debugCheck(){
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
if (isDebugger()) {
NSLog(@"检测到了!!");
}else{
NSLog(@"正常!!");
}
});
dispatch_resume(timer);
}
//检测是否被调试
BOOL isDebugger(){
//控制码
int name[4];//里面放字节码.查询信息
name[0] = CTL_KERN;//内核查看
name[1] = KERN_PROC;//查询进程
name[2] = KERN_PROC_PID;//传递的参数是进程的ID(PID)
name[3] = getpid();//PID的值告诉
struct kinfo_proc info;//接受进程查询结果信息的结构体
size_t info_size = sizeof(info);//结构体的大小
int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
assert(error == 0);//0就是没有错误,其他就是错误码
//1011 1000 1010 1010 1101 0101 1101 0101
//&
//0000 0000 0000 1000 0000 0000 0000 0000
// == 0 ? 没有 有!!
return ((info.kp_proc.p_flag & P_TRACED) != 0);
}
void debugerCheck(){
if (isDebugger()) {
NSLog(@"进程被调试!!");
}
//开启反调试
ptrace(PT_DENY_ATTACH, getpid(), 0, 0);
}
+(void)load
{
debugerCheck();
}
@end
004--攻防博弈!找到你就赢
loadCommand: 改变原始代码
ptrace (process trace 进程跟踪)
ptrace 系统函数,是有符号的
查看 ptrace
下个符号断点
运行程序,立刻进入断点:目的 就是为了看函数调用栈
(lldb)bt // 显示当前线程的调用堆栈(bt:back stack)
(lldb)image list // 查看库
看不到函数调用栈,解决方案:用 Debug 模式
重新编译运行
用 Hopper Disassembler 分析MacO文件,找到上面对应的地址
快捷键:alt + A
同上
修改MacO文件:跳出 ptrace 方法的执行
导出 新的MacO文件
新的MacO 文件 导入MonkeyApp 创建的工程里,运行,可以调试了!
005--破解悬疑已久的反HOOK
这里涉及到以前的章节:1011- HOOK-代码的防护
终端命令:
压缩成ipa包
zip -ry ZMHook--基本防护.ipa Payload
zip -ry antiHook基本防护.ipa Payload
zip -ry antiHook基本防护2.ipa Payload
zip -ry antiHook基本防护exit.ipa Payload
1、先加载ZMHook 库 再加载 ZMHookManager,也就是hook代码在先,防护在后,所以防护失效
2、先加载ZMHookManager 库 再加载 ZMHook,现在防护,再hook 就交互交换不到方法了,已经被防护住了
3、对于检测到对方的hook,采取的方法式 退出程序 exit !!
#import "ZMHookManager.h"
#import "fishhook.h"
#import
@implementation ZMHookManager
//专门HOOK
+(void)load
{
NSLog(@"ZMHookManager--Load");
//内部用到的交换代码!
Method old = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick1:));
Method new = class_getInstanceMethod(self, @selector(click1Hook:));
method_exchangeImplementations(old, new);
//基本防护
struct rebinding bd;
bd.name = "method_exchangeImplementations";
bd.replacement = myExchang;
bd.replaced = (void *)&exchangeP;
// struct rebinding rebindings[] = {bd};
// rebind_symbols(rebindings, 1);
// method_getImplementation
// method_setImplementation
struct rebinding bd1;
bd1.name = "method_getImplementation";
bd1.replacement = myExchang;
bd1.replaced = (void *)&getIMP;
struct rebinding bd2;
bd2.name = "method_setImplementation";
bd2.replacement = myExchang;
bd2.replaced = (void *)&setIMP;
struct rebinding rebindings[] = {bd,bd1,bd2};
rebind_symbols(rebindings, 3);
}
//保留原来的交换函数
IMP _Nonnull (*setIMP)(Method _Nonnull m, IMP _Nonnull imp);
IMP _Nonnull (*getIMP)(Method _Nonnull m);
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);
//新的函数
void myExchang(Method _Nonnull m1, Method _Nonnull m2){
NSLog(@"检测到了HOOK!!!");
//强制退出!
exit(1);
}
-(void)click1Hook:(id)sendr{
NSLog(@"原来APP的HOOK保留!!");
}
@end
5.1 定位反hook的 退出进程的 地方
5.2 hopper 查看 MacO 文件
5.3 hopper 修改内存地址,让防护的代码,找不到要交换的方法,就可以去hook了
%hook ViewController
- (void)btnClick1:(id)sender {
NSLog(@"HOOK到了!!");
}
%end
总结:
001--反调试 sysctl.wmv (防护)
#import
// sysctl:检测app进程是否被附加 放在最前面执行
002--破解 sysctl.wmv (攻)
创建动态库:injectSysctl
导入fishhook
#import "injectCode.h"
#import "fishhook.h"
#import
// fishhook 交换 sysctl 方法
003--ptrace&sysctl提前执行.wmv (防护)
创建动态库:antiDebug
注意:antiDebugCode 防护在前(MonkeyApp 也进攻不了)
- 反调试 (上节课有讲解)
ptrace (process trace 进程跟踪)
此函数提供了一个进程监听控制另外一个进程.并且可以检测被控制进程的内存和寄存器里面的数据!
它可以用来实现断点调试和系统调用跟踪.debugserver就是用的它
iOS 中没有提供相关的头.
书籍:<程序员的自我修养>
*/
原理:防护的代码执行的太早!
导致:我Hook的代码执行在其后!
004--攻防博弈!找到你就赢.wmv
MacO loadCommand 段:改变原始代码
ptrace (process trace 进程跟踪)
ptrace 系统函数,是有符号的
下个ptrace符号断点
运行程序,立刻进入断点:目的 就是为了看函数调用栈
(lldb)bt // 显示当前线程的调用堆栈(bt:back stack)
(lldb)image list // 查看库
修改MacO文件:跳出 ptrace 方法的执行
导出 新的MacO文件
新的MacO 文件 导入MonkeyApp 创建的工程里,运行,可以调试了
005--破解悬疑已久的反HOOK.wmv
这里涉及到以前的章节:1011- HOOK-代码的防护
1、先加载ZMHook 库 再加载 ZMHookManager,也就是hook代码在先,防护在后,所以防护失效
2、先加载ZMHookManager 库 再加载 ZMHook,现在防护,再hook 就交互交换不到方法了,已经被防护住了
3、对于检测到对方的hook,采取的方法式 退出程序 exit !!
反hook方案:
5.1 定位反hook的 退出进程的 地方
5.2 hopper 查看 MacO 文件
5.3 hopper 修改内存地址,让防护的代码,找不到要交换的方法,就可以去hook了