Flare-ON#3:理解程序中的某些部分有问题

逆向工程 艾达 拆卸 部件 二元分析 x86
2021-06-25 21:15:52

我在挑战中尝试耀斑。在尝试挑战#3 时,我遇到了一些麻烦,无法解决。在查看其他人编写的解决方案后,我现在确实知道该程序是如何工作的,但我对以下行感到困惑。

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

我正在阅读的解决方案指出,该指令正在将地址移动到ecx寄存器中,并与eax寄存器结合使用以替换同一位置中的某些值。执行此操作的循环是:

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

但是当我尝试输入位置 40107C 时,该位置似乎有以下说明:

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
...

由于该位置用于存储价值,因此该位置不应该为空或具有组装说明以外的其他值,或者我在这里误解了什么,有人可以澄清一下吗?

我正在阅读的解决方案:https : //www.fireeye.com/content/dam/fireeye-www/global/en/blog/threat-research/Flare-On%202017/Challenge%20%233%20solution.pdf

2个回答

该位置不应该为空或具有除汇编指令之外的其他值...?

答案是不”。正如作者在文章中所说,这个二进制文件是自我修改的:

在这个阶段,您可能已经正确地假设示例修改了这些说明以便正确地达到0x401101.
...
在示例的 PE 标头中发现了另一个自修改代码的迹象。.text部分,且该计划的切入点所在,是可写的。

任何尝试拆卸从字节0x40107C0x40107C+0x79会引起错误和不义的汇编指令。因此,我们应该了解操作这些字节的函数。

了解修改功能

正如您已经注意到的,这是负责修改此范围内字节的代码:

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

让我们使用伪代码来了解它是如何工作的:

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)

因此,此范围内的每个字节都与某个键进行异或0x22运算,然后添加到结果中。


示范

剧透警报!
下一部分包含有关答案的剧透

您所附的文章包含正确密钥的解决方案,您应该在 XOR 操作中使用该解决方案来修改字节。我将在以下示例中使用此密钥。

关键是(悬停查看):

0xa2

让我们尝试自己解密这些字节。我将为此使用radare2,但您可以使用任何其他您喜欢的解决方案。

首先,让我们复制这个挑战,因为我们要编辑二进制文件:

$ cp greek_to_me.exe modified_greek_to_me.exe

现在在写模式下用radare2打开二进制文件:

$ r2 -w modified_greek_to_me.exe
[0x00401000]>

让我们努力0x40107c,看看它看起来像我们修改前的字节有:

[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

我在这个地址打印了 10 个操作码。如您所见,这些说明毫无意义,因为在当前状态下,它们不应被拆卸。

这是0x79来自该地址字节在十六进制中的样子:

[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.

现在我们要对0x79字节进行异或0x40107c,然后添加0x22到每个字节。我们可以使用radare2轻松做到这一点。

首先,我们应该定义我们想要操作的块大小,在我们的例子中它是 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

添加?到radare2 命令将显示有关该命令及其子命令的帮助

现在,让我们对来自0x40107cto的字节进行异或0x40107c + block_size,然后添加0x22到每个字节中

[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

现在我们的字节被修改了。让我们看看它们在十六进制模式下的样子:

[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  ]..E.@.E.f.E.l.E
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..

让我们拆开它,看看现在组装是否有意义:

[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

事实上,现在我们能够看到所有这些mov构建标志的指令:)

从上面的代码中ecx存储了缓冲区末尾的地址(loc_40107C+0x79)。eax点开始,然后,如果检查eax通过比较达到了缓冲区末尾eaxecx

至于缓冲区,0x40107C它可能不应该为空,因为值在循环中被修改。您粘贴的代码应被视为数据,因此应将其视为0xF1, 0x06, 0x81, 0x1e, 0xf0, 0xc4, 0x99, 0x1f....

现在,[ebp+buf]当在这个缓冲区上使用并添加0x22一些有意义的代码,下面有一些东西