Skip to content

Commit

Permalink
Update and cleanup "Crackmes" chapter
Browse files Browse the repository at this point in the history
Improve spelling, use common Markdown syntax.
Update most of rizin invocations.

For all changed command invocation was used rizin 0.7.3.
  • Loading branch information
winterheart committed Nov 23, 2024
1 parent d139324 commit 6aea95c
Show file tree
Hide file tree
Showing 21 changed files with 356 additions and 354 deletions.
3 changes: 1 addition & 2 deletions src/crackmes/avatao/01-reverse4/bytecode.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.bytecode
---------
## .bytecode

Well, we did the reverse engineering part, now we have to write a program for
the VM with the instruction set described in the previous paragraph. Here is
Expand Down
7 changes: 3 additions & 4 deletions src/crackmes/avatao/01-reverse4/first_steps.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.first_steps
------------
## .first_steps

OK, enough of praising rizin, lets start reversing this stuff. First, you have to
know your enemy:
Expand Down Expand Up @@ -34,7 +33,7 @@ binsz 8620
> be used to extract information (imports, symbols, libraries, etc.) about
> binary executables. As always, check the help (rz-bin -h)!
So, its a dynamically linked, stripped, 64bit Linux executable - nothing fancy
So, it's a dynamically linked, stripped, 64bit Linux executable - nothing fancy
here. Let's try to run it:

```
Expand Down Expand Up @@ -92,7 +91,7 @@ We can list all the strings rizin found:
[0x00400720]>
```

> ***rizin tip***: rizin puts so called flags on important/interesting offsets, and
> ***rizin tip***: rizin puts so-called flags on important/interesting offsets, and
> organizes these flags into flagspaces (strings, functions, symbols, etc.) You
> can list all flagspaces using *fs*, and switch the current one using
> *fs [flagspace]* (the default is \*, which means all the flagspaces). The
Expand Down
31 changes: 15 additions & 16 deletions src/crackmes/avatao/01-reverse4/instructionset.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
.instructionset
---------------
## .instructionset

We've now reversed all the VM instructions, and have a full understanding about
how it works. Here is the VM's instruction set:

| Instruction | 1st arg | 2nd arg | What does it do?
| ----------- | ------- | ------- | ----------------
| "A" | "M" | arg2 | \*sym.current_memory_ptr += arg2
| | "P" | arg2 | sym.current_memory_ptr += arg2
| | "C" | arg2 | sym.written_by_instr_C += arg2
| "S" | "M" | arg2 | \*sym.current_memory_ptr -= arg2
| | "P" | arg2 | sym.current_memory_ptr -= arg2
| | "C" | arg2 | sym.written_by_instr_C -= arg2
| "I" | arg1 | n/a | instr_A(arg1, 1)
| "D" | arg1 | n/a | instr_S(arg1, 1)
| "P" | arg1 | n/a | \*sym.current_memory_ptr = arg1; instr_I("P")
| "X" | arg1 | n/a | \*sym.current_memory_ptr ^= arg1
| Instruction | 1st arg | 2nd arg | What does it do? |
|-------------|---------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| "A" | "M" | arg2 | \*sym.current_memory_ptr += arg2 |
| | "P" | arg2 | sym.current_memory_ptr += arg2 |
| | "C" | arg2 | sym.written_by_instr_C += arg2 |
| "S" | "M" | arg2 | \*sym.current_memory_ptr -= arg2 |
| | "P" | arg2 | sym.current_memory_ptr -= arg2 |
| | "C" | arg2 | sym.written_by_instr_C -= arg2 |
| "I" | arg1 | n/a | instr_A(arg1, 1) |
| "D" | arg1 | n/a | instr_S(arg1, 1) |
| "P" | arg1 | n/a | \*sym.current_memory_ptr = arg1; instr_I("P") |
| "X" | arg1 | n/a | \*sym.current_memory_ptr ^= arg1 |
| "J" | arg1 | n/a | arg1_and_0x3f = arg1 & 0x3f;<br>if (arg1 & 0x40 != 0)<br>&nbsp;&nbsp;arg1_and_0x3f \*= -1<br>if (arg1 >= 0) return arg1_and_0x3f;<br>else if (\*sym.written_by_instr_C != 0) {<br>&nbsp;&nbsp;if (arg1_and_0x3f < 0)<br>&nbsp;&nbsp;&nbsp;&nbsp;++\*sym.good_if_ne_zero;<br>&nbsp;&nbsp;return arg1_and_0x3f;<br>} else return 2; |
| "C" | arg1 | n/a | \*sym.written_by_instr_C = arg1
| "R" | arg1 | n/a | return(arg1)
| "C" | arg1 | n/a | \*sym.written_by_instr_C = arg1 |
| "R" | arg1 | n/a | return(arg1) |
3 changes: 1 addition & 2 deletions src/crackmes/avatao/01-reverse4/intro.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Avatao R3v3rs3 4
------
## Avatao R3v3rs3 4

After a few years of missing out on wargames at
[Hacktivity](https://hacktivity.com), this year I've finally found the time to
Expand Down
11 changes: 5 additions & 6 deletions src/crackmes/avatao/01-reverse4/main.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.main
-----
## .main

As I was saying, I usually take a look at the entry point, so let's just do
that:
Expand Down Expand Up @@ -46,12 +45,12 @@ look at a function:
> It is possible to bring up the prompt in visual mode using the *:* key, and
> you can use *o* to seek.
Lets read main node-by-node! The first block looks like this:
Let's read main node-by-node! The first block looks like this:

![main bb-0c63](img/main/bb-0c63.png)

We can see that the program reads a word (2 bytes) into the local variable named
*local_10_6*, and than compares it to 0xbb8. That's 3000 in decimal:
*local_10_6*, and then compares it to 0xbb8. That's 3000 in decimal:

```
[0x00400c63]> % 0xbb8
Expand Down Expand Up @@ -179,7 +178,7 @@ the bytecode, and exits:

OK, so now we know that we have to supply a bytecode that will generate that
string when executed. As we can see on the minimap, there are still a few more
branches ahead, which probably means more conditions to meet. Lets investigate
branches ahead, which probably means more conditions to meet. Let's investigate
them before we delve into *vmloop*!

If you take a look at the minimap of the whole function, you can probably
Expand Down Expand Up @@ -239,7 +238,7 @@ more checks:
This piece of code may look a bit strange if you are not familiar with x86_64
specific stuff. In particular, we are talking about RIP-relative addressing,
where offsets are described as displacements from the current instruction
pointer, which makes implementing PIE easier. Anyways, rizin is nice enough to
pointer, which makes implementing PIE easier. Anyway, rizin is nice enough to
display the actual address (0x602104). Got the address, flag it!

```
Expand Down
3 changes: 1 addition & 2 deletions src/crackmes/avatao/01-reverse4/outro.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.outro
------
## .outro

Well, what can I say? Such VM, much reverse! :)

Expand Down
3 changes: 1 addition & 2 deletions src/crackmes/avatao/01-reverse4/rizin.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.rizin
--------
## .rizin

I've decided to solve the reversing challenges using
[rizin](http://www.rizin.org/r/), a free and open source reverse engineering
Expand Down
27 changes: 13 additions & 14 deletions src/crackmes/avatao/01-reverse4/vmloop.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.vmloop
-------
## .vmloop

```
[offset]> fcn.vmloop
Expand All @@ -24,7 +23,7 @@ First, lets analyze what we already have! First, *rdi* is put into local_3.
Since the application is a 64bit Linux executable, we know that *rdi* is the
first function argument (as you may have recognized, the automatic analysis of
arguments and local variables was not entirely correct), and we also know that
*vmloop*'s first argument is the bytecode. So lets rename local_3:
*vmloop*'s first argument is the bytecode. So let's rename local_3:

```
:> afvn local_3 bytecode
Expand Down Expand Up @@ -102,7 +101,7 @@ This is how the disassembly looks like after we add this metadata:
```

As we can see, the address 0x400c04 is used a lot, and besides that there are 9
different addresses. Lets see that 0x400c04 first!
different addresses. Let's see that 0x400c04 first!

![vmloop bb-0c04](img/vmloop/bb-0c04.png)

Expand Down Expand Up @@ -161,7 +160,7 @@ how we can create the missing basic blocks for the instructions:
```

It is also apparent from the disassembly that besides the instructions there
are three more basic blocks. Lets create them too!
are three more basic blocks. Let's create them too!

```
[0x00400ec0]> afb+ 0x00400a45 0x00400c15 0x00400c2d-0x00400c15 0x400c3c 0x00400c2d
Expand All @@ -187,7 +186,7 @@ By the way, here is how IDA's graph of this same function looks like for compari
![IDA graph](img/vmloop_ida.png)

As we browse through the disassembly of the *instr_LETTER* basic blocks, we
should realize a few things. The first: all of the instructions starts with a
should realize a few things. The first: all the instructions starts with a
sequence like these:

![vmloop bb-0a80](img/vmloop/bb-0a80.png)
Expand All @@ -196,9 +195,9 @@ sequence like these:

It became clear now that the 9 dwords at *sym.instr_dirty* are not simply
indicators that an instruction got executed, but they are used to count how many
times an instruction got called. Also I should have realized earlier that
times an instruction got called. Also, I should have realized earlier that
*sym.good_if_le_9* (0x6020f0) is part of this 9 dword array, but yeah, well, I
didn't, I have to live with it... Anyways, what the condition
didn't, I have to live with it... Anyway, what the condition
"*sym.good_if_le_9* have to be lesser or equal 9" really means is that *instr_P*
can not be executed more than 9 times:

Expand Down Expand Up @@ -249,7 +248,7 @@ that address!
```

Oh, and by the way, I do have a hunch that *instr_C* also had a function call in
the original code, but it got inlined by the compiler. Anyways, so far we have
the original code, but it got inlined by the compiler. Anyway, so far we have
these two instructions:

- *instr_R(a1):* returns with *a1*
Expand Down Expand Up @@ -396,9 +395,9 @@ not the case here - e.g. the larger grey boxes are clearly not identical. This
is something I'm definitely going to take a deeper look at after I've finished
this writeup.

Anyways, after we get over the shock of being lied to, we can easily recognize
Anyway, after we get over the shock of being lied to, we can easily recognize
that *instr_S* is basically a reverse-*instr_A*: where the latter does addition,
the former does subtraction. To summarize this:
the former does' subtraction. To summarize this:

- *arg1* == "M": subtracts *arg2* from the byte at *sym.current_memory_ptr*.
- *arg1* == "P": steps *sym.current_memory_ptr* backwards by *arg2* bytes.
Expand Down Expand Up @@ -433,16 +432,16 @@ It's local var rename time again!

This function is pretty straightforward also, but there is one oddity: const_M
is never used. I don't know why it is there - maybe it is supposed to be some
kind of distraction? Anyways, this function simply writes *arg1* to
*sym.current_memory_ptr*, and than calls *instr_I("P")*. This basically means
kind of distraction? Anyway, this function simply writes *arg1* to
*sym.current_memory_ptr*, and then calls *instr_I("P")*. This basically means
that *instr_P* is used to write one byte, and put the pointer to the next byte.
So far this would seem the ideal instruction to construct most of the "Such VM!
MuCH reV3rse!" string, but remember, this is also the one that can be used only
9 times!

###instr_X

Another simple one, rename local vars anyways!
Another simple one, rename local vars anyway!

```
:> afvn local_1 arg1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
After un-compressing the challenge file `Find The Easy Pass.zip`, we can find
a file named `EasyPass.exe` inside it.

We using `rz-bin` to identify the executable file.
We're using `rz-bin` to identify the executable file.

```bash
C:\Users\User\Desktop\htb>rz-bin -I EasyPass.exe
Expand Down
4 changes: 2 additions & 2 deletions src/crackmes/intro.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Crackmes
========

Crackmes (from "crack me" challenge) are the training ground for reverse engineering people. This section will go over tutorials on how to defeat various crackmes using rizin.

Crackmes (from "crack me" challenge) are the training ground for reverse engineering people. This section will go over
tutorials on how to defeat various crackmes using Rizin.
6 changes: 4 additions & 2 deletions src/crackmes/ioli/intro.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
IOLI CrackMes
=============

The IOLI crackme is a good starting point for learning rizin. This is a set of tutorials based on the tutorial at [dustri](https://dustri.org/b/defeating-ioli-with-radare2.html)
The IOLI crackme is a good starting point for learning Rizin. This is a set of tutorials based on the tutorial
at [dustri](https://dustri.org/b/defeating-ioli-with-radare2.html)

The IOLI crackmes are available at a locally hosted [mirror](https://github.com/rizinorg/book/raw/master/src/crackmes/ioli/IOLI-crackme.tar.gz)
The IOLI crackmes are available at a locally hosted
[mirror](https://github.com/rizinorg/book/raw/master/src/crackmes/ioli/IOLI-crackme.tar.gz)
14 changes: 7 additions & 7 deletions src/crackmes/ioli/ioli_0x00.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
IOLI 0x00
=========
# IOLI 0x00

This is the first IOLI crackme, and the easiest one.

Expand All @@ -10,15 +9,16 @@ Password: 1234
Invalid Password!
```

The first thing to check is if the password is just plaintext inside the file. In this case, we don't need to do any disassembly, and we can just use rz-bin with the -z flag to search for strings in the binary.
The first thing to check is if the password is just plaintext inside the file. In this case, we don't need to do
any disassembly, and we can just use rz-bin with the -z flag to search for strings in the binary.

```
$ rz-bin -z ./crackme0x00
$ rz-bin -z ./crackme0x00
[Strings]
nth paddr vaddr len size section type string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
nth paddr vaddr len size section type string
---------------------------------------------------------------------------
0 0x00000568 0x08048568 24 25 .rodata ascii IOLI Crackme Level 0x00\n
1 0x00000581 0x08048581 10 11 .rodata ascii Password:
1 0x00000581 0x08048581 10 11 .rodata ascii Password:
2 0x0000058f 0x0804858f 6 7 .rodata ascii 250382
3 0x00000596 0x08048596 18 19 .rodata ascii Invalid Password!\n
4 0x000005a9 0x080485a9 15 16 .rodata ascii Password OK :)\n
Expand Down
Loading

0 comments on commit 6aea95c

Please sign in to comment.