2021强网杯 LongTimeAgo

我们这题被锤了,理由是与摘星实验室wp重合度高

重合度有多高我不知道,但是我们所有人都压根没听说过这个实验室

所以在这里放一个更加细致的wp,不想让几十个小时的努力付之东流。

文件打开了,函数很多,有3800个

先查字符串,对照着程序的运行结果

找到main函数

在这里,IDA 7.0无法很好的解释该程序,导致F5得到结果看起来正确但实际并不完整。

而IDA 7.6则会显著的标出错误部分,方便汇编代码上的审查

2021强网杯 LongTimeAgo

这是IDA7.6最初分析出来的main函数

看一下汇编代码,发现其中有很多字节码的混淆

2021强网杯 LongTimeAgo2021强网杯 LongTimeAgo

这些才是导致IDA误判函数内容的原因

手动修复一下

得到main函数

void __usercall sub_4A2980(__int64 a1@<rbx>, __int64 a2@<rbp>, __int64 a3@<rdi>, __int64 a4@<rsi>, __int64 a5@<r12>, __int64 a6@<r13>, __int64 a7@<r14>, __int64 a8@<r15>)
{
  char *v8; // r15
  char *v9; // rdi
  int *v10; // r12
  char *v11; // r14
  char *v12; // rbx
  char *v13; // r13
  int v14; // eax
  signed __int64 v15; // rax
  int v16; // edx
  int v17; // eax
  signed __int64 v18; // rax
  int v19; // edx
  int v20; // ecx
  int v21; // eax
  __int64 v22; // rax
  char v23; // dl
  char v24; // [rsp+30h] [rbp-3F8h]
  __int64 v25; // [rsp+70h] [rbp-3B8h]
  char v26; // [rsp+80h] [rbp-3A8h]
  __int64 v27; // [rsp+C8h] [rbp-360h]
  __int64 v28; // [rsp+110h] [rbp-318h]
  __int64 v29; // [rsp+158h] [rbp-2D0h]
  char v30; // [rsp+1A0h] [rbp-288h]
  int v31; // [rsp+1C4h] [rbp-264h]
  __int64 v32; // [rsp+1E8h] [rbp-240h]
  int v33; // [rsp+20Ch] [rbp-21Ch]
  char v34; // [rsp+2C0h] [rbp-168h]
  char v35[8]; // [rsp+3E0h] [rbp-48h]

  sub_40CC40();
  memset(&v24, 0, 0x50ui64);
  sub_49F840(&unk_4A68E0, "Input Your Key:");
  sub_4A04A0(&unk_4A6580, &v24);
  if ( strlen(&v24) == 64 )
  {
    if ( __OFADD__(1, 2004318072) )
    {
      if ( !__OFADD__(1, 2004318072) )
        JUMPOUT(*(_QWORD *)&byte_4A2A4F);
    }
    v8 = &v24;
    v9 = &v34;
    v10 = (int *)&unk_4A4020;
    v11 = &v34;
    sub_49F840(&unk_4A68E0, "Are You Sure You Want To Keep Waiting...\n");
    v12 = &v26;
    v13 = &v26;
    do
    {
      v14 = sub_401DB0(v8, 8i64);
      v12[8] = 0;
      *((_DWORD *)v12 + 1) = v14;
      v15 = 4i64;
      while ( 1 )
      {
        v16 = v15;
        if ( v12[v15 + 3] )
          break;
        if ( !--v15 )
        {
          v16 = 0;
          break;
        }
      }
      *(_DWORD *)v12 = v16;
      v17 = *v10;
      v11[8] = 0;
      *((_DWORD *)v11 + 1) = v17;
      v18 = 4i64;
      while ( 1 )
      {
        v19 = v18;
        if ( v11[v18 + 3] )
          break;
        if ( !--v18 )
        {
          v19 = 0;
          break;
        }
      }
      v8 += 8;
      *(_DWORD *)v11 = v19;
      v12 += 36;
      v11 += 36;
      ++v10;
    }
    while ( v8 != (char *)&v25 );
    sub_403460(&v30, 13i64);
    sub_403460(&v31, 14i64);
    sub_403460(&v32, 15i64);
    sub_403460(&v33, 16i64);
    sub_4029E0(&v26, &v30);
    sub_4029E0(&v27, &v30);
    sub_402030(&v28, &v30);
    sub_402030(&v29, &v30);
    v20 = 0;
    while ( 1 )
    {
      v21 = *(_DWORD *)v13;
      if ( *(_DWORD *)v13 != *(_DWORD *)v9 )
        break;
      if ( v21 - 1 >= 0 )
      {
        if ( v35[36 * v20 - 861 + v21] != v35[36 * v20 - 285 + v21] )
          break;
        v22 = v21 - 2;
        while ( (signed int)v22 >= 0 )
        {
          v23 = v13[v22-- + 4];
          if ( v23 != v9[v22 + 5] )
            goto LABEL_2;
        }
      }
      ++v20;
      v13 += 36;
      v9 += 36;
      if ( v20 == 8 )
      {
        sub_401550("QWB{%s}\n");
        return;
      }
    }
  }
LABEL_2:
  sub_401550("sorry\n");
}

第一关做了一个小判断,在修复函数前是很难看出来什么意思的

但也可以用x64dbg进行动态调试,勉强能够猜出是判断字符串的长度是不是等于0x40

之后遇到一个很费时的一个函数401EF0

进去之后基本看不懂,但是输入是写死的,只需要把每一个返回值找到就行了

记录下这些返回值,就是产生的key

key = [0xfffd,0x1fffd,0x3fffd,0x7fffd]

在下面的函数中被用到

随后来到函数sub_403460

2021强网杯 LongTimeAgo

看到这里(v16>>11) & 3

基本上就能猜出来是XTEA加密了

同时delta是0xE6EF3D20 sum是0x70C88617

其中的运算符全部用函数来代替了

接着再看sub_402030

2021强网杯 LongTimeAgo

里面又出现了401EF0函数,用来产生一个值

再往下看又遇见了xor函数

即把密文与401EF0产生的值进行异或操作

这四个函数都是相同的操作

依次找出所有的异或值

0xfd,0x1fd,0x3fd,0x7fd

然后就是进行字符串的比对了

2021强网杯 LongTimeAgo

由此写出脚本

def TEAdecode(c, key):
    tmp_0 = c[0]
    tmp_1 = c[1]
    sum = 0xa6a53780
    delta = 0x3d3529bc
    for i in range(32):
        tmp_1 -= ((tmp_0<<4) + key[2]) ^ (tmp_0 + sum) ^ ((tmp_0>>5) + key[3])
        tmp_1 &= 0xffffffff
        tmp_0 -= ((tmp_1<<4) + key[0]) ^ (tmp_1 + sum) ^ ((tmp_1>>5) + key[1])
        tmp_0 &= 0xffffffff
        sum -= delta
    return (tmp_0, tmp_1)
 
def XTEAdecode(circle, c, key):
    tmp_0 = c[0]
    tmp_1 = c[1]
    delta = 0x70C88617
    sum = 0xE6EF3D20
    for i in range(circle):    
        tmp_1 -= (((tmp_0 << 4) ^ (tmp_0 >> 5)) + tmp_0) ^ (sum + key[(sum>>11) & 3])
        tmp_1 &= 0xffffffff        
        sum += delta;  
        tmp_0 -= (((tmp_1 << 4) ^ (tmp_1 >> 5)) + tmp_1) ^ (sum + key[sum & 3])
        tmp_0 &= 0xffffffff
    return (tmp_0, tmp_1)


 
c = [0x1F306772, 0xB75B0C29, 0x4A7CDBE3, 0x2877BDDF, 0x1354C485, 0x357C3C3A, 0x738AF06C, 0x89B7F537]
key = [0xfffd,0x1fffd,0x3fffd,0x7fffd]



for i in range(0, 4, 2):
    c[i] ^= 0xfd
    c[i+1] ^= 0x1fd
for i in range(4, 8, 2):
    c[i] ^= 0x3fd
    c[i+1] ^= 0x7fd
 

flag = ''  
for i in range(0, 4, 2):
    ans = XTEAdecode(32, c[i:], key)
    flag += hex(ans[0])[2:] + hex(ans[1])[2:]
for i in range(4, 8, 2):
    ans = TEAdecode(c[i:], key)
    flag += hex(ans[0])[2:] + hex(ans[1])[2:]
print("QWB{"+flag.upper()+"}")

不知道是不是因为xtea和tea解密脚本相似度高的原因

但是如果是因为这个而ban掉参赛队伍,未免不太负责.毕竟解密脚本全网统一,我也是从网上找的代码....

上一篇:BUUCTF Reverse [RoarCTF2019]polyre


下一篇:lldb常用指令