5

I was trying the flare on challenge. When trying the challenge#3 I got into some trouble and could not solve it. After looking into solutions wrote by other I now do know how the program works, but i have confusion in the following line.

mov     ecx, offset loc_40107C
add     ecx, 79h
mov     eax, offset loc_40107C
mov     dl, [ebp+buf]

The solution that I am reading states that this instruction is moving the address into the ecx register and is used in combination with eax register to replace some values in that same location. The loop that does this is:

loc_401039:
mov     bl, [eax]
xor     bl, dl
add     bl, 22h
mov     [eax], bl
inc     eax
cmp     eax, ecx
jl      short loc_401039

But when i try and enter the location 40107C it seems the location has following instructions:

icebp
push    es
sbb     dword ptr [esi], 1F99C4F0h
les     edx, [ecx+1D81061Ch]
out     6, al           ; DMA controller, 8237A-5.
                        ; channel 3 base address
                        ; (also sets current address)
and     dword ptr [edx-11h], 0F2638106h
push    es
...

Should not the location be empty or have some other values than assembly instructions since the location is being used for storing value, Or have I misunderstood something here, Can someone please clarify ?

The solution I was reading : https://www.fireeye.com/content/dam/fireeye-www/global/en/blog/threat-research/Flare-On%202017/Challenge%20%233%20solution.pdf

1
  • the disassembly will lead to code like this buf[i] = (buf[i] ^ (char *)0x40107c[i] ) + 0x22
    – blabb
    Commented Dec 31, 2017 at 6:40

2 Answers 2

7

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 :)

2

From the above code ecx stores the address of the end of the buffer (loc_40107C + 0x79). eax points to the beginning and then in is checked if eax has reached the end of the buffer by comparing eax with ecx.

As for the buffer at 0x40107C it probably shouldn't be empty as the values are modified in the loop. The code that you pasted should be treated as data so it should be viewed as 0xF1, 0x06, 0x81, 0x1e, 0xf0, 0xc4, 0x99, 0x1f....

Now, there's something under [ebp+buf] that when used on this buffer and adding 0x22 gives some meaningful code.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.