Binary Exploitation

Dynamic Tracing: ltrace & strace

Dynamic analysis using ltrace and strace to trace library calls and system calls, revealing runtime behavior of binary executables.

Contents

Dynamic Tracing: ltrace & strace

Sources: HackTricks - Reversing Tools | Crypto-Cat CTF


ltrace — Library Call Tracer

Intercepts and records library function calls (libc, etc.) made by a process.

Basic Usage

ltrace ./binary                   # Trace all library calls
ltrace -i ./binary                # Show instruction pointer
ltrace -e strcmp ./binary          # Filter: only strcmp calls
ltrace -e strcmp+strlen ./binary   # Filter: multiple functions
ltrace -s 200 ./binary            # Show 200 chars of strings (default=32)
ltrace -o output.txt ./binary     # Save output to file
ltrace -p <PID>                   # Attach to running process
ltrace -C ./binary                # Demangle C++ names
ltrace -f ./binary                # Follow forked children

What to Look For in Malware/CTF Analysis

Library CallWhat It Reveals
strcmp("password", user_input)Hardcoded password comparison!
strncmp(buf, "FLAG{", 5)Flag format check
fopen("/etc/shadow", "r")Credential access attempt
system("wget http://...")Second-stage download
dlopen("libevil.so")Dynamic library loading
connect(fd, ...)Network connection
getenv("SECRET_KEY")Environment variable check
rand() / srand(seed)Predictable RNG (brute-forceable)

Example: Cracking a Password Check

$ ltrace ./crackme
puts("Enter password: ")                              = 17
fgets("hunter2\n", 256, 0x7f...)                      = 0x7ffd...
strcmp("s3cr3t_p4ss!", "hunter2\n")                    = -1
puts("Wrong!")                                         = 7

# Password leaked: s3cr3t_p4ss!

Example: Seeing Encryption Keys

$ ltrace -s 100 ./encryptor flag.txt
fopen("flag.txt", "r")                                = 0x55a...
fread("HTB{this_is_the_flag}", 1, 1024, 0x55a...)     = 21
srand(1337)                                            = 0
rand()                                                 = 846930886
# Now you know the seed → can reproduce the entire key stream

strace — System Call Tracer

Intercepts and records kernel system calls made by a process.

Basic Usage

strace ./binary                   # Trace all syscalls
strace -e trace=open ./binary     # Filter: only open() calls
strace -e trace=network ./binary  # Filter: all network syscalls
strace -e trace=file ./binary     # Filter: all file operations
strace -e trace=process ./binary  # Filter: fork, exec, exit, etc.
strace -e trace=memory ./binary   # Filter: mmap, brk, mprotect
strace -f ./binary                # Follow forked children
strace -p <PID>                   # Attach to running process
strace -o output.txt ./binary     # Save output to file
strace -c ./binary                # Summary: syscall count + time
strace -t ./binary                # Timestamps
strace -T ./binary                # Time spent in each syscall
strace -y ./binary                # Decode file descriptors → paths

Syscall Categories (Filters)

FilterSyscalls IncludedUse Case
trace=fileopen, stat, chmod, unlink, renameWhat files does it touch?
trace=networksocket, connect, bind, sendto, recvfromC2 communication
trace=processclone, fork, execve, wait, killProcess creation/injection
trace=memorymmap, mprotect, brk, munmapRWX memory (shellcode?)
trace=signalsignal, sigaction, killSignal handling
trace=ipcshmget, semop, msggetInter-process communication

What to Look For

Syscall PatternMeaning
openat(AT_FDCWD, "/etc/passwd")Reading system files
connect(3, {sa_family=AF_INET, sin_port=htons(4444)})Reverse shell / C2
mprotect(0x7f..., 4096, PROT_READ|PROT_WRITE|PROT_EXEC)Making memory executable (shellcode)
execve("/bin/sh", ["/bin/sh", "-c", "..."])Spawning shell
ptrace(PTRACE_TRACEME)Anti-debugging (if fails = being debugged)
unlink("/tmp/malware")Self-deletion
clone(child_stack=...)Creating threads / forking

Example: Spotting Anti-Debugging

$ strace ./malware 2>&1 | grep ptrace
ptrace(PTRACE_TRACEME, ...)      = -1 EPERM (Operation not permitted)
# Binary detected it's being traced and will exit or change behavior

Example: Tracking File Drops

$ strace -e trace=file -y ./dropper 2>&1 | grep -i "creat\|open.*W\|unlink"
openat(AT_FDCWD, "/tmp/.hidden_payload", O_WRONLY|O_CREAT) = 4
# Malware dropping payload to /tmp/.hidden_payload

ltrace vs strace — When to Use Which

ScenarioUse
Crackme / password checkltrace (shows strcmp, strncmp)
What files does malware access?strace (-e trace=file)
What network connections?strace (-e trace=network)
What libraries/APIs called?ltrace
Does it execute other programs?strace (-e trace=process)
Anti-debug detection?strace (shows ptrace calls)
Static binary (no dynamic libs)?strace only (ltrace won’t work)

Pro Tips

# Combine both for full visibility
ltrace -o ltrace.log ./binary &
strace -o strace.log -p $!

# Run binary with ltrace and pipe password
echo "test_password" | ltrace -s 200 ./crackme

# Compare behavior with/without debug
strace -c ./binary              # Normal run timing
strace -c gdb -batch ./binary   # Under GDB — detect anti-debug timing gaps

References