Reverse Engineering
Binaries
C Fundamentals
C Fundamentals
Before you start reversing binaries and analyzing compiled code, it's crucial to have a solid understanding of the foundational concepts that will come up repeatedly during the process:
- Library Functions
Memory Management:
malloc()
: Allocates a block of memory of a specified size. It returns a pointer to the first byte of the allocated memory, orNULL
if the allocation fails.free()
: Releases a block of memory that was previously allocated bymalloc()
orcalloc()
. Failing to free memory leads to memory leaks.realloc()
: Resizes a previously allocated block of memory. It can expand or shrink the memory block. If the reallocation is successful, it returns a pointer to the new memory location.
String Manipulation:
strcpy()
: Copies a null-terminated string from the source to the destination. It is unsafe and can lead to buffer overflows if not used carefully.strncpy()
: Copies up ton
characters from one string to another. It is safer thanstrcpy()
as it prevents buffer overflows (but still requires caution to avoid truncating strings).strcmp()
: Compares two strings lexicographically. It returns0
if the strings are identical, a positive value if the first string is lexicographically greater, or a negative value if the second string is greater.strlen()
: Returns the length of a null-terminated string, excluding the null terminator. It’s used frequently to determine the size of buffers or strings.
File I/O:
fopen()
: Opens a file for reading, writing, or both, depending on the mode. It returns a pointer to aFILE
object that represents the open file.fclose()
: Closes an open file. Always ensure files are closed after use to avoid memory leaks or file locking issues.fread()
: Reads data from an open file stream into a buffer. The size of the data read is specified by the user.fwrite()
: Writes data to an open file stream from a buffer.
Input/Output:
printf()
: Prints formatted output to the standard output (stdout
). It supports various format specifiers for formatting strings, integers, floating-point numbers, etc.scanf()
: Reads formatted input from the standard input (stdin
). It allows the user to provide input in a specified format.puts()
: Writes a string to the standard output (stdout
) followed by a newline. It is a simpler version ofprintf()
.getchar()
: Reads a single character from the standard input (stdin
). It is often used in simple input scenarios.
- System Calls
Process Management:
fork()
: Creates a new process by duplicating the calling process. The new process is a child process and has its own memory space.execvp()
: Replaces the current process with a new one. It executes the command specified by the argument (often used in combination withfork()
).exit()
: Terminates the calling process and returns an exit status to the operating system. It is often used at the end of a program or when a fatal error occurs.setuid()
: Sets the user ID (UID
) for the calling process. A common use is to escalate privileges (e.g., setting theUID
to0
for root privileges).getuid()
: Returns theUID
of the calling process.
Memory Management:
mmap()
: Maps files or devices into memory. It is commonly used for memory-mapped files or to allocate large blocks of memory for a program.brk()
: Used to control the end of the data (heap) segment. It’s an older memory management function, and it is rarely used in modern programs.sbrk()
: Moves the program’s break (end of the data segment) by a specified increment. Likebrk()
, it is an older memory management system call and not commonly used in newer programs.
File Operations:
open()
: Opens a file (or creates it if it doesn't exist) for reading, writing, or both. Returns a file descriptor, which is used for other operations (e.g.,read()
,write()
).read()
: Reads data from a file descriptor into a buffer. Returns the number of bytes read, or-1
on error.write()
: Writes data from a buffer to a file descriptor. Returns the number of bytes written, or-1
on error.close()
: Closes a file descriptor, freeing up system resources associated with it.
- Signals
Used to handle asynchronous events in a process, such as interruptions, timeouts, or the termination of child processes. They allow programs to respond to events without explicitly checking for them in the main execution flow:
signal()
: Sets a handler function for a particular signal. For example, you can set a custom handler forSIGINT
to catch interrupt signals (likeCtrl+C
).kill()
: Sends a signal to a process. It can be used to terminate processes or trigger specific handlers.SIGCHLD
: Sent to a parent process when a child process terminates. This is useful for handling child process lifecycles (e.g., in process management).SIGINT
: Sent when a user interrupts a process (e.g., pressingCtrl+C
). It is typically used to terminate processes.SIGSEGV
: Sent when a program attempts to access memory that it is not allowed to (segmentation fault). It usually indicates a bug in the program, like a null pointer dereference.SIGKILL
: A signal that immediately terminates a process. UnlikeSIGTERM
, the process cannot catch or ignoreSIGKILL
.
Understanding ltrace
Outputs
The quickest way to get a feel for what a binary is doing is to run it with ltrace
, which will print all the library calls it’s making:
By analyzing these outputs, you can infer the program's behavior, detect privilege escalation, identify input validation mechanisms, and spot security features like whitelists and blacklists:
UID
Checks and Privilege EscalationThe
setuid(0)
function call attempts to set theUID
toroot
. If it succeeds returns0
.A failure (
-1
) may indicate the program requires elevated permissions to execute certain operations.
Whitelists/Blacklists
strncmp
orstrcmp
calls are used to compare input against predefined strings. A return value of-1
indicates a mismatch.strcspn
calls are used to check for forbidden characters (e.g.,|
,&
,>
, which could be part of command injection attempts).
File Operations and File Descriptors
Look for files related to user credentials, configuration, or logs.
External Command Execution
Calls to
system()
,execvp()
, or similar functions: These often indicate the program is executing shell commands.Input passed to these commands: If user input directly influences these calls, it might indicate an injection vulnerability.
Signals and Inter-Process Communication
Signals like
SIGCHLD
,SIGSEGV
, orSIGKILL
in the output.Use of
kill()
to manage or terminate processes, which can indicate how the program interacts with other processes.
Last updated