在分析报告的开始之前,这是我的MachineCode以及调试时采用的SerialNumber
一、 采用DestroyWindow方式进行破解。
此时MachineCode为9385C461
输入序列号12345678
点击Register,出现弹窗Bad
Ctrl+G,输入DestroyWindow.
在,此处设置一个断点。
点击Ok。
此时来到
用F8,回到上一次函数调用。此时来到这里
向上翻没有发现什么特别的东西。于是再回到上一次函数调用。来到这里
我先前调用了004A4068,是破坏的。前面发现了一个je,并且跳开了中间的函数。有点可疑,于是在je前设置断点。
再次注册,发现依旧弹出了Bad。可见这个函数并没有什么特别的东西,还是在判断失败以后。所以直接离开这一块内容。再回到上级调用。此时来到
发现上面并没有跳开什么地方,于是继续回到上一级。此时来到
此时这个地方相当可疑。注意到直接跳开了我们断开的函数。
在这里我再次设置了一个断点,跑起来之后发现还是产生了错误,故继续下一级调用,此时来到
再回到上一级,来到
向上翻发现可疑点
发现jump跳开了函数。
设下断点。点击注册,发现没有弹出Bad,而是挺住了。同时,我令下处的跳转不实现,点击run。发现弹出了Good
那么我们就追究这个函数跳转的原因。观察
此时有
这个值为软盘指纹的值。
那么对函数上面代码进行分析。分析结果如下。
首先我们看到最后的一个异或
也就是[ebp-3C]^0x13572468 = Machine Code
同时我也查看了此时的ebp-3C指向的数据
第一步的逆向、
[ebp-3C] = Machine Code ^ 0x13572468.
代码如下
紧接着向上看,
关注到上面的这一系列代码。运行到004017BA,下面窗口定位到[ebp-3C]
发现如下情况
,也就是这一串似乎与我的12345678有点相像。
基于这个情况,我再向上找,找到了12345678的完整情况。
当我运行到004017A4时,ebp-3C处的数据如下
也就是说,在这中间,发生了什么事情,使得这一串发生了改变。但是有意思的是,123456并没有发生改变。
但是我们先前(在第一步的逆向之前)发现这一串数字是发生改变了的。
那么分析这call函数以后的代码。
此时,ebp指向原来78的位置,ebp+1指向56的位置。依次类推
按F7,56的情况发生了改变。
很容易可以明白,56的改变,发生于上一个函数。
此时我们对我图中俩红色之间的代码分析。
分析结果是,它将原来1234的顺序改为了1324。
由此我们可以得到
第二步的逆向、
先获得result的每一个位。取出其相应的十六进制表示,归到原来的位置中。
紧接着我们来分析56的情况。
进入函数
F7过后,在此时这个点时,eax出现了我们想要的56
此时情况如下
ecx = 8->(减去edx的2)à6->(edx赋值2)à2
ebx = eax(为56)向左移位6个。
eax向右移位2。
此处的2来自调用函数前的
此时万分注意,有一个非非非常重要的点
算术右移。
然后对结果进行或。
分析结果如下:
56位所代表的的8位中
x1x2x3x4y1y2y3y4
à y3y4x1x2x3x4y1y2
但是,y3y4并不一定是y3y4基于算术右移的可能性,有可能直接变成了11。故此位置有可能是任何值,这取决于X1的值,因为数量不多,就不分析X1了,直接给出所有可能结果。
第三步的逆向、
逆向,将其规规矩矩得到
y3y4x1x2x3x4y1y2
再将其进行
如果与11进行或的话,那么可以得到4个不同的结果。
如果与00进行或的话,那么可以password就是作为结果。(其他的意义不大)
———————————————————————————————————————
接下来分析78的情况。
传入ebp-3C地址,还有push1,以及al是78的得到。
紧接着我们来到了函数内部。
分析代码:
同样注意到
此处分析结果是
x1x2x3x4y1y2y3y4
à x2x3x4y1y2y3y4x1
有可能是跟1111111 x1进行或的。
假如和1111111x1进行或的话,就依次进行。密码有2^7种。我的代码不作分析。(罗列所有可能情况),实际取决于x1的结果。
所以得到
第四步的逆向、
#include
#include
int main()
{
unsigned temp=0, password=0;
unsigned result=0;
unsigned Machine_Code=0;
unsigned ch1=0, ch2=0, ch3=0, ch4=0;
printf("请输入Machine Code\n");
scanf("%xu", &Machine_Code);
result = Machine_Code^(0x13572468);
ch4 = result & (0x0FF);
ch3 = (result>>8) & (0x0FF);
ch2 = (result>>16) & (0x0FF);//24状态
ch1 = (result>>24) & (0x0FF);//13状态
password |= ((ch1&0x0F)<<20);//第三个十六进制归位
password |= ( ((ch1&0x0F0)>>4) << 28);//第一个十六进制归位
password |= ((ch2&0x0F)<<16);//第四个十六进制归位
password |= ( ((ch2&0x0F0)>>4) << 24);//第二个十六进制归位
unsigned password11 = 0;
unsigned password21 = 0;
unsigned password22 = 0;
unsigned password23 = 0;
unsigned password24 = 0;
password |= (ch4>>1);//最后两位十六进制右移一位
password |= (ch4&0x1)<<7;
/*
有两种情况,左移后把1弄没了,那么右移有两种情况,+0x80或者不加
*/
password |= ((ch3>>6) + ( ((ch3&0x3F) << 2)) )<<8;//56两位十六进制,的78位放在12位上。
password21 = (password&0x0FFFFFFFF);
password22 = (password&0x0FFFFBFFF);
password23 = (password&0x0FFFF3FFF);
password24 = (password&0x0FFFF7FFF);
/*
如果和00或的话,原来的就是结果。
如果与11或的话,那两位必然就为11
此时有四个可能
*/
printf("注册码:Password = %x\n", password);
printf("其他可能也OK的注册码如下:\n");
/*printf("Password 1 = %x\n", password21);
printf("Password 2 = %x\n", password22);
printf("Password 3 = %x\n", password23);
printf("Password 4 = %x\n", password24);
*/
system("pause");
}
几个要点:
一、 在算术移位的情况下,可能出现并行的注册码(多个注册码都可以成功)。
我在代码中列出了一种类型。
二、跟踪分析的时候其实我还跟踪了关于将字符串转换成为普通的字符。本来以为是字符串比较,后来才发现是直接转化成十六位进制的比较。
三、找到调用的函数要逐个分析,不要一棍子打死。(这里有两种分析类型,险些出了岔子)。