reverse例题讲解

reverse答案

培训中例题的答案

第一题

h2e7aF.png

32位exe程序,c++编写的,没有加壳

运行一下看看

h2mkRA.png

程序需要输入serial

直接查看main函数,f5查看伪代码

h2mwi4.png

int __cdecl main(int argc, const char **argv, const char **envp)
{
  signed int v3; // ebx
  char v4; // al
  int result; // eax
  int v6; // [esp+0h] [ebp-70h]
  int v7; // [esp+0h] [ebp-70h]
  char v8; // [esp+12h] [ebp-5Eh]
  char v9[20]; // [esp+14h] [ebp-5Ch]
  char v10; // [esp+28h] [ebp-48h]
  __int16 v11; // [esp+48h] [ebp-28h]
  char v12; // [esp+4Ah] [ebp-26h]
  char v13; // [esp+4Ch] [ebp-24h]

  strcpy(&v13, "437261636b4d654a757374466f7246756e");//把字符串"437261636b4d654a757374466f7246756e"复制到v13
  while ( 1 )
  {
    memset(&v10, 0, 0x20u);
    v11 = 0;
    v12 = 0;
    sub_40134B(aPleaseInputYou, v6);//这里调用函数sub_40134B,输出aPleaseInputYou里的字符:"please input your serial:"
    scanf(aS, v9);//获取输入字符,给v9
    if ( strlen(v9) > 0x11 )
      break;//v9长度大于17就退掉
    v3 = 0;//设置v3为计数器
    do
    {
      v4 = v9[v3];
      if ( !v4 )
        break;//v4为0x00时退掉
      sprintf(&v8, asc_408044, v4);//asc_408044为"%x"    sprintf(&v8,"%x",v4)把v4的值的16进制发到v8
      strcat(&v10, &v8);//连接字符串v10与v8并把得到的字符串赋值给v10
      ++v3;//计数器增加
    }
    while ( v3 < 17 );
    if ( !strcmp(&v10, &v13) )
      sub_40134B(aSuccess, v7);//strcmp(&v10, &v13) 在v10的字符串与v13的相等时返回0
    else
      sub_40134B(aWrong, v7);
  }
  sub_40134B(aWrong, v7);
  result = stru_408090._cnt-- - 1;
  if ( stru_408090._cnt < 0 )
    return _filbuf(&stru_408090);
  ++stru_408090._ptr;
  return result;
}

程序基本逻辑是将输入的值v9转为16进制后与v13作比较,相同则success

v13=437261636b4d654a757374466f7246756e

接下来只要把v13从16进制转为字符串即可

h2QAD1.png

第二题

h2QyV0.png

和上一道题一样

直接查看main函数伪代码

h2lud0.png

这里我们先shift + f12查看一下字符串

h2lUdx.png

发现有一行字符串是flag get

双击进入汇编语言看一下

h2lfFf.png

可以发现又出现了和上一道题一样的大串的数据

这里我们呢直接使用ida自带的工具查看一下这串数据是什么

h21MnA.png

可以看出来ida已经自动识别出了这段数据具体的内容是什么

将两段数据恢复为可以识别的形态

h21t1g.png

可以发现数据恢复了,但是顺序有问题

这里由于使用的是大端序(主机使用大端序,网络使用小端序),所以字符串是反着的

这里我们呢只要将第一段数据右键转为数据

h21Wu9.png

这里可以发现数据格式已经从xmmword格式转为db格式了

然后右键选择我所标注的选项,就可以将数据自动修复为正序的数据

h23ADs.png

h231KJ.png

h23JV1.png

第三题

exeinfo检查和上面两道题一样

ida打开

h28ISO.png

这里发现程序调用的函数是出奇的多,逻辑也是很复杂。当面对这种情况是,就需要使用动态调试的方法

这里我们使用x32dbg进行调试

h2GAkq.png

这里我们选择搜索--所有模块--字符串

h2Gt1O.png

这里我们呢直接搜索flag

h2GUje.png

可以看到很明显的48B0F0:"done!!! the flag is "

h2JeUI.png

在这段语句下面紧接着调用了call函数,猜测这段call指令应该是输出了flag

下面我们根据程序界面的关键字,就是需要输入n的地方查看一下

h2YIpV.png

h2tm1f.png

可以看到输入后就有call函数来判断,那么我们只要使得这些判断和判断后进行赋值的语句失效,那么我们是否可以直接让程序输出flag

h2tOKS.png

h2NP2V.png

直接将输入后的语句全部nop填充掉,看看程序

h2NK8x.png

程序已经因为流程被打断,直接输出了flag

第四题

h28YLj.png

可以看出不一样了,程序不是一个常规的PE程序,而是一个elf格式的文件,这个格式是Linux执行文件

这里我们使用动态分析的方式对程序进行分析

虽说是动态分析,但是依然要借助ida

先看main函数

hAqfII.png

main函数一共调用了四个函数,一个个看

setlocale

hAL9QU.png

banner

hALeW6.png

prompt_authentication

hAL3TA.png

authenticate

hALUl8.png

通览一遍,感觉最重要的函数是authenticate

记下来我们详细看一下authenticate

先分别看一下其中的unk_8048B44unk_8048BA4

unk_8048B44

.rodata:08048B44 unk_8048B44     db  53h ; S             ; DATA XREF: authenticate+78↑o
.rodata:08048B45                 db    0
.rodata:08048B46                 db    0
.rodata:08048B47                 db    0
.rodata:08048B48                 db  75h ; u
.rodata:08048B49                 db    0
.rodata:08048B4A                 db    0
.rodata:08048B4B                 db    0
.rodata:08048B4C                 db  63h ; c
.rodata:08048B4D                 db    0
.rodata:08048B4E                 db    0
.rodata:08048B4F                 db    0
.rodata:08048B50                 db  63h ; c
.rodata:08048B51                 db    0
.rodata:08048B52                 db    0
.rodata:08048B53                 db    0
.rodata:08048B54                 db  65h ; e
.rodata:08048B55                 db    0
.rodata:08048B56                 db    0
.rodata:08048B57                 db    0
.rodata:08048B58                 db  73h ; s
.rodata:08048B59                 db    0
.rodata:08048B5A                 db    0
.rodata:08048B5B                 db    0
.rodata:08048B5C                 db  73h ; s
.rodata:08048B5D                 db    0
.rodata:08048B5E                 db    0
.rodata:08048B5F                 db    0
.rodata:08048B60                 db  21h ; !

success

unk_8048BA4

.rodata:08048BA4 unk_8048BA4     db  41h ; A             ; DATA XREF: authenticate:loc_804878F↑o
.rodata:08048BA5                 db    0
.rodata:08048BA6                 db    0
.rodata:08048BA7                 db    0
.rodata:08048BA8                 db  63h ; c
.rodata:08048BA9                 db    0
.rodata:08048BAA                 db    0
.rodata:08048BAB                 db    0
.rodata:08048BAC                 db  63h ; c
.rodata:08048BAD                 db    0
.rodata:08048BAE                 db    0
.rodata:08048BAF                 db    0
.rodata:08048BB0                 db  65h ; e
.rodata:08048BB1                 db    0
.rodata:08048BB2                 db    0
.rodata:08048BB3                 db    0
.rodata:08048BB4                 db  73h ; s
.rodata:08048BB5                 db    0
.rodata:08048BB6                 db    0
.rodata:08048BB7                 db    0
.rodata:08048BB8                 db  73h ; s
.rodata:08048BB9                 db    0
.rodata:08048BBA                 db    0
.rodata:08048BBB                 db    0
.rodata:08048BBC                 db  20h
.rodata:08048BBD                 db    0
.rodata:08048BBE                 db    0
.rodata:08048BBF                 db    0
.rodata:08048BC0                 db  64h ; d
.rodata:08048BC1                 db    0
.rodata:08048BC2                 db    0
.rodata:08048BC3                 db    0
.rodata:08048BC4                 db  65h ; e
.rodata:08048BC5                 db    0
.rodata:08048BC6                 db    0
.rodata:08048BC7                 db    0
.rodata:08048BC8                 db  6Eh ; n
.rodata:08048BC9                 db    0
.rodata:08048BCA                 db    0
.rodata:08048BCB                 db    0
.rodata:08048BCC                 db  69h ; i
.rodata:08048BCD                 db    0
.rodata:08048BCE                 db    0
.rodata:08048BCF                 db    0
.rodata:08048BD0                 db  65h ; e
.rodata:08048BD1                 db    0
.rodata:08048BD2                 db    0
.rodata:08048BD3                 db    0
.rodata:08048BD4                 db  64h ; d
.rodata:08048BD5                 db    0
.rodata:08048BD6                 db    0
.rodata:08048BD7                 db    0
.rodata:08048BD8                 db  21h ; !
.rodata:08048BD9                 db    0
.rodata:08048BDA                 db    0
.rodata:08048BDB                 db    0
.rodata:08048BDC                 db  0Ah
.rodata:08048BDD                 db    0

accessdenied

一个是成功,一个是访问被拒,很显然,这个就是输出我们flag是否正确的函数

接下来我们向上看

s2 = decrypt(&s, &dword_8048A90);
  if ( fgetws(ws, 0x2000, stdin) )
  {
    ws[wcslen(ws) - 1] = 0;
    if ( !wcscmp(ws, s2) )
      wprintf(&unk_8048B44);
    else
      wprintf(&unk_8048BA4);
  }
  free(s2);
}

判断s2和ws是否匹配

匹配输出success,反之输出accessdenied

而s2是经过decrypt函数加密过的,我们跟进一下decrypt函数

hAXYM8.png

可以大致看出函数的加密流程,但是加密流程较为复杂(我看不懂)所以在这考虑使用动态分析的方式,直接读取寄存器中加密过后的s2数值

接下来我们需要找到s2加密后储存在那个寄存器中

而这就需要去authenticate函数的汇编代码里面找

hAXszV.png

可以看到其中有一处是通过call汇编指令,将数据送入了decrypt函数,出来后的数据被直接存放在eax

hAXbLD.png

现在我们的目的就是让程序执行decrypt函数,然后查看eax寄存器中的值

先给decrypt函数打个断点

hAjPOS.png

接下来程序运行到打断点的位置停下来

hAjkwQ.png

这时候程序在刚碰到decrypt函数的时候就停了下来,所以我们需要让他步进这段函数

使用指令n

hAjnS0.png

可以看到gdb输出的信息,其中说明了程序已经执行完了decrypt函数

接下来我们直接查看eax寄存器中的值

hAjB0e.png

6--显示6行数据
s--字符型
w--字节形式

posted @ 2021-09-04 20:48  MuRKuo  阅读(192)  评论(0编辑  收藏  举报