

没有看到加密过程,能确定的就是input和cpdata,初步判断,猫腻应该在debugbreak那里。动调一下,直接退出,是有反调试。断点下在输入之前
,还是直接闪退。查看一下main函数之前做了什么。
经过查看,可以定位到scrt_common_main函数有反调试,
在这个函数中,可以看到36行调用了invoke_main函数,而invoke_main调用了main函数,所以任务很简单,让其执行到这里即可。经过单步调试发现,在执行完26行之后,程序就卡死了,尝试了一下将这条指令nop掉,成功。然后保存文件。

在读取完四十五字节的输入之后,有一个int 3的系统调用,而在此之前,还自定义了int 3的处理函数,也就是sub_4140d7,
经动调分析,这里就是主加密部分了,这一段是不能反编译的,因为参杂着大量的花指令,一类是利用call的假跳转
另一类是jz、jnz的永真跳转

动态跟了数条指令之后猜测可能是tea加密,因为有几条指令是按位移动


可以发现规律,每一个基本块中只有一条是真正的指令,其余的要么是花指令,要么是跳转指令。可以利用trace将执行部分高亮处理,然后将其余部分nop掉。
选择instruction trace,然后一直f8
执行到很长时间不再提示将数据解析为代码时,就差不多了,此时就可以比较轻松的去除花指令和无效数据了,但是由于大量的跳转,我猜测有可能f5失败。另一种方法就是提取所有的有效指令,对于上图,有效指令就是xor eax,ecx,然后提取出来机器码,最终将所有的机器码提取出来,再patch进去。从最开始的
提取一个push ebp机器码是0x55,然后忽略jmp指令的机器码,来到下一个块,同样只提取一条有用的指令……最后patch到push ebp的位置
然后按p解析成函数,
正如我们的猜测,是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
| #include <stdio.h> #include <stdint.h> #include<windows.h>
int main() { unsigned int v1[12]={0xc44ea811,0xd98ae0d6,0x984227d4,0x1080a783,0xf994d294,0xc4ce08ce,0x3d40ab34,0x97960549,0xfbae12d0,0xb776de91,0x4a3f6dd3,0xb115b2e9}; unsigned int key[]={0x6B0E7A6B, 0xD13011EE, 0xA7E12C6D, 0xC199ACA6};
int e = 0; unsigned int z; int y; int myrounds =50; unsigned int sum=0x2B3AD324; y=v1[0]; do { int i=0; e = (sum >> 2) & 3; for(i=0xb;i>0;i--) { z=v1[i-1]; y=v1[i]-=(((z ^ key[e ^ i & 3]) + (y ^ sum)) ^ (((16 * z) ^ ((unsigned int)y >> 3)) + ((4 * y) ^ (z >> 5)))); } z=v1[11]; y=v1[0]-=(((z ^ key[e ^ i & 3]) + (y ^ sum)) ^ (((16 * z) ^ ((unsigned int)y >> 3)) + ((4 * y) ^ (z >> 5)))); sum+=0x5B4B9F9E;
} while (--myrounds);
for(int i=0;i<12;i++) { printf("0x%x,",v1[i]); }
return 0;
}
|
本来以为这就结束了,拿比较数据操作的一遍,果然没这么简单。在22mu师傅的不断摸索下,发现调用完这个xxtea之后,esp又落到了函数的开始,也就是xxtea被连续调用了两次。然后就是尝试两次解密,还是不对。
这时候就开始考虑反调试修改数据之类的了,在以前的比赛因为反调试栽过不少跟头,基本上对xxtea的每一个变量都进行了交叉引用,没发现什么异常。然后返回一开始查看,发现input那里存在一处可疑的交叉引用。
代码量很少,但是很诡异
可以说没有人类逻辑。
3cly师傅靠着题目刚开始的提示“ HEAVEN or HELL?”,在看雪发现了天堂之门技术 | Taardis’s blog (taardisaa.github.io)
这篇文章,就是在32位程序运行64位的代码,将这个函数dump下来,随便找一个64位的程序patch进去
1
| 558BEC81ECC00000005356578BFD33C9B8CCCCCCCCF3AB5756415641574831FF8B34BDA83442004D31F64989F749C1EF1F4983FF01750AD1E681F62F97A684EB02D1E649FFC64983FE2075DE8934BDA834420048FFC74883FF0C75C4415F415E5E5F6A2368F379410048CB
|

简单明了了,首先判断符号位,如果为1,先右移一位,在异或。如果不为1,则直接右移一位。这里的异或数据末尾为1,所以和右移一位后(最低位为0)的数据异或后末尾为1。直接右移的末尾为0。可以根据此将32位还原
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
| #include<stdio.h> int main() { unsigned int cpdata[12] = {0xA790FAD6, 0xE8C8A277, 0xCF0384FA, 0x2E6C7FD7, 0x6D33968B, 0x5B57C227, 0x653CA65E, 0x85C6F1FC, 0xE1F32577, 0xD4D7AE76, 0x3FAF6DC4, 0x0D599D8C}; for(int i=0;i<12;i++) { unsigned int tmp=cpdata[i]; for(int j=0;j<32;j++) { if(tmp&0x1==1) { tmp=((tmp^0x84A6972F)>>1)|0x80000000; } else { tmp=tmp>>1; } } cpdata[i]=tmp; } for(int i=0;i<12;i++) { printf("0x%x,",cpdata[i]); } }
|
加密逻辑:xxtea –>xxtea—>位操作
解密逻辑:位操作–>xxtea–>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
| #include <stdio.h> #include <stdint.h> #include<windows.h>
int main() { unsigned int v1[12]={0xc44ea811,0xd98ae0d6,0x984227d4,0x1080a783,0xf994d294,0xc4ce08ce,0x3d40ab34,0x97960549,0xfbae12d0,0xb776de91,0x4a3f6dd3,0xb115b2e9}; unsigned int key[]={0x6B0E7A6B, 0xD13011EE, 0xA7E12C6D, 0xC199ACA6};
int e = 0; unsigned int z; int y; int myrounds =50; unsigned int sum=0x2B3AD324; y=v1[0]; do { int i=0; e = (sum >> 2) & 3; for(i=0xb;i>0;i--) { z=v1[i-1]; y=v1[i]-=(((z ^ key[e ^ i & 3]) + (y ^ sum)) ^ (((16 * z) ^ ((unsigned int)y >> 3)) + ((4 * y) ^ (z >> 5)))); } z=v1[11]; y=v1[0]-=(((z ^ key[e ^ i & 3]) + (y ^ sum)) ^ (((16 * z) ^ ((unsigned int)y >> 3)) + ((4 * y) ^ (z >> 5)))); sum+=0x5B4B9F9E;
} while (--myrounds);
for(int i=0;i<12;i++) { printf("0x%x,",v1[i]); } return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <stdio.h> #include <stdint.h>
int main() { unsigned int v[12] = {0x68627544,0x46544365,0x6532387b,0x66336531,0x35382d38,0x36346566,0x382d6639,0x64393934,0x2d383464,0x61363634,0x30366439,0x7d};
for (int i = 0; i < 12; i++) { for (int j = 0; j < sizeof(unsigned int); j++) { printf("%c", (v[i] >> (j * 8)) & 0xFF); } printf(""); } printf("\n");
return 0; }
|