June 30, 2026
๐ Reverse Engineering 101: Solving CrackMe Using Ghidra
๐ Introduction

By Abhishek Solanki
3 min read
Reverse engineering is all about uncovering how software behaves when the source code isn't available. Instead of relying on trial and error, the objective is to analyze the binary, follow its execution flow, and understand the logic behind every decision the application makes.
One of the best ways to practice these skills is by solving CrackMe challenges. These small programs are intentionally designed to teach common reverse engineering concepts such as input validation, control flow, conditional branching, and password verification.
In this walkthrough, we'll analyze a simple CrackMe using Ghidra and identify the expected password by understanding the application's validation logic. No brute force, no patching โ just static analysis and a systematic approach.
๐ ๏ธ Environment
For this analysis, I used the following tool:
- Ghidra โ NSA's open-source reverse engineering framework.
Once the binary was imported, I allowed Ghidra's default auto-analysis to complete before beginning the investigation.
๐ Step 1 โ Exploring the Binary
After the analysis finished, the first step was to inspect the available functions.
Among the discovered functions were:
main
canaccess
printaccessmain
canaccess
printaccessThe presence of these function names immediately suggested a straightforward execution flow.
Since main() is the entry point of the application, it became the logical place to begin understanding how the program works.
๐งญ Step 2 โ Understanding the Execution Flow
Rather than starting with assembly instructions, I switched to Ghidra's Decompiler window.
The decompiled code clearly showed the application's overall structure.
The program:
- Displays a password prompt.
- Reads user input.
- Stores the input in a local variable.
- Compares that value with a predefined constant.
- Decides whether access should be granted.
Even before examining every line, the overall behavior of the application was already becoming clear.
๐ Step 3 โ Tracing User Input
One of the most effective habits in reverse engineering is to follow user-controlled data.
In this binary, the password entered by the user is read using scanf() and stored inside a local variable named local_14.
Instead of trying to understand every instruction in the binary, I simply focused on answering one question:
Where does the program validate the value stored in
local_14?
This approach dramatically reduces the amount of code that needs to be analyzed.
๐ Step 4 โ Finding the Password Verification
Following the input variable eventually led to the application's validation logic.
The comparison looked like this:
if (local_14 == 0xb7b5)if (local_14 == 0xb7b5)This single condition determines whether execution continues toward the success path or immediately returns an access denied message.
Whenever you encounter comparisons like this during reverse engineering, you've usually found the most important part of the application.
๐งฎ Step 5 โ Understanding the Constant
One interesting detail is that the comparison value is written as:
0xb7b50xb7b5The prefix 0x indicates that the value is represented in hexadecimal.
However, the application reads user input using:
scanf("%d", &local_14);scanf("%d", &local_14);The %d format specifier expects a decimal integer.
Therefore, the hexadecimal constant must first be converted into its decimal representation before entering it as input.
After converting the value, the expected password becomes:
4702947029Providing this value causes the application to continue along the successful execution path.
๐ Visualizing the Program Logic
The application's behavior can be summarized with the following flow:
Program Starts
โ
โผ
Display Password Prompt
โ
โผ
Read User Input
โ
โผ
Store Value
โ
โผ
Compare Input
โ
โโโโโโดโโโโโโ
โ โ
False True
โ โ
Access canaccess()
Denied โ
โผ
printaccess()
โ
โผ
Access GrantedProgram Starts
โ
โผ
Display Password Prompt
โ
โผ
Read User Input
โ
โผ
Store Value
โ
โผ
Compare Input
โ
โโโโโโดโโโโโโ
โ โ
False True
โ โ
Access canaccess()
Denied โ
โผ
printaccess()
โ
โผ
Access GrantedBreaking the logic into a simple flowchart often makes the binary much easier to understand than reading dozens of assembly instructions.
๐ก Lessons Learned
Although this challenge is relatively small, it demonstrates several important reverse engineering principles.
โ Always begin your analysis from the program's entry point.
โ Use the decompiler to understand the application's overall behavior before diving into assembly.
โ Follow user-controlled variables instead of trying to understand every instruction.
โ Identify the comparison responsible for deciding success or failure.
โ Let the application's logic guide your analysis instead of relying on guesswork.
๐ฏ Conclusion
This CrackMe demonstrates a classic example of password validation through a direct comparison.
Rather than attempting to brute-force the password, analyzing the binary revealed exactly how the application processes and validates user input.
Challenges like this are excellent for building a strong foundation in reverse engineering because they encourage analytical thinking instead of memorization.
Every solved binary introduces a new concept, and every new concept makes the next challenge easier to approach.
๐ Next Steps
The next objective is to explore binaries that introduce more advanced validation techniques, including:
- String comparisons using
strcmp() - Memory comparisons with
memcmp() - XOR-based password verification
- Loop-driven validation routines
- Serial key generation
- Basic anti-debugging techniques
Each challenge adds another piece to the reverse engineering puzzle.
๐ Final Thoughts
Reverse engineering isn't about finding shortcuts โ it's about understanding software at a deeper level.
The more binaries you analyze, the more patterns you'll recognize. Over time, functions that once looked confusing begin to tell a story, and solving CrackMes becomes less about finding the password and more about understanding why that password works.