buuctf re [GWCTF 2019]xxor题解

目录

1.看位数

2.ida64打开

 3.程序逻辑

 4.关键函数

5.解题脚本

6.注意事项


1.看位数

2.ida64打开

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int i; // [rsp+8h] [rbp-68h]
  int j; // [rsp+Ch] [rbp-64h]
  __int64 flag[6]; // [rsp+10h] [rbp-60h] BYREF
  __int64 flag_encrypted[6]; // [rsp+40h] [rbp-30h] BYREF

  flag_encrypted[5] = __readfsqword(0x28u);
  puts("Let us play a game?");
  puts("you have six chances to input");
  puts("Come on!");
  memset(flag, 0, 40);
  for ( i = 0; i <= 5; ++i )                    // 输入六次,每次指定的是四个字节,
  {
    printf("%s", "input: ");
    a2 = (flag + 4 * i);                        // 感觉这个char**有误导,应该是当一级指针用
    __isoc99_scanf("%d", a2);                   // 应该是输入的数字赋给flag,一共6个int32四字节,还剩余24字节
  }
  memset(flag_encrypted, 0, 40);
  for ( j = 0; j <= 2; ++j )                    // 进行三次循环即可获取上方输入的6个四字节数据
  {
    high_dword = flag[j];                       // 分别获取高四位和低四位
    low_dword = HIDWORD(flag[j]);
    a2 = &dword_601060;
    encode(&high_dword, &dword_601060);
    LODWORD(flag_encrypted[j]) = high_dword;    // 加密后的数据赋给encrypted数组
    HIDWORD(flag_encrypted[j]) = low_dword;
  }
  if ( cmpare(flag_encrypted, 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;
}

 3.程序逻辑

flag是连续输入6次,每次4个字节,一共24字节,这里a2可能识别为二级指针,有点误导,实际上是当作一级指针使用,可以按键盘上\隐藏掉类型提示

由于flag是int64类型的数组,后续每次取flag[i]的高四位和低四位进行加密处理

加密之后的字符串有一个比较操作,在这个比较函数里面可以通过数学关系求出加密后的字符串值

 4.关键函数

encode函数:

其中形参a2是dword类型,原始数据位于601060,转换后如下:

这个加密并不复杂,只需要将+号改为-号,调整语句顺序即可

但是v5循环后的终值要作为解密函数循环的初始值

我们需要动态调试,得到v5=0x62F35080

 cmpare函数可以解得加密后的数组的值为:

    a[0] = -548868226;
    a[1] = 550153460;
    a[2] = 3774025685;
    a[3] = 1548802262;
    a[4] = 2652626477;
    a[5] = -2064448480; 

5.解题脚本

#include<stdio.h>
void decode(unsigned int* high, int* a2)
{
	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 = *high;                                   // 高四字节
	v4 = high[1];                                 // 低四字节
	v5 = 0x62F35080;							//v5初值即原来的循环终值,要动态调试才可以得到
	for (i = 0; i <= 0x3F; ++i)                 // 加密循环,解密把顺序调换,+换成-即可,但是要注意v5的初始值
	{
		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;
	}
	*high = v3;
	high[1] = v4;
}
int main()
{
	__int64 tmp;
	int a[7];
	int a2[4] = { 2,2,3,4 };
	a[0] = -548868226;
	a[1] = 550153460;
	a[2] = 3774025685;
	a[3] = 1548802262;
	a[4] = 2652626477;
	a[5] = -2064448480;
	a[6] = 0;			//补零保证数组不越界
	for (int i = 0; i < 3; i++)
	{
		tmp ^=tmp ;
		decode((unsigned int*)&a[i * 2], a2);//一次解密八个字节
		tmp += a[i * 2];					//获取高四字节
		tmp = tmp << 32;					//每次获取八字节
		tmp += a[i * 2 + 1];				//获取低四字节
		printf("%llx", tmp);                //必须是%llx
	}
	return 0;
}

得到flag{re_is_great!}

6.注意事项

直接用puts输出解密后的字符串是不行的,因为有一部分字节值为00

如果使用逐字节输出也是行不通的,得到的是错误答案

根据题目提示,要转成16进制输出,再用16进制转字符串

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

OrientalGlass

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

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

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

打赏作者

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

抵扣说明:

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

余额充值