本帖最后由 codelive 于 2014-5-8 17:33 编辑
今天刚注册的吾爱,也是第一次发帧,先自我介绍一下吧,我是程序员一枚,从事编程15年了,擅长C++/C,没事也经常搞一些破解,但多数都是爆破,对反汇编后的算法研究很少,之前一直没在论坛里混过,感觉很孤独,许多时候在破解的很无助,现在终于加入大家庭了,希望在这里能得到大家的帮助,共同提高。
参加360这个破解大赛纯属是为了学习,起初以为应该很简单的,结果发现这个题目中涉及了非常多的技术和陷阱,能力有限,只进行了一些简单的分析,下面的文档已经提交给360了,不知道是否能得分,发此帖了算是记录一下吧.
<<360安全破解题CrackMe分析>> Adong - 2014/04/24 //////////////////////////////////////////////////////////////////////// Name : 刘东发, 15工作经验的软件开发人员 WeiBo: http://weibo.com/206069452, @源带码 //////////////////////////////////////////////////////////////////////// l 首先进行了简单运行和测试,有以下发现: 1. 程序有加壳,原程序的区块进行压缩处理,用查找签名工具无法查出是何种程序开发语言或者是哪种已知的壳
2. 程序在运行时首先对程序数据解压缩,完全后会使用CreateProcess创建自己新的进程,新进程运行后,父进程退出。
3. 使用工具PETools对进程进行Dump,然后用ImportREC对IAT进行修复,虽然IAT修复成功,但程序运行会崩溃,初步判断程序运行后可能对部分程序数据进行了修改,虽然不能运行,但可以用 IDA Pro工具进行静态分析。
4. 对Dump后的程序使用IDA Pro进行静态分析,发现有使用以下加解密API: CryptAcquireContextW CryptCreateHash CryptDecrypt CryptDeriveKey CryptDestroyHash CryptDestroyKey CryptHashData
5. 在使用IDA Pro分析的字符串部分看到了 Cinflate 1.1.4 Copyright 1995-2002Mark Adler,表明程序可能是zlib压缩的。
l 对程序进行调试分析: 1. 使用 OllyDbg Attach到运行的进程进行调试,程序有一些反跟踪/反调试处理, 1) 频繁的SetTimer的调用,防止设置断点GetWindowTextW 2) 有调用CreateThread创建一个线程,这个线程有可能是进行用户名和密码进行验证,但如果对线程函数部分进行调试,调试器会崩溃,可能是OD的问题,最终分析发现,这个线程就是Diasble/Enable “Register”按钮的,没其他作用 .360:0040255A push 0 .360:0040255C push 0 .360:0040255E push edi .360:0040255F push offset sub_402050 .360:00402564 push 0 .360:00402566 push 0 .360:00402568 call CreateThread
.360:00402050 sub_402050 procnear ; .360:00402050 .360:00402050 arg_0 = dword ptr 8 .360:00402050 .360:00402050 push ebp .360:00402051 mov ebp, esp .360:00402053 mov ecx, [ebp+arg_0] .360:00402056 push 0 ; bEnable .360:00402058 push 3E8h ; nIDDlgItem .360:0040205D call sub_417280 .360:00402062 mov ecx, eax .360:00402064 call sub_417156 .360:00402069 push 7D0h ; dwMilliseconds .360:0040206E call Sleep .360:00402074 mov ecx, [ebp+arg_0] .360:00402077 push 1 ; bEnable .360:00402079 push 3E8h ; nIDDlgItem .360:0040207E call sub_417280 .360:00402083 mov ecx, eax .360:00402085 call sub_417156 .360:0040208A xor eax, eax .360:0040208C pop ebp .360:0040208D retn 4 .360:0040208D sub_402050 endp
3) 设置断点GetWindowTextW/GetDlgItemTextW获取用户输入函数后调试器还是崩溃(或许和调试器有关系,使用WinDbg没这个问题) 4) 程序中使用了一些花指令防止静态分析 5) 程序还做了欺骗,简单的改变CMP/JE指令,仍然是Failed,所以应该是在线程中进行的处理
6) 对是否被调试有检查,会调用 IsDebuggerPresent , ZwQueryInformationProcess等API来Check,如果被Debug则计算错误 7) 程序本身好像有些问题,比如第一次输入了username和password,计算出了一个结果,然后重新输入后不管是否正确就不在重新计算验证了。
2. 写了一个DLL,HOOK一些API函数,比如GetWindowTextW等,使用工具CFF 增加DLL导入,以便可以HOOK到进程的API调用
3. 在运行中发现,修改过的程序在计算的时候结果是不正确的,猜测可能是程序有检验,通过使用Procmon.exe监视程序访问的文件或者注册表发现, 程序会读取文件尾部4个字节的数据 35 F6 73 9C,这个数值一样是类似CRC32的一样计算结果 ,Procmon Log : ReadFile C:\test\360\360.exe Offset: 780,362, Length: 4
4. 因为不能修改程序,要破解算法也复杂,所以使用动态注入DLL的方式,工具是我很久以前写的程序:
主要是HOOK几个API:
CryptAcquireContextW, CryptCreateHash, CryptDecrypt,CryptDeriveKey, CryptHashData
下图是用给的提示用户名:360和正确的密码输入,返回API HOOK的Log output:
解密的结果: 5375636365737300000000000000000000000000000000000000000000000000 就是字符串: Success, HASH数据 6C696E67647578就是: lingdux,如果输入错误的密码,则不会调用到CryptDecrypt相关的函数,因此可能在此之前就有一个预先的判断。 5. 写了一个程序对API过程进行了模拟,大概代码是: // "lingdux" const BYTE password[] = { 0x6C, 0x69, 0x6E, 0x67,0x64, 0x75, 0x78 }; CryptAcquireContextW(&hCryptProv, NULL,MS_ENHANCED_PROV_W, PROV_RSA_FULL, 0); CryptCreateHash(hCryptProv, CALG_MD5, 0, 0,&hHash); CryptHashData(hHash, (BYTE *)password,sizeof(password), 0); CryptDeriveKey(hCryptProv, CALG_3DES_112, hHash,KEYLENGTH, &hKey);
解密: CryptDecrypt(hKey, 0, bEOF, 0, pbBuffer, &dwCount); 加密: CryptEncrypt(hKey, NULL, bEOF, 0, pbBuffer,&dwCount, dwBufferLen);
所以综上所述,只要用户名和密码变换后加密的数据是: 1D55F56FED567B9533643A387D13D91FA80C08B173AF80820D5C5E91216546EBCB368D08EEA3691B,就是正确的。
6. 对username和password的变换分析: 通过查看程序资源,可以得知username EditBox的ID是1001(3E9h),password的ID是1002(3EAh),所以可以很容易知道这个位置是获取输入的代码: 其实到这里,就已经很容易做一个Patch程序来暴利破解了,当然如果要实现注册机,就必须知道程序的具体算法,还需要再进行分析,本人由于时间关系,目前就分析到这里了,不过自己确信最终一定能够分析出算法,等我有时间会再继续。 最后非常感谢360公司举办的大赛,这个CrackMe确实是一个非常不错的,融合了多种反调试/防破解技术,是一个很好的学习程序,在破解的同时自己的水平也有了提高。
|