吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4897|回复: 12
收起左侧

[CTF] 2021NCTF RE

  [复制链接]
pupububu 发表于 2021-11-29 15:44

Re

Shadowbringer

c++64位程序,ida载入

std::string::string(v4, "U>F2UsQXN`5sXMELT=:7M_2<X]^1ThaWF0=KM?9IUhAsTM5:T==_Ns&<Vhb!", &v6);
  std::allocator<char>::~allocator(&v6);
  std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Welcome.Please input your flag:\n");
  std::operator>><char>(refptr__ZSt3cin, (std::string *)input);
  std::string::string((std::string *)v8, (const std::string *)input);// strcpy
  base64encode1((std::string *)v7, (std::string *)v8);// 换表的base64
  std::string::operator=((std::string *)input, (const std::string *)v7);// 赋值 第一层密文
  std::string::~string((std::string *)v7);
  std::string::~string((std::string *)v8);
  std::string::string((std::string *)v10, (const std::string *)input);// 复制一个对象v10
  base64encode2((std::string *)v9, (std::string *)v10); // base64换表 两次 不同的表
  std::string::operator=((std::string *)input, (const std::string *)v9);
  std::string::~string((std::string *)v9);
  std::string::~string((std::string *)v10);
  if ( (unsigned __int8)std::operator==<char>(input, v4) )
    std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Right.");
  else
    std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Wrong.");
  std::string::~string((std::string *)v4);

主要用到了c++ string类来进行处理,结合动调,大致经过了两次base64变表加密,在和v4进行比较。
第一组表,
‘#$%&’,27h,‘()*+,-.s0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[h]’+‘^_`ab’

第二组表
‘ba`_^]h[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210s.-,+*)(’,27h,‘&’‘+’%$#’

两次加密的代码大致相同,主要通过表的长度和每次处理的二进制长度判断为base64.

std::bitset<8ull>::to_string(v13, v14);     // 转为2进制
for ( j = 0; j < (unsigned __int64)std::string::size((std::string *)&v9); j += 6 )// 6个二进制一组
v7 = (char *)std::string::operator[](&hisoralce, v6);//表索引

while ( (std::string::size(a1) & 3) != 0 )
  {
    std::operator+<char>(v19, a1, '!');
    std::string::operator=(a1, (const std::string *)v19);
    std::string::~string((std::string *)v19);
  }
//不为4的倍数就不断+!

了解流程后写解密脚本即可

import base64
table1='#$%&'+'\x27'+'()*+,-.s0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[h]'+'^_`ab'
table2='ba`_^]h[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210s.-,+*)('+'\x27'+'&%$#'
base='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
enc='U>F2UsQXN`5sXMELT=:7M_2<X]^1ThaWF0=KM?9IUhAsTM5:T==_Ns&<Vhb!'
#enc='FsJ7M?b<U->2M>U:'#123456789测试
def newbase(enc,table):
    m=''
    for i in range(len(enc)):
        if enc[i] in table:
            m+=base[table.index(enc[i])]
        else:
            m+='='
    print(base64.b64decode(m))
    return base64.b64decode(m)
c1=newbase(enc,table2).decode()
newbase(c1,table1)
#NCTF{H0m3_r1d1n9_h0m3_dy1n9_h0p3}

鲨鲨的秘密

32位程序,ida载入

 IpAdress = malloc(0x20u);
  VirtualProtect(IpAdress, 0x20u, 0x40u, &flOldProtect);
  dword_404E48 = (int)IpAdress;
  *(_BYTE *)IpAdress = 0xC3;                    // ret的机器码
  ((void (*)(void))IpAdress)

刚载入就有种莫名其妙的熟悉感,和西湖论剑的一道逆向题思路差不多,又是体力活。
是一种修改代码的操作数并单语句执行的SMC,通过一个数组来确定赋值代码长度的大小,和选定相应的操作数和修改的位置。

挖出汇编代码,结合动调分析语句还原算法。

mov     ds:dword_403474, 0FFFFFFFFh            // mov output ,0xffffffff
mov     ecx, ds:dword_403464                         // mov ecx,index(0) 
mov     dl, byte ptr ds:VirtualProtect[ecx]        // mov dl,input[0]
mov     byte ptr ds:dword_403470, dl             // mov temp,dl
movzx   eax, byte ptr ds:dword_403470         //  mov eax, temp  输入传给eax
xor     eax, ds:dword_403474                          //  xor   eax,output 取反类似
mov     byte ptr ds:dword_403470, al            //   mov temp , al  保存取反的值
movzx   ecx, byte ptr ds:dword_403470        //   mov ecx,temp 
and     ecx, 0FFh                                             //   and  ecx,0xff
mov     byte ptr ds:dword_403470, cl            //   mov temp,cl
mov     edx, ds:dword_403474                      //    mov edx,output 
shr     edx,   8                                                 //    shr   edx,8
mov     ds:dword_403474, edx                      //    mov output,edx
movzx   eax, byte ptr ds:dword_403470       //    mov eax,temp
mov     ecx, ds:dword_403474                         //    mov ecx,output
xor     ecx, dword ptr ds:byte_403058[eax*4]     //  xor ecx, sbox[4*eax]   //174841BC  xor sbox[4*0x9e] 结果保存到output
mov     ds:dword_403474, ecx                              
mov     edx, ds:dword_403464                            ....
mov     al, [edx+403005h]                
mov     byte ptr ds:dword_403470, al                
movzx   ecx, byte ptr ds:dword_403470                
xor     ecx, ds:dword_403474                
mov     byte ptr ds:dword_403470, cl        
mov     edx, ds:dword_403474
shr     edx, 8
mov     ds:dword_403474, edx
movzx   eax, byte ptr ds:dword_403470
mov     ecx, ds:dword_403474
xor     ecx, dword ptr ds:byte_403058[eax*4]     //xor ecx,sbox[4*eax]  //eax 0xdd
mov     ds:dword_403474, ecx                            //mov output,ecx
mov     edx, ds:dword_403474                            //mov edx,output
xor     edx, 0FFFFFFFFh                           //xor     edx, 0FFFFFFFFh
mov     ds:dword_403474, edx                          //mov    output edx

python代码如下

input='a'*40
output=0xffffffff
for index in range(0,40,2):
        tmp=(ord(input[index])^output)&0xff
        output=output>>8
        output=output^somebox[tmp]
        #print("%x %x"%(tmp,output))
        tmp = (ord(input[index+1]) ^ output) & 0xff
        output = output >> 8
        output = output ^ somebox[tmp]
        output=output^0xffffffff
        print("%x %x" % (tmp, output))

可知是两个字节为一组进行的处理,z3解因为涉及下标问题不好下手,所以直接爆破。

somebox=[0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]
enc=[0xC0F6605E, 0x00B16E0A, 0x3319A2D2, 0x57CAB7B7, 0x9A646D9C, 0xBDD82726, 0xD838FB91, 0x8DE10BB3, 0x176B0DAD, 0x685FDEEF, 0x2C1FF7B1, 0x6C444296, 0xA15CFE90, 0x20CD8721, 0x62967CE8, 0x2C1641FD, 0x572D0F9A, 0xAE52DC2C, 0x50497DCF, 0xFF6ABF4A]
s=''
enc=[0xC0F6605E, 0x00B16E0A, 0x3319A2D2, 0x57CAB7B7, 0x9A646D9C, 0xBDD82726, 0xD838FB91, 0x8DE10BB3, 0x176B0DAD, 0x685FDEEF, 0x2C1FF7B1, 0x6C444296, 0xA15CFE90, 0x20CD8721, 0x62967CE8, 0x2C1641FD, 0x572D0F9A, 0xAE52DC2C, 0x50497DCF, 0xFF6ABF4A]
for i  in range(20):
    for  m in range(32,128):
        for n in range(32,128):
            output = 0xffffffff
            tmp=(m^output)&0xff
            output=output>>8
            output=output^somebox[tmp]
            #print("%x %x"%(tmp,output))
            tmp = (n ^ output) & 0xff
            output = output >> 8
            output = output ^ somebox[tmp]
            output=output^0xffffffff
            if output==enc[i]:
                s+=chr(m)+chr(n)

print(s)
#NCTF{rLdE57TG0iHA39qUnFZp6LeJyYEBcxMNL7}

狗狗的秘密

挺不错的,解完想暴打出题人。
32位程序,ida载入获得假flag一枚

不过main之前有个TlsCallback函数,直接下个断点,动态分析。

 if ( !v9 && !IsDebuggerPresent() )
    {
      off_825014 = (int (__cdecl *)(_DWORD))sub_823000;
      v8 = (unsigned int *)((char *)sub_823000 + 256);
      for ( i = 0; i < 24; ++i )
        v8 += 2;
      for ( j = 0; j < 24; ++j )
      {
        v8 -= 2;
        sub_8211F0(v8);
      }
    }

反调试,off_825014在主函数出现过,但是个假逻辑,所以这部分内容是SMC修改技术。

unsigned int __cdecl sub_8211F0(unsigned int *a1)
{
  unsigned int result; // eax
  int i; // [esp+0h] [ebp-Ch]
  unsigned int v3; // [esp+4h] [ebp-8h]
  unsigned int v4; // [esp+8h] [ebp-4h]

  v4 = *a1;
  v3 = a1[1];
  for ( i = 0; i < 64; ++i )
  {
    v3 -= (dword_825004[(*(_DWORD *)delta >> 11) & 3] + *(_DWORD *)delta) ^ (v4 + ((v4 >> 5) ^ (16 * v4)));
    *(_DWORD *)delta += dword_825000;
    v4 -= (dword_825004[delta[0] & 3] + *(_DWORD *)delta) ^ (v3 + ((v3 >> 5) ^ (16 * v3)));
  }
  *a1 = v4;
  result = v3;
  a1[1] = v3;
  return result;
}

直接改eip绕过这个反调试即可,同时修改代码用的xTea,不过delta的值有个小坑,main函数中有个创建线程的函数,将delta赋值为0xDA76C600,patch进行修改,后面下个断F9。
修复函数后拿到真正处理逻辑。

int __cdecl sub_823000(const char *a1)
{
  signed int v2; // [esp+0h] [ebp-98h]
  unsigned int v3; // [esp+10h] [ebp-88h]
  signed int v4; // [esp+1Ch] [ebp-7Ch]
  int v5; // [esp+2Ch] [ebp-6Ch]
  int v6; // [esp+2Ch] [ebp-6Ch]
  char v7; // [esp+32h] [ebp-66h]
  signed int Size; // [esp+34h] [ebp-64h]
  unsigned int v9; // [esp+38h] [ebp-60h]
  int k; // [esp+38h] [ebp-60h]
  unsigned __int8 *v11; // [esp+3Ch] [ebp-5Ch]
  int i; // [esp+40h] [ebp-58h]
  signed int j; // [esp+40h] [ebp-58h]
  signed int m; // [esp+40h] [ebp-58h]
  signed int n; // [esp+40h] [ebp-58h]
  signed int ii; // [esp+40h] [ebp-58h]
  char v17[62]; // [esp+44h] [ebp-54h]
  int v18; // [esp+82h] [ebp-16h]
  int v19; // [esp+86h] [ebp-12h]
  int v20; // [esp+8Ah] [ebp-Eh]
  int v21; // [esp+8Eh] [ebp-Ah]
  __int16 v22; // [esp+92h] [ebp-6h]

  v3 = strlen(a1);
  Size = 146 * v3 / 0x64 + 1;
  v4 = 0;
  v11 = (unsigned __int8 *)malloc(Size);
  v17[0] = 82;
  v17[1] = -61;
  v17[2] = 26;
  v17[3] = -32;
  v17[4] = 22;
  v17[5] = 93;
  v17[6] = 94;
  v17[7] = -30;
  v17[8] = 103;
  v17[9] = 31;
  v17[10] = 31;
  v17[11] = 6;
  v17[12] = 6;
  v17[13] = 31;
  v17[14] = 23;
  v17[15] = 6;
  v17[16] = 15;
  v17[17] = -7;
  v17[18] = 6;
  v17[19] = 103;
  v17[20] = 88;
  v17[21] = -78;
  v17[22] = -30;
  v17[23] = -116;
  v17[24] = 15;
  v17[25] = 42;
  v17[26] = 6;
  v17[27] = -119;
  v17[28] = -49;
  v17[29] = 42;
  v17[30] = 6;
  v17[31] = 31;
  v17[32] = -104;
  v17[33] = 26;
  v17[34] = 62;
  v17[35] = 23;
  v17[36] = 103;
  v17[37] = 31;
  v17[38] = -9;
  v17[39] = 58;
  v17[40] = 68;
  v17[41] = -61;
  v17[42] = 22;
  v17[43] = 51;
  v17[44] = 105;
  v17[45] = 26;
  v17[46] = 117;
  v17[47] = 22;
  v17[48] = 62;
  v17[49] = 23;
  v17[50] = -43;
  v17[51] = 105;
  v17[52] = 122;
  v17[53] = 27;
  v17[54] = 68;
  v17[55] = 68;
  v17[56] = 62;
  v17[57] = 103;
  v17[58] = -9;
  v17[59] = -119;
  v17[60] = 103;
  v17[61] = -61;
  v18 = 0;
  v19 = 0;
  v20 = 0;
  v21 = 0;
  v22 = 0;
  memset(v11, 0, Size);
  v9 = 0;
  for ( i = 0; i < 256; ++i )
  {
    v7 = byte_825018[i];
    byte_825018[i] = byte_825018[(i + *((unsigned __int8 *)&delta + i % 4)) % 256];// delta变为0了
    byte_825018[(i + *((unsigned __int8 *)&delta + i % 4)) % 256] = v7;
  }
  while ( v9 < strlen(a1) )
  {
    v5 = a1[v9];
    for ( j = 146 * v3 / 0x64; ; --j )
    {
      v6 = v5 + (v11[j] << 8);
      v11[j] = v6 % 47;
      v5 = v6 / 47;
      if ( j < v4 )
        v4 = j;
      if ( !v5 && j <= v4 )
        break;
    }
    ++v9;
  }
  for ( k = 0; !v11[k]; ++k )
    ;
  for ( m = 0; m < Size; ++m )
    v11[m] = byte_825118[v11[k++]];             // 单表替换
  while ( m < Size )
    v11[m++] = 0;
  v2 = strlen((const char *)v11);
  for ( n = 0; n < v2; ++n )
    v11[n] ^= byte_825018[v11[n]];              // 异或处理
  for ( ii = 0; ii < v2; ++ii )
  {
    if ( v11[ii] != (unsigned __int8)v17[ii] )
    {
      printf("Wrong!\n", v2);
      exit(0);
    }
  }
  printf("Right!\n", v2);
  return 0;
}

delta的值是0,需要注意一下,接着就是写脚本逆向,z3不好直接求解,加密流程是先将输入转为47进制下每位的值存在数组v11中,找到第一个非0值的下标k,接着进行单表替换和异或。
因为涉及到表索引和本身异或不好逆向还原,所以想着在爆破v11数组。

enc=[0x52, 0xC3, 0x1A, 0xE0, 0x16, 0x5D, 0x5E, 0xE2, 0x67, 0x1F, 0x1F, 0x06, 0x06, 0x1F, 0x17, 0x06, 0x0F, 0xF9, 0x06, 0x67, 0x58, 0xB2, 0xE2, 0x8C, 0x0F, 0x2A, 0x06, 0x89, 0xCF, 0x2A, 0x06, 0x1F, 0x98, 0x1A, 0x3E, 0x17, 0x67, 0x1F, 0xF7, 0x3A, 0x44, 0xC3, 0x16, 0x33, 0x69, 0x1A, 0x75, 0x16, 0x3E, 0x17, 0xD5, 0x69, 0x7A, 0x1B, 0x44, 0x44, 0x3E, 0x67, 0xF7, 0x89, 0x67, 0xC3]
c=[]
for i in range(61):
    temp=[]
    for j in range(47):
        tmp=tb2[j]
        tmp=tmp^table[tmp]
        if tmp==enc[i]:
            temp.append(j)
    if len(temp)==1:
        c.append(temp[0])
    else:
        c.append(temp)
c.insert(0,0)

#[0, 2, 0, [33, 45], 44, 30, 40, 8, 23, [7, 11, 22], [34, 37], [34, 37], [19, 20, 43], [19, 20, 43], [34, 37], 24, [19, 20, 43], [4, 31], 29, [19, 20, 43], [7, 11, 22], 13, 5, 23, 41, [4, 31], 35, [19, 20, 43], 9, 14, 35, [19, 20, 43], [34, 37], 3, [33, 45], 10, 24, [7, 11, 22], [34, 37], 38, 1, 25, 0, 30, 6, 42, [33, 45], 36, 30, 10, 24, 21, 42, 26, 28, 25, 25, 10, [7, 11, 22], 38, 9, [7, 11, 22]]

v11第一位是0,根据加密的最后一位是0xc3,或者多次测试都可知,不过这解有点多,下面就是对c进行排列组合,之后47进制转,long_to_bytes下即可,不过这…tmd,dfs不太会写,直接硬爆破了,大概跑了半小时,直接整emo了。
完整如下

from Crypto.Util.number import *

def dododo(c):
    sum = 0
    for i in range(62):
        sum += c[i] * pow(47, 61 - i)
    m=long_to_bytes(sum)
    try:
        flag=m.decode()
        print(flag)
        exit(0)
    except:
        pass

enc=[0x52, 0xC3, 0x1A, 0xE0, 0x16, 0x5D, 0x5E, 0xE2, 0x67, 0x1F, 0x1F, 0x06, 0x06, 0x1F, 0x17, 0x06, 0x0F, 0xF9, 0x06, 0x67, 0x58, 0xB2, 0xE2, 0x8C, 0x0F, 0x2A, 0x06, 0x89, 0xCF, 0x2A, 0x06, 0x1F, 0x98, 0x1A, 0x3E, 0x17, 0x67, 0x1F, 0xF7, 0x3A, 0x44, 0xC3, 0x16, 0x33, 0x69, 0x1A, 0x75, 0x16, 0x3E, 0x17, 0xD5, 0x69, 0x7A, 0x1B, 0x44, 0x44, 0x3E, 0x67, 0xF7, 0x89, 0x67, 0xC3]
table=[0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0x65, 0xA2, 0x9B, 0xF4, 0xDF, 0xAC, 0x7C, 0xA1, 0xC6, 0x16, 0xD0, 0x0F, 0xDD, 0xDC, 0x73, 0xC5, 0x6B, 0xD1, 0x96, 0x47, 0xC2, 0x26, 0x67, 0x4E, 0x41, 0x82, 0x20, 0x56, 0x9A, 0x6E, 0x33, 0x92, 0x88, 0x29, 0xB5, 0xB4, 0x71, 0xA9, 0xCE, 0xC3, 0x34, 0x50, 0x59, 0xBF, 0x2D, 0x57, 0x22, 0xA6, 0x30, 0x04, 0xB2, 0xCD, 0x36, 0xD5, 0x68, 0x4D, 0x5B, 0x45, 0x9E, 0x85, 0xCF, 0x9D, 0xCC, 0x61, 0x78, 0x32, 0x76, 0x31, 0xE3, 0x80, 0xAD, 0x39, 0x4F, 0xFA, 0x72, 0x83, 0x4C, 0x86, 0x60, 0xB7, 0xD7, 0x63, 0x0C, 0x44, 0x35, 0xB3, 0x7B, 0x19, 0xD4, 0x69, 0x08, 0x0B, 0x1F, 0x3D, 0x11, 0x79, 0xD3, 0xEE, 0x93, 0x42, 0xDE, 0x23, 0x3B, 0x5D, 0x8D, 0xA5, 0x77, 0x5F, 0x58, 0xDB, 0x97, 0xF6, 0x7A, 0x18, 0x52, 0x15, 0x74, 0x25, 0x62, 0x2C, 0x05, 0xE8, 0x0D, 0x98, 0x2A, 0x43, 0xE2, 0xEF, 0x48, 0x87, 0x49, 0x1C, 0xCA, 0x2B, 0xA7, 0x8A, 0x09, 0x81, 0xE7, 0x53, 0xAA, 0xFF, 0x6F, 0x8E, 0x91, 0xF1, 0xF0, 0xA4, 0x46, 0x3A, 0x7D, 0x54, 0xEB, 0x2F, 0xC1, 0xC0, 0x0E, 0xBD, 0xE1, 0x6C, 0x64, 0xBE, 0xE4, 0x02, 0x3C, 0x5A, 0xA8, 0x9F, 0x37, 0xAF, 0xA0, 0x13, 0xED, 0x1B, 0xEC, 0x8B, 0x3E, 0x7E, 0x27, 0x99, 0x75, 0xAB, 0xFE, 0xD9, 0x3F, 0xF3, 0xEA, 0x70, 0xF7, 0x95, 0xBA, 0x1D, 0x40, 0xB0, 0xF9, 0xE5, 0xF8, 0x06, 0xBC, 0xB6, 0x03, 0xC9, 0x10, 0x9C, 0x2E, 0x89, 0x5C, 0x7F, 0xB1, 0x1A, 0xD6, 0x90, 0xAE, 0xDA, 0xE6, 0x5E, 0xB9, 0x84, 0xE9, 0x55, 0xBB, 0xC7, 0x0A, 0xE0, 0x66, 0xF2, 0xD8, 0xCB, 0x00, 0x12, 0xB8, 0x17, 0x94, 0x6A, 0x4A, 0x01, 0x24, 0x14, 0x51, 0x07, 0x65, 0x21, 0xC8, 0x38, 0xFD, 0x8F, 0xC4, 0xF5, 0xFC]
#delta=[0,0xc6,0x76,0xda]
tb2=[0xA7, 0x1C, 0x7E, 0xAF, 0xD9, 0xC2, 0xC0, 0xBE, 0x1F, 0x45, 0x9A, 0x85, 0x26, 0xE3, 0x87, 0xC3, 0x21, 0xE0, 0x95, 0x10, 0x71, 0x70, 0x02, 0x75, 0x35, 0xA5, 0x1D, 0x0D, 0x2F, 0xEE, 0x25, 0x7B, 0xB5, 0x82, 0x66, 0x8D, 0xDB, 0x53, 0x3A, 0x29, 0xD4, 0x43, 0x99, 0x97, 0x9D, 0xE8, 0x49, 0x00]

c=[]

for i in range(61):
    temp=[]
    for j in range(47):
        tmp=tb2[j]
        tmp=tmp^table[tmp]
        if tmp==enc[i]:
            temp.append(j)
    if len(temp)==1:
        c.append(temp[0])
    else:
        c.append(temp)
c.insert(0,0)
print(c)
for i in c:
    if isinstance(i,int):
        pass
    else:
        print(i)
c[3]=45
tblen=[]
l=1
index=[]
for i in range(len(c)):
    try:
        tblen.append(len(c[i]))
        l*=len(c[i])
        index.append(i)
    except:
        tblen.append(1)

print(tblen)
print(index)

sum=0
t1=[7, 11, 22]
t2=[34, 37]
t3=[19, 20, 43]
t4=[4, 31]
t5=[33, 45]

for  a1 in range(3):
    c[9]=t1[a1]
    for a2 in range(2):
        c[10]=t2[a2]
        for a3 in range(2):
            c[11]=t2[a3]
            for a4 in range(3):
                c[12]=t3[a4]
                for a5 in range(3):
                    c[13]=t3[a5]
                    for a6 in range(2):
                        c[14]=t2[a6]
                        for a7 in range(3):
                            c[16]=t3[a7]
                            for a8 in range(2):
                                c[17]=t4[a8]
                                for a9 in range(3):
                                    c[19]=t3[a9]
                                    for a10 in range(3):
                                        c[20]=t1[a10]
                                        for a11 in range(2):
                                            c[25]=t4[a11]
                                            for a12 in range(3):
                                                c[27]=t3[a12]
                                                for a13 in range(3):
                                                    c[31]=t3[a13]
                                                    for a14 in range(2):
                                                        c[32]=t2[a14]
                                                        for a15 in range(2):
                                                            c[34]=t5[a15]
                                                            for a16 in range(3):
                                                                c[37]=t1[a16]
                                                                for a17 in range(2):
                                                                    c[38]=t2[a17]
                                                                    for a18 in range(2):
                                                                        c[46]=t5[a18]
                                                                        for a19 in range(3):
                                                                            c[58]=t1[a19]
                                                                            for a20 in range(3):
                                                                                c[61]=t1[a20]
                                                                                dododo(c)

#NCTF{ADF0E239-D911-3781-7E40-A575A19E5835}

easy_mobile

so被ollvm了,1400行。

image-20211129012024722

但是我用deflat去混淆,最后只剩三分一的代码?,没法只能用原来的看。

我尝试去动调,发现下不了断点?

想到只有1400行而已决定手撕。

然后我比较菜,花了一个多小时才整理了逻辑。

首先,我在719行找到了获取输入

image-20211129012436292

然后发现判断长度为24

image-20211129012535248

交叉索引我们的输入

image-20211129012607500
发现,程序会将前16个字节分成4个字节一组分成四组的进行操作,最后8个字节分成两组。

我先看了程序对后面八个字节进行了什么操作

image-20211129012800370

他作为输入传进了下面这个函数。并且上面还将一个长为16字节的字符串传了进去

跟进去看了一下

image-20211129012844350

我顿时反应过来了,这和tea怎么那么像?

然后我手动恢复了一下

image-20211129012924350

这不就是改了delta但还是原汁原味的tea吗?而且他a2就是我们传入的第二个字符串,那就是KEY

我直接用我祖传脚本梭哈得到了我们后8个字符。

#include <stdio.h>  
#include <stdint.h>  

//加密函数  
void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0, i;           /* set up */
    uint32_t delta = 0x9e3779b9;                     /* a key schedule constant */
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
    for (i = 0; i < 32; i++) {                       /* basic cycle start */
        sum += delta;
        v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    }                                              /* end cycle */
    v[0] = v0; v[1] = v1;
}
//解密函数  
void decrypt(unsigned int* v, unsigned int* k) {
    unsigned int v0 = v[0], v1 = v[1], i;
    int sum = 0x12345678 << 5;/* set up */
    uint32_t delta = 0x12345678;  // 0x9e3779b8                   /* a key schedule constant */
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
    for (i = 0; i < 32; i++) {                         /* basic cycle start */
        v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
        v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        sum -= delta;
    }                                              /* end cycle */
    v[0] = v0; v[1] = v1;
}

int main()
{
    unsigned int v[2] = { 0xC65AEDA,0xADBF8DB1 }, k[4] = { 1634232689, 1852399976, 1851879017, 1835101793 };

    // v为要加密的数据是两个32位无符号整数  
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  
    //printf("%x %xx\n", v[0], v[1]);
    decrypt(v, k);
   printf("%x %x\n", v[0], v[1]);

    puts((char*)v);
//58af2715c
    return 0;
}

然后去继续交叉索引到第一次被调用的地方

然后理解一下

image-20211129013205315

就是将我们的前4个字符,保存在一个int32x4的数据类型中,可以理解为他是一个大小为四的int32类型数组。

下面一样的操作,当取完前16个字节后,他会取一些常量,如下

image-20211129013412954

然后整理一下就是这也

                  v48 = *v299;                  // [0x20,0x22,0x23,0x24]
                  v447 = *v295;                 // [flag0,flag1,flag2,flag3]
                  v446 = v48;
                  v445 = vmulq_s32(v447, v48);
                  *v295 = v445;
                  v49 = *v300;                  // [0x37,0x38,0x39,0x3a]
                  v450 = *v295;
                  v449 = v49;
                  v448 = vsubq_s32(v450, vnegq_s32(v49));
                  *v295 = v448;                 // enc0
                  v50 = *v299;                  // [0x20,0x22,0x23,0x24]
                  v468 = *v296;                 // [flag4,flag5,flag6,flag7]
                  v467 = v50;
                  v466 = vmulq_s32(v468, v50);
                  *v296 = v466;
                  v51 = *v300;                  // [0x37,0x38,0x39,0x3a]
                  v465 = *v296;
                  v464 = v51;
                  v463 = vsubq_s32(v465, vnegq_s32(v51));
                  *v296 = v463;                 // enc1
                  v52 = *v301;                  // [0x30,0x31,0x32,0x33]
                  v462 = *v297;                 // [flag8,flag9,flag10,flag11]
                  v461 = v52;
                  v460 = vmulq_s32(v462, v52);
                  *v297 = v460;
                  v53 = *v302;                  // [0x50,0x52,0x53,0x54]
                  v459 = *v297;
                  v458 = v53;
                  v457 = vsubq_s32(v459, vnegq_s32(v53));
                  *v297 = v457;                 // enc2
                  v54 = *v299;                  // [0x20,0x22,0x23,0x24]
                  v456 = *v298;                 // [flag12,flag13,flag14,flag15]
                  v455 = v54;
                  v454 = vmulq_s32(v456, v54);
                  *v298 = v454;
                  v55 = *v300;                  // [0x37,0x38,0x39,0x3a]
                  v453 = *v298;
                  v452 = v55;
                  v451 = vnegq_s32(vsubq_s32(vnegq_s32(v55), v453));// v451=-((-v300)-v453)  v453=v451-v300
                  *v298 = v451;                 // enc3

一开始尝试爆破,然后我发现我傻了,直接求逆不就行了?然后一把梭

enc=[    0x00000CD7, 0x00000698, 0x00000D7C, 0x000006FA, 0x00000CB7, 0x000007CA, 0x0000079B, 0x000007D2,
    0x00000950, 0x00000AD9, 0x00000ADF, 0x000014A6, 0x00000CF7, 0x00000720, 0x00000732,0x000007F6]
v299=[0x20,0x22,0x23,0x24]
v300=[0x37,0x38,0x39,0x3a]
v301=[0x30,0x31,0x32,0x33]
v302=[0x50,0x52,0x53,0x54]
def mul(a,b):
    c=[]
    for i in range(4):
        c.append(a[i] * b[i])
    return c
#set0
c=[]
e=enc[0:4]
for i in range(4):
    c.append(e[i]-v300[i])

for i in range(4):
    print(chr(c[i]//v299[i]),end='')

#set1
c=[]
e=enc[4:8]
for i in range(4):
    c.append(e[i]-v300[i])

for i in range(4):
    print(chr(c[i]//v299[i]),end='')

#set2
c=[]
e=enc[8:12]
for i in range(4):
    c.append(e[i]-v302[i])

for i in range(4):
    print(chr(c[i]//v301[i]),end='')

#set3
c=[]
e=enc[12:16]
for i in range(4):
    c.append(e[i]-v300[i])

for i in range(4):
    print(chr(c[i]//v299[i]),end='')
#e0a0d966076ff437

e0a0d966076ff43758af2715

免费评分

参与人数 6吾爱币 +7 热心值 +6 收起 理由
yjl888 + 1 + 1 热心回复!
LegendSaber + 1 + 1 我很赞同!
wangxinwei121 + 1 + 1 我很赞同!
fengbolee + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
lwj1987 + 1 + 1 我很赞同!
knife9 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

dreamingctf 发表于 2021-12-4 22:36
对“狗狗的秘密”这个题提出几个细节问题:
1)为了 patch 反调试,具体位置在哪里。我在TlsCallBack_0函数以及7811C0函数patch过程中,还是无法进入正确流程。
2)是在IDA里、还是在OD里运行完SMC,才能看关键指针函数783300的malloc(146 * strlen(a1) / 0x64 + 1); 等之后的代码。
现在挡住我的不是后面的算法。而是可以看到完整算法的流程和步骤我复现不出来。所以特来求助。希望您给回复。非常感谢。
qiaopf888 发表于 2021-12-10 09:17
看晕了,需要仔细研读才行。还有那一堆for循环,是不是可以换一种精简写法,如果 100000个for 层怎么办。。。
suxiaosu67 发表于 2021-12-1 11:10
wendalao 发表于 2021-12-1 20:50
大佬nb
ngq0530 发表于 2021-12-1 22:20
不明觉厉
xyz1234 发表于 2021-12-2 06:30
向大佬学习
sean123 发表于 2021-12-2 10:25
学习打卡
偶尔的曾经 发表于 2021-12-3 16:25
哎,这些对于我来说,搞不懂啊,只能呵呵了
cubolia 发表于 2021-12-4 20:45
大佬可以分享一下题目的原题文件吗?
sandon 发表于 2021-12-7 07:59
感谢分享!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 11:39

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表