re1
1.ida分析
程序加了扰乱堆栈的花指令去除即可。
花指令:
改跳转逻辑即可,去除后。
2.程序执行流程
首先程序验证了输入长度在[0xC,0x2D]之中,并且格式为WMCTF{xxxxxxxxx}。
然后取出{}内的字符串的前4个按一定规则生成一个表,然后再读取后16个字符。
程序会对读取到的不同特殊字符执行不同的操作,特殊字符为_@#?!&-$+。
通过调试和阅读代码可以得到每个字符对应的操作。
然后验证前4个字符是否为'Hah4',最后把读取的16个字符和一个特殊的密钥进行xtea加密,最后验证加密后的数据。
3.解决方法
首先求出前4个字符的内容。
from z3 import * s=Solver() key=[BitVec('x%d'%i,32) for i in range(4)] s.add(key[0]+key[1]==0x11ab7a7a) s.add(key[1]-key[2]==0x1cd4f222) s.add(key[2]+key[3]==0xc940f021) s.add(key[0]+key[2]-key[3]==0x7c7d68d1) if s.check()==sat: m=s.model() m=[hex(m[key[i]].as_long()) for i in range(4)] print(m)
#include <stdio.h> #include<stdlib.h> #include<stdint.h> unsigned int box[256]; char res[5]; int number[] = { 0x100,0x100,0xf,0x1c }; unsigned enc[] = { 2750330814,1841087164,1357369498,2019106695 }; void gen_box() { unsigned int j; // [rsp+4h] [rbp-Ch] unsigned int i; // [rsp+8h] [rbp-8h] unsigned int v3; // [rsp+Ch] [rbp-4h] for (i = 0; i < 0x100; ++i) { v3 = i; for (j = 0; j < 8; ++j) { if ((v3 & 1) != 0) v3 = (v3 >> 1) ^ 0x8320EDB8; else v3 >>= 1; } box[i] = v3; } } unsigned int fun1(unsigned int a1, unsigned char a2[256], unsigned int a3) { unsigned int v4; // [rsp+4h] [rbp-1Ch] unsigned int v5; // [rsp+8h] [rbp-18h] v5 = 0; v4 = a1; while (v5 < a3) v4 = (v4 >> 8) ^ box[(unsigned char)(a2[v5++] ^ v4)]; return a1 ^ v4; } unsigned int bp(int up, int number, unsigned int pre, unsigned int next) { for (int i = 0; i < 127; i++) { unsigned char block[256]; for (int j = 0; j < number; j++) { block[j] = i + j + up; } if (fun1(pre, block, number) == next) return i; } } int main() { gen_box(); for (int i = 0; i < 4; i++) { if (i == 0) res[i] = bp(i, number[i], -2, enc[i]); else { res[i] = bp(i, number[i], enc[i - 1], enc[i]); } } puts(res); }
最后求出为'Hah4'
然后xtea输入的内容,一开始使用的密钥为k[4] = { 0x78591fad,0x6dbcc2bc,0xa3eeb7be,0x50e7de9a },但是发现怎么也解不出,才测*(_98+0x111)这个地方的值是会变的,爆破这个值。
#include <stdio.h>
#include<stdlib.h>
#include<stdint.h>
void decrypt(uint32_t v[2], uint32_t const key[4]) { unsigned int i; uint32_t v0 = v[0], v1 = v[1], delta = 0x9981abcd, sum = delta * 0x20; for (i = 0; i < 0x20; i++) { v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]); sum -= delta; v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); } v[0]=v0, v[1] = v1; } int check(unsigned a) { for (int i = 0; i < 4; i++) { if (((char*)&a)[i] < 32 || ((char*)&a)[i] > 127) return 0; } return 1; } int main() { int i,j = 0; unsigned int v78 = 0x50e7d09a, v80 = 0xa3eeb7be, v7c = 0x6dbcc2bc, v74,v92 = 0x78591f87; v78 = v78 & 0xffff00ff; v74 = v92 & 0xffffff00; v78 |= 0xdead & 0xff00; v74 = v92 & 0xffffff00 | 0xdead; //printf("%x,%x,%x,%x\n", v74, v7c, v80, v78); unsigned int k[4] = { 0x78591fad,0x6dbcc2bc,0xa3eeb7be,0x50e7de9a }; //unsigned int k[4] = { 0xa3eeb7be ,0x50e7de9a ,0x6dbcc2bc,0x78591fad }; for (i = 0; i < 0xff; i++) { for (j = 0; j < 0xff; j++) { uint32_t v[2] = { 0x1989fb2b,0x83f5a243 }; //uint32_t v[2] = { 0x556E2853,0x4393DF16 }; k[0] &= 0xffffff00; k[0] |= i; k[3] &= 0xffff00ff; k[3] |= j<<8; decrypt(v, k); if (check(v[0]) && check(v[1])) { for (int t = 0; t < 8; t++) { printf("%c", ((char*)v)[t]); } printf("%x,%x", i, j); putchar(10); } } } }
根据结果的语义得出值为0xad,0xb7。用来解另一个数据,最后得到_D0_yOu_L1kE_It!
最后再根据那些特殊字符的对应操作来推理出后面的内容。
最后为
WMCTF{Hah4_D0_yOu_L1kE_It!@FFFE#0F20-11B7}