为了账号安全,请及时绑定邮箱和手机立即绑定

iOS应用反调试方法全面解析:ptrace与sysctl防止调试器附加与检测

标签:
iOS

iOS反调试

在iOS应用开发中,保护应用免受调试和逆向工程是重要的安全措施。除了手动实现反调试代码,使用专业的混淆工具如IpaGuard可以进一步强化应用安全性。IpaGuard提供代码混淆和调试信息清理功能,有效增加反编译和调试的难度。

反调试分为两种,第一种阻止调试器附加,第二种是检测是否有调试器存在

一、第一种方法:

1.在main.m里面加入以下代码:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import </usr/include/sys/ptrace.h>

int main(int argc, char * argv[]) {
    @autoreleasepool {
        ptrace(PT_DENY_ATTACH, 0, 0, 0);
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
12345678910

ptrace是系统用来对运行中的进程进行调试和跟踪的工具,通过ptrace,可以对另一个进程实现调试跟踪。PT_DENY_ATTACH,值是31,这个参数用户告诉系统阻止调试器附加。

2.但是这样做,可能被hook掉,所以需要自定义ptrace

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import </usr/include/sys/ptrace.h>
#import <dlfcn.h>
typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);

int main(int argc, char * argv[]) {
    @autoreleasepool {
//        ptrace(PT_DENY_ATTACH, 0, 0, 0);

        void *handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);

        ptrace_ptr_t ptrace_ptr = (ptrace_ptr_t)dlsym(handle, "ptrace");

        ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
12345678910111213141516171819

我们通过dlopen,函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。

然后通过dlsym,根据动态链接库操作句柄与符号,返回符号对应的地址。

拿到ptrace,填入PT_DENY_ATTACH,拒绝让调试器附加到应用程序。对于更全面的保护,可以考虑使用IpaGuard等工具进行代码混淆,自动处理类似的反调试逻辑,减少手动编码风险。

二、第二种方法:

1.在main.m里面加入以下代码:

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import </usr/include/sys/ptrace.h>
#import <dlfcn.h>
#import <sys/sysctl.h>
BOOL isDebuggerPresernt(){
    int name[4];//指定查询信息的数组
    struct kinfo_proc info;//查询的返回结果
    size_t info_size = sizeof(info);//结构体的大小
    info.kp_proc.p_flag = 0;//标志

    name[0] = CTL_KERN;//查询的内核
    name[1] = KERN_PROC;//查询的进程信息
    name[2] = KERN_PROC_PID;//传的参数是进程的pid
    name[3] = getpid();//把pid给它
    if (sysctl(name, 4, &info, &info_size, NULL, 0) == -1) {
        NSLog(@"sysctl error ...");
        return NO;
    }
    return ((info.kp_proc.p_flag & P_TRACED) != 0);


}

int main(int argc, char * argv[]) {
    @autoreleasepool {
        if (isDebuggerPresernt()) {
            NSLog(@"检测到调试器!!!");
        }

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
123456789101112131415161718192021222324252627282930313233

可以通过sysctl查看内核进程状态的调试信息,如果一个进程在调试状态,P_TRACED来判定是不是被调试,有没有这个标志。

这段代码是程序运行一次才会检测一次,可以写个定时器,去做检查,sysctl也可能被hook。

2.修改成自定义的函数,防止被hook

//原始函数的地址
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);
}
123456789101112131415161718192021222324252627282930313233

结合手动反调试方法,使用IpaGuard这样的工具可以自动化实现代码混淆和调试信息清理,提升应用的整体安全性,避免被逆向分析。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消