I am trying to run ltrace on this file:

./launcher: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=f6f8cf3307e0ee26723f4d03ec68f022d15e56b6, stripped

When I pop it open in ghidra, and view the decompiled c, I can see that it changes the program flow to somewhere I don't want to be when ltrace is running.

  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

Looking at the man page for ptrace, I see:

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

Meaning that if the program? or ltrace? were to run with a different PID, I would be able to successfully run my program using ltrace.

This is the current output I get when running the program with 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) +++

Without ltrace:

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

Enter the password:
Away now, you anklebiter!

[1]+  Stopped                 ./launcher

(This is my second buffer overflow CTF challenge, where the main goal is to mess with this block of code:)

  int iVar1;
  char local_1e [10];
  int local_14;
  int local_10;
  local_10 = 0;
  puts("\nEnter the password: ");
  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))();

How can I run ltrace in a way such that it isn't detected?

2 Answers 2


Ghidra method

You can modify the binary via Ghidra in the following way:

  • load the track
  • move in the assembly code to the point where it checks the result (if statement)
  • you will probably be faced with a jump instruction JNZ, just right click on it and select "Patch Instruction" and replace it with the opposite condition JZ (or vice versa).
  • Now save the project (Ctrl+S)
  • Then navigate to File>Export Program and decide where to save the modified binary

If you have problems with the exported binary, try this script: https://github.com/schlafwandler/ghidra_SavePatch


  • Create a file called ptrace.c with the following content:
long ptrace(int request, int pid, void *addr, void *data) {
    return 0;
  • Now build the file as a shared library: gcc -shared ptrace.c -o ptrace.so;
  • Now lunch the following command: export LD_PRELOAD=./ptrace.so
  • Run ltrace ./launcher

Note: you can also use LD_PRELOAD method with GDB

GDB method

  • use GDB to lunch the binary: gdb ./launcher
  • in the GDB client shell: catch syscall ptrace
  • GDB allows you tun run a series of command when you reach a BP: command 1
  • type: set ($rax) = 0, that will change the value inside the "return" register (aka the result of ptrace syscall) x86-registers
  • then enter: continue and end (as two separated commands)
  • place a BP on the main function: b main and then type r to continue the execution

Another option is to use Qiling framework and hook the function/syscall and always return any other value than "-1", but that seems a bit overkill.


You can patch the CALL to ptrace with NOPs or use LD_PRELOAD to inject your own fake ptrace code which does nothing but return a value other than -1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.