buuctf Dig the way 题解

一道很有意思的题,写wp记录一下。

题目自带ida文件,打开。

主函数逻辑

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax
  int v4; // ebx
  size_t v5; // eax
  int v6; // ebx
  char Str[20]; // [esp+1Ch] [ebp-48h] BYREF
  _DWORD v8[3]; // [esp+30h] [ebp-34h] BYREF
  size_t v9; // [esp+3Ch] [ebp-28h]
  int v10; // [esp+40h] [ebp-24h]
  int v11; // [esp+44h] [ebp-20h]
  _DWORD v12[3]; // [esp+48h] [ebp-1Ch]
  int v13; // [esp+54h] [ebp-10h]
  size_t len; // [esp+58h] [ebp-Ch]
  FILE *v15; // [esp+5Ch] [ebp-8h]

  __main();
  v12[0] = func0;                               // exchange
  v12[1] = func1;                               // |x+y|-|x|-|y|+2
  v12[2] = func2;                               // |x|+|y|+2-|x+y|
  v8[0] = 0;
  v8[1] = 1;
  v8[2] = 2;
  v9 = 3;
  v10 = 3;
  v11 = 4;
  v15 = fopen("data", "rb");
  if ( !v15 )
    return -1;
  fseek(v15, 0, 2);
  len = ftell(v15);
  fseek(v15, 0, 0);
  v13 = ftell(v15);
  if ( v13 )
  {
    puts("something wrong");
    result = 0;
  }
  else
  {
    for ( i = 0; i < len; ++i )
    {
      v4 = i;
      Str[v4] = fgetc(v15);
    }
    v5 = strlen(Str);
    if ( v5 <= len )
    {
      len = v9;
      i = 0;
      v13 = v11;
      while ( i <= 2 )
      {
        v6 = i + 1;
        v8[v6] = (v12[i])(v8, v10, v11);
        v10 = ++i;
        v11 = i + 1;
      }
      if ( v9 )
      {
        result = -1;
      }
      else
      {
        get_key(len, v13);
        system("PAUSE");
        result = 0;
      }
    }
    else
    {
      result = -1;
    }
  }
  return result;
}

get key函数打印flag。一开始简单看了下逻辑,发现参数就是3,4,遂写了个脚本跑了一遍,结果是flag: 20c2030ccc203002;直接wa。。。。。

说明里面有玄机,再次认真看看函数。

这里,在前面的赋值中v9=3,如果没有差错getkey函数不会被执行。

可能猫腻出在上面的加密里,看一看循环的逻辑。

三个函数都不复杂。v10,v11为下标。观察函数,发现在第三次循环时,赋值的对象是v8[3],超出了v8的范围,观察数据,发现v8[3]正好为v9。所以第三次循环的结果为v9时可以得到正确的执行路线。

再看前面的函数。函数打开了一个data文件,从里面读入字符填充str(长度20)这里v14相当于文件大小,v5为字符串长度,构造字节数量大于20的文件就可以满足执行

看完了逻辑来捋一遍思路。我们需要构造一个data,满足长度大于20,同时使第三次循环时函数返回值为0就可以解出flag。

按照正常逻辑,第三次循环的函数返回值是|x|+|y|+2-|x+y|,这个式子恒大于0。。

让我们奇思妙想。观察数据栈

(这是我命名后的样子)

既然第三个函数恒大于0;我们能不能通过第二个函数|x+y|-|x|-|y|+2来得到0呢,巧妙的是,我们可以通过第一个函数交换两个函数指针所指向的函数(在栈上可以看出,函数2,3分别对应v8[7],v8[8])从而实现构造0。而v8数组又可以通过data来控制。

现在我们可以开始构造data文件了。使用010editor

注意小端序存储。

前20个数据存入str,然后是v8数组(四个字节)。现在开始构造函数输入的数据。|x|+|y|+2-|x+y|这个式子当x,y大于零时,恒等于2。所以在|x+y|-|x|-|y|+2中,构造x=-1,y=2即可得到0

因此数组的前三个我们可以不管。第四个也就是v8[3],我们令它为0xffffffff(-1)

再往下是第一次函数交换时v8的下标,改为7和8。

保存后运行题目文件,得到flag。

flag{8cda1bdb68a72a392a3968a71bdb8cda}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值