[NPUCTF2020]Baby Obfuscation

题目:[NPUCTF2020]Baby Obfuscation

64位无壳程序
在这里插入图片描述

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v4; // ebx
  int v5; // esi
  int v6; // ebx
  int v7; // ebx
  int v8; // esi
  int v9; // ebx
  int v10; // ebx
  int v11; // ebx
  int v12; // esi
  int v13; // eax
  int v14; // ebx
  int v15; // esi
  int v16; // ebx
  int v17; // eax
  bool v18; // bl
  int v19; // eax
  int v20; // esi
  int v21; // ebx
  int v22; // ebx
  int v23; // eax
  int v24; // eax
  int v25; // eax
  int v26; // ebx
  int v28[68]; // [rsp+20h] [rbp-60h] BYREF
  char Str[1008]; // [rsp+130h] [rbp+B0h] BYREF
  int v30[1008]; // [rsp+520h] [rbp+4A0h] BYREF
  int v31[4]; // [rsp+14E0h] [rbp+1460h]
  int v32; // [rsp+14F0h] [rbp+1470h]
  int k; // [rsp+14F4h] [rbp+1474h]
  int j; // [rsp+14F8h] [rbp+1478h]
  int i; // [rsp+14FCh] [rbp+147Ch]

  _main(argc, argv, envp);
  memset(v30, 0, 0xFA0ui64);
  v30[1000] = 0;
  memset(v28, 0, 0x100ui64);
  v28[64] = 0;
  for ( i = 0; i <= 64; ++i )
    v28[i] = i + 1;
  v31[0] = 2;
  v31[1] = 3;
  v31[2] = 4;
  v31[3] = 5;
  v30[1004] = 2;
  v30[1005] = 3;
  v30[1006] = 4;
  v30[1007] = 5;
  puts("WHERE IS MY KEY!?");
  scanf("%32s", Str);
  v32 = strlen(Str);
  v3 = F0X1(v28[j], v28[j]);
  for ( j = v3 / v28[j]; j <= v32; ++j )
  {
    v4 = (v28[j] + v28[j + 1]) * (v28[j] + v28[j + 1]);
    if ( v4 >= (int)(F0X5(2, 2) * v28[j] * v28[j + 1]) )
    {
      v5 = ~Str[(int)F0X4(j, 1)];
      v6 = F0X4(j, 1);
      v30[j] = ~(v5 + v31[v6 % (int)F0X5(2, 2)]);
    }
    v7 = F0X1(v28[j], v28[j + 1]);
    if ( v7 > (int)F0X1(v28[j + 1], ~(~v28[j + 1] + v28[j])) )
    {
      v8 = v30[j];
      v9 = F0X4(j, 1);
      v30[j] = ~(~v8 + v28[v9 % (int)F0X5(2, 2)]) * v8;
    }
    v10 = v28[j + 1];
    v11 = F0X5(2, 1) * v10;
    v12 = v28[j];
    v13 = F0X5(2, 1);
    v14 = F0X1(v12 * v13, v11);
    v15 = F0X5(2, 1);
    if ( v14 == v15 * (unsigned int)F0X1(v28[j], v28[j + 1]) )
    {
      v16 = F0X4(j, 1);
      v30[j] ^= v31[v16 % (int)F0X5(2, 2)];
    }
    v17 = F0X5(V0X3, v28[j]);
    v18 = v17 < v28[j] + 1;
    v19 = F0X5(2, 4);
    if ( (unsigned __int8)F0X3(v19 >= j, v18) )
    {
      v20 = ~Str[(int)F0X4(j, 1)];
      v21 = F0X4(j, 1);
      v30[j] ^= ~(v20 + v31[v21 % (int)F0X5(2, 2)]);
    }
    v22 = F0X5(2, 3);
    v23 = F0X1(v28[j], v28[j]);
    v30[j] *= v22 + (unsigned int)F0X5(2, v23 / v28[j]);
  }
  v24 = F0X5(2, 4);
  if ( (unsigned int)F0X4(v24, 1) != v32 )
    goto LABEL_23;
  v25 = F0X1(v28[k], v28[k]);
  for ( k = v25 / v28[k]; k <= v32; ++k )
  {
    v26 = v30[k];
    if ( v26 == (int)F0X4(A0X6[k], 1) / 10 )
      ++V0X2;
  }
  if ( V0X2 == v32 )
    puts("\nPASS");
  else
LABEL_23:
    puts("\nDENIED");
  return 0;
}

先分析一下几个处理函数再分析主函数

F0X1

看出来是欧几里得算法,返回a1和a2的最大公约数。

__int64 __fastcall F0X1(unsigned int a1, int a2)
{
  __int64 result; // rax

  if ( a2 )
    result = F0X1(a2, a1 % a2);
  else
    result = a1;
  return result;
}

F0X2 & F0X3

只有两个参数都是1的时候才返回1,别的都返回0。

_BOOL8 __fastcall F0X2(char a1, char a2)
{
  return a1 == a2 && a1 != 1;
}
__int64 __fastcall F0X3(bool a1, bool a2)
{
  char v2; // bl
  char v3; // al

  v2 = F0X2(a2, a2);
  v3 = F0X2(a1, a1);
  return F0X2(v3, v2);
}

F0X4

看着很奇怪的运算,其实就是 a1 - a2。

__int64 __fastcall F0X4(int a1, int a2)
{
  return ~(~a1 + a2);
}

F0X5

返回a1^a2。

__int64 __fastcall F0X5(int a1, int a2)
{
  unsigned int v4; // [rsp+Ch] [rbp-4h]

  v4 = 1;
  while ( a2 )
  {
    if ( (a2 & 1) != 0 )
      v4 *= a1;
    a1 *= a1;
    a2 >>= 1;
  }
  return v4;
}

main

知道了这几个函数的实现就可以看主函数了。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v4; // ebx
  int v5; // esi
  int v6; // ebx
  int v7; // ebx
  int v8; // esi
  int v9; // ebx
  int v10; // ebx
  int v11; // ebx
  int v12; // esi
  int v13; // eax
  int v14; // ebx
  int v15; // esi
  int v16; // ebx
  int v17; // eax
  bool v18; // bl
  int v19; // eax
  int v20; // esi
  int v21; // ebx
  int v22; // ebx
  int v23; // eax
  int v24; // eax
  int v25; // eax
  int v26; // ebx
  int v28[68]; // [rsp+20h] [rbp-60h] BYREF
  char Str[1008]; // [rsp+130h] [rbp+B0h] BYREF
  int v30[1008]; // [rsp+520h] [rbp+4A0h] BYREF
  int v31[4]; // [rsp+14E0h] [rbp+1460h]
  int v32; // [rsp+14F0h] [rbp+1470h]
  int k; // [rsp+14F4h] [rbp+1474h]
  int j; // [rsp+14F8h] [rbp+1478h]
  int i; // [rsp+14FCh] [rbp+147Ch]

  _main(argc, argv, envp);
  memset(v30, 0, 0xFA0ui64);
  v30[1000] = 0;
  memset(v28, 0, 0x100ui64);
  v28[64] = 0;
  for ( i = 0; i <= 64; ++i )
    v28[i] = i + 1;
  v31[0] = 2;
  v31[1] = 3;
  v31[2] = 4;
  v31[3] = 5;
  v30[1004] = 2;
  v30[1005] = 3;
  v30[1006] = 4;
  v30[1007] = 5;
  puts("WHERE IS MY KEY!?");
  scanf("%32s", Str);
  v32 = strlen(Str);
  v3 = F0X1(v28[j], v28[j]);                    // v3=v28[j]
  for ( j = v3 / v28[j]; j <= v32; ++j )
  {
    v4 = (v28[j] + v28[j + 1]) * (v28[j] + v28[j + 1]);// v4=(2j+3)^2=4j^2+12j+18(数学表达式)
    if ( v4 >= (F0X5(2, 2) * v28[j] * v28[j + 1]) )// 满足
    {
      v5 = ~Str[F0X4(j, 1)];                    // v5 = ~Str[j-1]
      v6 = F0X4(j, 1);                          // v6=j-1
      v30[j] = ~(v5 + v31[v6 % F0X5(2, 2)]);    // v30[j]=Str[j-1]-v31[(j-1)%4]
    }
    v7 = F0X1(v28[j], v28[j + 1]);
    if ( v7 > F0X1(v28[j + 1], ~(~v28[j + 1] + v28[j])) )// 不满足
    {
      v8 = v30[j];
      v9 = F0X4(j, 1);
      v30[j] = ~(~v8 + v28[v9 % F0X5(2, 2)]) * v8;
    }
    v10 = v28[j + 1];                           // v10=j+2
    v11 = F0X5(2, 1) * v10;                     // v11=2*j+4
    v12 = v28[j];                               // v12=j+1
    v13 = F0X5(2, 1);                           // v13=2
    v14 = F0X1(v12 * v13, v11);                 // v14=gcd(2*j+2,2*j+4)
    v15 = F0X5(2, 1);                           // v15=2
    if ( v14 == v15 * F0X1(v28[j], v28[j + 1]) )// 满足
    {
      v16 = F0X4(j, 1);
      v30[j] ^= v31[v16 % F0X5(2, 2)];          // v30[j] ^=v31[(j-1)%4]
    }
    v17 = F0X5(V0X3, v28[j]);
    v18 = v17 < v28[j] + 1;                     // v18=0
    v19 = F0X5(2, 4);
    if ( F0X3(v19 >= j, v18) )                  // 不满足
    {
      v20 = ~Str[F0X4(j, 1)];
      v21 = F0X4(j, 1);
      v30[j] ^= ~(v20 + v31[v21 % F0X5(2, 2)]);
    }
    v22 = F0X5(2, 3);
    v23 = F0X1(v28[j], v28[j]);
    v30[j] *= v22 + F0X5(2, v23 / v28[j]);      // v30[j] *= 10;
  }
  v24 = F0X5(2, 4);
  if ( F0X4(v24, 1) != v32 )
    goto LABEL_23;
  v25 = F0X1(v28[k], v28[k]);
  for ( k = v25 / v28[k]; k <= v32; ++k )       // k=1
  {
    v26 = v30[k];
    if ( v26 == F0X4(A0X6[k], 1) / 10 )         // v30[k]== (A0X6[k] - 1) / 10;
                                                // A0X6[]={0, 1E79h, 1E79h, 2135h, 170Dh, 1F41h,1901h, 2CEDh,11F9h, 2649h, 2581h,2DB5h, 14B5h, 25E5h, 2A31h, 30D5h.0,0, 415770h, 0,0,0,0,0}
      ++V0X2;
  }
  if ( V0X2 == v32 )
    puts("\nPASS");
  else
LABEL_23:
    puts("\nDENIED");
  return 0;
}

不难看出,v30数组是跟flag有密切联系的。进一步排查,其中v30的赋值语句中只有下面三个与flag加密有关。

  • v30[j] = ~(v5 + v31[v6 % F0X5(2, 2)]);
  • v30[j] ^= v31[v16 % F0X5(2, 2)];
  • v30[j] *= v22 + F0X5(2, v23 / v28[j]);

这三个等价于

  • v30[j]=Str[j-1]-v31[(j-1)%4]
  • v30[j] ^=v31[(j-1)%4]
  • v30[j] *= 10;

EXP

A0X6=[0x0, 0x1E79, 0x1E79, 0x2135, 0x170D, 0x1F41,0x1901, 0x2CED,0x11F9, 0x2649, 0x2581,0x2DB5, 0x14B5, 0x25E5, 0x2A31, 0x30D5,0x0,0x0,0x415770,0x0,0x0,0x0,0x0,0x0]
flag=''
v31=[2,3,4,5]
for j in range(1,len(A0X6)):
	A0X6[j]//=100      #两次乘10
	A0X6[j]^=v31[(j-1)%4]
	A0X6[j]+=v31[(j-1)%4]
	flag+=chr(A0X6[j])
print(flag)

在这里插入图片描述

flag{0bfu5er}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Em0s_Er1t

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值