• Buuoj reverse3


    1 打开reverse3.exe

    reverse3.exe

    2 ida32

    2.1 丢进ida反编译后,搜索字符串“flag”可以找到以下源码

    main0

    从下往上分析:
      (1)如果Dest和Str2前v2个字节相同,则得到的是正确的flag。而v2就是Dest的长度;
      (2)for循环对Dest进行修改,第j位元素的ASCII加上j;
      (3)将v1拷贝给Dest;
      (4)将Str经过sub_4110BE()后赋值给v1。sub_4110BE()只会return一个sub_411AB0()所以这个函数至关重要。
    Str2的值为:
    str2

    2.2 sub_411AB0函数

    由于截图截不全,直接把代码贴过来

    void *__cdecl sub_411AB0(char *a1, unsigned int a2, int *a3)
    {
      int v4; // STE0_4
      int v5; // STE0_4
      int v6; // STE0_4
      int v7; // [esp+D4h] [ebp-38h]
      signed int i; // [esp+E0h] [ebp-2Ch]
      unsigned int v9; // [esp+ECh] [ebp-20h]
      int v10; // [esp+ECh] [ebp-20h]
      signed int v11; // [esp+ECh] [ebp-20h]
      void *Dst; // [esp+F8h] [ebp-14h]
      char *v13; // [esp+104h] [ebp-8h]
    
      if ( !a1 || !a2 )
        return 0;
      v9 = a2 / 3;
      if ( (signed int)(a2 / 3) % 3 )
        ++v9;
      v10 = 4 * v9;
      *a3 = v10;
      Dst = malloc(v10 + 1);
      if ( !Dst )
        return 0;
      j_memset(Dst, 0, v10 + 1);
      v13 = a1;
      v11 = a2;
      v7 = 0;
      while ( v11 > 0 )
      {
        byte_41A144[2] = 0;
        byte_41A144[1] = 0;
        byte_41A144[0] = 0;
        for ( i = 0; i < 3 && v11 >= 1; ++i )
        {
          byte_41A144[i] = *v13;
          --v11;
          ++v13;
        }
        if ( !i )
          break;
        switch ( i )
        {
          case 1:
            *((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2];
            v4 = v7 + 1;
            *((_BYTE *)Dst + v4++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)];
            *((_BYTE *)Dst + v4++) = aAbcdefghijklmn[64];
            *((_BYTE *)Dst + v4) = aAbcdefghijklmn[64];
            v7 = v4 + 1;
            break;
          case 2:
            *((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2];
            v5 = v7 + 1;
            *((_BYTE *)Dst + v5++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)];
            *((_BYTE *)Dst + v5++) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | 4 * (byte_41A144[1] & 0xF)];
            *((_BYTE *)Dst + v5) = aAbcdefghijklmn[64];
            v7 = v5 + 1;
            break;
          case 3:
            *((_BYTE *)Dst + v7) = aAbcdefghijklmn[(signed int)(unsigned __int8)byte_41A144[0] >> 2];
            v6 = v7 + 1;
            *((_BYTE *)Dst + v6++) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | 16 * (byte_41A144[0] & 3)];
            *((_BYTE *)Dst + v6++) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | 4 * (byte_41A144[1] & 0xF)];
            *((_BYTE *)Dst + v6) = aAbcdefghijklmn[byte_41A144[2] & 0x3F];
            v7 = v6 + 1;
            break;
        }
      }
      *((_BYTE *)Dst + v7) = 0;
      return Dst;
    }
    
    1. 比较关键的地方从while里的for循环开始,它把v13的值传给了byte_41A144。v13实际上就是a1(我们再对应main里的变量,实际它就是那个我们输入的Str)。
    2. 然后这个i实际经过循环以后就是3,它是在for循环以前就被声明了。所以while中最核心的是
      b64
    3. 似曾相识,它就是base64,我在Base64百度百科中找到了最容易对应理解的一段话。
      base64
      以下的移位在上述解释中没提到
      移位
      很容易理解,这里移位前进行的变换对移位结果其实并没有啥影响。byte_41A144[1]&0xF0也就是11110000以后再右移4位和直接移位道理是一样的。下边那行同理。

    查看编码表aAbcdefghijklmn,是常规的Base64编码表
    编码表

    3 解密

    以上分析完,思路已经很清晰了。顺过程是:输入的字符串会先经过base64后,利用for循环把第j位元素的ASCII加上j再赋给第j位的元素。所以逆过程得到flag的步骤是:

    import base64
    str2 = 'e3nifIH9b_C@n@dH'
    rawDest = ""
    
    for i in range(len(str2)):
        rawDest += chr(ord(str2[i]) - i)
    print(rawDest)
    flag = base64.b64decode(rawDest)
    print(flag)
    

    flag{i_l0ve_you}

  • 相关阅读:
    《朗读手册》【美】吉姆·崔利斯
    《web全栈工程师的自我修养》 读书笔记
    2016/06 书单
    PostgreSQL数据库的安装
    MySQL数据库的安装
    异构数据库迁移——DATAX
    初探12C碰到的那些“坑”
    关于Ubuntu 16.04 pip安装Docker-Compose
    启动与关闭容器
    容器标识符
  • 原文地址:https://www.cnblogs.com/vict0r/p/13205229.html
Copyright © 2020-2023  润新知