Dynamic Tracing: ltrace & strace
Dynamic analysis using ltrace and strace to trace library calls and system calls, revealing runtime behavior of binary executables.
Contents
- ltrace — Library Call Tracer
- Basic Usage
- What to Look For in Malware/CTF Analysis
- Example: Cracking a Password Check
- Example: Seeing Encryption Keys
- strace — System Call Tracer
- Basic Usage
- Syscall Categories (Filters)
- What to Look For
- Example: Spotting Anti-Debugging
- Example: Tracking File Drops
- ltrace vs strace — When to Use Which
- Pro Tips
- References
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 Call | What 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)
| Filter | Syscalls Included | Use Case |
|---|---|---|
trace=file | open, stat, chmod, unlink, rename | What files does it touch? |
trace=network | socket, connect, bind, sendto, recvfrom | C2 communication |
trace=process | clone, fork, execve, wait, kill | Process creation/injection |
trace=memory | mmap, mprotect, brk, munmap | RWX memory (shellcode?) |
trace=signal | signal, sigaction, kill | Signal handling |
trace=ipc | shmget, semop, msgget | Inter-process communication |
What to Look For
| Syscall Pattern | Meaning |
|---|---|
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
| Scenario | Use |
|---|---|
| Crackme / password check | ltrace (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
- HackTricks - Reversing Tools & Methods
- Crypto-Cat Binary Exploitation Setup
man ltrace,man strace