關於反調試及反反調試那些事

前言

在逆向和保護的過程當中,總會涉及到反調試和反反調試的問題,這篇文章主要是總結一下幾種常見的反調試手段以及反反調試的方法。python

反調試

ptrace的

爲了方便應用軟件的開發和調試,從Unix的的早期版本開始就提供了一種對運行中的進程進行跟蹤和控制的手段,那就是系統調用ptrace()。 經過ptrace能夠對另外一個進程實現調試跟蹤,同時ptrace還提供了一個很是有用的參數那就是PT_DENY_ATTACH,這個參數用來告訴系統,阻止調試器依附。ios

因此經常使用最反的調試方案就是經過調用ptrace來實現反調試。git

#ifndef PT_DENY_ATTACH
    #define PT_DENY_ATTACH 31
#endif

typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);

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);

複製代碼

的sysctl

當一個進程被調試的時候,該進程會有一個標記來標記本身正在被調試,因此經過能夠sysctl去查看當前進程的信息,看有沒有這個標記位便可檢查當前調試狀態。github

BOOL isDebuggerPresent(){
    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;
    name[3] = getpid();         

    if(sysctl(name, 4, &info, &info_size, NULL, 0) == -1){
        NSLog(@"sysctl error ...");
        return NO;
    }

    return ((info.kp_proc.p_flag & P_TRACED) != 0);
}

複製代碼

檢測到調試器就退出,或者製造崩潰,或者隱藏工程啥的,固然也能夠定時去查看有沒有這個標記。面試

系統調用

爲從實現從用戶態切換到內核態,系統提供了一個系統調用函數syscall,講到上面的ptrace也是經過系統-調用去實現的。macos

Kernel Syscalls 71 這裏能夠找到對應ptrace的編號。api

26\. ptrace               801e812c T

複製代碼

因此以下的調用等同於調用ptrace數組

syscall(26,31,0,0,0);

複製代碼

syscall是經過軟中斷來實現從用戶態到內核態,能夠也。彙編經過svc調用來實現。bash

#ifdef __arm__
        asm volatile(
            "mov r0,#31\n"
            "mov r1,#0\n"
            "mov r2,#0\n"
            "mov r12,#26\n"
            "svc #80\n"

        );
#endif
#ifdef __arm64__
        asm volatile(
            "mov x0,#26\n"
            "mov x1,#31\n"
            "mov x2,#0\n"
            "mov x3,#0\n"
            "mov x16,#0\n"
            "svc #128\n"
        );
#endif

複製代碼

下面幾種可能在實際中用到的比較少,不過也能夠嘗試一下。iphone

SIGSTOP

捕獲經過系統- SIGSTOP信號來判斷。

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGSTOP, 0, dispatch_get_main_queue());
dispatch_source_set_event_handler(source, ^{
    NSLog(@"SIGSTOP!!!");
    exit(0);
});
dispatch_resume(source);

複製代碼

網上看到的,未普遍測試〜

task_get_exception_ports

獲取異常端口:

struct macosx_exception_info{
    exception_mask_t masks[EXC_TYPES_COUNT];
    mach_port_t ports[EXC_TYPES_COUNT];
    exception_behavior_t behaviors[EXC_TYPES_COUNT];
    thread_state_flavor_t flavors[EXC_TYPES_COUNT];
    mach_msg_type_number_t cout;
};

struct macosx_exception_info *info = malloc(sizeof(struct macosx_exception_info));
task_get_exception_ports(mach_task_self(),
                                            EXC_MASK_ALL,
                                            info->masks,
                                            &info->cout,
                                            info->ports,
                                            info->behaviors,
                                            info->flavors);

for(uint32_t i = 0; i < info->cout; i ++){
    if(info->ports[i] != 0 || info->flavors[i] == THREAD_STATE_NONE){
        NSLog(@"debugger detected via exception ports (null port)!\n");
    }
}

複製代碼

isatty

if (isatty(1)) {
    NSLog(@"Being Debugged isatty");
}

複製代碼

IOCTL

if (!ioctl(1, TIOCGWINSZ)) {
    NSLog(@"Being Debugged ioctl");
}

複製代碼

反反調試(TWEAK)

瞭解了幾種不一樣的反調試的方法,那麼就能夠根據幾種經常使用的反調試方法來反反調試。

這裏主要針對ptracesysctlsyscall來反反調試,作法就很簡單了,鉤函數,判斷參數,返回結果。

#import <substrate.h>
#import <sys/sysctl.h>

static int (*orig_ptrace) (int request, pid_t pid, caddr_t addr, int data);
static int my_ptrace (int request, pid_t pid, caddr_t addr, int data){
    if(request == 31){
		NSLog(@"[AntiAntiDebug] - ptrace request is PT_DENY_ATTACH");
		return 0;
	}
	return orig_ptrace(request,pid,addr,data);
}

static void* (*orig_dlsym)(void* handle, const char* symbol);
static void* my_dlsym(void* handle, const char* symbol){
	if(strcmp(symbol, "ptrace") == 0){
		NSLog(@"[AntiAntiDebug] - dlsym get ptrace symbol");
		return (void*)my_ptrace;
    }
   	return orig_dlsym(handle, symbol);
}

static int (*orig_sysctl)(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize);
static int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){
	int ret = orig_sysctl(name,namelen,info,infosize,newinfo,newinfosize);
	if(namelen == 4 && name[0] == 1 && name[1] == 14 && name[2] == 1){
		struct kinfo_proc *info_ptr = (struct kinfo_proc *)info;
        if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){
            NSLog(@"[AntiAntiDebug] - sysctl query trace status.");
            info_ptr->kp_proc.p_flag ^= P_TRACED;
            if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){
                NSLog(@"[AntiAntiDebug] trace status reomve success!");
            }
        }
	}
	return ret;
}

static void* (*orig_syscall)(int code, va_list args);
static void* my_syscall(int code, va_list args){
	int request;
    va_list newArgs;
    va_copy(newArgs, args);
    if(code == 26){
        request = (long)args;
        if(request == 31){
            NSLog(@"[AntiAntiDebug] - syscall call ptrace, and request is PT_DENY_ATTACH");
            return nil;
        }
    }
    return (void*)orig_syscall(code, newArgs);
}

%ctor{
	MSHookFunction((void *)MSFindSymbol(NULL,"_ptrace"),(void*)my_ptrace,(void**)&orig_ptrace);
	MSHookFunction((void *)dlsym,(void*)my_dlsym,(void**)&orig_dlsym);
	MSHookFunction((void *)sysctl,(void*)my_sysctl,(void**)&orig_sysctl);
	MSHookFunction((void *)syscall,(void*)my_syscall,(void**)&orig_syscall);

	NSLog(@"[AntiAntiDebug] Module loaded!!!");
}

複製代碼

反反調試(LLDB)

經過lldb下斷點,而後修改參數,或者直接返回也能夠達到反反調試的效果。不過講這裏的的英文經過python腳本把過程自動化的一種方法。

網求方便爲了直接使用facebookchisel來增長腳本。

新建一個文件夾,而後使用

commandsDirectory = os.path.join(lldbHelperDir, '文件名')
loadCommandsInDirectory(commandsDirectory)

複製代碼

加載便可。

的英文下面python代碼:

#!/usr/bin/python
# -*- coding: utf-8 -*-

""" 反反調試腳本,過了反調試後記得: aadebug -d 不然會很卡,若是有定時器定時檢測,建議寫tweak """

import lldb
import fblldbbase as fb
import fblldbobjcruntimehelpers as objc

def lldbcommands():
    return [
        AMAntiAntiDebug()
    ]

class AMAntiAntiDebug(fb.FBCommand):
    def name(self):
        return 'aadebug'

    def description(self):
        return "anti anti debug ptrace syscall sysctl"

    def options(self):
        return [
            fb.FBCommandArgument(short='-d', long='--disable', arg='disable', boolean=True, default=False, help='disable anti anti debug.')
        ]

    def run(self, arguments, options):
        if options.disable:
            target = lldb.debugger.GetSelectedTarget()
            target.BreakpointDelete(self.ptrace.id)
            target.BreakpointDelete(self.syscall.id)
            target.BreakpointDelete(self.sysctl.id)
            print "anti anti debug is disabled!!!"
        else:
            self.antiPtrace()
            self.antiSyscall()
            self.antiSysctl()
            print "anti anti debug finished!!!"

    def antiPtrace(self):
        ptrace = lldb.debugger.GetSelectedTarget().BreakpointCreateByName("ptrace")
        if is64Bit():
            ptrace.SetCondition('$x0==31')
        else:
            ptrace.SetCondition('$r0==31')
        ptrace.SetScriptCallbackFunction('sys.modules[\'' + __name__ + '\'].ptrace_callback')
        self.ptrace = ptrace

    def antiSyscall(self):
        syscall = lldb.debugger.GetSelectedTarget().BreakpointCreateByName("syscall")
        if is64Bit():
            syscall.SetCondition('$x0==26 && *(int *)$sp==31')
        else:
            syscall.SetCondition('$r0==26 && $r1==31')
        syscall.SetScriptCallbackFunction('sys.modules[\'' + __name__ + '\'].syscall_callback')
        self.syscall = syscall

    def antiSysctl(self):
        sysctl = lldb.debugger.GetSelectedTarget().BreakpointCreateByName("sysctl")
        if is64Bit():
            sysctl.SetCondition('$x1==4 && *(int *)$x0==1 && *(int *)($x0+4)==14 && *(int *)($x0+8)==1')
        else:
            sysctl.SetCondition('$r1==4 && *(int *)$r0==1 && *(int *)($r0+4)==14 && *(int *)($r0+8)==1')
        sysctl.SetScriptCallbackFunction('sys.modules[\'' + __name__ + '\'].sysctl_callback')
        self.sysctl = sysctl

    def antiExit(self):
        self.exit = lldb.debugger.GetSelectedTarget().BreakpointCreateByName("exit")
        exit.SetScriptCallbackFunction('sys.modules[\'' + __name__ + '\'].exit_callback')

#暫時只考慮armv7和arm64
def is64Bit():
    arch = objc.currentArch()
    if arch == "arm64":
        return True
    return False

def ptrace_callback(frame, bp_loc, internal_dict):
    print "find ptrace"
    register = "x0"
    if not is64Bit():
        register = "r0"
    frame.FindRegister(register).value = "0"
    lldb.debugger.HandleCommand('continue')

def syscall_callback(frame, bp_loc, internal_dict):
    print "find syscall"
    #不知道怎麼用api修改sp指向的內容QAQ
    lldb.debugger.GetSelectedTarget().GetProcess().SetSelectedThread(frame.GetThread())
    if is64Bit():
        lldb.debugger.HandleCommand('memory write "$sp" 0')
    else:
        lldb.debugger.HandleCommand('register write $r1 0')
    lldb.debugger.HandleCommand('continue')

def sysctl_callback(frame, bp_loc, internal_dict):
    module = frame.GetThread().GetFrameAtIndex(1).GetModule()
    currentModule = lldb.debugger.GetSelectedTarget().GetModuleAtIndex(0)
    if module == currentModule:
        print "find sysctl"
        register = "x2"
        if not is64Bit():
            register = "r2"
        frame.FindRegister(register).value = "0"
    lldb.debugger.HandleCommand('continue')

def exit_callback(frame, bp_loc, internal_dict):
    print "find exit"
    lldb.debugger.GetSelectedTarget().GetProcess().SetSelectedThread(frame.GetThread())
    lldb.debugger.HandleCommand('thread return')
    lldb.debugger.HandleCommand('continue')

複製代碼

總結

反調試的方式有多種,能夠經過:

ebugserver *:1234 -x auto /path/to/executable

複製代碼

啓動附加,而後斷點測試。

小編這裏推薦一個羣:691040931 裏面有大量的書籍和麪試資料,不少的iOS開發者都在裏面交流技術

資料截圖.png

本文代碼地址:

AntiAntiDebug 200 

相關文章
相關標籤/搜索