很惭愧,这篇题解写的并不是很好,因为我平时刷题的题解都是做题笔记,并不像比赛上交的题解那样直入主题,做破解的时候肯定要尝试猜测,会走很多弯路,比赛题解不会记载这些弯路,而做题笔记会.
这样的笔记更能让读者了解到我到底是怎么做的,这也是我入门期期望能读到的东西. 直接向答案去的题解虽然能看懂,但是只是授之以鱼, 很难让我积累太多经验,当然,复现的时候也是经验的积累
为什么说这篇题解写的不好呢,因为走的弯路实在是有点多,把无效的分析当重点,最后才发现题的核心部分只有短短一段,而且很好识别,如果早些采用这个路线,这道题早就做出来了.但是我还是把它发出来了,希望各位师傅看到其中的缺点也能加以指导吧.
这是一道核心加密为XXTEA,并且加了大量混淆的普通加密逆向, 废话就说到这儿,下面上做题过程
这题的名字叫SoMuchCode, 先来欣赏一下main的长度
这是把最上面放大了的,可以看到跳转也不是特别清晰,跳来跳去的.
但是还是那句话,我们在做题而不是实战, 既然是题,它就是为了我们能做出来而生的. 类似这种超长的,难以人力分析的, 无非两种情况:有固定模式或规律/用自动化解题脚本.
否则大概只有刚学C++的新手才会把一个main写这么长吧(((
通过IDA的图, 我们把这个大概分成几段结构相似/相同的代码,一一去分析
首先是这部分:
这三个黄框里的代码块结构大体相似,我们先分析上面独立的代码块,再分析这部分
独立代码块里主要完成了两部分工作, 一是给一些变量赋初值:0或0xF,二是给buf2和一段明文内存放进6160函数, 动调跟了一下感觉就是一个申请内存并memcpy, 并且还动了一个Size变量的值
Buf2附近的内存,可以猜测这还是一个String, size就是该string的size, 声明一个结构体
看到这儿内存的中文我认为应该先运行一下看看前面是不是都是输出,都是输出就没什么好看的了, 直接分析下面的代码块好了
接下来是这样的结构,我们结合动调看看
给106一个定值,然后转成字符串塞到以432+5为末尾的内存, 有点类似栈的先进后出
112和113分别是字符串的首地址和末地址, 16太短了,只有两个字节,我们跳过去分析下一部分
下一部分的转化是123123, 六个字节,好看一点
之后进入一个循环:
每次从最末尾取一个char ch, 使变量tmp为(ch-48) * pow(10, k) + tmp, 也就是..再转成int.
我有亿点没懂,这int转str再转int..我们这边叫脱了裤子放屁.凡是这种脱了裤子放屁的肯定不会是人写的,就是一个混淆,不用再看了
之后它进了这样一个函数,这鬼东西也好长好长好长, 但是这个dword的值是前面设置过的, 用的也同样是刚才这种方式,既然输入无关我们就不管了,等到能用上的时候直接查内存, 这里改了11A6D0-11A6D3和A700-A704
接下来是23个这样的代码块
这么多函数调用,我才不分析呢...
直接往后看或者看输入到底用在了哪儿把
这是最后判断成功失败,左支是成功右边失败,既然前往后难以进行下去,我们试试后往前.
最后这部分是每次判断424里面是不是数字,然后对比和给定数字一不一样.
我们注意到这里要377等于383,且376大于等于32才能成功.
先看377和383
62c0就是10^y, 这里也就还是一个str转十进制, 我们直接动调一波,发现这两个数第一次,一个是187, 一个是92, 这显然不符合我们的要求,但是看上去又不直接是输入,我们得找到这两个数字到底是从哪来的,这两个指针一个是5F80(v423), 一个是5F80(v424)... 还是有点无从下手, 我们转头尝试从输入下手好了.
给输入打上一个硬件断点
断在了1310函数的这里
你看这..<<4, >>3, >>5, << 2, XXTEA, 捏妈妈的,终于找到了
接下来要翻一翻Key就是刚刚转的内存(0x36B0, 0x13816, 0x10, 0x1E0F3), Delta很容易就能找到是0x33445566,
最后要找一下密文. XXTEA加密之后应该是32, 对应着刚刚32次对比, 这样我们就能拿到密文了.
动调,直接拿到位于A6D0的密文(基址不一样,不同情况下地址可能也会不一样
#include <cstdint>
#include <cstdio>
#define DELTA 0x33445566
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
uint8_t ida_chars[] =
{
0x5C, 0xAB, 0x3C, 0x99, 0x29, 0xE1, 0x40, 0x3F, 0xDE, 0x91,
0x77, 0x77, 0xA6, 0xFE, 0x7D, 0x73, 0xE6, 0x59, 0xCF, 0xEC,
0xE3, 0x4C, 0x60, 0xC9, 0xA5, 0xC0, 0x82, 0x96, 0x1E, 0x2A,
0x6F, 0x55
};
uint32_t key[] = {
0x36B0, 0x13816, 0x10, 0x1E0F3
};
void btea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
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) /* Decoding Part */
{
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 *p = (uint32_t *)ida_chars;
btea(p, -8, key);
for(int i = 0; i < 32; i ++ ) {
printf("%c", ida_chars[i]);
}
}
9b34a61df773acf0e4dec25ea5fb0e29