DDCTF2019 RE Windows Reverse1

源文件、脱壳文件、IDA分析文件打包下载:http://file.eonew.cn/ctf/re/reverse1_final.zip

一道比较简单的逆向题,简述一下思路。

查壳

可以用Exeinfope来查看是否有壳,这里为了方便,我直接使用file命令查看:

ex@Ex:~/Downloads$ file reverse1_final.exe 
reverse1_final.exe: PE32 executable (console) Intel 80386, 
for MS Windows, UPX compressed

可以看出是UPX壳,直接使用UPX脱壳即可:

ex@Ex:~/Downloads$ upx -d reverse1_final.exe 
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2018
UPX 3.95        Markus Oberhumer, Laszlo Molnar & John Reiser   Aug 26th 2018

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
      7680 <-      5632   73.33%    win32/pe     reverse1_final.exe

Unpacked 1 file.

解压完成后,在Windows上直接运行是会有问题,查看出错点的汇编代码可知

.text:00991880 mov     eax, ds:403000h

该地方是使用绝对地址来访问的,但是由于程序开启了ASLR,使得403000h地址并不在程序中,所以只要用pe工具关闭程序的ASLR即可。

核心代码

主函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+4h] [ebp-804h]
  char v5; // [esp+5h] [ebp-803h]
  char v6; // [esp+404h] [ebp-404h]
  char Dst; // [esp+405h] [ebp-403h]

  v6 = 0;
  memset(&Dst, 0, 0x3FFu);
  v4 = 0;
  memset(&v5, 0, 0x3FFu);
  printf("please input code:");
  scanf("%s", &v6);
  check(&v6);
  if ( !strcmp(&v4, "DDCTF{reverseME}") )
    printf("You've got it!!%s\n", &v4);
  else
    printf("Try again later.\n");
  return 0;
}

检查函数

unsigned int __cdecl check(const char *a1)
{
  _BYTE *v1; // ecx
  unsigned int v2; // edi
  unsigned int result; // eax
  int v4; // ebx

  v2 = 0;
  result = strlen(a1);
  if ( result )
  {
    v4 = a1 - v1;
    do
    {
      *v1 = byte_402FF8[(char)v1[v4]];
      ++v2;
      ++v1;
      result = strlen(a1);
    }
    while ( v2 < result );
  }
  return result;
}

可以看出只要我们输入的字符串经过check之后等于DDCTF{reverseME}即可。

由于程序的汇编被人为修改过,所以IDA反汇编的会有些偏差,具体情况需要看汇编代码来理解

lea     eax, [esp+82Ch+input]
push    eax
lea     ecx, [esp+830h+check_buf]
call    check
add     esp, 28h

可以从上面看出,check_buf被人为修改为用ecx来传参。

但是程序相对来说很简单,经过几遍调试就能发现,check函数只是通过一个映射表将我们的字符串映射成新的字符串,映射规则也很简单,就是:str[i] = 158 - str[i],所以直接写exp即可。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char str[] = "DDCTF{reverseME}";
    int i;
    for (i = 0; i < strlen(str); i++)
    {
        str[i] = 158 - str[i];
    }
    puts(str);

    return 0;
}

运行实例

x@Ex:~/test$ gcc exp.c -o exp
ex@Ex:~/test$ ./exp
ZZ[JX#,9(9,+9QY!

检查实例

root@36851e23817c:~# wine reverse1_final.exe 
please input code:ZZ[JX#,9(9,+9QY!
You've got it!!DDCTF{reverseME}

总结

做题的时候多多去尝试尝试,说不定就能成功了。