参赛题目
Windows平台CrackMe
题目答案
75A29C09E180217C048420956C15DA309FF2B69170
详细的题目设计
1. 为程序写了一个简单的壳,对程序进行简单的异或加密(加了壳之后程序会报毒,水平有限暂时无法解决)。若对程序进行dump,会丢失藏在文件中但没有读入内存的DES解密函数,使序列号无法正常解密
2. 使用自己实现LoadLibrary将kernel32导入到内存中,并使用自己实现的GetProcAddress通过已加密的函数名获取函数地址,隐藏api调用
3. 程序入口处判断了是否处于调试状态,包括检查PEB的BeingDebugged、堆标志位和父进程名是否为explore.exe或cmd.exe
1) 如果不为调试状态,则以调试方式打开程序本身,创建子进程
2) 如果处于调试状态,则显示CrackMe对话框
4. 通过SetUnhandledExceptionFilter设置了异常筛选器
5. 当用户点击确定按钮时,会触发除0异常。如果本进程是通过父进程以调试模式打开,则该异常会被父进程捕获;否则,会被异常筛选器给捕获(正常情况不会来这里)
6. 程序本身没有正常调用验证序列号的流程。当父进程捕捉到除0异常之后(程序第一次点击确认按钮时),会对错误的验证序列号的函数进行hook,从而跳转到正确的流程。
7. 验证序列号流程
-
程序中提供前96字节的DES解密算法明文(记为fuc1)。验证前会将pe文件中已的DES解密算法密文(记为fuc2)读入内存中。
-
验证码的前10个字符组成4字节和1字节的两个秘钥,这两个秘钥对fuc2进行简单移位异或操作解密并与fuc1的前96字节比较,验证成功则继续。
-
验证码的后32字符组成16字节密文,通过程序中提供的秘钥调用fuc1对密文进行解密,验证解密出的明文与程序中的明文进行比较,字符串相同则为提示成功。
破解思路
1. 对程序进行脱壳dump。可以通过修改自己加载的kernel32的地址为系统kernel32的地址,使用OD调试时即可观察到程序调用api情况
2. 在WinMain中通过修改全局的调试状态标志位使得程序能够在调试状态下创建子进程(默认只能通过explore.exe和cmd.exe打开的进程才会创建子进程)
3. 在处理调试事件的函数中下断点,找到程序的hook点和hook的内容,直接对程序对应位置修改机器码。此时还原了程序正确的流程,点击确认按钮就可以正常验证序列号
4. 解密des函数的两个秘钥(共5个字节)可以通过穷举法获取,异或算法较为简单,很容易就能还原出来,通过解密密文和程序中的前96字节明文对比可以确认秘钥是否正确。需要注意的是,des函数需要在原文件中提取。这里获得的两个秘钥转为十六进制字符,得到序列号前10个字符。通过测试,对于i5-4210h CPU单线程需要跑20分钟
5. 识别出变形的des算法(在加密前和解密后需要对偶数位进行取反,即异或0x55),根据程序中提供的16位明文和秘钥进行加密,得到16位密文,对密文转为十六进制字符,得到序列号的后32个字符。此时组成的48位序列号即为最终答案