首页
社区
课程
招聘
[原创]初学者的静态分析挑战writeup
发表于: 2019-7-8 11:26 8225

[原创]初学者的静态分析挑战writeup

2019-7-8 11:26
8225

题目来源至  1c9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2E0j5h3I4%4j5i4u0W2N6r3g2U0K9q4)9J5k6h3y4G2L8g2)9J5c8X3u0W2k6$3W2F1L8X3g2J5i4K6u0V1L8h3q4D9N6$3q4J5k6g2)9J5k6s2u0W2N6X3g2J5M7$3W2F1k6#2)9J5k6r3y4Z5j5h3I4D9k6h3&6Y4k6i4x3`.


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



exe包含一个或多个未加密的flag,需要找到正确flag。


string1难度等级为1星


strings1.exe包含存储在可执行文件中的未加密flag。运行时,程序将输出flag的MD5哈希值,但不输出原始值。你能得到flag吗?


本地解压后如下:


拖进IDA里,查看下。


很明显,IDA很智能地识别了一些关键的方法,如md5_hash,猜测这就是生成flag的主方法。


call上面为push eax,入栈操作,很智能地显示了eax的类型,这里可以断定eax为md5_hash函数的参数。


mov eax, off_432294


eax的值来自一个地址,跟进此地址中,在IDA中双击此地址,来到了数据区域,发现此地址为FLAG字符串的起始地址。



那 FLAG{CAN-I-MAKE-IT-ANYMORE-OBVIOUS} 到底是不是flag呢?



在网页中进行检查



是真的flag。


string2难度等级为1星


strings2.exe包含存储在可执行文件中的未加密flag。运行时,程序将输出flag的MD5哈希值,但不输出原始值。你能得到flag吗?


本地解压后如下:


拖进IDA里,查看下,此时与string1完全不一样了。



前面是一些IDA为局部变量与参数设置的标识,先不看,来到计算hash的地方。


这里,eax依然作为md5_hash函数的参数,eax的值取自var_28的地址。


从最上面翻到eax赋值这里,发现mov操作为规律赋值,猜测可能是一个字符串或者字符数组。


右键转换为字符,查看下var_28赋值了什么,发现是大写字母F。



发现了是FLAG{STA......,猜测这就是flag。


转换完成后,将这段字符串进行检测即可 ,这里不再记录过程。


string3难度等级为2星


strings3.exe包含存储在可执行文件中的未加密flag。运行时,程序将输出flag的MD5哈希值,但不输出原始值。你能得到flag吗?


本地解压后如下:


拖进IDA里,查看下,发现与string1与string2完全不一样。


还是原先的步骤,先找到hash生成函数。


这里发现生成hash的函数使用了类的结构,因为call    ??0MD5@@QAE@XZ  ; MD5::MD5(void) 执行了类对象的构造方法。


重点来到 call  ?digestString@MD5@@QAEPADPAD@Z ; MD5::digestString(char *)


这里是生成hash的主方法,IDA标识了eax为char* 类型,与这个方法的参数类型一致,所以判断push eax为参数入栈。


lea  eax, [ebp+var_4A0]


eax的值为var_4A0变量的地址,var_4A0变量在上面的call    ds:LoadStringA这个API函数中有涉及。


LoadStringA函数


从与指定模块关联的可执行文件中加载字符串资源,并将字符串复制到具有终止空字符的缓冲区中,或者返回指向字符串资源本身的只读指针。


int LoadStringA( HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax );


参数

hInstance

类型:HINSTANCE

可执行文件包含字符串资源的模块实例的句柄。要获取应用程序本身的句柄,请使用NULL调用GetModuleHandle函数。


uID

输入:UINT

要加载的字符串的标识符。


lpBuffer

类型:LPTSTR

接收字符串的缓冲区(如果cchBufferMax非零)或者是字符串资源本身的只读指针(如果cchBufferMax为零)。长度必须足以容纳指针(8个字节)。


cchBufferMax

输入:int

缓冲区的大小,以字符为单位。如果字符串长于指定的字符数,则该字符串将被截断并以null结尾。如果此参数为0,则lpBuffer将接收指向字符串资源本身的只读指针。


来源: 51bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8$3y4K6i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6h3&6Q4x3X3c8#2M7#2)9J5c8Y4N6A6L8X3c8G2N6%4y4Q4x3V1k6V1k6i4y4C8N6r3!0H3i4K6u0r3j5i4m8A6i4K6u0r3N6$3W2F1N6i4y4W2M7W2)9J5c8X3&6X3i4K6u0V1N6$3W2F1N6i4y4W2M7W2)9J5k6r3I4G2j5h3c8K6N6s2u0A6L8X3N6S2


win32 API函数的调用约定为stdcall,参数从右至左入栈。

所以上面的4个push操作就是参数入栈。


cchBufferMax为3FFh,十进制为1023


lpBuffer为ecx


uID为edx


hInstance为0,也就是为NULL

lpBuffer为ecx,ecx为var_4A0变量所在的地址,而往上查,发现var_4A0已经被赋值为0,所以ecx为0。


uID为edx,edx=[ebp+var_4],而[ebp+var_4]=eax。


eax的计算是下面这几条汇编指令:

最后算得eax=272。


LoadStringA(0, 272, &var_4A0, 1023);


这里还有个快速的方法,F5反编译。直接使用IDAF5插件反编译功能翻译成伪c代码。

LoadStringA函数是加载字符串资源,所以目前需要使用另一个工具,ResourceHacker。


uID为要加载的字符串的标识符,使用ResourceHacker打开string3,来到字符串资源处。


查找下272标识符里的内容

正确flag



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


shellcode1.exe


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


本地解压后:



IDA打开,如下:


还是先找一下生成hash的方法,可以确定 call  ?digestString@MD5@@QAEPADPAD@Z ; MD5::digestString(char *) 为生成hash的方法。


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


发现Str为一个字符串的地址



可以先将字符串当做flag输入进行检测,经过实践后,发现这里的字符串并不是真正的flag。


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


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调用的地址。

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


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


目前是以数据显示,猜测这里应该是代码(不然call调用了无法执行)。所以选中unk_404068,Edit 选中Code,生成代码。

call    [ebp+Dst] 这里已经解决了,接着查找这个函数的输入参数。


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


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

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

[ebp+var_4]

接着[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] 函数里进行分析

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}

shellcode2.exe


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


按照惯例,使用IDA打开。

发现了涉及hash的函数,接着找输入参数。


push  edx   ; char *   这里是通过edx传入参数


lea   edx, [ebp+str[0]] ;edx保存了一个字符数组的首地址。


因为之前已做过了,这里已经手工对连续排列的参数进行创建数组的处理。


猜测数组保存的应该就是输入的flag,查看上述流程里对该数组做了哪些操作。


call    [ebp+Dst]


依据前面的经验,这里Dst为堆空间地址,之后通过mencpy复制了内容,所以所在的地址为代码,所以现在找到这个地址查看下,


也就是push  offset sub_404040 ; Src  中的sub_404040。


双击进入,如果发现是db ... 等显示,可以按字母c转换为代码格式。

这里已经转换为代码格式,按F5让IDA自动生成伪代码,看看这个函数的作用。

这里已经重命名了很多代码,当然主要的知识点就是 LoadLibraryA与GetProcAddress。


通过这个两个API函数,可以调用系统dll里具体的方法。


v78 = LoadLibraryA(&msvcrt.dll);

v27 = LoadLibraryA(&kernel32.dll);


_GetModuleFileNameA = (void (__stdcall *)(_DWORD, char *, signed int))GetProcAddress(v27, &GetModuleFileNameA);

_fopen = (int (__cdecl *)(char *, char *))GetProcAddress(v78, &fopen);

_fseek = (void (__cdecl *)(int, signed int, _DWORD))GetProcAddress(v78, &fseek);

_fread = (void (__cdecl *)(char *, signed int, signed int, int))GetProcAddress(v78, &fread);

_fclose = (int (__cdecl *)(int))GetProcAddress(v78, &fclose);


这里加载了两个dll,之后获取了5个函数的内存实际地址。


  _GetModuleFileNameA(0, &v11, 260);            // v11=当前exe执行的绝对路径

  ptr_file = _fopen(&v11, &rb);

  _fseek(ptr_file, 78, 0);                      // 移动文件指针至离文件开始位置78个字节处

  _fread(v79, 38, 1, ptr_file);                 // 读取38个字节放入v79数组中


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

最后于 2019-7-15 11:19 被jishuzhain编辑 ,原因: 附件添加
上传的附件:
收藏
免费 8
支持
分享
最新回复 (11)
雪    币: 227
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
最后一题可以的。。。
2019-7-9 17:32
0
雪    币: 58782
活跃值: (21915)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
3
附件能否直接上传到论坛本地一份?
2019-7-14 20:21
0
雪    币: 17428
活跃值: (5064)
能力值: ( LV9,RANK:450 )
在线值:
发帖
回帖
粉丝
4
kanxue 附件能否直接上传到论坛本地一份?
好的
2019-7-15 11:15
0
雪    币: 16
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
shellcode1那个题,str原始值咋看的呀,求大神解答,才开始学
2019-7-20 16:32
0
雪    币: 17428
活跃值: (5064)
能力值: ( LV9,RANK:450 )
在线值:
发帖
回帖
粉丝
6
茉莉fly shellcode1那个题,str原始值咋看的呀,求大神解答,才开始学[em_20]
发现前面存在一个push操作,为 push  offset Str ; "2b\n:蹥B*bb",双击Str,IDA会自动跳到数据区,dd xx 等就是数据。
2019-7-20 23:45
0
雪    币: 18
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
第一题的string样本解压密码不对 ?
2019-7-23 21:33
0
雪    币: 18
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
wx_tf 第一题的string样本解压密码不对 ?
不好意思,是我多按了个空格,尴尬!
2019-7-23 21:35
0
雪    币: 1128
活跃值: (72)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
这篇文章,花费了不少心血
2019-8-5 11:20
0
雪    币: 20
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
大佬还原函数名那里太六了
2019-8-9 19:51
0
雪    币: 20
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
~
最后于 2019-8-9 21:01 被qAq哼唧编辑 ,原因: 上个问题知道了
2019-8-9 20:27
0
雪    币: 99
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
Mark
2019-9-11 01:12
0
游客
登录 | 注册 方可回帖
返回