湖湘杯2020easyre题解
湖湘杯ezsyre题解
所需工具
- IDA、任意Windows下调试器
解题流程
- 入手题目。file查
~/Downloads/湖湘 » file easyre.exe wangxiaocheng@MacBook-
easyre.exe: PE32 executable (console) Intel 80386, for MS Windows
PE32,无脑打开run一下,可以看到是正常的输入flag然后检测
-
黑盒测试试探。用Pin自带的inscount工具插桩一下程序,先模糊出输入长度后,改动输入,看指令数是否有变化。
测试了几次,每次的指令数量都会有变化,可能是VS编译的方式吧,仅仅是个试探,于是没有深究。 -
加载IDA中,交叉引用程序输出的字符串,可以很快定位到关键的代码。可以看到大概的流程,简单的接受参数,判断长度,然后后面的代码就有点迷茫,一大段的nop,什么都没有做。开始怀疑是不是在程序加载的时候会把这段nop替换为正常指令,于是开始动态调试。
-
动态调试使用IDA自带的调试工具。调试的时候会发现比较怪异,程序总是会意外的飞走。
-
点开检测长度的函数,可以看到有很多的“花指令”,引用了很多参数,看到最后引用到了参数49

看一下栈的分布,可以知道这两个参数地址正是上层函数的返回地址的2个低字节位,明显改变了控制流。
-
跳转到0x4048DA

完全没有函数的样子,看样子是要分析汇编
-
分析汇编()
.text:004048DA mov dword ptr [ebp-8], 0 .text:004048E1 mov dword ptr [ebp-14h], 18h .text:004048E8 sub esp, 0Ch .text:004048EB pop eax .text:004048EC mov [ebp-8], eax ; -8为输入,-0C为循环变量 .text:004048EF mov ecx, [ebp-8] .text:004048F2 movzx edx, byte ptr [ecx] .text:004048F5 and edx, 0E0h .text:004048FB mov [ebp-0Dh], dl .text:004048FE mov dword ptr [ebp-0Ch], 0 .text:00404905 jmp short loc_404910 .text:00404907 ; --------------------------------------------------------------------------- .text:00404907 .text:00404907 loc_404907: ; CODE XREF: .text:00404952↓j .text:00404907 mov eax, [ebp-0Ch] ;看这个结构就知道是个for循环 .text:0040490A add eax, 1 .text:0040490D mov [ebp-0Ch], eax .text:00404910 .text:00404910 loc_404910: ; CODE XREF: .text:00404905↑j .text:00404910 mov ecx, [ebp-14h] .text:00404913 sub ecx, 1 .text:00404916 cmp [ebp-0Ch], ecx .text:00404919 jge short loc_404954 ;前17位进行操作 .text:0040491B mov edx, [ebp-8];当前字节shl 3位,下一字节sar 5位 .text:0040491E add edx, [ebp-0Ch] .text:00404921 movzx eax, byte ptr [edx] .text:00404924 shl eax, 3 .text:00404927 mov ecx, [ebp-8] .text:0040492A add ecx, [ebp-0Ch] .text:0040492D movzx edx, byte ptr [ecx+1] .text:00404931 sar edx, 5 .text:00404934 or eax, edx .text:00404936 mov ecx, [ebp-8] .text:00404939 add ecx, [ebp-0Ch] .text:0040493C mov [ecx], al .text:0040493E mov edx, [ebp-8] .text:00404941 add edx, [ebp-0Ch] .text:00404944 movzx eax, byte ptr [edx] .text:00404947 xor eax, [ebp-0Ch] .text:0040494A mov ecx, [ebp-8] .text:0040494D add ecx, [ebp-0Ch] .text:00404950 mov [ecx], al .text:00404952 jmp short loc_404907 .text:00404954 ; --------------------------------------------------------------------------- .text:00404954 .text:00404954 loc_404954: ; CODE XREF: .text:00404919↑j .text:00404954 mov edx, [ebp-8] .text:00404957 add edx, [ebp-14h] .text:0040495A movzx eax, byte ptr [edx-1] .text:0040495E shl eax, 3 .text:00404961 movzx ecx, byte ptr [ebp-0Dh] .text:00404965 sar ecx, 5 .text:00404968 or eax, ecx .text:0040496A mov edx, [ebp-8];处理最后一位 .text:0040496D add edx, [ebp-14h] .text:00404970 mov [edx-1], al .text:00404973 push offset loc_40D7F6 ;retn后的地址 .text:00404978 retn需要关注的点就是for里的运算和最后的push and retn。
-
运算。前17位都是取自己的低5位与下一字节的高3位组合,顺序是自己低5位在前,然后异或循环变量。以此类推,到最后一位的时候,把第一位的高3位放到后面。
-
push and retn即jmp,jmp后为一个简单的验证算法,结果数组也直接写在了内存里。
.text:0040D7F6 loc_40D7F6: ; CODE XREF: .text:00404978↑j .text:0040D7F6 ; DATA XREF: .text:00404973↑o .text:0040D7F6 mov dword ptr [ebp-8], 0 .text:0040D7FD sub esp, 44h .text:0040D800 pop eax .text:0040D801 add esp, 40h .text:0040D804 mov [ebp-8], eax .text:0040D807 mov dword ptr [ebp-18h], 18h .text:0040D80E mov dword ptr [ebp-0Ch], 0 .text:0040D815 jmp short loc_40D820 .text:0040D817 ; --------------------------------------------------------------------------- .text:0040D817 .text:0040D817 loc_40D817: ; CODE XREF: .text:loc_40D880↓j .text:0040D817 mov ecx, [ebp-0Ch] .text:0040D81A add ecx, 1 .text:0040D81D mov [ebp-0Ch], ecx .text:0040D820 .text:0040D820 loc_40D820: ; CODE XREF: .text:0040D815↑j .text:0040D820 mov edx, [ebp-0Ch] .text:0040D823 cmp edx, [ebp-18h] .text:0040D826 jge short loc_40D882 .text:0040D828 mov eax, [ebp-8] .text:0040D82B add eax, [ebp-0Ch] .text:0040D82E movzx ecx, byte ptr [eax] .text:0040D831 mov edx, [ebp-0Ch] .text:0040D834 movzx eax, byte_411000[edx];结果数组 .text:0040D83B cmp ecx, eax .text:0040D83D jz short loc_40D880;循环检测 .text:0040D83F mov dword ptr [ebp-10h], 0 .text:0040D846 jmp short loc_40D851 .text:0040D848 ; --------------------------------------------------------------------------- .text:0040D848 .text:0040D848 loc_40D848: ; CODE XREF: .text:0040D876↓j .text:0040D848 mov ecx, [ebp-10h] .text:0040D84B add ecx, 1 .text:0040D84E mov [ebp-10h], ecx .text:0040D851 .text:0040D851 loc_40D851: ; CODE XREF: .text:0040D846↑j .text:0040D851 cmp dword ptr [ebp-10h], 0Ah .text:0040D855 jge short loc_40D878 .text:0040D857 mov edx, [ebp-10h] .text:0040D85A movzx eax, byte_411020[edx] .text:0040D861 xor eax, 8Fh .text:0040D866 push eax .text:0040D867 mov ecx, ds:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::basic_ostream<char,std::char_traits<char>> std::cout .text:0040D86D push ecx .text:0040D86E call sub_401370 .text:0040D873 add esp, 8 .text:0040D876 jmp short loc_40D848 .text:0040D878 ; --------------------------------------------------------------------------- .text:0040D878 .text:0040D878 loc_40D878: ; CODE XREF: .text:0040D855↑j .text:0040D878 push 0 .text:0040D87A call ds:__imp_exit .text:0040D880 ; --------------------------------------------------------------------------- .text:0040D880 .text:0040D880 loc_40D880: ; CODE XREF: .text:0040D83D↑j .text:0040D880 jmp short loc_40D817 .text:0040D882 ; --------------------------------------------------------------------------- .text:0040D882 .text:0040D882 loc_40D882: ; CODE XREF: .text:0040D826↑j .text:0040D882 mov dword ptr [ebp-14h], 0 .text:0040D889 jmp short loc_40D894 .text:0040D88B ; --------------------------------------------------------------------------- .text:0040D88B .text:0040D88B loc_40D88B: ; CODE XREF: .text:0040D8BA↓j .text:0040D88B mov edx, [ebp-14h] .text:0040D88E add edx, 1 .text:0040D891 mov [ebp-14h], edx .text:0040D894 .text:0040D894 loc_40D894: ; CODE XREF: .text:0040D889↑j .text:0040D894 cmp dword ptr [ebp-14h], 33h .text:0040D898 jge short loc_40D8BC .text:0040D89A mov eax, [ebp-14h] .text:0040D89D movzx ecx, byte_41102C[eax] .text:0040D8A4 xor ecx, 8Fh .text:0040D8AA push ecx .text:0040D8AB mov edx, ds:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::basic_ostream<char,std::char_traits<char>> std::cout .text:0040D8B1 push edx .text:0040D8B2 call sub_401370 .text:0040D8B7 add esp, 8 .text:0040D8BA jmp short loc_40D88B .text:0040D8BC ; --------------------------------------------------------------------------- .text:0040D8BC .text:0040D8BC loc_40D8BC: ; CODE XREF: .text:0040D898↑j .text:0040D8BC push 0 .text:0040D8BE call ds:__imp_exit这段代码就俩exit,猜一下就知道一个输出成功一个输出失败,虽然猜不猜都一样,主要关注最上面的循环验证就行了,提取结果数组直接逆运算就可得flag。
-
解密脚本IDApython
addr = 0x411000 print("-------") a='' for i in range(24): a+=bin(Byte(addr+i)^i)[2:] print(a)然后把后三位剪切到前面,直接网上二进制转字符串,得到flag
ea5yre_1s_50_ea5y_t0_y0u最后md5一下
总结
这题主要是汇编阅读吧。还有一道IBM指令集的,实在是看不动,太菜了。

浙公网安备 33010602011771号