在逆向和保護的過程當中,總會涉及到反調試和反反調試的問題,這篇文章主要是總結一下幾種常見的反調試手段以及反反調試的方法。python
爲了方便應用軟件的開發和調試,從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
去查看當前進程的信息,看有沒有這個標記位便可檢查當前調試狀態。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
信號來判斷。
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);
複製代碼
網上看到的,未普遍測試〜
獲取異常端口:
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");
}
}
複製代碼
if (isatty(1)) {
NSLog(@"Being Debugged isatty");
}
複製代碼
if (!ioctl(1, TIOCGWINSZ)) {
NSLog(@"Being Debugged ioctl");
}
複製代碼
瞭解了幾種不一樣的反調試的方法,那麼就能夠根據幾種經常使用的反調試方法來反反調試。
這裏主要針對ptrace
,sysctl
,syscall
來反反調試,作法就很簡單了,鉤函數,判斷參數,返回結果。
#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
下斷點,而後修改參數,或者直接返回也能夠達到反反調試的效果。不過講這裏的的英文經過python
腳本把過程自動化的一種方法。
網求方便爲了直接使用facebook
的chisel
來增長腳本。
新建一個文件夾,而後使用
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
複製代碼
啓動附加,而後斷點測試。
本文代碼地址:
本文做者: AloneMonkey
本文連接: iosre.com/t/topic/817…