-
-
[原创]叹息之墙wp
-
发表于: 2018-10-2 00:21 4065
-
文件下载下来后使用ida打开,看见主函数直接调用了一个函数,然而这个函数长这个样子:
整个函数又长又乱七八糟的还不能F5不知道是什么鬼。稍微下移一段看见很长一段都只使用了add,sub,xor等操作,只能先当它是没用的花指令,直接搜索call,发现了一段输出提示信息的逻辑。
对着printf按x找了下对printf的调用,看了到几个"输入错误"、"格式错误"啥的之后就发现了成功提示。
于是马上将这一段前的label改名为success并按x看看是从哪跳过来的,发现是从之前被我忽略掉的这样一段跳过去的:
而且这一段还很长,观察了一下之后发现这其实是一个大跳转表,每一个小逻辑都是取出[esi 3010h]的值,减去一个常量,等于0了的话就跳转,否则继续到下一小段。
这样的话想要继续追踪是从哪里跳过来的,就要搜索0AD1C95B5h,就是跳转到success前去比对的那个常量。因为肯定是有哪里先将这个值放到了[esi 3010h]里(后来发现其实是[esi 301Ch]里)再跳过来的。
这里根据[esi 3053h]的值进行了跳转。
看看是从哪跳到这里的,发现还是从跳转表过来的,于是继续搜索对应的常量,就找到了一段有意思的逻辑。
这里布置好4个参数然后去调用了一个函数,判断函数的返回值是不是等于"4can"(就是0x6e616b34),相等时会设置[esi 3053h]之后一路跳到success。
在这里下了一个断点,测试了一下发现没有反调试机制,而且发现在输入程序给的示例 0x1x23x45x67x350X 时这个函数的参数是:
就是执行了afunc(0x65757832, 0, 0xf9a1cd94, 2)
,0x65757832 发现是"2xue"。(后来分析出其实只有两个8字节参数:0x65757832和0x2f9a1cd94)
之后就要找出0x2f9a1cd94是怎么来的。
观察这一段发现0x2f9a1cd94这个参数是从[esi 3024h]里存的指针中取出来的,于是全局查找[esi 3024h],找到了:
其中dword_3CFE40静态看了一下全是0,下断点动态看了下就是输入的那几个数字
再观察这段逻辑就分析出它将输入的数字作为下标去数组dword3CF000中取值,并和原来[esi 3024h]中存的值相加再存回去。数组大小是351个4字节整数。
稍微花了点时间用python把dword3CF000数组转换了出来,并测试了下第0 1 23 45 67 350个数相加确实等于0x2f9a1cd94。
于是现在的任务就是分析afunc的逻辑,找出它的参数应该是什么才会返回0x6e616b34。
点进afunc的逻辑看到它和smg函数长得差不多,先找一找return:
返回的是[esi 5C0h]里的值,于是搜索[esi 5C0h]:
看到是从[esi 5B8h]里取出来的,在搜索[esi 5B8h]时找到了好几段逻辑,并发现和[esi 5B0h]有一点联系,其中甚至有花指令产生的逻辑在
等我以为是什么复杂的算法并分析成这个样子时往下一看还有很长才感觉不对。。23333
后来经过搜索和动静态分析再结合一点猜测,找到了两段感觉是实际在做计算的事情的代码段:
搜索了一下__aullrem函数是求余数的函数,并分析了一下这两段在做什么:
结合一点经验发现是这样的代码:
发现是一个快速模幂运算,于是问题就变成了这样:
求解x使得0x65757832^x mod 0xffa1cf8f == 0x6e616b34
幸好这些数还算比较小,这里可以爆破,爆破代码:
找到了值0x55121c15。
但是0x55121c15显然不是我们要输入的参数,因为数组dword3CF000中的值普遍都占满了4字节,最终我们输入的应该是一个稍大一点的数字。
模空间有一个循环群的性质:a^b mod p = a^(b+p-1) mod p
所以我们给这个函数的参数可以是0x55121c15+n*0xffa1cf8e。
于是就是在351个数字中寻找最多9个数字使它们的和模0xffa1cf8e为0x55121c15。
一开始我想到了01背包问题上去,所不同的是背包问题取价值最大,这里是要正好填满。想了想简单写了个递归的遍历函数,侥幸心理跑了挺长一段时间没出来,感觉方向没对。
后来观察这351个数字,发现它们除了5个数字以外其它数都是10的倍数,这五个数为:857758902 2573276706 2144397255 3431035608 1715517804
而且模数0xffa1cf8e也是10的倍数:4288794510,其中2144397255是4288794510的二分之一。
我们要找的余数0x55121c15十进制是1427250197,个位数是7;这样我们几个数字的和的个位数肯定要是7,于是这些数字里肯定要有2144397255,而且要从其它4个不是10的倍数的数字里凑个个位数是2的数出来:
857758902
3431035608 1715517804
2573276706 1715517804 857758902
然后突然发现其中 857758902 2573276706 = 3431035608,根据解肯定唯一来看就要排除2573276706 1715517804 857758902的选择,3431035608 1715517804可以用,但这样就肯定要是9个数的和。
最有可能的解还是857758902和2144397255。
花了一段时间分析才又发现这些数字都是互补的,就是说除了2144397255是4288794510的二分之一以外,其它350个数字每个都能和350个数字中的另一个相加等于4288794510。
这样最后的解肯定只能是8个或者9个数字相加,不然就会存在多解。
之后为了分析,给这351个数字排了序并查看了前一个数字减去后一个数字的差值,发现出现了大量的15825810,后来又查看了它们模15825810的余数,发现只有76个数字是10的倍数但不是15825810的倍数;
这样的话就计算了一下1427250197模15825810的余数是2927297,并将递归遍历的范围限定在在这76个数字中,个数限制为6到7个,求它们的和模15825810的余数是2927297的组合(因为有2个数字已经确定为857758902和2144397255)
遍历代码为:
跑了不到半分钟就出来的结果如下:
其中只有第一行是6个数字的解,其它都是7个数字的解。
于是选择第一行6个数字的解,加上3002156157,再在其它是15825810的倍数的数字中寻找最后一个数字使它们的和模4288794510为1427250197,就找到了最后一个数14409162140
组合这个数字和6个数字的解,再加上857758902和2144397255,最后组成9个数字,这9个数是:857758902,2144397255,553392840,1559561640,2450739720,2859196340,3027384360,3958887240,1171109940
最终找到它们的下标并拼起来得到解答:17x27x60x97x133x161x243x292x309X
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [原创]追凶者也 writeup 3822
- [原创]半加器 writeup 3017
- [原创]叹息之墙wp 4066