'); }

强网杯_LongTimeAgo


64位无壳,ida,会发现有花指令,手动去除就行了

image-20211019005841442

去掉后的主函数内容:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *v3; // rdx
  int v4; // ecx
  unsigned int v5; // eax
  char *v7; // r15
  char *v8; // rdi
  int *v9; // r12
  char *v10; // r14
  char *v11; // rbx
  char *v12; // r13
  int v13; // eax
  __int64 v14; // rax
  int v15; // edx
  int v16; // eax
  __int64 v17; // rax
  int v18; // edx
  int v19; // ecx
  int v20; // eax
  __int64 v21; // rax
  char v22; // dl
  char v23[80]; // [rsp+30h] [rbp-3F8h] BYREF
  char v24[72]; // [rsp+80h] [rbp-3A8h] BYREF
  __int64 v25; // [rsp+C8h] [rbp-360h] BYREF
  __int64 v26; // [rsp+110h] [rbp-318h] BYREF
  __int64 v27; // [rsp+158h] [rbp-2D0h] BYREF
  char v28[36]; // [rsp+1A0h] [rbp-288h] BYREF
  int v29; // [rsp+1C4h] [rbp-264h] BYREF
  __int64 v30; // [rsp+1E8h] [rbp-240h] BYREF
  int v31; // [rsp+20Ch] [rbp-21Ch] BYREF
  char v32[360]; // [rsp+2C0h] [rbp-168h] BYREF

  sub_40CC40(argc, argv, envp);
  memset(v23, 0, sizeof(v23));
  printf_0(byte_4A68E0, "Input Your Key:");
  scanf(byte_4A6580, v23);
  v3 = v23;
  do
  {
    v4 = *(_DWORD *)v3;
    v3 += 4;
    v5 = ~v4 & (v4 - 16843009) & 0x80808080;
  }
  while ( !v5 );
  if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
    v5 >>= 16;
  if ( (~v4 & (v4 - 16843009) & 0x8080) == 0 )
    v3 += 2;
  if ( &v3[-__CFADD__((_BYTE)v5, (_BYTE)v5) - 3] - v23 == 64 )
  {
    if ( __OFADD__(1, 2004318072) && !__OFADD__(1, 2004318072) )
      JUMPOUT(0x4A2A4Fi64);
    v7 = v23;
    v8 = v32;
    v9 = (int *)&unk_4A4020;
    v10 = v32;
    printf_0(byte_4A68E0, "Are You Sure You Want To Keep Waiting...\n");
    v11 = v24;
    v12 = v24;
    do
    {
      v13 = sub_401DB0(v7, 8i64);
      v11[8] = 0;
      *((_DWORD *)v11 + 1) = v13;
      v14 = 4i64;
      while ( 1 )
      {
        v15 = v14;
        if ( v11[v14 + 3] )
          break;
        if ( !--v14 )
        {
          v15 = 0;
          break;
        }
      }
      *(_DWORD *)v11 = v15;
      v16 = *v9;
      v10[8] = 0;
      *((_DWORD *)v10 + 1) = v16;
      v17 = 4i64;
      while ( 1 )
      {
        v18 = v17;
        if ( v10[v17 + 3] )
          break;
        if ( !--v17 )
        {
          v18 = 0;
          break;
        }
      }
      v7 += 8;
      *(_DWORD *)v10 = v18;
      v11 += 36;
      v10 += 36;
      ++v9;
    }
    while ( v7 != &v23[64] );
    sub_403460(v28, 13i64);
    sub_403460(&v29, 14i64);
    sub_403460(&v30, 15i64);
    sub_403460(&v31, 16i64);
    sub_4029E0(v24, v28);
    sub_4029E0(&v25, v28);
    sub_402030(&v26, v28);
    sub_402030(&v27, v28);
    v19 = 0;
    while ( 1 )
    {
      v20 = *(_DWORD *)v12;
      if ( *(_DWORD *)v12 != *(_DWORD *)v8 )
        break;
      if ( v20 - 1 >= 0 )
      {
        if ( v32[36 * v19 - 573 + v20] != v32[36 * v19 + 3 + v20] )
          break;
        v21 = v20 - 2;
        while ( (int)v21 >= 0 )
        {
          v22 = v12[v21-- + 4];
          if ( v22 != v8[v21 + 5] )
            goto LABEL_8;
        }
      }
      ++v19;
      v12 += 36;
      v8 += 36;
      if ( v19 == 8 )
      {
        sub_401550("QWB{%s}\n", v23);
        return 0;
      }
    }
  }
LABEL_8:
  sub_401550("sorry\n");
  return 0;
}

逐步分析逻辑:

image-20211019005909063

这里进行了一个判断,判断是否等于64,动调可以知道,这里其实就是判断输入值的长度

image-20211019005923674

然后就是一些操作,都没有影响我们的输入值。

最关键的是接下来的几个函数:

image-20211019005938572

前面四个实际上是创造四个key值,内部函数如下:

void __fastcall make_key(__int64 a1, int a2)
{
  int v3; // eax
  __int64 v4; // rax
  int v5; // edx

  v3 = sub_401EF0(3, a2);                       // 内部malloc了一大堆空间,并且没有进行释放
  *(_BYTE *)(a1 + 8) = 0;
  *(_DWORD *)(a1 + 4) = v3;
  v4 = 4i64;
  while ( 1 )
  {
    v5 = v4;
    if ( *(_BYTE *)(a1 + v4 + 3) )
      break;
    if ( !--v4 )
    {
      v5 = 0;
      break;
    }
  }
  *(_DWORD *)a1 = v5;
}

由于开拓的内存空间并没有释放,会导致并不能直接动调获取,非要动调需要花费一定的时间,换个思路,可以通过部分区间动调判断函数内部进行了什么操作

image-20211019010041434

可以确定RDX寄存器保存a2的值,RAX寄存器为函数输出值,动调获取多组数据,判断函数内部进行的操作,规律如下:

RDX  RAX    10进制   差值
0X0  0X5    5        -
0x1  0xD    13       8         
0x2  0x1D   29       16        //从这里开始,可以视作等比数列求和+13
0x3  0x3D   61       32
0x4  0x7D   125      64
0x5  0xFD   253      128
0x6  0x1FD  509      256
0x7  0x3FD  1021     512
0x8  0x7FD  2045     1024
0x9  0XFFD  4093     2048
......

基本确定规律:类似于求一个等比数列的和

   {5,n=0
Sn={13,n=1
   {((2<<(input-2))-1)*16+13,n>1

推出四个key值:

0xfffd,0x1fffd,0x3fffd,0x7fffd

加密部分:
xtea加密内部,主要内容:

sum = 0;
  do
  {
    left_move((__int64)v72, &a2, 4);            // v72=a2<<4
    right_move((__int64)v73, &a2, 5);           // v73=a2>>5
    Xor(v74, v72, v73);                         // v74=v72^v73
    Plus(v75, v74, &a2);                        // v75=v74+a2
    v58 = 0;
    v14 = 4i64;
    v57 = sum;
    while ( 1 )
    {
      v15 = v14;
      if ( *((_BYTE *)&v56 + v14 + 3) )
        break;
      if ( !--v14 )
      {
        v15 = 0;
        break;
      }
    }
    v56 = v15;
    v16 = sum & 3;
    sum -= 0x70C88617;                          // sum+=0x8F3779E9
    Plus(v76, &v56, &key[9 * v16]);
    Xor(v77, v75, v76);                         // all:v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3])    sum+=0x8F3779E9
    Plus(&v52, &v52, v77);
    left_move((__int64)v78, &v52, 4);
    right_move((__int64)v79, &v52, 5);
    Xor(v80, v78, v79);
    Plus(v81, v80, &v52);
    v58 = 0;
    v17 = 4i64;
    v57 = sum;
    while ( 1 )
    {
      v18 = v17;
      if ( *((_BYTE *)&v56 + v17 + 3) )
        break;
      if ( !--v17 )
      {
        v18 = 0;
        break;
      }
    }
    v56 = v18;
    Plus(v82, &v56, &key[9 * ((sum >> 11) & 3)]);
    Xor(v84, v81, v82);
    Plus(&a2, &a2, v84);                        // all:v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])
  }
  while ( sum != 0xE6EF3D20 );                  // 0xE6EF3D20=-0x1910C2E0 ==>-9e3779b9//6

然后对值进行了Xor处理,是一个变种xtea,tea加密过程一样,也是有点小改动的加密
其中delta的值:
image-20211019010405937

同样对值进行了Xor处理,简单计算可以得:delta=0x3d3529bc
最后一部分,判断:
image-20211019010435755

解题脚本:

#include<stdio.h>
#include <stdint.h>
void xtea_decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0]^0xfd, v1=v[1]^0x1fd, delta=0x8F3779E9, sum=delta * num_rounds;
    for (i=0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}
void tea_decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0]^0x3fd, v1=v[1]^0x7fd, sum=0xA6A53780, i;  
    uint32_t delta=0x3d3529bc;                     
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   
    for (i=0; i<32; i++) {                         
        v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }                                              
    v[0]=v0; v[1]=v1;
}
int main()
{
    uint32_t v[8]={0x1F306772,0xB75B0C29,0x4A7CDBE3,0x2877BDDF,0x1354C485,0x357C3C3A,0x738AF06C,0x89B7F537},arr[2],k[4]={0xfffd,0x1fffd,0x3fffd,0x7fffd};
    unsigned int num_rounds=0;
    int sum=0;
    do{
        sum-=0x70C88617;
        num_rounds++;
    }while(sum!=0xE6EF3D20);
    for(int i=0;i<8;i+=2)
    {
        if(i<4)
        {
            arr[0]=v[i];
            arr[1]=v[i+1];
            xtea_decipher(num_rounds,arr,k);
        }
        else
        {
            arr[0]=v[i];
            arr[1]=v[i+1];
            tea_decrypt(arr,k);
        }
        printf("%08X%08X",arr[0],arr[1]);
    }
}
//answer:QWB{CD402B6A139283822F0DEA49E65794356F44EA9B3F56652F2DA39881EC491878}

  目录