zoukankan      html  css  js  c++  java
  • 2019 安洵杯 Re 部分WP

    0x01.EasyEncryption

    测试文件:https://www.lanzous.com/i7soysb

    1.IDA打开

    int sub_416560()
    {
      int v0; // eax
      int v1; // edx
      int v2; // edx
      int v3; // ecx
      int v4; // ST08_4
      char v6[4]; // [esp+310h] [ebp-7E0h]
      char Str; // [esp+700h] [ebp-3F0h]
      int v8; // [esp+AECh] [ebp-4h]
      int savedregs; // [esp+AF0h] [ebp+0h]
    
    
      sub_41132A((int)&unk_424091);
      sub_411294(std::cout, "输入flag: ");
      sub_41113B(std::cin, &Str);
      sub_4111F4(&Str, (int)v6);                    // v6="artqkoehqpkbihv"
      if ( (unsigned __int8)sub_4112B7(v6) )
      {
        sub_41105F("you are right
    ");
        system("pause");
        sub_411339(v3, v2);
      }
      else
      {
        v0 = sub_411294(std::cout, "wrong");
        sub_41114A(v0, 10);
      }
      v4 = v1;
      sub_41137A(&savedregs, &dword_416660, 0);
      return sub_411339((unsigned int)&savedregs ^ v8, v4);
    }

    2.代码分析

    输入flag之后,首先经过sub_4111F4(&Str, (int)v6)函数处理,再经过sub_4112B7(v6)函数判断。因为v6未知,所以首先通过最后一个函数找到v6 

    2.1 sub_4112B7函数分析

    打开sub_4112B7函数

    int __cdecl sub_413980(char *Str)
    {
      int v1; // edx
      int v2; // ecx
      int v3; // edx
      int v4; // ecx
      int v5; // edx
      int v6; // ecx
      char *Str1; // [esp+D0h] [ebp-8h]
    
    
      sub_41132A((int)&unk_42405B);
      Str1 = (char *)sub_4112D5(Str);               // Base64
      if ( !j_strcmp(Str1, "YXJ0cWtvZWhxcGtiaWh2") )
      {
        free(Str1);
        sub_411339(v6, v5);
      }
      else
      {
        free(Str1);
        sub_411339(v2, v1);
      }
      return sub_411339(v4, v3);
    }

    通过分析得到,sub_4112D5函数是Base6加密,因此这个函数实际上就是将Str进行Base64加密,得到字符串Str1与"XJ0cWtvZWhxcGtiaWh2"比较。将"XJ0cWtvZWhxcGtiaWh2"进行Base64解密,得到Str,即v6="artqkoehqpkbihv"

    2.2 sub_4111F4函数分析

    接着,打开sub_4111F4函数,太长了,就不贴出来了。这个函数,分为三个部分:

    0x01 第一部分:

     for ( i = 0; byte_41EC80[i]; ++i )
      {
        v16 = (unsigned __int8)byte_41EC80[i] - 97;
        v2 = j_abs(v16);
        v15[i] = v2;
      }

    byte_41EC80已知,可以写出脚本变换,得到v15

    Serial = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    
    
    Li = []
    
    
    for i in Serial:
        Li.append(abs(ord(i) - 97)

    0x02 第二部分

     v10 = j_strlen(Str);
      if ( v10 % i <= 0 )
      {
        v3 = v10 % i;                               // 余数
        v9 = v10 / i;                               //
      }
      else
      {
        v3 = v10 % i;
        v9 = v10 / i + 1;
      }

    0x03 第三部分

      for ( j = 0; j < v9; ++j )
      {
        for ( k = 0; k < i; ++k )
        {
          if ( Str[v14] )                           // 输入的字符值不能为0
          {
            if ( Str[v14] < 97 || Str[v14] > 122 )  // 输入只能是小写字母
              exit(1);
            if ( (Str[v14] + v15[k] - 97) % 26 + 97 > 122 )
              v4 = (Str[v14] + v15[k] - 97) % 26 + 71;
            else
              v4 = (Str[v14] + v15[k] - 97) % 26 + 97;
            v8 = v4;
            v3 = v14 + a2;
            *(_BYTE *)(v14++ + a2) = v8;
          }
        }
      }

    第二部分,第三部分和v6,结合分析,可以得到输入的flag应该是15,那么v9=1,v3=15,而第三部分实际上就是一个根据输入字符,进行选择变换得到v14(即v6),因为输入只能是小写字母,那我逆向变换的时候,只要得到的是小写字母,那就行了

    3.脚本解密

    Serial = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    
    
    Li = []
    
    
    for i in Serial:
        Li.append(abs(ord(i) - 97))
    print(Li)
    
    
    t1 = len(Li) - 1
    
    
    enc = "artqkoehqpkbihv"
    v10 = len(enc)
    v14 = 0
    Str = ''
    for j in range(1):
        for k in range(v10):
            for n in range(10):
                tmp1 = ord(enc[v14]) - 71 + 26 * n + 97 - Li[k]
                tmp2 = ord(enc[v14]) - 97 + 26 * n + 97 - Li[k]
                if tmp1 >= 97 and tmp1 <= 122:
                    print ("SUCCESS!")
                    Str += chr(tmp1)
                    break
                elif tmp2 >= 97 and tmp2 <= 122:
                    print ("SUCCESS!")
                    Str += chr(tmp2)
                    break
                else:
                    print("ERROR!")
            v14 = v14 + 1
    print (Str)
    
    

    4.get flag!

    flag{umpnineissogood}

     0x02 crackme

    测试文件:https://www.lanzous.com/i7sucre

     

    1.函数定位

    首先定位到起始的函数sub_412AB0

     1 int __stdcall sub_412AB0(int a1, int a2, int a3, int a4)
     2 {
     3   size_t i; // [esp+D8h] [ebp-8h]
     4 
     5   for ( i = 0; i < j_strlen(BASE64_table_41A080); ++i )
     6   {
     7     if ( BASE64_table_41A080[i] <= 122 && BASE64_table_41A080[i] >= 97 )
     8     {
     9       BASE64_table_41A080[i] -= 32;
    10     }
    11     else if ( BASE64_table_41A080[i] <= 90 && BASE64_table_41A080[i] >= 65 )
    12     {
    13       BASE64_table_41A080[i] += 32;
    14     }
    15   }
    16   MessageBoxA(0, "hooked", "successed", 0);
    17   AddVectoredExceptionHandler(0, Handler);
    18   return 0;
    19 }

     

    2.程序分析

    2.1 Base64变表1

    根据起始函数的第一个for循环,这里首先对Base64的表进行的变换,将大小写进行对换。

    #include <iostream>
    #include <string>
    
    
    using namespace std;
    
    string Str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    
    int main()
    {
        char v2;
    
        size_t i; // [esp+D8h] [ebp-8h]
    
        for (i = 0; i < Str.length(); ++i)
        {
            if (Str[i] <= 122 && Str[i] >= 97)
            {
                Str[i] -= 32;
            }
            else if (Str[i] <= 90 && Str[i] >= 65)
            {
                Str[i] += 32;
            }
        }
    
        cout << Str << endl;
    
        system("PAUSE");
        return 0;
    }
    Base64大小写变换

    得到新base64表"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"

    2.2 向量化异常处理

    SetUnhandledExceptionFilter()函数:https://baike.baidu.com/item/SetUnhandledExceptionFilter/2334228?fr=aladdin

    AddVectoredExceptionHandler()函数:https://www.cnblogs.com/suanguade/p/6674232.html

    接着使用向量化异常处理,进入 Handler

     1 int __stdcall Handler_0(_DWORD **a1)
     2 {
     3   char v2; // [esp+D0h] [ebp-18h]
     4   char v3; // [esp+D1h] [ebp-17h]
     5   char v4; // [esp+D2h] [ebp-16h]
     6   char v5; // [esp+D3h] [ebp-15h]
     7   char v6; // [esp+D4h] [ebp-14h]
     8   char v7; // [esp+D5h] [ebp-13h]
     9   char v8; // [esp+D6h] [ebp-12h]
    10   char v9; // [esp+D7h] [ebp-11h]
    11   char v10; // [esp+D8h] [ebp-10h]
    12   char v11; // [esp+D9h] [ebp-Fh]
    13   char v12; // [esp+DAh] [ebp-Eh]
    14   char v13; // [esp+DBh] [ebp-Dh]
    15   char v14; // [esp+DCh] [ebp-Ch]
    16   char v15; // [esp+DDh] [ebp-Bh]
    17   char v16; // [esp+DEh] [ebp-Ah]
    18   char v17; // [esp+DFh] [ebp-9h]
    19 
    20   if ( **a1 == -1073741819 )
    21   {
    22     v2 = 'w';
    23     v3 = 'h';
    24     v4 = 'e';
    25     v5 = 'r';
    26     v6 = 'e';
    27     v7 = '_';
    28     v8 = 'a';
    29     v9 = 'r';
    30     v10 = 'e';
    31     v11 = '_';
    32     v12 = 'u';
    33     v13 = '_';
    34     v14 = 'n';
    35     v15 = 'o';
    36     v16 = 'w';
    37     v17 = '?';
    38     sm4_func((int)&unk_41A218, (int)&v2);
    39     SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopLevelExceptionFilter);
    40   }
    41   return 0;
    42 }

    2.2.1 sm4加密

    pysm4包下载安装教程:https://www.cnblogs.com/Mayfly-nymph/p/11939336.html

    进入sm4_func函数(这个我改过名了)

    int __cdecl sub_411F50(int a1, unsigned int *a2)
    {
      unsigned int v2; // eax
      int v3; // ecx
      int result; // eax
      unsigned int v5; // [esp+D0h] [ebp-B8h]
      unsigned int v6; // [esp+DCh] [ebp-ACh]
      unsigned int v7; // [esp+E0h] [ebp-A8h]
      unsigned int v8; // [esp+E4h] [ebp-A4h]
      int v9; // [esp+E8h] [ebp-A0h]
      int v10[34]; // [esp+ECh] [ebp-9Ch]
      unsigned int v11; // [esp+174h] [ebp-14h]
      unsigned int v12; // [esp+178h] [ebp-10h]
      unsigned int v13; // [esp+17Ch] [ebp-Ch]
      unsigned int v14; // [esp+180h] [ebp-8h]
    
      v5 = 0;
      v11 = _byteswap_ulong(*a2);
      v12 = _byteswap_ulong(a2[1]);
      v13 = _byteswap_ulong(a2[2]);
      v2 = _byteswap_ulong(a2[3]);
      v14 = v2;
      v6 = v11 ^ 0xA3B1BAC6;
      v7 = dword_417A68[1] ^ v12;
      v8 = dword_417A68[2] ^ v13;
      v3 = dword_417A68[3] ^ v2;
      result = 12;
      v9 = v3;
      while ( v5 < 0x20 )
      {
        v10[v5] = *(&v6 + v5) ^ sub_4114E0(dword_417A78[v5] ^ *(&v9 + v5) ^ *(&v8 + v5) ^ *(&v7 + v5));
        *(_DWORD *)(a1 + 4 * v5) = v10[v5];
        result = v5++ + 1;
      }
      return result;
    }

    Google搜了下0xA3B1BAC6

     

    发现了这个函数应该是sm4加密

    2.2.2 异常处理

    接着,使用SetUnhandledExceptionFilter捕获异常,进入TopLevelExceptionFilter

     1 _DWORD *__cdecl sub_412C30(_DWORD *a1)
     2 {
     3   _DWORD *result; // eax
     4   char v2; // STD7_1
     5   size_t i; // [esp+DCh] [ebp-8h]
     6 
     7   result = a1;
     8   if ( *(_DWORD *)*a1 == -1073741819 )
     9   {
    10     for ( i = 0; i < j_strlen(Str2); i += 2 )
    11     {
    12       v2 = Str2[i];
    13       Str2[i] = Str2[i + 1];
    14       Str2[i + 1] = v2;
    15     }
    16     Str1 = sub_41126C(byte_41A180);
    17     *(_DWORD *)(a1[1] + 176) = *(_DWORD *)(*a1 + 20);
    18     *(_DWORD *)(a1[1] + 164) = *(_DWORD *)(*a1 + 24);
    19     *(_DWORD *)(a1[1] + 172) = *(_DWORD *)(*a1 + 28);
    20     *(_DWORD *)(a1[1] + 168) = *(_DWORD *)(*a1 + 32);
    21     *(_DWORD *)(a1[1] + 156) = *(_DWORD *)(*a1 + 36);
    22     *(_DWORD *)(a1[1] + 160) = *(_DWORD *)(*a1 + 40);
    23     *(_DWORD *)(a1[1] + 184) = sub_411136;
    24     result = (_DWORD *)-1;
    25   }
    26   return result;
    27 }

    第一个for循环就是在将Str2相邻两位互换

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    string Str2 = "1UTAOIkpyOSWGv/mOYFY4R!!";
    
    int main()
    {
        char v2;
    
        for (int i = 0; i < Str2.length(); i += 2)
        {
            v2 = Str2[i];
            Str2[i] = Str2[i + 1];
            Str2[i + 1] = v2;
        }
    
        cout << Str2 << endl;
    
        system("PAUSE");
        return 0;
    }
    Str2相邻位变换

    接着通过sub_41126C函数传入byte_41A180,返回值为Str2,最后将Str1与Str2比较是否相同,输出success或者error,这就很明显了,肯定要输出‘success’,那Str2就要等于'U1ATIOpkOyWSvGm/YOYFR4!!'

    2.2.3 Base64变表2

    打开sub_41126C函数

     1 _BYTE *__cdecl sub_413090(char *Str)
     2 {
     3   int k; // [esp+E4h] [ebp-5Ch]
     4   int v3; // [esp+F0h] [ebp-50h]
     5   signed int j; // [esp+FCh] [ebp-44h]
     6   int v5; // [esp+108h] [ebp-38h]
     7   signed int i; // [esp+114h] [ebp-2Ch]
     8   _BYTE *v7; // [esp+120h] [ebp-20h]
     9   signed int v8; // [esp+12Ch] [ebp-14h]
    10   int v9; // [esp+138h] [ebp-8h]
    11 
    12   v5 = 0;
    13   v8 = j_strlen(Str);                           // Str长度
    14   if ( v8 % 3 )                                 // 设置字节长度
    15     v9 = 4 * (v8 / 3) + 4;
    16   else
    17     v9 = 4 * (v8 / 3);
    18   v7 = malloc((v9 + 1) | -__CFADD__(v9, 1));    // 申请空间
    19   v7[v9] = 0;
    20   for ( i = 0; i < v8; i += 3 )                 // 三位三位的处理,base64?
    21   {
    22     v3 = 0;
    23     for ( j = 0; j < 3; ++j )
    24       v3 |= (unsigned __int8)Str[j + i] << 8 * (2 - j);
    25     for ( k = 0; k < 4; ++k )
    26     {
    27       if ( k >= 4 - (i + 3 - v8) && i + 3 > v8 )// 长度大于等于4的部分使用'!'补齐
    28         v7[v5] = '!';
    29       else
    30         v7[v5] = ::Str[sub_4110FF((v3 >> 6 * (3 - k)) & 0x3F)];
    31       ++v5;
    32     }
    33   }
    34   return v7;
    35 }

    在函数sub_4110FF有一步不同的操作

    int __cdecl sub_412760(int a1)
    {
      return (a1 + 24) % 64;
    }

    这里+24,相当于变表的值为原表取值右移24位

    Str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"
    
    Str1 = ''
    
    for i in Str:
        Str1 += Str[(Str.find(i)+24) % len(Str)]
    print (Str1)

    得到新的Base64表"yzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvwx"

    到这我们整个过程就分析完毕了,接下来只需要逆向操作就行了。

    3.逆向解密

    # encoding: utf-8
    from pysm4 import decrypt,encrypt
    from base64 import b64decode
    
    Str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/"
    Str_ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
    
    Str1 = ''
    
    # 变换之后的Base64表
    for i in Str:
        Str1 += Str[(Str.find(i)+24) % len(Str)]
    print (Str1)
    
    # 之前是用变换之后的表进行Base64加密
    # 现在转换为正常的Base64加密,
    # 再解密得到sm4加密之后的字符串
    enc = "U1ATIOpkOyWSvGm/YOYFR4!!"
    dec1 = ''
    for i in range(len(enc)):
        if enc[i] == '!':
            dec1 += '='
        else:
            dec1 += Str_[Str1.find(enc[i])]
    print (dec1)
    
    dec2 = b64decode(dec1)
    print (dec2)
    
    import codecs
    
    # 先进行hex编码,再转换为十进制整型
    encode_hex = codecs.getencoder("hex_codec")
    dec3 = int(encode_hex(dec2)[0],16)
    print (dec3)
    
    # 将key转换为十进制
    key = "where_are_u_now?"
    key = int(encode_hex(key)[0],16)
    print (key)
    
    # 将解密的字符串转换会hex
    decode_hex = codecs.getdecoder("hex_codec")
    dec4 = decrypt(dec3, key)
    dec4 = str(hex(dec4)[2:-1])
    
    print (decode_hex(dec4)[0])

    4. get flag!

     flag{SM4foRExcepioN?!}

    官方公布源码:https://github.com/D0g3-Lab/i-SOON_CTF_2019

    其他WP:https://blog.csdn.net/Zarcs_233/article/details/103338006

    这次进入线下,希望能够好好发挥,加油!

  • 相关阅读:
    计数排序【代码】
    快速排序【代码】
    基于最大堆实现最大优先队列
    Spring入门(1)
    AJAX初步理解
    选择器
    Hibernate的映射
    Hibernate配置(2)
    查看mysql的安装路径
    Hibernate入门(1)
  • 原文地址:https://www.cnblogs.com/Mayfly-nymph/p/11972774.html
Copyright © 2011-2022 走看看