iOS逆向1024-防护进阶

001--反调试sysctl(代码防护)

// sysctl:检测app进程是否被附加 (防护进程被调试) 《程序员的自我修养》

#import "ViewController.h"
#import <sys/sysctl.h>

@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

image.png

导入fishhook

image.png
#import "injectCode.h"
#import "fishhook.h"
#import <sys/sysctl.h>
@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

image.png
image.png

注意:antiDebugCode 防护在前

#import "antiDebugCode.h"
#import "fishhook.h"
#import "MyPtraceHeader.h"
#import <sys/sysctl.h>

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

image.png

下个符号断点

image.png
image.png
image.png

运行程序,立刻进入断点:目的 就是为了看函数调用栈

(lldb)bt        // 显示当前线程的调用堆栈(bt:back stack)
(lldb)image list      // 查看库
image.png

看不到函数调用栈,解决方案:用 Debug 模式

image.png

重新编译运行

image.png
image.png

Hopper Disassembler 分析MacO文件,找到上面👆对应的地址

image.png
image.png

快捷键:alt + A
同上

image.png

修改MacO文件:跳出 ptrace 方法的执行

image.png
image.png

导出 新的MacO文件

image.png

新的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 <objc/message.h>

@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的 退出进程的 地方

image.png
image.png

5.2 hopper 查看 MacO 文件

image.png

5.3 hopper 修改内存地址,让防护的代码,找不到要交换的方法,就可以去hook了

image.png
%hook ViewController
- (void)btnClick1:(id)sender {
    NSLog(@"HOOK到了!!");
}
%end



总结:

001--反调试 sysctl.wmv (防护)

#import <sys/sysctl.h>
// sysctl:检测app进程是否被附加 放在最前面执行

002--破解 sysctl.wmv (攻)

创建动态库:injectSysctl
导入fishhook
#import "injectCode.h"
#import "fishhook.h"
#import <sys/sysctl.h>
// 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了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,001评论 25 707
  • 上周,因为某天凌晨四点,我妈打来电话,把我惊醒,结果只是不小心按到,但是回完电话我已无法入睡。于是中午的...
    冰栀樱阅读 194评论 0 0
  • 奥黛拉 维护 保护的意思, 美国亚特兰大历史学教授 和一个纳粹的崇拜者在英国打关于证伪没有纳粹大屠杀的谎言。 愤怒...
    我的真谛阅读 156评论 0 0
  • 数算十项恩福 1.感恩今天的天气,不是大太阳也没有下雨,有少许的微风。给人一阵阵凉爽的感觉...
    夏夏Jasmine阅读 242评论 2 2