160个Crackme之033学习笔记

33CM程序,打开程序,选择“Help—Register”命令,输入name/serial=52pojie/1234567890”,点击“OK”按钮,注册窗口消失,弹出两次错误提示框:

   

第一步、查壳:

无壳,ASM汇编程序:第二步、爆破:OD载入Cruehead.1.exe,先中文搜索,很容易看到了各种文本提示内容,有一个正确提示和两个错误提示:

双击“Good work!”这一行进入CPU窗口:

向下查看,0040134D00401361处是弹出正确提示框的子程序代码,004013620040137D处是错误提示框的子程序代码,再向下004013AD004013BC处又是错误提示框的代码。从上图看到正确提示框最后一行代码是retn,说明这一段应该是一段子程序,要有调用的地址。点击0040134D这一行,信息栏中出现“本地调用来自 0040124C”的提示;

再向下点击第一段错误提示框的子程序开始行00401362处,信息栏中出现“本地调用来自 00401245”的提示:

第二段错误提示框的代码被包含于0040137E004013C1处的子程序中,点击子程序首行0040137E处,信息栏中出现含“本地调用来自 0040122D”的提示。

注意看了一下这三个调用来源,地址基本上是在一起的,所以在任一信息栏中右键点击“本地调用来自 XXXXXXXX”这一行,选择“转到CALL来自XXXXXXXX”命令,均可来到调用来源处查看相应代码,

这里我返回第二段错误提示的代码调用地址0040122D处:仔细观察上下文代码,0040122D00401245两处调用错误子程序,那么将其改为调用正确提示的子程序地址0040134D,那么不就行了吗?下图为已修改过的代码,存为可执行文件Cruehead.1.call.sucess.exe,运行一下,如果不输入name/serial,点击OK按钮,注册窗口消失,不弹出正确提示;随意输入name/serial,则弹出两次正确提示,还没有完全爆破成功。

将修改的两处call 正确提示子程序处撤消修改,再来看这一段代码:00401228处得到name字符串,0040122D调用第二个错误子程序(这里注释成第二个错误子程序是错误的),在0040122D处下断,F9运行CM程序,选择“Help—Register”命令,输入name/serial=52pojie/1234567890”,点击“OK”按钮,程序中断,F7跟入0040137E处:

F8单步向下,运行到0040138B处,跳转到004013AC处成立,会弹出失败提示框,也就是说name字符的最小值是大写字母A,所以在寄存器窗口将双击标志位“C”的值“1”,将其改变为“0”,使跳转不成立,然后继续单步向下,一直到004013C1处,retn00401232处。可以看出这段代码的作用是先判断name输入框中的每一个字符的ASC值是否不小于0x41,如果小于则弹出失败提示框,这就是在注册窗口输入name/serial=52pojie/1234567890”后会出现两次错误提示的原因了,第一次是name字符串不合要求,第二次是serial不匹配name。如果字符的ASC值大于0x5A则减去0x20,然后在004013C2处对name字符串进行运算处理。所以要爆破,可以在0040137E处直接retn掉,或者在0040122Dnop掉,根本不对name进行任何判断和处理,就不会弹出第一次错误提示框了。F8继续向下,可以看出00401241处为关键比较,00401243处是关键跳,跳到正确提示框。

所以爆破的话,将0040122Dnop掉,将00401243je改成jmp,将修改后的文件保存为可执行文件Cruehead.1.nop_jmp.exe,运行一下,随意在name/serial文本框中输入任意字符,点击“OK”按钮,弹出正确提示,爆破成功。第三步,追码:再来查找注册算法:Ctrl+F2重载CM程序,F9运行,因为爆破中已经对0040137E处进行了大致分析,知道name\字符串的要求,所以在注册界面输入name/serial=wapojie/1234567890”,点击“OK”按钮,程序中断于0040122D处。上下观察代码,00401228处,将存储name字符串的地址压栈,作为下一行指令中0040137E这个call的参数,得到结果存入eax中;00401233处,将存储serial字符串的地址压栈,调用004013D8处的子程序;继续向下将结果存入ebx中,比较eaxebx,相等则跳向正确,不等则失败。可知0040122D00401238处的调用的两个call分别对name/serial进行运算,这两个call内就是注册算法了。

F7跟入0040137E这个call中,F8向下:前面已经对0040137E0040139A处进行了分析,直接到0040139C处,将esiname.text)压栈到作为下一行004013C2这个call的参数;F8向下,F72进入004013C中,

这是一个小循环,以name字符串的长度作为循环次数,作用是将name字符串得到的每一个ASC值进行累加,值存入edi中,循环结束返回004013A2处,继续F8运行,004013A2004013C1处,edi = edi xor 0x5678,再存入eax中,返回00401232处,此时eax=0x5477F8向下,到00401238F7进入004013D8

这里也有一个循环,作用是将每一个serial中的字符ASC值减去0x30,乘以0xA,再加上下一个字符ASC值减去0x30,得到新的结果,这个结果再乘以0xA,这样循环次数到serial字符串长度值时结束。如果注册码只是数字的话,其实就是将注册码的数字所有的0全部去掉得到的值再乘以10,再与46600x60)异或得到ebx的值。如果注册码中含有其他字符,暂时不考虑。程序验证注册码的算法出来了,用name字符串的ASC值累加,得到的值与0x5678异或,最终存储到eax中;将注册码中所有的0全部去掉得到的值再乘以10,再与46600x60)异或得到ebx的值;如果eax=ebx,则注册码正确。所以注册机算法就是先得到name字符串,将每个字符的ASC值相加,得到的值分别与0x56780x1234异或后转换成10进制数即可(不知道serial用字母行不行,没试验这一点):VB形式的代码如下:【刚开始时没有“If Len(name) > 11 Then name = Mid(name, 1, 11)”这一句,所以在name字符串长度超过11位之后生成的注册码中出现了错误,在OD中自己将API函数基本上都注释了一遍,所以发现了在004012C4004012E4这两个API函数GetDlgItemTextA中对文本长度进行了限制,最多只有11位】

[Visual Basic] 纯文本查看 复制代码

Option Explicit
Private Sub Command1_Click()
Dim name As String
Dim NameInt, n(), serial, i As Integer
    name = Text1.Text
    If name = "" Then
        Text1.Text = "WAPOJIE"
        Text2.Text = "17987"
        Exit Sub
    End If
    If Len(name) > 11 Then name = Mid(name, 1, 11)
    ReDim n(1 To Len(name))
    For i = 1 To Len(name)
        n(i) = Asc(Mid(name, i, 1))
        If n(i) > 90 Then n(i) = n(i) - 32
        NameInt = NameInt + n(i)
    Next i
    serial = NameInt Xor 17484
    Text1.Text = name
    Text2.Text = serial
End Sub
Private Sub Text1_KeyPress(KeyAscii As Integer)
    If KeyAscii < 65 Or KeyAscii > 122 Then KeyAscii = 0
End Sub

附件

033.rar

(213.18 KB, 下载次数: 0)

2019-8-3 15:45 上传
点击文件名下载附件

,含CM原程序、爆破后的程序、注册机、OD的调试文件等。百度链接是:http://pan.baidu.com/s/1skMkJY9,密码: 86pm160CM、我已练习过的前33crackme程序(不含012)都在里面。

THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发
管埋员的头像-小北的自留地

昵称

取消
昵称