[buuctf][gwctf 2019]xxor

[gwctf 2019]xxor

思路

还是先查壳和系统elf可执行文件,64位系统,之后我们打开
在这里插入图片描述
放入ida中,先在linux下运行一下看看开始的字符串是什么
在这里插入图片描述
查找字符串找到位置

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed int i; // [rsp+8h] [rbp-68h]
  signed int j; // [rsp+Ch] [rbp-64h]
  __int64 v6; // [rsp+10h] [rbp-60h]
  __int64 v7; // [rsp+18h] [rbp-58h]
  __int64 v8; // [rsp+20h] [rbp-50h]
  __int64 v9; // [rsp+28h] [rbp-48h]
  __int64 v10; // [rsp+30h] [rbp-40h]
  __int64 v11; // [rsp+40h] [rbp-30h]
  __int64 v12; // [rsp+48h] [rbp-28h]
  __int64 v13; // [rsp+50h] [rbp-20h]
  __int64 v14; // [rsp+58h] [rbp-18h]
  __int64 v15; // [rsp+60h] [rbp-10h]
  unsigned __int64 v16; // [rsp+68h] [rbp-8h]

  v16 = __readfsqword(0x28u);
  puts("Let us play a game?");
  puts("you have six chances to input");
  puts("Come on!");
  v6 = 0LL;
  v7 = 0LL;
  v8 = 0LL;
  v9 = 0LL;
  v10 = 0LL;
  for ( i = 0; i <= 5; ++i )
  {
    printf("%s", "input: ", (unsigned int)i);
    a2 = (char **)((char *)&v6 + 4 * i);
    __isoc99_scanf("%d", a2);
  }
  v11 = 0LL;
  v12 = 0LL;
  v13 = 0LL;
  v14 = 0LL;
  v15 = 0LL;
  for ( j = 0; j <= 4; j += 2 )
  {
    dword_601078 = *((_DWORD *)&v6 + j);
    dword_60107C = *((_DWORD *)&v6 + j + 1);
    a2 = (char **)&unk_601060;
    sub_400686((unsigned int *)&dword_601078, &unk_601060);
    *((_DWORD *)&v11 + j) = dword_601078;
    *((_DWORD *)&v11 + j + 1) = dword_60107C;
  }
  if ( (unsigned int)sub_400770(&v11, a2) != 1 )
  {
    puts("NO NO NO~ ");
    exit(0);
  }
  puts("Congratulation!\n");
  puts("You seccess half\n");
  puts("Do not forget to change input to hex and combine~\n");
  puts("ByeBye");
  return 0LL;
}

追到了这里,之后稍微修正一下变的容易阅读一些。

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  signed int i; // [rsp+8h] [rbp-68h]
  signed int j; // [rsp+Ch] [rbp-64h]
  __int64 v6[0]; // [rsp+10h] [rbp-60h]
  __int64 v6[1]; // [rsp+18h] [rbp-58h]
  __int64 v6[2]; // [rsp+20h] [rbp-50h]
  __int64 v6[3]; // [rsp+28h] [rbp-48h]
  __int64 v6[4]; // [rsp+30h] [rbp-40h]
  __int64 v7[0]; // [rsp+40h] [rbp-30h]
  __int64 v7[1]; // [rsp+48h] [rbp-28h]
  __int64 v7[2]; // [rsp+50h] [rbp-20h]
  __int64 v7[3]; // [rsp+58h] [rbp-18h]
  __int64 v7[4]; // [rsp+60h] [rbp-10h]
  unsigned __int64 v16; // [rsp+68h] [rbp-8h]

  v16 = __readfsqword(0x28u);
  puts("Let us play a game?");
  puts("you have six chances to input");
  puts("Come on!");
  v6[0] = 0LL;
  v6[1] = 0LL;
  v6[2] = 0LL;
  v6[3] = 0LL;
  v6[4] = 0LL;
  for ( i = 0; i <= 5; ++i )
  {
    printf("%s", "input: ", (unsigned int)i);
    __isoc99_scanf("%d", (char *)&v6[0] + 4 * i);
  }
  v7[0] = 0LL;
  v7[1] = 0LL;
  v7[2] = 0LL;
  v7[3] = 0LL;
  v7[4] = 0LL;
  for ( j = 0; j <= 4; j += 2 )
  {
    dword_601078 = *((_DWORD *)&v6[0] + j);
    dword_60107C = *((_DWORD *)&v6[0] + j + 1);
    sub_400686((unsigned int *)&dword_601078, &unk_601060);// unk_601060 == 2,2,3,4
    *((_DWORD *)&v7[0] + j) = dword_601078;
    *((_DWORD *)&v7[0] + j + 1) = dword_60107C;
  }
  if ( (unsigned int)sub_400770(&v7[0]) != 1 )
  {
    puts("NO NO NO~ ");
    exit(0);
  }
  puts("Congratulation!\n");
  puts("You seccess half\n");
  puts("Do not forget to change input to hex and combine~\n");
  puts("ByeBye");
  return 0LL;
}

之后开始反着来先进入sub_400700函数中查看

signed __int64 __fastcall sub_400770(_DWORD *a1)
{
  signed __int64 result; // rax

  if ( a1[2] - a1[3] != 2225223423LL || a1[3] + a1[4] != 4201428739LL || a1[2] - a1[4] != 1121399208LL )
  {
    puts("Wrong!");
    result = 0LL;
  }
  else if ( *a1 != -548868226 || a1[5] != -2064448480 || a1[1] != 550153460 )
  {
    puts("Wrong!");
    result = 0LL;
  }
  else
  {
    puts("good!");
    result = 1LL;
  }
  return result;
}

这里就需要运算了,这里要注意最好转成十六进制,因为整数和无类型数,最后得到的答案是不一样的,之后利用python脚本计算出,这些数值是什么,为了以后做准备,脚本在下面,之后进入上面那个函数sub_400686中查看

__int64 __fastcall sub_400686(unsigned int *a1, _DWORD *a2)
{
  __int64 result; // rax
  unsigned int v3; // [rsp+1Ch] [rbp-24h]
  unsigned int v4; // [rsp+20h] [rbp-20h]
  int v5; // [rsp+24h] [rbp-1Ch]
  unsigned int i; // [rsp+28h] [rbp-18h]

  v3 = *a1;
  v4 = a1[1];
  v5 = 0;
  for ( i = 0; i <= 0x3F; ++i )
  {
    v5 += 1166789954;
    v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
    v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
  }
  *a1 = v3;
  result = v4;
  a1[1] = v4;
  return result;
}

又是一个表达式,之后进行反向的运算即可。

脚本

python利用z3约束来计算。

from z3 import *

a0, a1, a2, a3, a4, a5 = Ints('a0 a1 a2 a3 a4 a5')
s = Solver()
s.add(a2 - a3 == 0x84A236FF)
s.add(a3 + a4 == 0xFA6CB703)
s.add(a2 - a4 == 0x42D731A8)
s.add(a0 == 0xDF48EF7E)
s.add(a5 == 0x84F30420)
s.add(a1 == 0x20CAACF4)
if s.check() == sat:
    print(s.model())

得到a0-a5是

[a2 = 3774025685,
 a1 = 550153460,
 a5 = 2230518816,
 a0 = 3746099070,
 a3 = 1548802262,
 a4 = 2652626477]

之后那时候我说了一嘴那个无类型的问题,如果我用直接十进制计算。

from z3 import *

a0, a1, a2, a3, a4, a5 = Ints('a0 a1 a2 a3 a4 a5')
s = Solver()
s.add(a2 - a3 == 2225223423)
s.add(a3 + a4 == 4201428739)
s.add(a2 - a4 == 1121399208)
s.add(a0 == -548868226)
s.add(a5 == -2064448480)
s.add(a1 == 550153460)
if s.check() == sat:
    print(s.model())

答案会变成

[a2 = 3774025685,
 a1 = 550153460,
 a5 = -2064448480,
 a0 = -548868226,
 a3 = 1548802262,
 a4 = 2652626477]

所以推荐如果是无类型,最好是转换成十六进制之后利用z3进行约束计算。
之后利用c语言写sub_400686脚本,我写的尽量是按照他的格式进行写的,为了能看明白

#include <stdio.h>
int main()
{
    int a1[6] = { 3746099070,550153460,3774025685,1548802262,2652626477,2230518816 };
    unsigned int a2[4] = { 2,2,3,4 };
    unsigned int v3;
    unsigned int v4;
    int v5;
    for (unsigned int j = 0; j < 5; j += 2)
    {
        v3 = a1[j];
        v4 = a1[j + 1];
        v5 = 1166789954 * 64;
        for (unsigned int i = 0; i < 64; i++)
        {
            v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
            v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
            v5 -= 1166789954;
        }
        a1[j] = v3;
        a1[j + 1] = v4;
    }//小端序
    for (unsigned int i = 0; i < 6; i++)
        printf("%c%c%c", *((char*)&a1[i] + 2), *((char*)&a1[i] + 1), *(char*)&a1[i]);
}

最后算出来的就是flag{re_is_great!}就是flag。

总结

看你z3会不会用,其实手算也是可以算,但是后期数字在变大,和争夺时间做题速度的时候,其实很主要就是自动化,还有对于逻辑的分析,怎么样

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逆向萌新

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

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

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

打赏作者

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

抵扣说明:

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

余额充值