iOS逆向1024-防護(hù)進(jìn)階

001--反調(diào)試sysctl(代碼防護(hù))

// sysctl:檢測(cè)app進(jìn)程是否被附加 (防護(hù)進(jìn)程被調(diào)試) 《程序員的自我修養(yǎng)》

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

@interface ViewController ()
@end

static dispatch_source_t timer;

@implementation ViewController

// 1秒鐘檢測(cè)一次
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(@"檢測(cè)到了!!");
        }else{
            NSLog(@"正常!!");
        }
    });
    dispatch_resume(timer);
}


// 真機(jī)運(yùn)行 沒(méi)有DebuggerServer,所以不會(huì)檢測(cè)到調(diào)試
// sysctl(int * 控制碼, u_int 字節(jié), void * 查詢結(jié)果, size_t * 結(jié)構(gòu)體, void * 結(jié)構(gòu)體的大小, size_t)
// #define    P_TRACED    0x00000800    /* Debugged process being traced: 跟蹤調(diào)試過(guò)程 */

//檢測(cè)是否被調(diào)試
BOOL isDebugger(){
    //控制碼
    int name[4];//里面放字節(jié)碼.查詢信息
    name[0] = CTL_KERN;     //內(nèi)核查看
    name[1] = KERN_PROC;    //查詢進(jìn)程
    name[2] = KERN_PROC_PID;//傳遞的參數(shù)是進(jìn)程的ID(PID)   //同:$ ps -A
    name[3] = getpid();     //PID的值告訴(進(jìn)程id)
    
    struct kinfo_proc info; //接受進(jìn)程查詢結(jié)果信息的結(jié)構(gòu)體
    size_t info_size = sizeof(info);//結(jié)構(gòu)體的大小
    //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就是沒(méi)有錯(cuò)誤,其他就是錯(cuò)誤碼
    //1011 1000 1010 1010 1101 0101 1101 0101
    //&
    //0000 0000 0000 1000 0000 0000 0000 0000
    // == 0 ? 沒(méi)有、有!!
    return ((info.kp_proc.p_flag & P_TRACED) != 0);  // P_TRACED: 跟蹤調(diào)試過(guò)程
}

- (void)viewDidLoad {
    [super viewDidLoad];

    debugCheck();
    
}
@end


002--破解sysctl(攻擊)

創(chuàng)建動(dòng)態(tài)庫(kù):injectSysctl

image.png

導(dǎo)入fishhook

image.png
#import "injectCode.h"
#import "fishhook.h"
#import <sys/sysctl.h>
@implementation injectCode

//原始函數(shù)的地址
int (*sysctl_p)(int *, u_int, void *, size_t *, void *, size_t);

//自定義函數(shù)
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提前執(zhí)行 (再防護(hù))

創(chuàng)建動(dòng)態(tài)庫(kù):antiDebug

image.png
image.png

注意:antiDebugCode 防護(hù)在前

#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(@"檢測(cè)到了!!");
        }else{
            NSLog(@"正常!!");
        }
    });
    dispatch_resume(timer);
}


//檢測(cè)是否被調(diào)試
BOOL isDebugger(){
    //控制碼
    int name[4];//里面放字節(jié)碼.查詢信息
    name[0] = CTL_KERN;//內(nèi)核查看
    name[1] = KERN_PROC;//查詢進(jìn)程
    name[2] = KERN_PROC_PID;//傳遞的參數(shù)是進(jìn)程的ID(PID)
    name[3] = getpid();//PID的值告訴
    
    struct kinfo_proc info;//接受進(jìn)程查詢結(jié)果信息的結(jié)構(gòu)體
    size_t info_size = sizeof(info);//結(jié)構(gòu)體的大小
    int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
    assert(error == 0);//0就是沒(méi)有錯(cuò)誤,其他就是錯(cuò)誤碼
    
    //1011 1000 1010 1010 1101 0101 1101 0101
    //&
    //0000 0000 0000 1000 0000 0000 0000 0000
    // == 0 ? 沒(méi)有  有!!
    return ((info.kp_proc.p_flag & P_TRACED) != 0);
}

void debugerCheck(){
    if (isDebugger()) {
        NSLog(@"進(jìn)程被調(diào)試!!");
    }
    //開啟反調(diào)試
    ptrace(PT_DENY_ATTACH, getpid(), 0, 0);
}

+(void)load
{
    debugerCheck();
}
@end


004--攻防博弈!找到你就贏

loadCommand: 改變?cè)即a
ptrace (process trace 進(jìn)程跟蹤)
ptrace 系統(tǒng)函數(shù),是有符號(hào)的
查看 ptrace

image.png

下個(gè)符號(hào)斷點(diǎn)

image.png
image.png
image.png

運(yùn)行程序,立刻進(jìn)入斷點(diǎn):目的 就是為了看函數(shù)調(diào)用棧

(lldb)bt        // 顯示當(dāng)前線程的調(diào)用堆棧(bt:back stack)
(lldb)image list      // 查看庫(kù)
image.png

看不到函數(shù)調(diào)用棧,解決方案:用 Debug 模式

image.png

重新編譯運(yùn)行

image.png
image.png

Hopper Disassembler 分析MacO文件,找到上面??對(duì)應(yīng)的地址

image.png
image.png

快捷鍵:alt + A
同上

image.png

修改MacO文件:跳出 ptrace 方法的執(zhí)行

image.png
image.png

導(dǎo)出 新的MacO文件

image.png

新的MacO 文件 導(dǎo)入MonkeyApp 創(chuàng)建的工程里,運(yùn)行,可以調(diào)試了!


005--破解懸疑已久的反HOOK

這里涉及到以前的章節(jié):1011- HOOK-代碼的防護(hù)

終端命令:
壓縮成ipa包
zip -ry ZMHook--基本防護(hù).ipa Payload
zip -ry antiHook基本防護(hù).ipa Payload
zip -ry antiHook基本防護(hù)2.ipa Payload
zip -ry antiHook基本防護(hù)exit.ipa Payload

1、先加載ZMHook 庫(kù) 再加載 ZMHookManager,也就是hook代碼在先,防護(hù)在后,所以防護(hù)失效
2、先加載ZMHookManager 庫(kù) 再加載 ZMHook,現(xiàn)在防護(hù),再hook 就交互交換不到方法了,已經(jīng)被防護(hù)住了
3、對(duì)于檢測(cè)到對(duì)方的hook,采取的方法式 退出程序 exit !!

#import "ZMHookManager.h"
#import "fishhook.h"
#import <objc/message.h>

@implementation ZMHookManager

//專門HOOK
+(void)load
{
    NSLog(@"ZMHookManager--Load");
    //內(nèi)部用到的交換代碼!
    Method old = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick1:));
    Method new = class_getInstanceMethod(self, @selector(click1Hook:));
    method_exchangeImplementations(old, new);
    
    //基本防護(hù)
    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);
}

//保留原來(lái)的交換函數(shù)
IMP _Nonnull (*setIMP)(Method _Nonnull m, IMP _Nonnull imp);
IMP _Nonnull (*getIMP)(Method _Nonnull m);
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);

//新的函數(shù)
void myExchang(Method _Nonnull m1, Method _Nonnull m2){
    NSLog(@"檢測(cè)到了HOOK!!!");
    //強(qiáng)制退出!
    exit(1);
}

-(void)click1Hook:(id)sendr{
    NSLog(@"原來(lái)APP的HOOK保留!!");
}
@end

5.1 定位反hook的 退出進(jìn)程的 地方

image.png
image.png

5.2 hopper 查看 MacO 文件

image.png

5.3 hopper 修改內(nèi)存地址,讓防護(hù)的代碼,找不到要交換的方法,就可以去hook了

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



總結(jié):

001--反調(diào)試 sysctl.wmv (防護(hù))

#import <sys/sysctl.h>
// sysctl:檢測(cè)app進(jìn)程是否被附加 放在最前面執(zhí)行

002--破解 sysctl.wmv (攻)

創(chuàng)建動(dòng)態(tài)庫(kù):injectSysctl
導(dǎo)入fishhook
#import "injectCode.h"
#import "fishhook.h"
#import <sys/sysctl.h>
// fishhook 交換 sysctl 方法

003--ptrace&sysctl提前執(zhí)行.wmv (防護(hù))

創(chuàng)建動(dòng)態(tài)庫(kù):antiDebug
注意:antiDebugCode 防護(hù)在前(MonkeyApp 也進(jìn)攻不了)

  • 反調(diào)試 (上節(jié)課有講解)
    ptrace (process trace 進(jìn)程跟蹤)
    此函數(shù)提供了一個(gè)進(jìn)程監(jiān)聽控制另外一個(gè)進(jìn)程.并且可以檢測(cè)被控制進(jìn)程的內(nèi)存和寄存器里面的數(shù)據(jù)!
    它可以用來(lái)實(shí)現(xiàn)斷點(diǎn)調(diào)試和系統(tǒng)調(diào)用跟蹤.debugserver就是用的它
    iOS 中沒(méi)有提供相關(guān)的頭.
    書籍:<程序員的自我修養(yǎng)>
    */

原理:防護(hù)的代碼執(zhí)行的太早!
導(dǎo)致:我Hook的代碼執(zhí)行在其后!

004--攻防博弈!找到你就贏.wmv

MacO loadCommand 段:改變?cè)即a
ptrace (process trace 進(jìn)程跟蹤)
ptrace 系統(tǒng)函數(shù),是有符號(hào)的
下個(gè)ptrace符號(hào)斷點(diǎn)

運(yùn)行程序,立刻進(jìn)入斷點(diǎn):目的 就是為了看函數(shù)調(diào)用棧
(lldb)bt // 顯示當(dāng)前線程的調(diào)用堆棧(bt:back stack)
(lldb)image list // 查看庫(kù)

修改MacO文件:跳出 ptrace 方法的執(zhí)行
導(dǎo)出 新的MacO文件
新的MacO 文件 導(dǎo)入MonkeyApp 創(chuàng)建的工程里,運(yùn)行,可以調(diào)試了

005--破解懸疑已久的反HOOK.wmv

這里涉及到以前的章節(jié):1011- HOOK-代碼的防護(hù)
1、先加載ZMHook 庫(kù) 再加載 ZMHookManager,也就是hook代碼在先,防護(hù)在后,所以防護(hù)失效
2、先加載ZMHookManager 庫(kù) 再加載 ZMHook,現(xiàn)在防護(hù),再hook 就交互交換不到方法了,已經(jīng)被防護(hù)住了
3、對(duì)于檢測(cè)到對(duì)方的hook,采取的方法式 退出程序 exit ?。?/p>

反hook方案:
5.1 定位反hook的 退出進(jìn)程的 地方
5.2 hopper 查看 MacO 文件
5.3 hopper 修改內(nèi)存地址,讓防護(hù)的代碼,找不到要交換的方法,就可以去hook了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,063評(píng)論 25 709
  • 上周,因?yàn)槟程炝璩克狞c(diǎn),我媽打來(lái)電話,把我驚醒,結(jié)果只是不小心按到,但是回完電話我已無(wú)法入睡。于是中午的...
    冰梔櫻閱讀 242評(píng)論 0 0
  • 奧黛拉 維護(hù) 保護(hù)的意思, 美國(guó)亞特蘭大歷史學(xué)教授 和一個(gè)納粹的崇拜者在英國(guó)打關(guān)于證偽沒(méi)有納粹大屠殺的謊言。 憤怒...
    我的真諦閱讀 210評(píng)論 0 0
  • 數(shù)算十項(xiàng)恩福 1.感恩今天的天氣,不是大太陽(yáng)也沒(méi)有下雨,有少許的微風(fēng)。給人一陣陣涼爽的感覺(jué)...
    夏夏Jasmine閱讀 305評(píng)論 2 2

友情鏈接更多精彩內(nèi)容