IMCAFS

Home

about anti debugging & anti debugging

Posted by fierce at 2020-03-21
all

Published on May 25, 2017 | classified in reverse   |  

Preface

In the process of reverse and protection, anti debugging and anti debugging are always involved. This article mainly summarizes several common anti debugging methods and anti debugging methods.

Anti debug

Ptrace

In order to facilitate the development and debugging of application software, from the early version of UNIX, it has provided a means to track and control the running process, that is, the system calls ptrace(). Through ptrace, debugging trace can be realized for another process. At the same time, ptrace also provides a very useful parameter, which is PT "deny" attach, which is used to tell the system and prevent the debugger from attaching.

ptrace() ptrace ptrace PT_DENY_ATTACH

Therefore, the most common anti debugging scheme is to call ptrace to achieve anti debugging.

ptrace

One

Two

Three

Four

Five

Six

Seven

Eight

Nine

Ten

Eleven

#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

When a process is being debugged, the process will have a tag to mark that it is being debugged, so you can view the information of the current process through sysctl to see if there is a marker bit to check the current debugging state.

sysctl

One

Two

Three

Four

Five

Six

Seven

Eight

Nine

Ten

Eleven

Twelve

Thirteen

Fourteen

Fifteen

Sixteen

Seventeen

Eighteen

Nineteen

Twenty

BOOL isDebuggerPresent(){

Int name [4]; / / specifies the array of query information

Struct kinfo_proc info; / / the returned result of the query

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

}

When the debugger is detected, you can exit, or make a crash, or hide the project. Of course, you can regularly check whether there is such a mark.

Syscall

In order to switch from user state to kernel state, the system provides a system call function syscall. The ptrace mentioned above is also implemented through system call.

syscall ptrace

You can find the corresponding number of ptrace in kernel syswells.

ptrace ptrace

One

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

Arm

Syscall is realized from user state to kernel state through soft interrupt, and can also be realized by assembling SVC call.

syscall svc

One

Two

Three

Four

Five

Six

Seven

Eight

Nine

Ten

Eleven

Twelve

Thirteen

Fourteen

Fifteen

Sixteen

Seventeen

Eighteen

Nineteen

Twenty

#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

The following may be used less in practice, but you can also try it.

SIGSTOP

Judge by acquiring sigstop signal of the system.

SIGSTOP

One

Two

Three

Four

Five

Six

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

Get exception port:

One

Two

Three

Four

Five

Six

Seven

Eight

Nine

Ten

Eleven

Twelve

Thirteen

Fourteen

Fifteen

Sixteen

Seventeen

Eighteen

Nineteen

Twenty

Twenty-one

Twenty-two

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

One

Two

Three

if (isatty(1)) {

NSLog(@"Being Debugged isatty");

}

IOCTL

One

Two

Three

if (!ioctl(1, TIOCGWINSZ)) {

NSLog(@"Being Debugged ioctl");

}

Anti debugging (tweak)

If you know several different methods of anti debugging, you can anti debug according to several commonly used anti debugging methods.

Here, we mainly use ptrace, sysctl and syscall to de debug, which is very simple. Hook function, judge parameters and return results.

ptrace sysctl syscall

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #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脚本把过程自动化的一种方法。

lldb python facebook chisel

Create a new folder and use the

One

Two

Commandsdirectory = os.path.join (lldbhelperdir, 'filename')

loadCommandsInDirectory(commandsDirectory)

Just load.

Here is the Python code:

python

One

Two

Three

Four

Five

Six

Seven

Eight

Nine

Ten

Eleven

Twelve

Thirteen

Fourteen

Fifteen

Sixteen

Seventeen

Eighteen

Nineteen

Twenty

Twenty-one

Twenty-two

Twenty-three

Twenty-four

Twenty-five

Twenty-six

Twenty-seven

Twenty-eight

Twenty-nine

Thirty

Thirty-one

Thirty-two

Thirty-three

Thirty-four

Thirty-five

Thirty-six

Thirty-seven

Thirty-eight

Thirty-nine

Forty

Forty-one

Forty-two

Forty-three

Forty-four

Forty-five

Forty-six

Forty-seven

Forty-eight

Forty-nine

Fifty

Fifty-one

Fifty-two

Fifty-three

Fifty-four

Fifty-five

Fifty-six

Fifty-seven

Fifty-eight

Fifty-nine

Sixty

Sixty-one

Sixty-two

Sixty-three

Sixty-four

Sixty-five

Sixty-six

Sixty-seven

Sixty-eight

Sixty-nine

Seventy

Seventy-one

Seventy-two

Seventy-three

Seventy-four

Seventy-five

Seventy-six

Seventy-seven

Seventy-eight

Seventy-nine

Eighty

Eighty-one

Eighty-two

Eighty-three

Eighty-four

Eighty-five

Eighty-six

Eighty-seven

Eighty-eight

Eighty-nine

Ninety

Ninety-one

Ninety-two

Ninety-three

Ninety-four

Ninety-five

Ninety-six

Ninety-seven

Ninety-eight

Ninety-nine

One hundred

One hundred and one

One hundred and two

One hundred and three

One hundred and four

One hundred and five

One hundred and six

One hundred and seven

One hundred and eight

One hundred and nine

One hundred and ten

One hundred and eleven

One hundred and twelve

One hundred and thirteen

One hundred and fourteen

One hundred and fifteen

#!/usr/bin/python

# -*- coding: utf-8 -*-

""

After anti debugging, remember:

Aadebug -d

Otherwise, it is too laggy. If there is timer timer detection, it is recommended to write 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')

#Only armv7 and arm64 are considered for the time being

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"

#I don't know how to modify the content QAQ pointed by SP with API

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

summary

There are many ways to de debug

One

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

Start the attach, and then the breakpoint test.

Code address:

AntiAntiDebug

If you have any questions or better methods, please discuss them together.

Welcome to sweep the WeChat official account above and subscribe to my blog!