【160Crackme】《wocy.1》《ACG-crcme1》

Crackme

Posted by Corax on November 2, 2023

第二道Crackme做的很爽。

crackmea01

直接打开看看

image-20231102210901710

显示未注册,如果输入正确的name和id应该是有成功的字样的。

先查壳看看基本信息

image-20231102211009243

拿VC写的,无壳。OD

image-20231102211136250

试着定位一下关键字符串

image-20231102211210478

可以看到程序流程还是比较明显的,对我们收入的字符串进行处理后比较,比较决定jnz是否跳转,如果要成功的话应该就是不让他跳。

image-20231102211311237

把他nop掉看看结果。

可以看到成功了

image-20231102211345159

基本上没做任何防爆破的手段。

下面来分析一下代码流程。

image-20231102211535451

最顶上的应该是个mfccall,是把我输入的某些信息接受过去,然后某东西跟0x4比较,我理解为这个应该是比较长度,如果说这里小于4,就算我下面nop掉也没用。试一试

image-20231102212008030

和我猜测的一样,直接失败了。

重新来,进行堆栈窗口跟随,可以看到在那个mfccall之后,

image-20231102212220873

经过这个函数把我们的字符串给倒置了

image-20231102212647627

应该是mfc里自带的一个函数

然后一个给eax,一个给edx,cmp

image-20231102212729878

就是这样了。

crcme1

这道的难度有三星,不晓得咋样。

随便填塞点东西,错误。

image-20231102212915386

查一下信息

image-20231102213546991

KeyFile

感觉没啥有价值的信息,扔到od里面看看

image-20231103010229790

第一个要执行的就是createfileA,这里的access为read,理解为读取文件。而读取的这个ACG.Key就可以理解成一个Keyfile,程序运行的必备文件。

接着往后面看

image-20231103010659804

比较读出来的大小和0xC(12)的大小,jnz为不相等时跳转,意思就是keyfile里面的东西要是十二位。

image-20231103010802121

之后读取文件流,不重要

image-20231103010908526

重要的来了

image-20231103010936688

这里有十二个类似代码块,每一块都是通过inc来遍历我们keyfile里面的东西。一个个看。假设我们keyfile里面是A

image-20231103011026867

可以看到第一个里面,正向逻辑是我们输入的A的ascii为0x41,这个0x41和0x1B进行异或,结果左移两位,然后判断是不是和0x168相同(这里判断分为xor test两步来写,test ebx,ebx 只有当ebx为0的时候jnz才不执行。也就是xor ebx和0x168必须要一样)。

逆向逻辑也很清楚了吧,即我们有的是0x168,然后0x168右移两位,再和0x1B进行异或,得到ascii值,再转成字符输入就可以了。

而后面几个代码块也仅仅是这个0x168不同

image-20231103011457128

所以就可以写成如下脚本

nEnc=[0x168,0x160,0x170,0xEC,0x13c,0x1cc,0x1f8,0xec,0x164,0x1f8,0x1a0,0x1bc]

for i in nEnc:

  temp1=i>>2

  temp2=temp1^0x1b

  print(chr(temp2),end='')

print(chr(0x20))

得到结果 ACG The Best。写进keyfile里面,运行到下面

image-20231103011624453

ok,keyfile就绪了,只要填写name和serial就可以了。

算法逆向

第一次随便输入一串东西,发现他到这里了。

image-20231103011800269

一个非常醒目的跳转吧。看看上面在哪。

image-20231103011824274

可以发现这里已经下面一些就是对name和serial进行处理了。

先浅看一下

image-20231103011916401

先读入两个数据,然后在name里面有cmp eax,0x5和jb连用

image-20231103012018160

意思name长度要大于等于5。接着看

image-20231103012352008

两个关键信息,第一个箭头是根据读入name的ascii判断是不是可以可见字符,如果比0x20小就不是了,读到了就会直接jb出去。

第二个箭头将所有eax的ascii值相加。接着看

image-20231103012704954

将目前的和右移3位,在异或0x515A5,push进栈等会用。接着看

image-20231103013050595

这里应该算是比较核心的区域了。

首先第一个框先给eax,0xA。然后三行代码用来判断什么时候跳出这个循环。

接着两个箭头,是比较0x30和0x39,对应的就是0到9的字符串,意思serial必须要是0到9的数字。然后通过sub获得一个纯数字。然后先将edi和eax相乘,意思就是每轮这里的edi都要乘一个0xA。再在edi本身的基础上加上刚刚的那个纯数字,用作下一轮要成的东西。

接着看

image-20231103013431935

出来之后的edi异或0x87ca,给ebx,然后ebx也就是异或出来的值和之前处理的压在栈里的数据相加,结果比较0x797E7。

不对的话则返回不对的信息。

首先爆破一下

image-20231103013634536

nop掉

image-20231103013646817

image-20231103013700162

就成了。

接下来写一个keygen吧。

keygen的作用就是根据name生成一个serial对吧,现在name的作用知道了,先写

image-20231103014141154

非常正确

image-20231103014752611

一致,一阶段ok。

现在这个0x797E7-329621就是ebx一个的值,168018,再异或0x87ca,0x21798就是上面那个serial处理得到的值。

然后!猛然一惊醒,这里

image-20231103020409596

其实就是这样

image-20231103020439167

就是将字符直接排列了,非常好看懂。

那么keygen其实已经写完了。

sName="cxyyy"

nSum=0

for i in sName:

  nSum+=ord(i)

nTmp=nSum<<0x3

nEnd1=nTmp^0x515A5

nEbx=0X797e7-nEnd1

nEdi=nEbx^0x87Ca

print(nEdi)

让他按照10进制直接输出即可,137112

image-20231103020554459

对了,换一个

image-20231103020638592

OK!

NAG

这个据说是什么外国那边的一个说法,意思是每次推出都有一个弹窗,叫我们把他抹去,应该比较好搞。

image-20231103020812281

每次弹窗信息,定位到这,让他跑

image-20231103020844130

image-20231103020909482

根据栈信息找到这个call,直接nop

image-20231103020950556

就没有啦