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!