初学者的静态分析挑战writeup4

题目来源至 https://www.malwaretech.com/beginner-malware-reversing-challenges

所有挑战都是在不使用调试器的情况下完成的,你的目标应该是能够在不运行exe的情况下完成每个挑战。

这些挑战利用与位置无关的代码来解密flag,弄清楚shellcode的作用并自己解密。

shellcode1.exe

包含存储在可执行文件中的flag。运行时,程序将输出flag的MD5哈希值,但不输出原始值,难度等级1星。

本地解压后:
初学者的静态分析挑战writeup4
IDA打开,如下:
初学者的静态分析挑战writeup4
还是先找一下生成hash的方法,可以确定 call ?digestString@MD5@@QAEPADPAD@Z ; MD5::digestString(char *) 为生成hash的方法。

找这个函数的参数,发现前面存在一个push操作,为 push offset Str ; “2b\n:蹥B*bb”

发现Str为一个字符串的地址,
初学者的静态分析挑战writeup4
初学者的静态分析挑战writeup4
可以先将字符串当做flag输入进行检测,经过实践后,发现这里的字符串并不是真正的flag。

说明这个地址保存的字符串在前面的流程中进行了改写,我们继续往上查看汇编代码。

call [ebp+Dst]

直接调用了一个地址,首先这个地址应该是一个函数的开始地址。那么如何得到这个地址的?

继续往上看

push    10h
push    0
call    ds:GetProcessHeap
push    eax
call    ds:HeapAlloc
mov     [ebp+var_4], eax
mov     eax, [ebp+var_4]
mov     dword ptr [eax], offset Str ; "2b\n:蹥B*bb"
push    offset Str      ; "2b\n:蹥B*bb"
call    strlen
add     esp, 4
mov     ecx, [ebp+var_4]
mov     [ecx+4], eax
push    40h
push    1000h
push    0Dh
push    0
call    ds:VirtualAlloc
mov     [ebp+Dst], eax
push    0Dh             ; MaxCount
push    offset unk_404068 ; Src
mov     edx, [ebp+Dst]
push    edx             ; Dst
call    memcpy
add     esp, 0Ch
mov     esi, [ebp+var_4]
call    [ebp+Dst]

首先往上发现了memcpy方法,属于C库函数。

void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字符到存储区 str1。

edx为str1,unk_404068为str2,0Dh为n

这里发现将unk_404068的内容复制到了Dst地址处,恰巧Dst为下面call调用的地址。

push    40h
push    1000h
push    0Dh
push    0
call    ds:VirtualAlloc
mov     [ebp+Dst], eax

这里使用VirtualAlloc生成了一块虚拟内存,并且设置为可执行,说明[ebp+Dst]处的地址是可执行的,具体可以参考MSDN此函数的用法。

我们跟进unk_404068看看,双击unk_404068进入如下:

初学者的静态分析挑战writeup4
目前是以数据显示,猜测这里应该是代码(不然call调用了无法执行)。所以选中unk_404068,Edit 选中Code,生成代码。
初学者的静态分析挑战writeup4
初学者的静态分析挑战writeup4
可以发现,IDA分析后确实生成了代码。
初学者的静态分析挑战writeup4
call [ebp+Dst] 这里已经解决了,接着查找这个函数的输入参数。

往上发现了mov esi, [ebp+var_4],而函数内部也对这个esi寄存器进行了操作,判断这里是寄存器传递参数。

现在的问题变成了(ebp+var_4)地址处的值是什么?

push    10h
push    0
call    ds:GetProcessHeap
push    eax
call    ds:HeapAlloc
mov     [ebp+var_4], eax

首先来到第一次对[ebp+var_4]进行操作的地方,这段汇编的意思是调用HeapAlloc生成了一段堆空间,并将起始地址赋值给了
[ebp+var_4]

mov     eax, [ebp+var_4]
mov     dword ptr [eax], offset Str ; "2b\n:蹥B*bb"
push    offset Str      ; "2b\n:蹥B*bb"
call    strlen
add     esp, 4
mov     ecx, [ebp+var_4]
mov     [ecx+4], eax

接着[ebp+var_4]赋值给了eax,而eax地址处的存储值变成了Str字符串的起始地址。

Str字符串地址入栈,调用了strlen C库函数。将字符串长度eax赋值给了[ecx+4]。

[ecx+4]为[ebp+var_4][1]

现在我们发现

[ebp+var_4][0]=Str[0]
[ebp+var_4][1]=eax=strlen(Str)

进一步,[ebp+var_4]目前的值为Str存储的字符串的地址。

而上面我们发现,esi的值为[ebp+var_4]的值。

所以现在进入 call [ebp+Dst] 函数里进行分析

               sub_404068      proc near               ; DATA XREF: start+5E↑o
.data:00404068                 mov     edi, [esi]
.data:0040406A                 mov     ecx, [esi+4]
.data:0040406D
.data:0040406D loc_40406D:                             ; CODE XREF: sub_404068+A↓j
.data:0040406D                 rol     byte ptr [edi+ecx-1], 5
.data:00404072                 loop    loc_40406D
.data:00404074                 retn
.data:00404074 sub_404068      endp

mov esi, [ebp+var_4]
call [ebp+Dst]

call strlen
add esp, 4
mov ecx, [ebp+var_4]
mov [ecx+4], eax

esi为Str字符串的起始地址,[esi+4]为eax的值,eax的值是strlen的结果,所以是字符串的长度。

rol byte ptr [edi+ecx-1], 5

这句汇编的含义是将Str的每个字符串循环左移5位之后再放回原位,所以最后的值是Str字符串。

之后可计算出flag

FLAG{SHELLCODE-ISNT-JUST-FOR-EXPLOITS}

上一篇:2019-2020-1 20199310《Linux内核原理与分析》第二周作业


下一篇:栈帧ebp,esp详解