【buu】【另一种抽象的xxtea】[2019红帽杯]xx b题看了一整天,总算是看明白了TMD
查克无壳64位,拖入ida
发现一很大一坨代码,慢慢分析吧
有个输入函数和v6
这里的v6后面的Code不是上面要输入Code,跟进发现是另外的一串字符
这里也是要吐槽煞笔ida伪代码的反编译的表达形式
*(v9 + Code - v5)表示的code[v9-v5]
这v13是检测v6的长度
if语句是遍历检测输入的字符是否在v6的范围内,是的话就跳出循环,
如果有不属于v6的字符存在v11就会累加到36
v14这一小段也是检测v6长度
当有不属于v6的字符存在时就会退出
v9 - v5 < 4表达的是这一段代码只截取输入的前四个字符
这里v3搞错了应该是19,这里的code是输入
v30动调出来的是输入的flag的前四个字符
下面的连续的4个 if 表明前四个字符不能是0
首先这个循环是一个密钥扩展,是把输入的flag前四个字母扩展成16位,也就是4个4位的密钥
然后内个sub_7FF7ADD11AB0是比较抽象的xxtea加密,具体是用一个插件FindCrypt 和结合题目猜测可能是xxtea
Size是动调出来的是个固定值24
然后就是进行位置交换混淆
这里的异或最开始没看懂
首先是这个++v22这个v22可以认为是一个数组,++v22是指向数组的后一个元素
然后里面的if语句表示要从3开始异或,所以前三个(0-2)元素不会进行操作
当从3开始会进行异或,把当前的v22的值 与从0位置开始的v20 进行异或
每三个元素为一组,每组比上一组多进行一次异或,
多进行的那一次异或,是将刚才异或得到的值 与**v20[(刚才得值+1)]**进行异或
一直到v21 = 23进行最后一次循环
v30 v30[1] v31 v32是密文。但是要注意小端序,建议动调调到这里直接提取
综上我们先把换位混淆的密文和迭代异或先给解回去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <iostream> #include <Windows.h> using namespace std;int main () { int mix[] = { 0xCE , 0xBC , 0x40 , 0x6B , 0x7C , 0x3A , 0x95 , 0xC0 , 0xEF , 0x9B , 0x20 , 0x20 , 0x91 , 0xF7 , 0x02 , 0x35 , 0x23 , 0x18 , 0x02 , 0xC8 , 0xE7 , 0x56 , 0x56 , 0xFA }; int enc[24 ]; int count = 0 ; for (int i = 23 ; i >=3 ; i--) { for (int j = 6 -count; j >= 0 ; j--) { mix[i]^=mix[j]; } if (i % 3 == 0 ) { count++; } } enc[2 ] = mix[0 ]; enc[0 ] = mix[1 ]; enc[3 ] = mix[2 ]; enc[1 ] = mix[3 ]; enc[6 ] = mix[4 ]; enc[4 ] = mix[5 ]; enc[7 ] = mix[6 ]; enc[5 ] = mix[7 ]; enc[10 ] = mix[8 ]; enc[8 ] = mix[9 ]; enc[11 ] = mix[10 ]; enc[9 ] = mix[11 ]; enc[14 ] = mix[12 ]; enc[12 ] = mix[13 ]; enc[15 ] = mix[14 ]; enc[13 ] = mix[15 ]; enc[18 ] = mix[16 ]; enc[16 ] = mix[17 ]; enc[19 ] = mix[18 ]; enc[17 ] = mix[19 ]; enc[22 ] = mix[20 ]; enc[20 ] = mix[21 ]; enc[23 ] = mix[22 ]; enc[21 ] = mix[23 ]; for (int i = 0 ; i < 24 ; i++) printf ("0x%x," , enc[i]); return 0 ; }
然后再找一个xxtea脚本进行解密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <stdio.h> #include <stdint.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y> >3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea (uint32_t *v, int n, uint32_t const key[4 ]) { uint32_t y, z, sum; unsigned p, rounds, e; if (n > 1 ) { rounds = 6 + 52 /n; sum = 0 ; z = v[n-1 ]; do { sum += DELTA; e = (sum >> 2 ) & 3 ; for (p=0 ; p<n-1 ; p++) { y = v[p+1 ]; z = v[p] += MX; } y = v[0 ]; z = v[n-1 ] += MX; }while (--rounds); } else if (n < -1 ) { n = -n; rounds = 6 + 52 /n; sum = rounds*DELTA; y = v[0 ]; do { e = (sum >> 2 ) & 3 ; for (p=n-1 ; p>0 ; p--) { z = v[p-1 ]; y = v[p] -= MX; } z = v[n-1 ]; y = v[0 ] -= MX; sum -= DELTA; }while (--rounds); } } int main () { uint32_t v[6 ]= {0x40cea5bc ,0xe7b2b2f4 ,0x129d12a9 ,0x5bc810ae ,0x1d06d73d ,0xdcf870dc }; uint32_t const k[4 ]= {(unsigned int )0x67616c66 ,(unsigned int )0x0 ,(unsigned int )0x0 ,(unsigned int )0x0 }; int n = 6 ; btea (v, -n, k); for (int i = 0 ; i<6 ; i++) printf ("%x\n" ,v[i]); return 0 ; }
然后把的出来的16进制转换成字符,注意小端序