作为练手的 160 个 CrackMe 系列整理分析

CrackMe 来源:【反汇编练习】160个CrackME索引目录1~160建议收藏备用

024

代码

流程是使用用户名注册码计算出 X 存入 [4012D9] 处,再对包含 [4012D9] 在内的一段代码进行异或检验计算。

这段计算的关键在于使用了代码段的一部分 (4011EC~4012E4 共 3E*4 个字节) 四字节循环异或计算校验值,其中 [4012D9] 这个双字会受到用户名和注册码的影响而变化,此外也不能打 int3 断点。

接下来进行倒推,假设 [4012D9] = 0xM1M2M3M4,注意 [4012D9] 没有 4 字节对齐
(4012D8 :04 M4 M3 M2 | M1 AD 33 D8)。

因为计算过程是每个双字代入异或,所以将 04 和 M1 交换不影响结果(两个都是最低位),由此得到 0xM2M3M4M1 = 0xAFFCCFFB ^ 0xFBDA24A3 = 0x5426EB58,其中 0xFBDA24A3 是将 [4012D9] 填入 0 时剩余部分计算的结果。

还原得到 [4012D9] = 0x585426EB。

当填入正确的机器码时,流程便会跳转到正确提示处

正确执行流程

004012BB    3105 D9124000        xor dword ptr ds:[4012D9],eax      ; eax 视为 X
004012C1    C1E8 10              shr eax,10
004012C4    66:2905 D9124000     sub word ptr ds:[4012D9],ax        ; 这里高 16 位可单独推算

根据上面的代码有公式 [4012D9] = ([初始4012D9] ^ X) – (X >> 16) = 0x585426EB, 代入 [4012D9] 初值 0x584554,
得出 X = 580C????,剩下的写个循环算一下得到 3BA3,所以 X = 580C3BA3

而 X 由

  • [40300B] 的初值 0x58455443
  • 用户名的计算和
  • atoi(注册码)

计算得到(参见代码图),方便起见用户名填入一个”1″(不能留空),得到注册码应为 X – 0x58455474 = 0xFFC6E72F = 4291225391,其中 0x58455474 是用户名填 1 时与 [40300B] 计算的中间值,即 0x58455443 + 0x31 = 0x58455474。

注:因为是按整个缓冲区的大小来对用户名进行计算的,所以比如先填了”2222″,再换成”1″,缓冲区中残留的 “22” 也会对计算造成影响,所以在程序运行后不要填写多余的字符才行。

得到一组注册码:

1

4291225391

结果


026

通过查找字符串可快速定位到计算注册码的代码。然后一直往上翻,即可找到函数的入口处。接下来顺序往下看(以用户名“123456”为例)

  1. (跳过用户名最小长度检测部分)
  2. 首先是一个循环,里面顺序取出用户名的每个字符,进行 ch * 432.4 * 17.79 / 15 = X1 的运算,并且通过 SendKeys 函数向窗口发送 home 键和 del 键的消息来取后续的用户名字符。因为每次循环都会将结果保存到同一个地方,所以等价为计算最后一个字符。 SendKeys 这里有反调试的效果,单步会使原程序收不到按键消息而进入死循环。2
  3. 将上一步的 X1 取整为 X11。3
  4. X11 加上用户名第一个字符(的ascii)到 X2。4
  5. X11 – (用户名第一个字符 * 0x19) 得到 X3。5
  6. X11 转 16 进制字符串得到 X4。
  7. 用户名第一个字符 * 用户名长度 – 0x1b 得到 X5。7
  8. 将 (10进制X2)、(16进制X3)、(X4)、(10进制X5)、(用户名长度)、(“-CM”) 依次连接,即得到正确注册码,最后比较。

8

Ps: vb代码真又臭又长。