前言
cm160已经第三篇了,做到了第七个cm(第五个被跳过了,之后有时间回头把这个做了)。
题目来源依旧是吾爱破解论坛上pk8900总结好的160个crackme,依旧只是做一下自己练习的记录,欢迎讨论学习,感谢吾爱论坛的各位大神。
程序本身无病毒,杀毒报错可无视,如果实在担心也可也用虚拟机练习
参考链接:
https://www.52pojie.cn/forum.php?mod=viewthread&tid=709699&extra=page=1&filter=author&orderby=dateline
Andrénalin.1
照例先检查下程序信息。
32位vb程序,没有加密壳,程序打开后只有一个输入框和ok按钮。随手输入后弹出来的错误提示,发现这语言有点看不懂,不知道是啥语言,那我们xdbg来看一下。
xdbg里面搜索字符串,发现了提示成功和失败的字符串,跟踪过去看一下具体的代码。
发现successful
提示的上面有个je跳转,跳转后会提示输入失败的信息。所以把这个nop掉看看。
翻译一下发现是德语的提示,直接给通过了。看来这个cm的逻辑还是挺简单的。简单在xdbg里面看一下,发现还有个字符串不知道用到哪了,而且使用的位置刚好在刚刚nop掉的判断的上面,测试了一下就发现是需要输入的key,那这个cm的判断逻辑就是固定值判断,密钥就是SynTaX 2oo1
Andrénalin.2
跟上面的题目是同一个作者,先检查文件,发现依旧是32位vb程序。
打开程序之后,发现这次的验证是需要name和key的,随手输入一下看一下报错的信息,感觉还是德文,待会再xdbg里面可以找一下。
然后拖进xdbg里面看一下。
所以这个RiCHTiG !
就是正确的提示。
那跟踪过去看一下
发现上面的je跳转,在阻止代码进入到正确的提示内容。所以Nop掉看一下。
这样就cm破解成功了。当然这样还不够,我们看一下这个获取key的逻辑是什么。
je是同噶zf寄存器的值来判断的,上面有个test bx,bx
会修改zf的值,bx不为零的时候就判断失败,程序不跳转。此处的 BX 值由MOV EBX, EAX(004022B7)
传递而来,而 EAX 是函数 __vbaVarTstEq
(变量相等性测试)的返回值。
所以猜测目的就是通过 __vbaVarTstEq 比较变量是否相等 → 结果存入 EAX/BX → 用 TEST+JE 判断比较结果是否为 0(即相等)。
那看一下这个__vbaVarTstEq
函数,是将ecx
和eax
进行比较,所以得看eax和ecx的数据是怎么来的,这两个判断的话,肯定有一个是来自于用户输入的,所以得从用户输入的地方开始,一直到这里判断这一大段的代码进行逻辑分析。
这里找了一大圈,我对vb代码不是很熟悉,所以没找到哪里开始获取用户输入的数据,只好找个反编译工具静态分析一下。
用的是VB Decompiler
,发现代码其实只有两个函数。
Private Sub Text2_Change() '4024F0Dim var_1C As Variantloc_00402553: var_18 = Text2.Textloc_00402587: ebx = (var_18 = vbNullString) + 1loc_0040259D: If (var_18 = vbNullString) + 1 = 0 Then GoTo loc_004025C3loc_004025AA: Set var_1C = (var_18 = vbNullString)loc_004025B7: Command1.Enabled = Falseloc_004025BF: If var_1C >= 0 Then GoTo loc_004025F7loc_004025C1: GoTo loc_004025E5loc_004025CE: Set var_1C = var_1Cloc_004025DB: Command1.Enabled = Trueloc_004025E3: If var_1C >= 0 Then GoTo loc_004025F7loc_004025E5: 'Referenced from: 004025C1loc_004025F1: var_1C = CheckObj(var_1C, var_00401DC8, 140)loc_004025F7: loc_0040260C: GoTo loc_00402621loc_00402620: Exit Subloc_00402621: 'Referenced from: 0040260C
End Sub
上面这个是获取输入框的代码
下面是核心验证的代码:
Private Sub Command1_Click() '401FF0loc_00402092: var_58 = Text2.Textloc_004020CA: var_44 = var_58loc_00402126: For var_24 = 1 To Len(var_44) Step 1loc_00402132: loc_00402134: If var_108 = 0 Then GoTo loc_004021D6loc_00402169: var_58 = CStr(Mid(var_44, CLng(var_24), 1))loc_00402176: var_B4 = Asc(var_58)loc_004021A0: var_34 = var_34 + Asc(var_58)loc_004021CB: Next var_24loc_004021D1: GoTo loc_00402132loc_004021D6: 'Referenced from: 00402134loc_00402204: var_34 = var_34 * 1234567890loc_00402276: var_58 = Text1.Textloc_00402298: var_64 = var_58loc_004022CB: If (var_58 = var_34) = 0 Then GoTo loc_00402391loc_004022D1: Beeploc_00402308: var_B4 = "RiCHTiG !"loc_00402327: var_A4 = " RiCHTiG !!!! .... weiter mit dem Nächsten !!!"loc_00402374: var_54 = MsgBox(" RiCHTiG !!!! .... weiter mit dem Nächsten !!!", 48, "RiCHTiG !", 10, 10)loc_0040238C: GoTo loc_00402446loc_00402391: 'Referenced from: 004022CBloc_004023C2: var_B4 = "LEiDER Falsch ! "loc_004023E1: var_A4 = "Leider Falsch! Nochmal veruschen ! Wenn Du es nicht schaffen solltest, schreib mir ! Andrenalin@gmx.net"loc_0040242E: var_54 = MsgBox("Leider Falsch! Nochmal veruschen ! Wenn Du es nicht schaffen solltest, schreib mir ! Andrenalin@gmx.net", 16, "LEiDER Falsch ! ", 10, 10)loc_00402446: 'Referenced from: 0040238Cloc_00402459: GoTo loc_0040248Floc_0040248E: Exit Subloc_0040248F: 'Referenced from: 00402459loc_004024C0: GoTo loc_00esi
End Sub
也给出了汇编的源码,因为太长了这里就不贴全了。
分析一下逻辑是:
遍历输入文本的每个字符
ord() 函数获取字符的ASCII值(等效VB的 Asc())
累加所有ASCII值到 ascii_sum
将ASCII总和乘以固定常数 1234567890
将第4个和第9个字符使用字符【-】替代
这里发现反编译的vb代码和汇编语言存在出入,怀疑是反编译时把部分汇编源码给遗漏了,vb代码中缺失了字符【-】替代的逻辑,但是汇编里面有,这里是试了好几次发现还是不对之后,又重新去看了有汇编代码之后才发现的。最后汇编代码反正看出来了逻辑,就没去细究这个反编译的问题(毕竟用的反编译的软件也挺老了)
知道逻辑之后写个破解脚本
def generate_key(account):# 计算ASCII总和ascii_sum = sum(ord(c) for c in account)# 乘以常数 (64位浮点运算)total = ascii_sum * 1234567890.0# 转换为长整型字符串key_str = str(int(total))# 替换第4和第9位字符 (VB索引从1开始)if len(key_str) >= 4:key_str = key_str[:3] + '-' + key_str[4:]if len(key_str) >= 9:key_str = key_str[:8] + '-' + key_str[9:]return key_str# 测试示例
name = input("输入name:")
print(generate_key(name)) # 输出类似 "168-925802-460"
测试一下:
发现判断成功了。那么这个cm的判断逻辑也找了出来。可以接着做下一道题目了。
Andrénalin.3
依旧是Andrénalin
作者的程序,接着查一下程序,依旧是32位vb程序,没有加密壳。
打开程序后发现只有一个key序列号的验证。
xdbg里面查找字符串,然后跟踪过去看一下代码,找到了提示成功的部分以及上面的je判断。
下个断点然后nop一下:
这样就直接成功了,但是依旧去看一下验证的逻辑。
上面发现一个怀疑是静态key的值kXy^rO|*yXo*m\\kMuOn*+
,还以为跟第一个程序一样是静态key,就试了一下,结果不是,那接着反编译一下。
找到了反编译的vb代码:
Private Sub Command1_Click() '401E20loc_00401EC2: var_58 = Text1.Textloc_00401EFA: var_44 = var_58loc_00401F56: For var_24 = 1 To Len(var_44) Step 1loc_00401F68: loc_00401F6A: If var_104 = 0 Then GoTo loc_0040202Bloc_00401FA3: var_58 = CStr(Mid(var_44, CLng(var_24), 1))loc_00401FB0: Asc(var_58) = Asc(var_58) + 000Ahloc_00401FC4: var_84 = Chr$(Asc(var_58))loc_00401FED: var_34 = var_34 & Chr$(Asc(var_58))loc_00402020: Next var_24loc_00402026: GoTo loc_00401F68loc_0040202B: 'Referenced from: 00401F6Aloc_00402053: If (var_34 = "kXy^rO|*yXo*m\kMuOn*+") = 0 Then GoTo loc_00402119loc_00402059: Beeploc_00402090: var_B4 = "RiCHTiG !"loc_004020AF: var_A4 = " RiCHTiG !!!! .... weiter mit dem Nächsten !!!"loc_004020FC: var_54 = MsgBox(" RiCHTiG !!!! .... weiter mit dem Nächsten !!!", 48, "RiCHTiG !", 10, 10)loc_00402114: GoTo loc_004021CEloc_00402119: 'Referenced from: 00402053loc_0040214A: var_B4 = "LEiDER Falsch ! "loc_00402169: var_A4 = "Leider Falsch! Nochmal veruschen ! Wenn Du es nicht schaffen solltest, schreib mir ! Andrenalin@gmx.net"loc_004021B6: var_54 = MsgBox("Leider Falsch! Nochmal veruschen ! Wenn Du es nicht schaffen solltest, schreib mir ! Andrenalin@gmx.net", 16, "LEiDER Falsch ! ", 10, 10)loc_004021CE: 'Referenced from: 00402114loc_004021E1: GoTo loc_00402217loc_00402216: Exit Subloc_00402217: 'Referenced from: 004021E1loc_00402248: GoTo loc_00esi
End Sub
有个第二题的经验,所以这个vb代码感觉不是特别可信,还得结合汇编去综合的看。
这个逻辑也蛮简单,大体是这样:
输入处理:从文本框 Text1 获取用户输入(var_44 = Text1.Text)。
字符加密:遍历输入字符串的每个字符,将其 ASCII 码值增加 10(Asc(var_58) + 10),再转换回字符并拼接为新字符串 var_34。
结果验证:
若加密后的字符串等于 "kXy^rO|*yXo*m\kMuOn*+",弹出成功消息框("RiCHTiG !")。
否则弹出失败消息框("LEiDER Falsch !")。
写出逆向的脚本:
def decrypt_ciphertext(ciphertext):plaintext = ""for char in ciphertext:decrypted_char = chr(ord(char) - 10)plaintext += decrypted_charreturn plaintexttarget_cipher = "kXy^rO|*yXo*m\kMuOn*+"original_key = decrypt_ciphertext(target_cipher)
print(f"原始key: {original_key}")
那么这个cm也就解出来了,逻辑也明白了,接着看下一个cm。
Andrénalin.4
依旧是同一个作者的题目,依旧是32位vb程序。
打开程序后发现样子不太一样:
右边的状态写的是德语的注册
,下面一个小键盘,让输入序列号,发现这个输入框不让输入,只能用程序里面的小键盘来输入。
进到VB Decompiler
里面反编译一下看一下:
下面13个Commandxx_Click()
函数,应该对应程序小键盘里面的十三个按键。
四个Timerx_Timer()
函数,每个函数里面都是大差不差的加密函数,加密后的数据等于对应的字符串,但是给出了非常多的字符串,哪个是正确的?
去找一下具体的限制条件,发现我们的输入只能是1234567890*#
这十二个符号,先看一下每个单独的加密是怎么样:
For var_24 = 1 To Len(var_44) Step 1char = Mid$(var_44, var_24, 1) ' 取单个字符asc_val = Asc(char) ' 获取ASCII值transformed = asc_val + var_CC ' 关键变换:ASCII值+偏移量hex_str = Hex$(transformed) ' 转换为十六进制字符串var_34 = var_34 & hex_str ' 拼接结果
Next
最后的结果一定全是十六进制字符串,所以找一下哪个满足条件。
在xdbg里面搜索字符串,把字符串复制出来,简单处理后找一下。
发现0817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C
是完全满足条件的。
根据上面计算的逻辑,写出逆向的Python代码:
def decrypt_key():# 加密字符串(来自代码比较部分)enc_hex = "817E747D7A7D7C7F82836D74747A7F7E7B7C7D826D817E7B7C"# 分割为每2字符一组,共25组(对应25字节)hex_parts = [enc_hex[i:i+2] for i in range(0, len(enc_hex), 2)]# 转换为整数列表(十六进制转十进制)enc_bytes = [int(part, 16) for part in hex_parts]valid_results = []allowed_chars = set("1234567890*#") # 定义允许的字符集# 遍历所有可能的 var_CC 值(0-255)for cc in range(0, 256):decrypted_chars = []valid = Truefor eb in enc_bytes:# 解密:减去 var_CC 并取模256(处理字节溢出)orig_byte = (eb - cc) % 256char = chr(orig_byte)# 双重验证:可打印ASCII + 指定字符集if not (32 <= orig_byte <= 126 and char in allowed_chars):valid = Falsebreak # 遇到无效字符,跳过当前ccdecrypted_chars.append(char)if valid:key = ''.join(decrypted_chars)# 验证整个密钥长度(25字符)if len(key) == len(enc_bytes):valid_results.append((cc, key))# 输出结果if valid_results:print("有效的 var_CC 和原始 key:")for cc, key in valid_results:print(f"var_CC = {cc} (0x{cc:02X}), key = '{key}'")print(f"\n共找到 {len(valid_results)} 组有效结果")else:print("未找到有效 key:请检查加密逻辑或字符集约束")# 执行解密
if __name__ == "__main__":decrypt_key()
这样跑出来了结果74*3032589#**0541238#7412
,去测试一下。
输入之后发现状态改变了,就是破解成功了,那么这个cm就完成了。
简要总结
一口气做了四个,同一个作者的,全部都是vb语言写的,vb语言没咋学过,所以分析逻辑的时候用了下ai分析,但是整体的破解逻辑还是挺有意思的,四个程序也是由易到难,很好的cm程序了,感谢吾爱的大神们。