运行 ltrace 以避免检测(在不同的 PID 上?)

逆向工程 调试 缓冲区溢出
2021-07-06 10:50:54

我试图ltrace在这个文件上运行

./launcher:ELF 32 位 LSB 共享对象,英特尔 80386,版本 1 (SYSV),动态链接,解释器 /lib/ld-linux.so.2,用于 GNU/Linux 2.6.32,BuildID[sha1]=f6f8cf3307e0ee26723f4d03ec66d85e0 , 剥离

当我在 ghidra 中打开它并查看反编译的 c 时,我可以看到它将程序流程更改为我不想在 ltrace 运行时出现的某个地方。

  attached_to_ptrace = ptrace(PTRACE_TRACEME,0,1,0);
  if (attached_to_ptrace == -1) {
    puts("I am not your property!");
    exit_code = 1;
  }
  else {
    // execute main loop
  }

查看 的手册页ptrace,我看到:

long ptrace(enum __ptrace_request request, pid_t pid,
                   void *addr, void *data);

意思是如果程序?或ltrace?如果要使用不同的 PID 运行,我将能够使用 ltrace 成功运行我的程序。

这是我在运行程序时得到的当前输出ltrace

~/ctf/cyberstart/level13/04 [master|…1] $ ltrace ./launcher
__libc_start_main(0x565a86f0, 1, 0xff837be4, 0x565a8970 <unfinished ...>
ptrace(0, 0, 1, 0)                                                     = 0xffffffff
puts("I am not your property!"I am not your property!
)                                        = 24
+++ exited (status 1) +++

没有 ltrace:

~/ctf/cyberstart/level13/04 [master|…1] $ ./launcher

Enter the password:
password
Away now, you anklebiter!

[1]+  Stopped                 ./launcher

(这是我的第二个缓冲区溢出 CTF 挑战,主要目标是弄乱这段代码:)

  int iVar1;
  char local_1e [10];
  int local_14;
  int local_10;
  
  local_10 = 0;
  puts("\nEnter the password: ");
  gets(local_1e);
  iVar1 = strcmp(local_1e,"PAssw0rd");
  if (iVar1 == 0) {
    puts("Well done! Unfortunately, you have to try harder.");
    local_10 = 0;
  }
  else {
    puts("Away now, you anklebiter!");
  }
  if (local_10 != 0) {
    printf("Unexpected error condition. Control char is %d\n",local_10);
    local_14 = param_2 * local_10;
    (*(code *)(local_14 + param_1))();
  }

我怎样才能以一种不被检测到的方式运行 ltrace?

2个回答

吉德拉法

您可以通过以下方式通过 Ghidra 修改二进制文件:

  • 加载轨道
  • 将汇编代码移至检查结果的位置(if 语句)
  • 您可能会遇到跳转指令JNZ,只需右键单击它并选择“补丁指令”并将其替换为相反的条件JZ(反之亦然)。
  • 现在保存项目 ( Ctrl+ S)
  • 然后导航到File> ExportProgram 并决定保存修改后的二进制文件的位置

如果导出的二进制文件有问题,请尝试使用此脚本:https : //github.com/schlafwandler/ghidra_SavePatch

LD_PRELOAD 方法

  • 创建一个包含ptrace.c以下内容的文件
long ptrace(int request, int pid, void *addr, void *data) {
    return 0;
}
  • 现在建立的文件作为共享库:gcc -shared ptrace.c -o ptrace.so;
  • 现在午餐执行以下命令: export LD_PRELOAD=./ptrace.so
  • ltrace ./launcher

注意:您也可以在 GDB 中使用 LD_PRELOAD 方法

GDB方法

  • 使用 GDB 来处理二进制文件: gdb ./launcher
  • 在 GDB 客户端 shell 中: catch syscall ptrace
  • GDB 允许您在到达 BP 时运行一系列命令: command 1
  • 类型:set ($rax) = 0,这将更改“返回”寄存器内的值(也称为 ptrace 系统调用的结果)x86 寄存器
  • 然后输入:continueend (作为两个分开的命令)
  • 在main函数上放置一个BP:b main然后输入r继续执行

另一种选择是使用 Qiling 框架并挂钩函数/系统调用并始终返回“-1”以外的任何其他值,但这似乎有点过头了。

您可以使用 NOP 将 CALL 修补为 ptrace 或使用 LD_PRELOAD 注入您自己的假 ptrace 代码,该代码除了返回 -1 之外的值之外什么都不做。