bernas198YT on 2025-01-09 15:27:
[Click to reveal]In the main function:
sub_401639 is called with v4 as target, v5 as input ("331") and a3 = 22.
This means it generates a key derived from "331" by applying an offset of 22.
For "331":
'3' → (3 + 22) % 10 = 5
'3' → (3 + 22) % 10 = 5
'1' → (1 + 22) % 10 = 3
Result/Correct Key: "553"
g4 on 2026-05-22 01:52:
bxplode's easycrackme tutorial
1. Look into DIE
Die scanned for
- 64 bit windows console application
- That it's made with MinGW (gcc)
- That there is no packer or encryption
2. Console
2 important takeaways is these two strings that can come in handy
- wrong key!!
- try again :))
These two strings can help us find the logic and the code itself that tells us what the key is that can unlock the correct key
3. Analysis
Loading the application/binary into Cutter, I found out that
- "CORRECT KEY!! \n" at 0x004a801b
- "wrong key!!" at 0x004a8091
- "please enter the key:\n" at 0x004a8076
I did Xref (or cross references or whatever you can call them) and saw that the code was able to read from the global flag byte at 0x004d1030. And if that byte were to be 1, then it will be able to print the correct key message. Any other integer will print the failure message.
4, Ghidra
Opening and analyzing the crackme application in Ghidra, I searched the 0x00401639 address, and double clicking the address showed some more decompiled code I can see:
longlong * FUN_00401639(longlong *param_1,undefi ned8 *param_2,int param_3)
{
undefined8 uVar1;
int iVar2;
longlong local_28;
longlong local_20;
char *local_18;
longlong *local_10;
FUN_00490ba0(param_1,param_2);
local_10 = param_1;
local_20 = FUN_0048f4e0(param_1);
local_28 = FUN_0048f3a0(local_10);
while (uVar1 = FUN_0041eed0(&local_20,&local_28), (char)uVar1 != '\0') {
local_18 = (char *)FUN_0041fdd0(&local_20);
if ((int)*local_18 - 0x30U < 10) {
iVar2 = *local_18 + -0x30 + param_3;
*local_18 = (char)iVar2 + (char)(iVar2 / 10) * -10 + '0' ;
}
FUN_0041dea0(&local_20);
}
return param_1;
}
and for the 0x004d1030 address I found this code:
{
undefined8 uVar1;
longlong local_108 [4];
longlong local_e8 [4];
longlong local_c8 [4];
longlong local_a8 [6];
longlong local_78 [6];
longlong local_48 [5];
undefined4 local_1c;
FUN_0040b410();
SetConsoleTitleA("bxtumations crackme");
FUN_00460b70();
FUN_00490b10(local_a8,"please enter the key:\n");
FUN_00401766(local_a8);
FUN_00491060(local_a8);
FUN_00460ba0();
FUN_00490cf0(local_c8);
FUN_00460b70();
FUN_00490b10(local_e8,"331");
FUN_00460ba0();
local_1c = 0x16;
FUN_00401639(local_108,local_e8,0x16);
while( true ) {
FUN_004a0e90(&DAT_004a6860,local_c8);
uVar1 = FUN_0049fbe0(local_c8,local_108);
if ((char)uVar1 != '\0') break;
FUN_00401560();
FUN_00460b70();
FUN_00490b10(local_78,"wrong key!!");
FUN_00401766(local_78);
FUN_00491060(local_78);
FUN_00460ba0();
FUN_00460b70();
FUN_00490b10(local_48,"\ntry again :))\n");
FUN_00401766(local_48);
FUN_00491060(local_48);
FUN_00460ba0();
}
DAT_004d1030 = 1;
FUN_0040157b();
FUN_00491060(local_108);
FUN_00491060(local_e8);
FUN_00491060(local_c8);
return 0;
}
What this code generally means that the param_2 is the strings "331" which was passed from main, param_3 is the shift value that makes 0x16 = 22, and also: if it's a digit, then it will convert the character to its numeric value, add 22 to that specified value, wraps the result back to a digit from 0-9 using mod 10, then it converts it back to a character.
Doing some manual calculations, we get the seed that 331 is processed in with the shift set to 22
'3' > 3 + 22 = 25 > 25 % 10 = 5 ('5')
'3' > 3 + 22 = 25 > 25 % 10 = 5 ('5')
'1' > 1 + 22 = 23 > 23 % 10 = 3 ('3')
combining the final digits up leads to the integer '553'.