[GWCTF 2019]xxor
首先可以到汇编界面从新定义(U+P)一下main函数,不然看着会有点乱
分析
追踪input变量
可以看到每次循环是获取四字节的输入
但后面对于tmp
变量的赋值我就有点看不懂了,不要紧,直接动调
动态调试
连接linux,下断点开调
我不知道为什么输入字符会直接跳出循环,所以输入了数字
F8步过
可以看到tmp1
和tmp2
被赋值了第一次输入和第二次输入
分析tea_encode
我们可以继续动调下去,可以看到v0和v1分别被赋值了tmp1
和tmp2
的值,会这样的原因是(unsigned int *)&tmp1
,这里tea_encode
函数调用的是tmp1
的地址,而tmp1
和tmp2
的地址仅相差4字节,在使用a1[1]
时,其实是a1
的地址加上一个unsigned int
指针的大小,即四字节,刚好就是tmp2
的地址,这下就明白是如何赋值的了
继续跟进看如何赋值
此时tmp1
和tmp2
加密后的值是这样
再看看v4
是如何赋值的
是将tmp2
作为高地址,tmp1
作为低地址拼接起来
按F4完成循环,v4
进行了三次这样的赋值
最后在sub_400770
函数中进行比较
这里a1
是个_DWORD
指针,类似与unsigned int
指针,所以每次调用v4
中四个字节的值
编写脚本
现在算是分析完了,把sub_400770
函数中的值进行以每两组代入tea_encode
就可以解出flag了
z3求解
from z3 import *
x2, x3, x4 = Ints('x2 x3 x4')
s = Solver()
s.add(x2 - x3 == 0x84A236FF)
s.add(x3 + x4 == 0xFA6CB703)
s.add(x2 - x4 == 0x42D731A8)
if s.check() == sat:
result = s.model()
# 转换为 Python 整数
x2 = hex(result[x2].as_long())
x3 = hex(result[x3].as_long())
x4 = hex(result[x4].as_long())
print(x2, x3, x4)
魔改tea加密求解
tea对称加密,魔改轮数和加密算法,进行三轮加密
#include <iostream>
using namespace std;
int main() {
unsigned int v[6] = { 0xDF48EF7E, 0x20CAACF4, 0xe0f30fd5, 0x5c50d8d6, 0x9e1bde2d, 0x84F30420 };
int key[4] = { 2, 2, 3, 4 };
int r = 64;
for (int i = 0; i < 6; i += 2) {
unsigned int v0 = v[i];
unsigned int v1 = v[i + 1];
unsigned int sum = 0x458BCD42 * r;
for (int j = 0; j < r; j++) {
v1 -= (v0 + sum + 20) ^ ((v0 << 6) + key[2]) ^ ((v0 >> 9) + key[3]) ^ 0x10;
v0 -= (v1 + sum + 11) ^ ((v1 << 6) + *key) ^ ((v1 >> 9) + key[1]) ^ 0x20;
sum -= 0x458BCD42;
}
v[i] = v0;
v[i + 1] = v1;
}for (unsigned int i = 0; i < 6; i++) {
for (unsigned int j = 2; j < 3; j--) { //转为大端序
printf("%c", *((char*)&v[i] + j));
}
}
}
解出flag flag{re_is_great!}