
Table of contents :
Intro & Tools:
Follow the instructions to set up the necessary configurations. in Resources section below!
Open the
crackme
challenge in Ghidra: Launch Ghidra and create a new project. Import the crackme executable or binary into the project. Ghidra will analyze the binary and present you with a disassembled view.Analyse the disassembled code: Explore the disassembled code to understand the logic and flow of the program. Look for function names, control flow structures, and interesting sections that might be relevant to the crackme challenge.
Identify the entry point: Locate the entry point or main function of the crackme challenge. This is usually the starting point of the program.
Follow the execution flow: Analyze the code and trace the execution flow from the entry point. Identify any conditional statements, loops, or jumps that can affect the behavior of the program.
Identify interesting functions or sections: Look for functions or sections of code that appear to perform important operations related to the crackme challenge. These might include input validation, encryption or decryption routines, or checks for a specific password or key.
Set breakpoints: Set breakpoints at strategic locations to observe the program's behaviour during runtime. Breakpoints allow you to pause the execution of the program at specific points and examine the values of registers, memory, and other variables.
Execute the Crackme challenge: Run the crackme challenge and trigger the breakpoints you've set. This will pause the execution at those points, allowing you to inspect the program's state.
Inspect memory and registers: When the program pauses at a breakpoint, examine the memory contents and register values to understand how the crackme challenge operates. Look for clues, strings, or patterns that might reveal the solution. more on this below
Terminology:
Register :
a register is a small amount of fast memory that is built into the CPU and is used to hold data that is being processed by the CPU. Registers are identified by names such as
eax
,ebx
,ecx
,edx
,esi
,edi
,ebp
,esp
, etc., depending on the specific architecture.Base Pointer:
A reference for accessing data on the stack. It points to the base address of the current stack frame, which is the region of memory that is allocated for the function's local variables and function arguments.
The base pointer register is used in conjunction with the stack pointer register (
sp
orrsp
) to access data on the stackFunction prologue :
The function prologue is a set of instructions that are executed at the beginning of a function to set up the function's stack frame. The stack frame is a region of memory on the stack that is used to store the function's local variables, function arguments, and the function's return address.
Function epilogue:
The function epilogue is a set of instructions that are executed at the end of a function to clean up the function's stack frame and return control to the calling function.
Compile explorer : Amazing to start writing your own code and see what does it looks like in assembly
eax
stands for "accumulator register" and was originally designed for use in arithmetic and logic operations, such as addition, subtraction, multiplication, and division. However, it is also commonly used for other purposes, such as storing function return values and holding pointers to memory locations.
In the context of our code above, eax
is used to store the function argument and the result of the calculation.
The imul
instruction is used to perform signed multiplication of two values. In this case, the instruction imul eax, eax
multiplies the value in the eax
register by itself, effectively squaring it.
So if the original value of eax
was n
, then after this instruction executes, the value of eax
will be n * n
, which is equal to n^2
, the square of the original value.
Note that imul
can also be used to multiply a register or memory location by an immediate value or another register, in which case the syntax would be imul dest, src
, where dest
is the destination register or memory location and src
is the source operand (either a register or a memory location).
Crackme challenge :
To understand what a function does, we need to examine its assembly code and look for clues that indicate its purpose. Here are some general steps you can follow to analyse a function:
Identify function arguments and local variables: Look for
mov
instructions that move values into memory locations relative to the base pointer register (e.g.,[rbp - 0x10]
). These instructions typically store function arguments or local variables in memory. You can also look for instructions that access memory locations relative to the base pointer register (e.g.,[rbp + local_20]
) to see how the function manipulates its arguments and variables.
Notes :
** QWORD
stands for "quadword" and represents a 64-bit integer. A QWORD
can hold integer values. In assembly language, the QWORD
data type is typically used to represent memory addresses, large integers, or other 64-bit values.
DWORD
stands for "doubleword" and represents a 32-bit integer. A DWORD
can hold integer values between -2,147,483,648 and 2,147,483,647. In assembly language, the DWORD
data type is typically used to represent integers or other 32-bit values.
The use of qword ptr
in the instruction suggests that the argument is a pointer, since pointers are typically 64 bits (8 bytes) on x86-64 architectures.
** The fact that the destination of the mov
instruction is [rbp + local_20]
suggests that local_20
is the offset of the local variable that will store the argument. This suggests that the function expects a single argument.
**The function does not perform any type conversions or manipulations on the argument before storing it in the local variable, which suggests that the argument is already in the correct format for the function's purposes.
Look for operation instructions: Look for instructions that perform arithmetic or logical operations on registers or memory locations. These instructions can give you clues about what the function is doing with its arguments and variables.
Identify the function's return value: Look for instructions that move a value into the
rax
register, which is typically used to store the function's return value.
Applying these steps to the checksum
function, we can see that:
The function prologue begins with
push rbp
andmov rbp, rsp
.The function takes a single argument, a pointer to a null-terminated string of characters, which is stored in the local variable
local_20
using the instructionmov qword ptr [rbp + local_20], param_1
.The function initializes the local variable
local_10
to zero using the instructionmov qword ptr [rbp + local_10], 0x0
.The function iterates over the characters in the input string using a loop that begins with the unconditional jump
jmp LAB_0040058c
and ends with the conditional jumpjnz LAB_00400578
. Within the loop, the function computes the ASCII value of each character and adds it to the running checksum using the instructionsmovzx eax, byte ptr [rax]
,movsx rax, al
, andadd qword ptr [rbp + local_10], rax
.The function returns the final checksum value, which is stored in the
rax
register, using the instructionmov rax, qword ptr [rbp + local_10]
.
Another Example : Source code and corresponding assembly!
Resources :
Live Coding: Crackme (reverse engineering challenge) Julien Barbier
Install Ghidra
Nice practice :
see..