Number of crackmes:
Number of writeups:
Comments:
Name | Author | Language | Arch | Difficulty | Quality | Platform | Date | Writeups | Comments |
---|
Crackme | Infos |
---|---|
KeygenMe again! | This KeygenMe challenge was a great experience for me. Thank you. |
Very easy disassembly execise | Static analysis of the main function shows a simple hardcoded comparison with value 124816. Password = 124816. |
emulation loader | # CrackM Writeup - karabatik ## Overview This writeup details the solution for the `crackmemain.exe` CrackMe challenge. The binary implements function pointer obfuscation and anti-debugging techniques, making it an interesting reverse engineering exercise. ## Initial Analysis ### File Information - **Filename**: crackmemain.exe - **Size**: 0xCE00 (52,736 bytes) - **MD5**: 592f7a190c872f6091dfad0e4fb9ee61 - **Architecture**: x64 Windows PE - **Base Address**: 0x140000000 - **Entry Point**: 0x14000a280 ### Runtime Behavior Running the executable shows a simple login prompt: ``` **********Welcome to CrackMe Loader..... Enter Login: test Enter Password: password Fail! Total pause: 0ms Press Enter to exit... ``` ## Static Analysis with IDA Pro ### Main Function Analysis The main function is located at `0x140001ab0` and contains several interesting features: 1. **Function Pointer Obfuscation**: All function calls are obfuscated using a magic number `0x2CC634AC8CA6AD95` 2. **Anti-Debug Protection**: Multiple conditional checks against global variables 3. **String Encryption**: All strings are encrypted and decrypted at runtime ### Key Functions Identified - `0x140001ab0` - Main function (1466 bytes) - `0x140002070` - Dynamic API loading - `0x140002600` - Anti-debug mechanism with 5x500ms delays - `0x140002d30` - **Validation function (TARGET)** - `0x140001230` - String processing utilities ### Deobfuscating Function Pointers The obfuscated function pointers follow this pattern: ```c ((void (*)(void))((char *)off_14000D150 - 0x2CC634AC8CA6AD95LL))() ``` To deobfuscate: `real_address = obfuscated_pointer - 0x2CC634AC8CA6AD95` ## Deep Dive: Validation Function ### Function Analysis The critical validation logic resides in `sub_140002D30`. After decompiling, the function reveals: ```c strcpy(v43, "panhauzer"); // Expected login strcpy(v42, "2digboob"); // Expected password ``` The function performs complex string comparison using regex-like pattern matching, but ultimately returns: - `1` for successful authentication - `0` for failed authentication ### Hardcoded Credentials Through static analysis, I discovered the valid credentials: - **Login**: `panhauzer` - **Password**: `2digboob` However, testing these credentials would be the "intended" solution. Instead, I chose a more elegant approach. ## Solution: Binary Patching ### Approach Rather than finding the exact password, I decided to patch the validation function to always return success. This demonstrates a common real-world attack vector. ### Patch Implementation **Target Address**: `0x140002d30` (start of validation function) **Original bytes**: ``` 41 57 41 56 56 57 ... (complex validation logic) ``` **Patched bytes**: ``` B8 01 00 00 00 C3 ``` **Assembly equivalent**: ```assembly mov eax, 1 ; Return success (1) ret ; Exit function immediately ``` ### Patching Process 1. Navigate to address `0x140002d30` in IDA Pro 2. Switch to Hex View 3. Press `F2` to enter edit mode 4. Replace the first 6 bytes: `41 57 41 56 56 57` → `B8 01 00 00 00 C3` 5. Press `F2` to exit edit mode 6. Save the patched binary ## Results After applying the patch, any login/password combination is accepted: ``` **********Welcome to CrackMe Loader..... Enter Login: anything Enter Password: whatever DLL Inject Success! [EMU] Total pause: 0ms Press Enter to exit... ``` The success message "DLL Inject Success! [EMU]" confirms the bypass worked perfectly. ## Alternative Solutions ### Method 1: Using Hardcoded Credentials The "intended" solution would be using the discovered credentials: - Login: `panhauzer` - Password: `2digboob` ### Method 2: Runtime Patching Instead of modifying the binary, one could: - Use a debugger to set breakpoint at `0x140002d30` - Modify the EAX register to return 1 - Continue execution ### Method 3: DLL Injection Advanced users could inject a DLL to hook the validation function and force it to return success. ## Technical Insights ### Anti-Analysis Techniques Observed 1. **Function Pointer Obfuscation**: Makes static analysis more difficult 2. **String Encryption**: Hides meaningful strings from basic analysis 3. **Anti-Debug Delays**: 5x500ms delays slow down dynamic analysis 4. **Complex Control Flow**: Multiple nested loops and conditions ## Tools Used - **IDA Pro 9.0**: Static analysis and disassembly - **Hex Editor**: Binary modification --- **Author**: karabatik **Date**: 08/18/2025 **Difficulty**: 4/10 **Primary Technique**: Binary Patching |
Comment | Link |
---|---|
In Binary Ninja, user input in main is compared with the target string generated by sub_140002f50 from XOR-ed 256-bit constants using memcmp. After decrypting and XOR-ing the constants, the license key was revealed: 123_isthekey-crkm. | ==> |
I stopped the binary right after its decode stub by planting an INT3 at RVA 0x92F00, dumped the entire in-memory image, opened the dump in Binary Ninja, and followed the actual control flow start → sub_7ff63656F40B → sub_7ff636592F00; Under a flag-driven, pushf/popf-based control flow flattening, I identified the actual password check in sub_7ff6365542a1, which reads certain indices from the input buffer via sub_7ff6365778c4(&buf, idx) and compares them to movsx/cmp imm8 literals in the order '2', '3', 's', '2', 'N', 'o', 'R', 't', 'e'; using x64dbg with ReadFile/WriteFile breakpoints, I traced the input and branch results to confirm the success path matches these comparisons; resulting password: 23s2NoRte. | ==> |
Opened the binary in IDA Pro. Found the username and key validation checks. Patched two jump instructions, flipped the conditions from jne to je. Now it accepts any password. Done. | ==> |
ret = (ret | ==> |
This was a nice little challenge. I analyzed the binary with Ghidra and found that the auth() function compares the hash result with 0x4262d2e9. Instead of trying to reverse the hash algorithm (which would be quite tedious with the modified djb2), I decided to patch the comparison directly. I located the CMP EAX,0x4262d2e9 instruction at the binary level and replaced it with CMP EAX,EAX followed by NOPs. This way, the comparison always results in true, and the program grants access regardless of the input. The hash function itself was interesting - starting with 0xA5A5A5A5 and using ret = (ret | ==> |
I opened it with Ghidra, and in the main function, there's an XOR operation. After decrypting with the key 0x2a, it revealed "easi123". | ==> |