Should not the location be empty or have some other values than assembly instructions...?
The answer is "no". As the author stated in the write-up, this binary is self-modifying:
At this stage you may have correctly assumed the sample modifies these
instructions in order to properly reach 0x401101
.
...
Another indication of self-modifying code is found in the sample’s PE headers.
The .text
section, where the program’s entry point resides, is
writeable.
Any try to disassemble the bytes from 0x40107C
to 0x40107C+0x79
will cause with wrong and non-sense assembly instructions. Thus, we should understand the function which manipulated this bytes.
Understanding the modifying function
As you noticed already, this is the code which responsible for modifying the bytes in this range:
loc_401039:
mov bl, [eax]
xor bl, dl
add bl, 22h
mov [eax], bl
inc eax
cmp eax, ecx
jl short loc_401039
Let's use pseudo-code to understand how it works:
start_addr = 0x0x40107c
end_addr = 0x40107c + 0x79 = 0x4010f5
key = 0x??
for addr in range(start_addr, end_addr+1):
# setByte (address, new_value); getByte (address)
setByte(addr, (getByte(addr)^key)+0x22)
So, each byte in this range is XOR'd with some key and then 0x22
is added to the result.
Demonstrating
Spoiler Alert!
The next part contains spoilers regarding the answer
The write-up you attached contains a solution for the right key that you should use in the XOR operation to modify the bytes. I'll use this key in the following example.
The key is (hover to see it):
0xa2
Let's try to decrypt this bytes by ourselves. I'll use radare2 for this but you can use any other solution you'd like to.
First, let's make a copy of this challenge since we are going to edit the binary:
$ cp greek_to_me.exe modified_greek_to_me.exe
And now open the binary with radare2 in write-mode:
$ r2 -w modified_greek_to_me.exe
[0x00401000]>
Let's seek to 0x40107c
and see how it looks like before we modify the bytes there:
[0x00401000]> s 0x40107c
[0x0040107c]> pd 10
0x0040107c 33e1 xor esp, ecx
0x0040107e c49911068116 les ebx, [ecx + 0x16810611]
0x00401084 f0 invalid
0x00401085 329fc4911706 xor bl, byte [edi + 0x61791c4]
0x0040108b 8114f0068115. adc dword [eax + esi*8], 0xf1158106
0x00401092 c4911a06811b les edx, [ecx + 0x1b81061a]
╭─< 0x00401098 e206 loop 0x4010a0
│ 0x0040109a 8118f2068119 sbb dword [eax], 0x198106f2
╰─> 0x004010a0 f1 int1
0x004010a1 06 push es
I printed 10 op-codes in this address. As you can see, the instructions make no sense because in their current state they should not be disassembled.
This is how the 0x79
bytes from this address look like in hex:
[0x0040107c]> px 0x79
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x0040107c 33e1 c499 1106 8116 f032 9fc4 9117 0681 3........2......
0x0040108c 14f0 0681 15f1 c491 1a06 811b e206 8118 ................
0x0040109c f206 8119 f106 811e f0c4 991f c491 1c06 ................
0x004010ac 811d e606 8162 ef06 8163 f206 8160 e3c4 .....b...c...`..
0x004010bc 9961 0681 66bc 0681 67e6 0681 64e8 0681 .a..f...g...d...
0x004010cc 659d 0681 6af2 c499 6b06 8168 a906 8169 e...j...k..h...i
0x004010dc ef06 816e ee06 816f ae06 816c e306 816d ...n...o.
Now we want to XOR 0x79
bytes from 0x40107c
and then add 0x22
to each byte. We can easily do it using radare2.
First, we should define the block size that we want to manipulate, in our case it's 0x79:
[0x0040107c]> b?
|Usage: b[f] [arg]
Get/Set block size
| b display current block size
| b 33 set block size to 33
...
...
[0x0040107c]> b 0x79
Adding ?
to radare2 command will show help about the command and its subcommands
Now, let's XOR the bytes from 0x40107c
to 0x40107c + block_size
and then add 0x22
to each one of them:
[0x0040107c]> wo?
|Usage: wo[asmdxoArl24] [hexpairs] @ addr[!bsize]
...
| woa [val] += addition (f.ex: woa 0102)
...
| wox [val] ^= xor (f.ex: wox 0x90)
[0x0040107c]> wox 0xa2
[0x0040107c]> woa 0x22
And now our bytes are modified. Let's see how they look like in hex-mode:
[0x0040107c]> px 0x79
- offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
0x0040107c b365 885d d5c6 45d6 74b2 5f88 55d7 c645 .e.]..E.t._.U..E
0x0040108c d874 c645 d975 8855 dac6 45db 62c6 45dc .t.E.u.U..E.b.E.
0x0040109c 72c6 45dd 75c6 45de 7488 5ddf 8855 e0c6 r.E.u.E.t.]..U..
0x004010ac 45e1 66c6 45e2 6fc6 45e3 72c6 45e4 6388 E.f.E.o.E.r.E.c.
0x004010bc 5de5 c645 e640 c645 e766 c645 e86c c645 ][email protected]
0x004010cc e961 c645 ea72 885d ebc6 45ec 2dc6 45ed .a.E.r.]..E.-.E.
0x004010dc 6fc6 45ee 6ec6 45ef 2ec6 45f0 63c6 45f1 o.E.n.E...E.c.E.
0x004010ec 6fc6 45f2 6dc6 45f3 00 o.E.m.E..
And let's disassemble it and see if now the assembly makes any sense:
[0x0040107c]> pD 0x79
0x0040107c b365 mov bl, 0x65 ; 'e' ; 101
0x0040107e 885dd5 mov byte [ebp - 0x2b], bl
0x00401081 c645d674 mov byte [ebp - 0x2a], 0x74 ; 't' ; 116
0x00401085 b25f mov dl, 0x5f ; '_' ; 95
0x00401087 8855d7 mov byte [ebp - 0x29], dl
0x0040108a c645d874 mov byte [ebp - 0x28], 0x74 ; 't' ; 116
0x0040108e c645d975 mov byte [ebp - 0x27], 0x75 ; 'u' ; 117
0x00401092 8855da mov byte [ebp - 0x26], dl
0x00401095 c645db62 mov byte [ebp - 0x25], 0x62 ; 'b' ; 98
0x00401099 c645dc72 mov byte [ebp - 0x24], 0x72 ; 'r' ; 114
0x0040109d c645dd75 mov byte [ebp - 0x23], 0x75 ; 'u' ; 117
0x004010a1 c645de74 mov byte [ebp - 0x22], 0x74 ; 't' ; 116
0x004010a5 885ddf mov byte [ebp - 0x21], bl
0x004010a8 8855e0 mov byte [ebp - 0x20], dl
0x004010ab c645e166 mov byte [ebp - 0x1f], 0x66 ; 'f' ; 102
0x004010af c645e26f mov byte [ebp - 0x1e], 0x6f ; 'o' ; 111
0x004010b3 c645e372 mov byte [ebp - 0x1d], 0x72 ; 'r' ; 114
0x004010b7 c645e463 mov byte [ebp - 0x1c], 0x63 ; 'c' ; 99
0x004010bb 885de5 mov byte [ebp - 0x1b], bl
0x004010be c645e640 mov byte [ebp - 0x1a], 0x40 ; '@' ; 64
0x004010c2 c645e766 mov byte [ebp - 0x19], 0x66 ; 'f' ; 102
0x004010c6 c645e86c mov byte [ebp - 0x18], 0x6c ; 'l' ; 108
0x004010ca c645e961 mov byte [ebp - 0x17], 0x61 ; 'a' ; 97
0x004010ce c645ea72 mov byte [ebp - 0x16], 0x72 ; 'r' ; 114
0x004010d2 885deb mov byte [ebp - 0x15], bl
0x004010d5 c645ec2d mov byte [ebp - 0x14], 0x2d ; '-' ; 45
0x004010d9 c645ed6f mov byte [ebp - 0x13], 0x6f ; 'o' ; 111
0x004010dd c645ee6e mov byte [ebp - 0x12], 0x6e ; 'n' ; 110
0x004010e1 c645ef2e mov byte [ebp - 0x11], 0x2e ; '.' ; 46
0x004010e5 c645f063 mov byte [ebp - 0x10], 0x63 ; 'c' ; 99
0x004010e9 c645f16f mov byte [ebp - 0xf], 0x6f ; 'o' ; 111
0x004010ed c645f26d mov byte [ebp - 0xe], 0x6d ; 'm' ; 109
0x004010f1 c645f300 mov byte [ebp - 0xd], 0
Indeed, now we are able to see all these mov
instructions which build the flag :)