H1ghker 发表于 2019-4-25 12:31

【新手】DDCTF-RE1、2

新手刚开始学习逆向,有很多地方说得不对或者不好还希望各位表哥能指正
Windows Reverse1
0x01
首先exeinfo查一下壳,发现是upx壳
https://ww1.sinaimg.cn/large/007rAy9hgy1g2eo8i15n2j30ei071mz5.jpg
0x02
脱壳
这里针对upx壳有很多办法,我就挑一个好懂的和一个好用的说
https://static.52pojie.cn/static/image/hrline/1.gif

1、首先是ESP定律脱壳,这里先载入OD,F8单步一次
https://ww1.sinaimg.cn/large/007rAy9hgy1g2eoej8mlrj314h0ggdhn.jpg
https://ww1.sinaimg.cn/large/007rAy9hgy1g2eokvdsglj312l0gr763.jpg
注意观察右边寄存器esp的变化,选中esp,选择在数据窗口中跟随
https://ww1.sinaimg.cn/large/007rAy9hgy1g2eona4d2lj30bz0c0jrp.jpg
可以看到这时左下方窗口中跟踪到数值所对应的地址正对应esp,在这里下硬件断点,选择断点-->硬件访问-->word
https://ww1.sinaimg.cn/large/007rAy9hgy1g2eouled6oj30br06d74b.jpg
F9运行一下
00407C47   .8D4424 80   lea eax,dword ptr ss:
00407C4B   >6A 00         push 0x0
00407C4D   .39C4          cmp esp,eax
00407C4F   .^ 75 FA         jnz short reverse1.00407C4B
00407C51   .83EC 80       sub esp,-0x80
00407C54   .- E9 9E97FFFF   jmp reverse1.004013F7


F4运行到7c51,F8步过一次,达到oep
004013F7    E8 7C040000   call reverse1.00401878
004013FC^ E9 9FFDFFFF   jmp reverse1.004011A0
00401401    8BFF            mov edi,edi
00401403    55            push ebp
00401404    8BEC            mov ebp,esp
00401406    81EC 28030000   sub esp,0x328
0040140C    A3 A0314000   mov dword ptr ds:,eax
00401411    890D 9C314000   mov dword ptr ds:,ecx


2、然后是一步到位法
od载入后ctrl+f搜索出栈指令
https://www.highker.wiki/wp-content/uploads/2019/04/3IYI7_HPSQV@NGI83HH.png
可以看到又到了上边的地址
00407C46   .61            popad
00407C47   .8D4424 80   lea eax,dword ptr ss:
00407C4B   >6A 00         push 0x0
00407C4D   .39C4          cmp esp,eax
00407C4F   .^ 75 FA         jnz short reverse1.00407C4B
00407C51   .83EC 80       sub esp,-0x80
00407C54   .- E9 9E97FFFF   jmp reverse1.004013F7




https://static.52pojie.cn/static/image/hrline/1.gif


lordpe提取一下
https://ww1.sinaimg.cn/large/007rAy9hgy1g2epgfbd74j30bw04owef.jpg
这时候修复一下iat
https://ww1.sinaimg.cn/large/007rAy9hgy1g2epqq67lij30hn09674i.jpg
https://ww1.sinaimg.cn/large/007rAy9hgy1g2eq3kofamj30ay04pmx2.jpg
0x03
找到地址后import rce获取输入表转储到文件即可,ida分析一波,直接F5大法

int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax@2
char v4; // @1
char v5; // @1
char v6; // @1
char Dst; // @1

v6 = 0;
memset(&Dst, 0, 0x3FFu);
v4 = 0;
memset(&v5, 0, 0x3FFu);
printf("please input code:");
scanf("%s", &v6);
sub_401000(&v6);
if ( !strcmp(&v4, "DDCTF{reverseME}") )
{
    printf("You've got it!!%s\n", &v4);
    result = 0;
}
else
{
    printf("Try again later.\n");
    result = 0;
}
return result;
}
分析一下对输入内容的check
unsigned int __cdecl sub_401000(const char *a1)
{
_BYTE *v1; // ecx@0
unsigned int v2; // edi@1
unsigned int result; // eax@1
int v4; // ebx@2

v2 = 0;
result = strlen(a1);
if ( result )
{
    v4 = a1 - v1;
    do
    {
      *v1 = byte_402FF8];
      ++v2;
      ++v1;
      result = strlen(a1);
    }
    while ( v2 < result );
}
return result;
}
可以发现这货啥都没干,那我们也不必看下去,可以直接OD载入,nop掉判断,输入DDCTF{reverseME}
004010FB    90            nop
004010FC    90            nop
004010FD    8D4C24 04       lea ecx,dword ptr ss:
00401101    51            push ecx
00401102    68 20214000   push dumped_.00402120                  ; You've got it!!%s\n
00401107    FFD6            call esi
00401109    83C4 08         add esp,0x8
0040110C    33C0            xor eax,eax
0040110E    5E            pop esi                                  ; kernel32.7C817077
0040110F    8B8C24 00080000 mov ecx,dword ptr ss:
00401116    33CC            xor ecx,esp
00401118    E8 29000000   call dumped_.00401146
0040111D    81C4 04080000   add esp,0x804
00401123    C3            retn


check通过
https://ww1.sinaimg.cn/large/007rAy9hgy1g2eqnhmu9kj30cb023mx1.jpg
Windows Reverse2
0x01
继续exeinfo查壳,发现是aspack,接着手脱即可
https://www.highker.wiki/wp-content/uploads/2019/04/9OG_Z@RLEU8REL23.png
脱壳步骤和上边的re1基本一致,使用esp定律脱掉即可,这里不多赘述
0x02
载入ida分析,F5大法
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Dest; // @4
char v5; // @4
char v6; // @1
char Dst; // @1
char v8; // @1
char v9; // @1

v6 = 0;
memset(&Dst, 0, 0x3FFu);
v8 = 0;
memset(&v9, 0, 0x3FFu);
printf("input code:");
scanf("%s", &v6);
if ( !(unsigned __int8)sub_4011F0() )
{
    printf("invalid input\n");
    exit(0);
}
sub_401240(&v8);
Dest = 0;
memset(&v5, 0, 0x3FFu);
sprintf(&Dest, "DDCTF{%s}", &v8);
if ( !strcmp(&Dest, "DDCTF{reverse+}") )
    printf("You've got it !!! %s\n", &Dest);
else
    printf("Something wrong. Try again...\n");
return 0;
}
首先看一下sub_4011F0函数
char __usercall sub_4011F0@<al>(const char *a1@<esi>)
{
signed int v1; // eax@1
signed int v2; // edx@1
int v3; // ecx@3
char v4; // al@4

v1 = strlen(a1);
v2 = v1;
if ( v1 && v1 % 2 != 1 )
{
    v3 = 0;
    if ( v1 <= 0 )
      return 1;
    while ( 1 )
    {
      v4 = a1;
      if ( (v4 < 48 || v4 > 57) && (v4 < 65 || v4 > 70) )
      break;
      if ( ++v3 >= v2 )
      return 1;
    }
}
return 0;
}
可以看出输入16进制字符串可以通过验证,然后是sub_401240函数
int __usercall sub_401240@<eax>(const char *a1@<esi>, int a2)
{
signed int v2; // edi@1
unsigned int v3; // edx@1
char v4; // bl@2
char v5; // al@3
char v6; // al@7
unsigned int v7; // ecx@11
char v9; // @0
char v10; // @1
char Dst; // @1

v2 = strlen(a1);
v10 = 0;
memset(&Dst, 0, 0x3FFu);
v3 = 0;
if ( v2 > 0 )
{
    v4 = v9;
    do
    {
      v5 = a1;
      if ( (unsigned __int8)(a1 - 48) > 9u )
      {
      if ( (unsigned __int8)(v5 - 65) <= 5u )
          v9 = v5 - 55;
      }
      else
      {
      v9 = a1 - 48;
      }
      v6 = a1;
      if ( (unsigned __int8)(a1 - 48) > 9u )
      {
      if ( (unsigned __int8)(v6 - 65) <= 5u )
          v4 = v6 - 55;
      }
      else
      {
      v4 = a1 - 48;
      }
      v7 = v3 >> 1;
      v3 += 2;
      *(&v10 + v7) = v4 | 16 * v9;
    }
    while ( (signed int)v3 < v2 );
}
return sub_401000(v2 / 2, (void *)a2);
}
好吧其实是有点长的,但是这里可以使些小技俩,结合程序本身进行推测,首先是第一段验证,只允许输入16进制字符串,那就随便输入个AF进去
https://www.highker.wiki/wp-content/uploads/2019/04/85Z_ZYWF1U7FZIMA8U6YM.png
可以看到输出结果很像base64编码,试着解码一下
https://www.highker.wiki/wp-content/uploads/2019/04/5759895FNZPS6RMRDDFM.png
那么就很简单了,我们开始构造payload
0x03
对最终需要进行对比的内容逆向分析,显然要经过base64解码,然后再转为16进制
https://www.highker.wiki/wp-content/uploads/2019/04/asdasdads.jpg
用python构造一下
>>> import base64
>>> import binascii
>>> a = 'reverse+'
>>> print(binascii.b2a_hex(base64.b64decode(a)).upper())
b'ADEBDEAEC7BE'
验证通过
https://www.highker.wiki/wp-content/uploads/2019/04/DS1OGALMHHLEUC8QE.png

Li1y 发表于 2019-4-25 18:38

冰露㊣神 发表于 2019-4-25 17:22
对啊,这种打印有什么用,他算法都没管,直接爆破出这个。那很多题都不用做了啊,想nop就nop,想jmp就jmp ...

做题求速度啊
把跳过GOT IT的跳转NOP,然后输入DDCTF{reverseME}就能看到flag,楼主思路很清晰,我看过其他分析算法的WP,但是还是觉得这个取巧的最好,比赛当然要这样,但是平时能逆算法还是逆算法吧

H1ghker 发表于 2019-4-25 18:17

冰露㊣神 发表于 2019-4-25 15:51
ddctf第一题你没是在逗我吧,把判断nop掉,还判断啥?真正的flag是一堆乱码一样的,自己百度个wp看下吧

建议表哥你再去审一下这个cm哦,这里nop掉是没有问题的,我只是没有自己写脚本去逆字符集解密,而是利用这个cm会将其输出的特点去直接得到flag的

冰露㊣神 发表于 2019-4-25 15:51

ddctf第一题你没是在逗我吧,把判断nop掉,还判断啥?真正的flag是一堆乱码一样的,自己百度个wp看下吧

瑟瑟发抖小菜虾 发表于 2019-4-25 16:55

冰露㊣神 发表于 2019-4-25 15:51
ddctf第一题你没是在逗我吧,把判断nop掉,还判断啥?真正的flag是一堆乱码一样的,自己百度个wp看下吧

他这个只是把判断 nop掉 然后直接让flag 打印出来。。。。。。 你可以看看上面他nop掉后的程序截图。。。

gyzzzzz 发表于 2019-4-25 17:20

第一个题他的check函数我没记错就是固定字符替换

冰露㊣神 发表于 2019-4-25 17:22

瑟瑟发抖小菜虾 发表于 2019-4-25 16:55
他这个只是把判断 nop掉 然后直接让flag 打印出来。。。。。。 你可以看看上面他nop掉后的程序截图。。。

对啊,这种打印有什么用,他算法都没管,直接爆破出这个。那很多题都不用做了啊,想nop就nop,想jmp就jmp,这不是乱来嘛

cat95f 发表于 2019-4-25 18:50

看不懂,还是谢谢楼主分享

冰露㊣神 发表于 2019-4-25 19:14

H1ghker 发表于 2019-4-25 18:17
建议表哥你再去审一下这个cm哦,这里nop掉是没有问题的,我只是没有自己写脚本去逆字符集解密,而是利用 ...

不好意思{:1_907:},我傻逼了,你那图check的图看不到,刚我试了下,确实可以,tql

GJH588 发表于 2019-4-25 19:56

虽然看不懂,但还是支持一下{:301_1004:}
页: [1] 2
查看完整版本: 【新手】DDCTF-RE1、2