Reverse Engineering For Beginners
Another reverse engineering challenge :)
Password
Opening the binary Ghidra shows the following pseudo-code of the function named entry
.
int entry(void)
{
[...]
unaff_ESI = FUN_00401090(); // this is the main function
[...]
}
The function entry
executes the function named FUN_00401090
renamed to main
. The function asks for a string using scanf
and checks the input against the string “cr4ckm3” with using strcmp
. If strncmp
returns 0
the password is correct.
PS C:\Users\re\Documents> .\Exer0_Password.exe
Enter password: cr4ckm3
Correct!
Good_Luck
The function entry
calls FUN_00401040
renamed to main
:
int entry(void)
{
[...]
unaff_ESI = FUN_00401040(*piVar8,iVar5);
[...]
}
atoi
converts argv[1]
to an integer. If argv[1]
contains a string and not an integer the function returns 0
.
PS C:\Users\re\Documents> .\Exer1_GoodLuck.exe AAAA
PS C:\Users\re\Documents>
After checking if argv[1]
contains an integer the function checks if the value of argv[1]
multiply 5
equals 6170
. If true the function prints “Verry Correct!”.
PS C:\Users\re\Documents> python
>>> 6170 / 5
1234
PS C:\Users\re\Documents> .\Exer1_GoodLuck.exe 1234
Very correct!
Julia
The first part of the function main
checks for a second argument, saves the length in the variable input_length
and copies the argument to the heap with the use of malloc
and strcpy
.
After copying the argument to the heap, every character is “checked” by the function input_check
in a while loop. If the result of the while loop saved in the array input_heap
minus the input_length
equals to the string VIMwXliFiwx
the function prints Brava!!!
.
The goal of the challenge is to determine what the function input_check
does and what input we have to enter to get the string VIMwXliFiwx
. The function input_check
performs 3 actions on the string input
explained in the pseudo code below. The character values used are ASCII characters.
To reverse the check of the input of the string VIMwXliFiwx
I recreated the function input_check
in Python.
from string import printable
ascii = {}
for s in printable:
input = ord(s)
if 96 < input and input < 123:
input += 4
input_var = input
if 64 < input and input < 91:
input += 4
input = chr((input_var >> 7) + input)
ascii[input] = s
flag = "VIMwXliFiwx"
result = ""
for f in flag:
result += ascii[f]
print(result)
re@DESKTOP-S7VKEO8:/mnt/c/Users/re/Documents$ python flag.py
REIsTheBest
PS C:\Users\re\Documents> .\Exer2_Juila.exe REIsTheBest
Brava!!!
After finishing the challenge I figured out I also could have used an online ceasar cypher website, but I like Python and recreating the function in a different programming language.
Minesweeper
The goal is to make Minesweeper print the flags on the positions where there are mines when starting up the game.
Opening the binary in Ghidra and looking for references to the function rand
shows an incoming reference from the function FUN_01003940
renamed to rand_caller
:
The function rand_caller
gets called two times from the function FUN_0100367a
.
The values passed to the function rand_caller
are at the addresses 01005334
and 01005338
. After that, the mines are set with the instruction OR byte ptr [y-as],0x80
.
Let’s debug the binary and watch the values at the address 0x01005330
. What stood out is the value 0xA
. This is the number of mines in the game.
The memory contents shows the mine field with the following values.
- 0x01005330 = mines = 0xA
- 0x01005334 = x-as = 0x9
- 0x01005338 = y-as = 0x9
- 0x10 = border
- 0x8F = mine
- 0x0F = empty
To cheat the game we can print the contents of memory and show where the mines are or show the mines at the start of the game with a flag. Let’s try modifying the binary to set the value of 0x8E
(flag) instead of 0x8f
(mine).OR byte ptr [y-as],0x80
changed to mov byte ptr ds:[eax], 0x8E
Yes, it shows the mines :)
While playing it marks the mines with flags to make it easier to cheat.