gpt4 book ai didi

c - lldb 查找应用程序的退出点

转载 作者:行者123 更新时间:2023-12-03 23:31:29 26 4
gpt4 key购买 nike

我正在调试一个可能有反调试措施的应用程序,设置断点和信号停止以退出应用程序并不会阻止应用程序退出,

$ lldb App 
(lldb) target create "App"
error: Invalid fde/cie next entry offset of 0x43029a18 found in cie/fde at 0x1404
Current executable set to 'App' (x86_64).
(lldb) br s -n exit
Breakpoint 1: 3 locations.
(lldb) br s -n _exit
Breakpoint 2: where = libsystem_kernel.dylib`__exit, address = 0x00000000000167a8
(lldb) br s -n _Exit
Breakpoint 3: where = libsystem_c.dylib`_Exit, address = 0x000000000005ed8b
(lldb) process launch -stop-at-entry
Process 17849 stopped
* thread #1: tid = 0xb9ebc, 0x00007fff5fc01000 dyld`_dyld_start, stop reason = signal SIGSTOP
frame #0: 0x00007fff5fc01000 dyld`_dyld_start
dyld`_dyld_start:
-> 0x7fff5fc01000 <+0>: popq %rdi
0x7fff5fc01001 <+1>: pushq $0x0
0x7fff5fc01003 <+3>: movq %rsp, %rbp
0x7fff5fc01006 <+6>: andq $-0x10, %rsp
Process 17849 launched: '/Users/admin/Downloads/App.app/Contents/MacOS/App' (x86_64)
(lldb) process handle -p false -s true
Do you really want to update all the signals?: [y/N] y
NAME PASS STOP NOTIFY
=========== ===== ===== ======
SIGHUP false true true
... [removed for brevity]
(lldb) c
Process 17849 resuming
Process 17849 exited with status = 45 (0x0000002d)
(lldb)

应用程序如何能够在不触发任何信号、exit、_exit 或 _Exit 的情况下退出?

在 lldb 中有没有办法运行该进程,然后在退出时“回溯”以查看它退出的位置?

有没有办法让 lldb 记录每个汇编指令等(比如它何时中断),以便您可以在退出时对其进行追溯?

最佳答案

对于那些感兴趣的人,可以找到对此答案的不同看法 here .

这里会发生什么?

您很可能正在处理这样的反调试技术:

ptrace(PT_DENY_ATTACH, 0, NULL, 0);

基本思想是只有一个进程可以 ptrace另一个同时,特别是 PT_DENY_ATTACH选项确保被跟踪者以 ENOTSUP 退出(45) 状态。见 man ptrace关于 PT_DENY_ATTACH :

This request is the other operation used by the traced process; it allows a process that is not currently being traced to deny future traces by its parent. All other arguments are ignored. If the process is currently being traced, it will exit with the exit status of ENOTSUP; otherwise, it sets a flag that denies future traces. An attempt by the parent to trace a process which has set this flag will result in a segmentation violation in the parent.



关于45的问题,看看 /System/Library/Frameworks/Kernel.framework/Versions/A/Headers/sys/errno.h :
#define ENOTSUP     45      /* Operation not supported */

如何重现这个?

编写一个表现出相同行为的程序是微不足道的:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ptrace.h>

int main() {
printf("--- before ptrace()\n");
ptrace(PT_DENY_ATTACH, 0, NULL, 0);
perror("--- ptrace()");
printf("--- after ptrace()\n");
return 0;
}

编译:
clang -Wall -pedantic ptrace.c -o ptrace

简单地运行它会成功退出,但尝试调试它会产生以下结果:
(lldb) r
Process 4188 launched: './ptrace' (x86_64)
--- before ptrace()
Process 4188 exited with status = 45 (0x0000002d)

由于此示例非常小,因此可以步进到 syscall操作说明:
(lldb) disassemble
libsystem_kernel.dylib`__ptrace:
0x7fff6ea1900c <+0>: xorq %rax, %rax
0x7fff6ea1900f <+3>: leaq 0x394f12f2(%rip), %r11 ; errno
0x7fff6ea19016 <+10>: movl %eax, (%r11)
0x7fff6ea19019 <+13>: movl $0x200001a, %eax ; imm = 0x200001A
0x7fff6ea1901e <+18>: movq %rcx, %r10
-> 0x7fff6ea19021 <+21>: syscall
0x7fff6ea19023 <+23>: jae 0x7fff6ea1902d ; <+33>
0x7fff6ea19025 <+25>: movq %rax, %rdi
0x7fff6ea19028 <+28>: jmp 0x7fff6ea10791 ; cerror
0x7fff6ea1902d <+33>: retq
0x7fff6ea1902e <+34>: nop
0x7fff6ea1902f <+35>: nop
(lldb) s
Process 3170 exited with status = 45 (0x0000002d)

所以是内核代码杀死了进程,但没有信号或正确的 exit系统调用。 (直到这一点,它仍然让我大吃一惊。)

执行哪个系统调用由 EAX的值决定注册,在这种情况下 0x200001A这可能看起来很奇怪,因为 ptrace系统调用号仅为 26 ( 0x1a ),参见 syscalls.master :
26  AUE_PTRACE  ALL { int ptrace(int req, pid_t pid, caddr_t addr, int data); }

经过一番挖掘,我想出了 syscall_sw.h :
#define SYSCALL_CONSTRUCT_UNIX(syscall_number) \
((SYSCALL_CLASS_UNIX << SYSCALL_CLASS_SHIFT) | \
(SYSCALL_NUMBER_MASK & (syscall_number)))

做数学运算的结果是 0x200001A
为什么 dtruss不查 ptrace系统调用?

使用 dtruss似乎是个好主意,不幸的是它没有报告 ptrace系统调用(我的理解是它没有这样做,因为在这种情况下 ptrace 系统调用不会返回)。

幸运的是,您可以编写一个 DTrace 脚本来记录进入后的系统调用(即,不是在它返回之后)。要触发该行为,程序必须从 lldb 启动:
$ lldb ./ptrace
(lldb) process launch --stop-at-entry

然后记下 PID:
sudo dtrace -q -n 'syscall:::entry /pid == $target/ { printf("syscall> %s\n", probefunc); }' -p $PID

最后 continuelldb ,结果应该是:
[...]
syscall> sysctl
syscall> csops
syscall> getrlimit
syscall> fstat64
syscall> ioctl
syscall> write_nocancel
syscall> ptrace

可能的解决方案

现在最好在 ptrace 之前打破syscall 并找到调用它的程序代码,或者在当前调试 session 中跳过它(LLDB: thread jump -a ADDRESS)。

当然,可以尝试破解 ptrace库调用,但如果这是真的,反调试尝试的机会是实际调用是在 asm 中执行的块,因此上述断点永远不会触发。

一个可能的解决方案是使用 DTrace 在系统调用之前放置一个断点,但这需要禁用系统完整性保护,所以我没有尝试。

或者,可以使用 ustack() 打印用户态堆栈跟踪功能:
sudo dtrace -q -n 'syscall:::entry /pid == $target && probefunc == "ptrace"/ { ustack(); }' -p $PID

关于c - lldb 查找应用程序的退出点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36237322/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com