[2019红帽杯]easyRE

7 篇文章 0 订阅
2 篇文章 0 订阅

首先ida64打开,shift+f12查看字符串,发现有you found me字段,跟进查看调用了它的函数。

发现是sub_4009C6()函数,分析

__int64 sub_4009C6()
{
  __int64 result; // rax
  int i; // [rsp+Ch] [rbp-114h]
  __int64 v2; // [rsp+10h] [rbp-110h]
  __int64 v3; // [rsp+18h] [rbp-108h]
  __int64 v4; // [rsp+20h] [rbp-100h]
  __int64 v5; // [rsp+28h] [rbp-F8h]
  __int64 v6; // [rsp+30h] [rbp-F0h]
  __int64 v7; // [rsp+38h] [rbp-E8h]
  __int64 v8; // [rsp+40h] [rbp-E0h]
  __int64 v9; // [rsp+48h] [rbp-D8h]
  __int64 v10; // [rsp+50h] [rbp-D0h]
  __int64 v11; // [rsp+58h] [rbp-C8h]
  char v12[13]; // [rsp+60h] [rbp-C0h] BYREF
  char v13[4]; // [rsp+6Dh] [rbp-B3h] BYREF
  char v14[19]; // [rsp+71h] [rbp-AFh] BYREF
  char v15[32]; // [rsp+90h] [rbp-90h] BYREF
  int v16; // [rsp+B0h] [rbp-70h]
  char v17; // [rsp+B4h] [rbp-6Ch]
  char v18[72]; // [rsp+C0h] [rbp-60h] BYREF
  unsigned __int64 v19; // [rsp+108h] [rbp-18h]
​
  v19 = __readfsqword(0x28u);
  qmemcpy(v12, "Iodl>Qnb(ocy", 12);
  v12[12] = 127;
  qmemcpy(v13, "y.i", 3);
  v13[3] = 127;
  qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));
  memset(v15, 0, sizeof(v15));
  v16 = 0;
  v17 = 0;
  sub_4406E0(0LL, v15, 37LL);
  v17 = 0;
  if ( sub_424BA0(v15) == 36 )
  {
    for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i )
    {
      if ( (unsigned __int8)(v15[i] ^ i) != v12[i] )
      {
        result = 4294967294LL;
        goto LABEL_13;
      }
    }
    sub_410CC0("continue!");
    memset(v18, 0, 65);
    sub_4406E0(0LL, v18, 64LL);
    v18[39] = 0;
    if ( sub_424BA0(v18) == 39 )
    {
      v2 = sub_400E44(v18);
      v3 = sub_400E44(v2);
      v4 = sub_400E44(v3);
      v5 = sub_400E44(v4);
      v6 = sub_400E44(v5);
      v7 = sub_400E44(v6);
      v8 = sub_400E44(v7);
      v9 = sub_400E44(v8);
      v10 = sub_400E44(v9);
      v11 = sub_400E44(v10);
      if ( !(unsigned int)sub_400360(v11, off_6CC090) )
      {
        sub_410CC0("You found me!!!");
        sub_410CC0("bye bye~");
      }
      result = 0LL;
    }
    else
    {
      result = 4294967293LL;
    }
  }
  else
  {
    result = 0xFFFFFFFFLL;
  }
LABEL_13:
  if ( __readfsqword(0x28u) != v19 )
    sub_444020();
  return result;
}

首先该函数对v12,v13,v14,v15进行了初始化操作,然后sub_4406E0是一个相当于gets的函数,将用户输入的字符串保存到v15中

接下来可以看出sub_424BA0函数是一个相当于strlen的函数,判断输入的字符串长度是否等于36,如果是再进行下一步操作,后续的you found me 输出刚好是在这第一个if条件里面,所以首先flag长度为36,具体是什么再继续进行分析。

下面for循环里面的if条件是一个关键,如果v15里面有一个字符异或i之后和v12里对应的字符不同,就会进行goto 操作,然后结束这个函数。

if ( sub_424BA0(v15) == 36 )
  {
    for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i )
    {
      if ( (unsigned __int8)(v15[i] ^ i) != v12[i] )
      {
        result = 4294967294LL;
        goto LABEL_13;
      }
    }
LABEL_13:
  if ( __readfsqword(0x28u) != v19 )
    sub_444020();

flag要满足的条件之2就是,v15[i] ^ i == v12[i], v12已经给出

但是具体 i 的范围是0~strlen(v15), 也就是说 0<= i < 36,而v12长度只有13,但是注意到这三个数组是连续存放的,所以再访问的时候应该也是连续访问,所以实际上就是三个数组合在一起成为目标数组。

char v12[13]; // [rsp+60h] [rbp-C0h] BYREF
char v13[4]; // [rsp+6Dh] [rbp-B3h] BYREF
char v14[19]; // [rsp+71h] [rbp-AFh] BYREF

按照逻辑,可以编写python脚本:

hint = []
str1 = "Iodl>Qnb(ocy"
for i in range(len(str1)):
    hint.append(ord(str1[i]))
hint.append(127)
​
str2 = "y.i"
for i in range(len(str2)):
    hint.append(ord(str2[i]))
hint.append(127)
​
str3 = "d`3w}wek9{iy=~yL@EC"
​
for i in range(len(str3)):
    hint.append(ord(str3[i]))
str = ""
for i in range(len(hint)):
    str += chr(hint[i] ^ i)
print(str)

结果是

提示说flag的前四位是flag。。。。。

关于v12,v13,v14三个数组是连续的, ida+Ubuntu动态调试证明一下

首先先在调用数组前下断点

进程停留在这里

可以看出这里是连续执行了36次mov操作,将存储在v12,v13,v14中的所有字符都放在了连续的地址中

那么在循环异或的时候,当i大于了v12的数组长度时,实际上取到的值就是v13的元素,类推。

而后是sub_400E44函数被调用了十次,双击查看发现函数的功能是base64编码。

也就是v18被base64编码了10次,最终的结果储存在v11中

然后是if判断,调用了sub_400360函数,是一个类似于strcmp的函数,如果off_6CC090和v11的所有元素都相等,就输出you found me

也就是找到了flag。

然后就是写脚本解码

import base64
lis =           "Vm0wd2VHUXhTWGhpUm1SWVYwZDRWVll3Wkc5WFJsbDNXa1pPVlUxV2NIcFhhMk0xVmpKS1NHVkdXbFpOYmtKVVZtcEtTMUl5VGtsaVJtUk9ZV3hhZVZadGVHdFRNVTVYVW01T2FGSnRVbGhhVjNoaFZWWmtWMXBFVWxSTmJFcElWbTAxVDJGV1NuTlhia0pXWWxob1dGUnJXbXRXTVZaeVdrWm9hVlpyV1hwV1IzaGhXVmRHVjFOdVVsWmlhMHBZV1ZSR1lWZEdVbFZTYlhSWFRWWndNRlZ0TVc5VWJGcFZWbXR3VjJKSFVYZFdha1pXWlZaT2NtRkhhRk5pVjJoWVYxZDBhMVV3TlhOalJscFlZbGhTY1ZsclduZGxiR1J5VmxSR1ZXSlZjRWhaTUZKaFZqSktWVkZZYUZkV1JWcFlWV3BHYTFkWFRrZFRiV3hvVFVoQ1dsWXhaRFJpTWtsM1RVaG9hbEpYYUhOVmJUVkRZekZhY1ZKcmRGTk5Wa3A2VjJ0U1ExWlhTbFpqUldoYVRVWndkbFpxUmtwbGJVWklZVVprYUdFeGNHOVhXSEJIWkRGS2RGSnJhR2hTYXpWdlZGVm9RMlJzV25STldHUlZUVlpXTlZadE5VOVdiVXBJVld4c1dtSllUWGhXTUZwell6RmFkRkpzVWxOaVNFSktWa1phVTFFeFduUlRhMlJxVWxad1YxWnRlRXRXTVZaSFVsUnNVVlZVTURrPQ=="
for i in range(10):
    lis = base64.b64decode(lis)
print(lis)

最后得到的结果是一个网址。。。。

看来是被坑了,这里面应该没有想要的flag

参考WP,发现程序在正常执行后要执行在这里的sub_400D35函数:

跟进查看:

unsigned __int64 sub_400D35()
{
  unsigned __int64 result; // rax
  unsigned int v1; // [rsp+Ch] [rbp-24h]
  int i; // [rsp+10h] [rbp-20h]
  int j; // [rsp+14h] [rbp-1Ch]
  unsigned int v4; // [rsp+24h] [rbp-Ch]
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]
​
  v5 = __readfsqword(0x28u);
  v1 = sub_43FD20(0LL) - qword_6CEE38;
  for ( i = 0; i <= 1233; ++i )
  {
    sub_40F790(v1);
    sub_40FE60();
    sub_40FE60();
    v1 = sub_40FE60() ^ 0x98765432;
  }
  v4 = v1;
  if ( ((unsigned __int8)v1 ^ byte_6CC0A0[0]) == 102 && (HIBYTE(v4) ^ (unsigned __int8)byte_6CC0A3) == 103 )
  {
    for ( j = 0; j <= 24; ++j )
      sub_410E90((unsigned __int8)(byte_6CC0A0[j] ^ *((_BYTE *)&v4 + j % 4)));
  }
  result = __readfsqword(0x28u) ^ v5;
  if ( result )
    sub_444020();
  return result;
}

关键代码区域是第二十行那里的if和for循环,第一个if判断, 可以根据flag和已知数组反向解出v1

后边的for循环可以根据已知数组和v4解出flag

这就是已知数组:

v1 = ''
enc1 = 'flag'
flag = ''
str = [0x40,0x35,0x20,0x56,0x5D,0x18,0x22,0x45,0x17,0x2F,0x24,0x6E,0x62,0x3C,0x27,0x54,0x48,0x6C,0x24,0x6E,0x72,0x3C,0x32,0x45,0x5B]
for i in range(4):
    v1 += chr(str[i] ^ ord(enc1[i]))
print (v1)
​
for i in range(len(str)):
    flag += chr(str[i] ^ ord(v1[i % 4]))
print(flag)

str里是已知数组对应的ASCII码16进制数,变量v1中存放的就是它的地址,然后将其赋值给v4后再在for循环中进行引用。

(&v4 + j % 4也就是v4[j % 4])参考C语言运算符优先级, % > + > &

最后的输出是

也就是说最终结果为

flag{Act1ve_Defen5e_Test}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值