I've seen this done on Windows using CreateProcess, although I believe it wasn't specifically for anti-debugging purposes but instead a process that wanted to reinitialise itself from the beginning.
A far more effective actual anti-debugging technique is to have the parent become the debugger of the child, preventing any other debugger from attaching to it.
cryptonector 25 days ago [-]
But then you can attach to the parent and cause it to stop debugging the child so you can. I think you want a process to be its own debugger; idk if ptrace(2) allows that. Then there's things like DTrace and eBPF -- I don't think you can prevent them from the target.
tonygo 25 days ago [-]
> A far more effective actual anti-debugging technique is to have the parent become the debugger of the child,
Do you have example of that? I am really curious, thanks for sharing tho :)
sim7c00 25 days ago [-]
this is how ptrace works in essence, so if you look in the man pages for that ptrace there's an example. you just ptrace_attach from the parent to the child pid. it couldn't be more straighforward usage of ptrace. https://man7.org/linux/man-pages/man2/ptrace.2.html
long ptrace(enum __ptrace_request op, pid_t pid,
void addr, void data);
it prints -1 due to some fail, but it cannot attach GDB to it :P
edit 9001: it notes the bash is attached to it which spawned the exe, not sure if that's correct or just buggy btw
tonygo 20 days ago [-]
Thanks a lot :)
I think that I should dig more on ptrace! Maybe a next post?
visil 25 days ago [-]
The patch code looks like a rather convoluted way of patching out the function code. Can we not just replace conditional branch with a regular one and nop out the rest? Or at least set w8 to 1 manually? I know next to nothing about ARM assembly, so I'm most likely missing something.
tonygo 20 days ago [-]
Hi :)
I am not really experienced with ARM haha :) So the way that I approached it was:
- how could I remove the call of fork (because I don't want to fork)
- how could I patch the register that should contains the result of the fork operation
I guess that it sounds like a naive approach haha
Feel free to propose an alternative I patch, I could update the post and credit you :)
a_t48 25 days ago [-]
Does follow-fork-mode in lldb not also defeat this?
tonygo 25 days ago [-]
I tried with LLDB using `settings set target.process.follow-fork-mode child` but for some reasons I feel like it still exit from the parent process.
```
(lldb) run
Process 14345 launched: '/anti-debug/swift/build/anti_debug' (arm64)
start pid = 14345
exit parent process for child pid = 14348
continue as child process pid = 14348
Process 14345 exited with status = 0 (0x00000000)
```
The UI did not even appeared as it should.
Maybe I miss something in my LLDB config...
tonygo 25 days ago [-]
Also it could come from a messy thing in the code.
cassepipe 25 days ago [-]
The main reason for using dlsym instead of calling fork directly is to make it harder for an ‘attacker’ to detect or set breakpoints on the fork function, thus obfuscating the anti-debugging mechanism. You have to more checks before being able to understand why you cannot attach the debuger.
You may still think that mode could be still able to catch a new child process but apparently people have tried and the answer is no
tonygo 20 days ago [-]
> You may still think that mode could be still able to catch a new child process but apparently people have tried and the answer is no
Not sure I got this. IIUC there is a link between the fact that we used dlsym and the fact the child process is not catched by lldb in the follow fork mode?
a_t48 23 days ago [-]
Ah, I never considered how follow forks mode might actually work/
tonygo 18 days ago [-]
I tried, but I was not able to determine so far...
A far more effective actual anti-debugging technique is to have the parent become the debugger of the child, preventing any other debugger from attaching to it.
Do you have example of that? I am really curious, thanks for sharing tho :)
long ptrace(enum __ptrace_request op, pid_t pid, void addr, void data);
. to debug oneself you can try https://gist.github.com/x64-elf-sh42/83393e319ad8280b8704fbe...
it prints -1 due to some fail, but it cannot attach GDB to it :P
edit 9001: it notes the bash is attached to it which spawned the exe, not sure if that's correct or just buggy btw
I think that I should dig more on ptrace! Maybe a next post?
I am not really experienced with ARM haha :) So the way that I approached it was: - how could I remove the call of fork (because I don't want to fork) - how could I patch the register that should contains the result of the fork operation
I guess that it sounds like a naive approach haha
Feel free to propose an alternative I patch, I could update the post and credit you :)
I also tried with a long living process: https://github.com/tony-go/antidebug-examples/tree/main/swif...
And I got this:
``` (lldb) run Process 14345 launched: '/anti-debug/swift/build/anti_debug' (arm64) start pid = 14345 exit parent process for child pid = 14348 continue as child process pid = 14348 Process 14345 exited with status = 0 (0x00000000) ```
The UI did not even appeared as it should.
Maybe I miss something in my LLDB config...
You may still think that mode could be still able to catch a new child process but apparently people have tried and the answer is no
Not sure I got this. IIUC there is a link between the fact that we used dlsym and the fact the child process is not catched by lldb in the follow fork mode?