首页
社区
课程
招聘
[原创]第五题 WriteUp
发表于: 2017-11-2 20:49 3326

[原创]第五题 WriteUp

2017-11-2 20:49
3326

这题……感觉难度比之前的大了一个档次……

标准MFC程序,使用XSpy定位按钮点击事件,查看流程:

乍一看流程是1000次连续base64后与指定字符串比对,但很显然一个base64过1000次而且截断的字符串是不可能出现等于号的,这是一个假的流程。
程序中有一个int 2d中断,查阅资料发现是一种反调试手段,如果有调试器的时候int 2d会被认为是软中断然后继续执行,而没有调试器的时候会产生异常,触发异常处理,真正的程序流程应该在异常处理中。

观察SEH结构偏移表,得知真正的程序流程应该在40717D处。
对程序进行patch如下,这里patch得比较暴力= =

(不跳转到7D的原因是7D是一个恢复esp的操作,这里使用jmp,没有改变函数栈帧,恢复esp可能会出现异常,当然也可以选择使用call来patch,再恢复esp)
反编译,真正的逻辑出现

程序首先生成了一个1*48的向量,内容是0-47,然后利用两个函数按字符串“KanXueCrackMe2017”和用户输入的字符来生成对向量的变换,接着检验是否能变回去,长度是否为12,以及一个判重函数(不过在我这次分析中并没有用到,猜测是长度为12的解有且仅有一个?)
变换函数


看上去好像非常的复杂,但实际上根据一定的调试,可以判断是实现了一个高精度类,含有构造函数,高精度加法,高精度乘法,高精度除法和取模。
对于传入的字符串,一位一位拆开字符并用0-9A-Za-z表示0-62(这里有点意思了)
大概的通项公式如下:

其中f[i]是最终结果,c[i]是每一位字符被转化为的数字,b[i]是个等比数列。
这种形式,实际上就是进制转换的形式!
实际上,是将传入的字符串当成"62进制数"(反的),转化为10进制数。

然后是下面一块,

非常典型的进制转换,十进制转18进制,也是反的。

至此,第一个函数分析完成。

将刚才转换的18进制字符串拆回数列(那转字符串干嘛,增加难度吗= =),然后每一位拆成(a × 3 + b)的形式,将(a, b+1)和之前的向量作为参数传向这个函数。
函数差不多可以理解为一个字节码解释器,就是传入(x, y),则执行x操作y次。
进入这个函数,发现不同的操作实际上也是同样的函数,只不过对象不同。
进入操作函数,观察形式。

看这个形式,内层循环48,外层循环48,显然是行和列指针,内层循环每做一次指针就移动48位,应该是移动一行。同时还有逐项相乘并相加的部分。
这个形式与左行右列的形式非常相似。
经过调试,确定这个想法,实质上是实现了一个矩阵乘法的操作。
程序中存放着6个48×48的矩阵(贼大……),当前面的操作数x为i时(i=0,1,...,5)则让i号矩阵对之前的向量右乘y次。

至此,对向量变换的函数全部分析完毕。
流程为:

首先知道了第一个固定的字符串是KanXueCrackMe2017,可以算出对应的操作码:

(Python的,懒得删L了……)
然后,对于程序中所有的48×48矩阵,发现有一个性质:
对应矩阵的逆矩阵都为自己的3次方,即矩阵自己乘4次相当于无变化
然后矩阵的运算是没有交换律的,但有结合律,所以要构造字节码,从右向左合并。
通过手算,得到以下的字节码:

(显然答案是不唯一的,这里这种因为考虑到12个字符的限制,将原来的操作码中自己算了4次的都合并了,故这里是总操作数最少的一种,按照作者的意思应该就是要考这一种)
然后编写脚本,逆回18进制再逆回62进制,得到flag。

CcLaoE37J45Y


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//