吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10666|回复: 14
收起左侧

[转贴] C-Free3.5的算法分析

  [复制链接]
cu629944 发表于 2011-4-27 12:49
本帖最后由 cu629944 于 2011-8-23 09:15 编辑

【文章标题】: C-Free3.5的算法分析
【文章作者】: Nisycc
【作者邮箱】: 1015636182@qq.com
【下载地址】: 自己搜索下载
【加壳方式】: ASPack 2.12
【保护方式】: 机器码 + 序列号 且 机器码 + 序列号
【编写语言】: Borland C++ 1999 / C++
【使用工具】: OD,PEID
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  [软件说明] :
    C-Free是一款基于Windows的C/C++集成化开发软件(IDE)。利用本软件,使用者可以轻松地编辑、编
    译、连接、运行、调试C/C++程序。特别地,这款软件对于C/C++的学习者非常容易使用,是迅速提高C/C++水平
    的好帮手。当然,C/C++高手也会在其中找到许多惊喜的功能。
    C-Free包含下列主要特征:
    支持MinGW编译器和C/C++解释器Ch
    集成化的调试环境
    工程管理
    可定制的语法加亮编辑器
    智能输入(大大地提高代码输入效率)
    函数列表
    集成化的C/C++库函数帮助
    快速创建控制台、窗口和DLL应用
    借助工程模板创建自己想要的工程类型
    完善的查找替换功能
    可定制的代码模板
    支持Window图形界面应用的开发
    对话框资源编辑器
      ASPack 2.12 脱壳很简单,ASPackDie也可以轻松对付。无自校验,脱壳后可直接运行。
      注册情况:机器码给出,输入用户名Nisycc和注册码12345678,确定,提示重启验证。
    说到重启验证,最简单最直接的就想到注册表,确认一下,打开注册表搜索用户名Nisycc,用注册表监控软件,
    在\HKEY_LOCAL_MACHINE\SOFTWARE\C-Free\3.5下找到了,同样列在其中的还有我们输入的假码12345678和
      我机器上的机器码(MachineCode)3294393771。这下我们就可以确定了软件确实是通过注册表来进行重启验证
      的。目标如此明确,载入脱壳后的程序,下断点RegQueryValueExA(我下了RegQueryValueA,可是没有~运气
      不好~),呵呵,可以了。F9运行,马上被断下,看堆栈,ValueName = "layout text",不是我们想要的,继
      续F9,注意断点不能取消,因为后面的对注册表的读取还是要靠这个函数,再次断下,还不是,再运行...,80
      次左右(没去数,好多~),堆栈中显示ValueName= "MachineCode",这就是要读取机器码了,注意。再次F9,
      断在读取RegistryCode也就是假码的地方,呵呵。
    再接下来是读取UserName,即用户名。到这里,计算注册码的准备工作就做完了,可是在那里计算的呢
    ?作者在软件启动的时候将所有的配置信息连同机器码,用户名和注册码一起读出,而且也没有读出后立即计
    算注册码继续比较,这就给我们定位注册码计算造成了困难。这个时候我们该怎么办?两个办法,一个就是下
    面都进行单步跟踪,直到找到关键函数为止,毕竟软件在启动前肯定会计算注册码的;另外一个办法就是在内
    存中搜索假码然后下内存断点,这个方法倒是即快又方便,但是要掌握时机,具体什么时候搜内存要看代码的
    动作。偶选择在内存中搜索假码~。当你在堆栈中看到
    ValueName = "EditorTabWidth"的时候,小心一些哦~
    ----------------------------------------------------------------------------------------
    00419654 |.>MOV WORD PTR DS:[EBX+10],4B8
    0041965A |.>MOV EDX,unpacked.005DAA4C ; ASCII "EditorTabWidth"
    0041965F |.>LEA EAX,DWORD PTR SS:[EBP-620]
    00419665 |.>CALL unpacked.0058D308
    0041966A |.>INC DWORD PTR DS:[EBX+1C]
    0041966D |.>MOV EDX,DWORD PTR DS:[EAX]
    0041966F |.>MOV EAX,ESI
    00419671 |.>CALL unpacked.004E936C
    00419676 |.>MOV ECX,DWORD PTR DS:[EDI]
    00419678 |.>MOV EDX,2
    0041967D |.>MOV DWORD PTR DS:[ECX+A0C],EAX
    00419683 |.>LEA EAX,DWORD PTR SS:[EBP-620]
    00419689 |.>DEC DWORD PTR DS:[EBX+1C]
    0041968C |.>CALL unpacked.0058D520
    00419691 |.>MOV ECX,DWORD PTR DS:[EDI]
    00419693 |.>MOV BYTE PTR DS:[ECX+8F4],0
    0041969A |.>MOV EAX,DWORD PTR DS:[EDI]
    0041969C |.>INC DWORD PTR DS:[EAX+8F0]
    004196A2 |.>CALL unpacked.00462F18 ; 取机器码送EAX
    004196A7 |.>MOV DWORD PTR SS:[EBP-764],EAX
    004196AD |.>MOV WORD PTR DS:[EBX+10],98
    004196B3 |.>MOV EDX,DWORD PTR DS:[EDI]
    004196B5 |.>MOV ECX,DWORD PTR DS:[EDX+8E4]
    004196BB |.>CMP ECX,DWORD PTR SS:[EBP-764]
    004196C1 |.>JNZ unpacked.00419772
    004196C7 |.>LEA EAX,DWORD PTR SS:[EBP-884]
    004196CD |.>PUSH EAX ; /Arg2
    004196CE |.>MOV EDX,DWORD PTR SS:[EBP-764] ; |[EBP-764]==机器码
    004196D4 |.>PUSH EDX ; |Arg1
    004196D5 |.>CALL unpacked.00462F70 ; \关键CALL,跟进
    004196DA |.>MOV WORD PTR DS:[EBX+10],4C4 ; 上面的这个CALL计算真码,存放在EAX中(哎!又是明文
    )
    004196E0 |.>ADD ESP,8
    004196E3 |.>LEA EDX,DWORD PTR SS:[EBP-884] ; 真码地址送入EDX
    004196E9 |.>LEA EAX,DWORD PTR SS:[EBP-624]
    004196EF |.>CALL unpacked.0058D308
    004196F4 |.>INC DWORD PTR DS:[EBX+1C]
    004196F7 |.>MOV EDX,DWORD PTR DS:[EAX]
    004196F9 |.>MOV EAX,DWORD PTR DS:[EDI]
    004196FB |.>MOV EAX,DWORD PTR DS:[EAX+8E8] ; 假码送入EAX,呵呵,准备比较了哦
    00419701 |.>CALL unpacked.004ECED4 ; 比较函数
    00419706 |.>TEST EAX,EAX
    00419708 |.>LEA EAX,DWORD PTR SS:[EBP-624]
    ----------------------------------------------------------------------------------------
    我们要找算法的计算过程,所以004196D5 处跟进:
    ----------------------------------------------------------------------------------------
    00462F70 /$>PUSH EBP
    00462F71 |.>MOV EBP,ESP
    00462F73 |.>ADD ESP,-0C
    00462F76 |.>XOR EDX,EDX
    00462F78 |.>PUSH EBX
    00462F79 |.>PUSH ESI
    00462F7A |.>PUSH EDI
    00462F7B |.>MOV EBX,25 ; EBX=0x25
    00462F80 |.>MOV ECX,DWORD PTR SS:[EBP+8] ; [EBP+8]==机器码
    00462F83 |.>XOR ECX,90909090 ; 机器码异或90909090,ECX==35571EE8
    00462F89 |.>MOV EAX,ECX
    00462F8B |.>DIV EBX ; 上面异或的结果除以25
    00462F8D |.>MOV EAX,EDX ; 余数送EAX
    00462F8F |.>CMP EAX,11 ; 余数同0x11比较
    00462F92 |.>JGE SHORT unpacked.00462F97 ; 大于等于就直接压栈准备函数调用
    00462F94 |.>ADD EAX,11 ; 否则余数+0x11,然后再入栈
    00462F97 |>>PUSH EAX ; /Arg3 余数入栈
    00462F98 |.>LEA EDX,DWORD PTR SS:[EBP-C] ; |
    00462F9B |.>PUSH EDX ; |Arg2
    00462F9C |.>PUSH ECX ; |Arg1 上面异或结果入栈
    00462F9D |.>CALL unpacked.005861F0 ; \跟进
    00462FA2 |.>MOV ECX,DWORD PTR SS:[EBP+C]
    00462FA5 |.>ADD ESP,0C
    00462FA8 |.>MOV ESI,ECX
    00462FAA |.>XOR EAX,EAX
    00462FAC |.>LEA EDI,DWORD PTR SS:[EBP-C]
    ----------------------------------------------------------------------------------------
    00462F9D 处继续跟进:
    ----------------------------------------------------------------------------------------
    005861F0 /$>PUSH EBP
    005861F1 |.>MOV EBP,ESP
    005861F3 |.>MOV EAX,DWORD PTR SS:[EBP+10]
    005861F6 |.>MOV EDX,DWORD PTR SS:[EBP+8]
    005861F9 |.>CMP EAX,0A ; 余数同0A比较
    005861FC |.>PUSH 61
    005861FE |.>SETE CL ; 条件为假,所以CL清零
    00586201 |.>AND ECX,1
    00586204 |.>CMP EAX,0A ; 仍然同0A比较
    00586207 |.>PUSH ECX
    00586208 |.>PUSH EAX
    00586209 |.>MOV ECX,DWORD PTR SS:[EBP+C]
    0058620C |.>PUSH ECX
    0058620D |.>JNZ SHORT unpacked.00586213
    0058620F |.>MOV EAX,EDX
    00586211 |.>JMP SHORT unpacked.00586215
    00586213 |>>MOV EAX,EDX
    00586215 |>>PUSH EAX ; |Arg1
    00586216 |.>CALL unpacked.00586160 ; \跟进
    0058621B |.>ADD ESP,14
    0058621E |.>POP EBP
    0058621F \.>RETN
    ----------------------------------------------------------------------------------------
    没有结果,00586216处继续跟进:
    ----------------------------------------------------------------------------------------
    00586160 /$>PUSH EBP
    00586161 |.>MOV EBP,ESP
    00586163 |.>ADD ESP,-24
    00586166 |.>PUSH EBX
    00586167 |.>PUSH ESI
    00586168 |.>PUSH EDI
    00586169 |.>MOV EDI,DWORD PTR SS:[EBP+10] ; [EBP+10]为前面压栈的余数
    0058616C |.>MOV ESI,DWORD PTR SS:[EBP+8] ; [EBP+8]为机器码异或90909090的结果
    0058616F |.>MOV EBX,DWORD PTR SS:[EBP+C]
    00586172 |.>CMP EDI,2 ; 余数同0x2比较
    00586175 |.>JL SHORT unpacked.005861C4 ; 小于跳
    00586177 |.>CMP EDI,24 ; 同0x24比较
    0058617A |.>JG SHORT unpacked.005861C4 ; 大于则跳
    0058617C |.>TEST ESI,ESI
    0058617E |.>JGE SHORT unpacked.0058618C
    00586180 |.>CMP BYTE PTR SS:[EBP+14],0
    00586184 |.>JE SHORT unpacked.0058618C
    00586186 |.>MOV BYTE PTR DS:[EBX],2D
    00586189 |.>INC EBX
    0058618A |.>NEG ESI
    0058618C |>>LEA ECX,DWORD PTR SS:[EBP-24] ; 下面为关键循环
    0058618F |>>/MOV EAX,ESI ; ESI==机器码异或结果
    00586191 |.>|XOR EDX,EDX ; EDX清零
    00586193 |.>|DIV EDI ; 将上面异或结果除以压栈的余数
    00586195 |.>|MOV BYTE PTR DS:[ECX],DL ; 上面计算的余数的一个字节写入内存
    00586197 |.>|INC ECX
    00586198 |.>|MOV EAX,ESI
    0058619A |.>|XOR EDX,EDX
    0058619C |.>|DIV EDI
    0058619E |.>|MOV ESI,EAX ; 又做了一次相同的计算,商送入ESI
    005861A0 |.>|TEST EAX,EAX ; 直到EAX==0为止
    005861A2 |.>\JNZ SHORT unpacked.0058618F ; 不为0则继续循环
    005861A4 |.>JMP SHORT unpacked.005861BD
    005861A6 |>>/DEC ECX
    005861A7 |.>|MOV AL,BYTE PTR DS:[ECX] ; 内存[ECX]的值送入AL
    005861A9 |.>|CMP AL,0A ; 同0A比较
    005861AB |.>|JGE SHORT unpacked.005861B5 ; 大于等于跳到下面进行另外的计算
    005861AD |.>|ADD EAX,30 ; 该值加上0x30
    005861B0 |.>|MOV BYTE PTR DS:[EBX],AL ; 这个值就是注册码的第i个值,写入内存保存起来
    005861B2 |.>|INC EBX ; 继续下一步
    005861B3 |.>|JMP SHORT unpacked.005861BD
    005861B5 |>>|ADD AL,BYTE PTR SS:[EBP+18] ; 上面如果大于0A,则加上[EBP+18]==61,
    005861B8 |.>|ADD AL,0F6 ; 再加上0F6
    005861BA |.>|MOV BYTE PTR DS:[EBX],AL ; 作为注册码的第i个值写入内存
    005861BC |.>|INC EBX
    005861BD |>> LEA EDX,DWORD PTR SS:[EBP-24] ; 取地址[EBP-24]
    005861C0 |.>|CMP ECX,EDX ; 比较是否结束循环
    005861C2 |.>\JNZ SHORT unpacked.005861A6 ; 没有结束则继续
    005861C4 |>>MOV BYTE PTR DS:[EBX],0
    005861C7 |.>MOV EAX,DWORD PTR SS:[EBP+C]
    005861CA |.>POP EDI
    005861CB |.>POP ESI
    005861CC |.>POP EBX
    005861CD |.>MOV ESP,EBP
    005861CF |.>POP EBP
    005861D0 \.>RETN


--------------------------------------------------------------------------------
【经验总结】
    呵呵,过程清晰明了吧?第一次循环:机器码异或0x90909090的结果除以前面求得的压栈的余数,然后这个过
    程的余数写入内存保留,商作为下一次循环的变量继续循环。第二次循环:将第一次循环中写入内存的值逆序
    读取出来,同0xA比较,小于就直接加上0x30,作为注册码的第i个字符写入内存;大于等于则加上61,再加
    0xF6,取低字节作为注册码的第i个字符写入内存。用户名没有参与计算。


--------------------------------------------------------------------------------
【版权声明】: 本文原创于Nisycc(本来想申请账号为Nisycc的,没弄好~成cu629944了~), 转载请注明作者并保持文章的完整, 谢谢!



免费评分

参与人数 3热心值 +3 收起 理由
eason0liu + 1 大牛要我顶的
zone0826 + 1 谢谢分享
missviola + 1 感谢您的分析,[吾爱破解]有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| cu629944 发表于 2011-4-27 13:05
回复 geography 的帖子

呃...是没有~因为俺暂时懒得写~嘿嘿~等有空再放出来~
geography 发表于 2011-4-27 12:56
本帖最后由 geography 于 2011-4-27 12:56 编辑

分析过程清晰明了!

感谢分享 追码心得!
不过易语言注册机的源码? 好像没有吧!!
 楼主| cu629944 发表于 2011-4-27 12:50
沙发自己的~嘿嘿~偶有空写完之后~再把易语言的注册机的源码放出来~嘿嘿~
missviola 发表于 2011-4-27 13:24
不错,有keygen源码就更好了。
zone0826 发表于 2011-4-27 13:36
原来是这样,许多地方看不懂,但是看了你的注译稍稍明白了一些,感谢你的分享。
羡小b 发表于 2011-4-27 13:50
感谢分享。话说感觉到自己的汇编又提高了。最近一直在啃汇编。哈哈。
chesion001 发表于 2011-4-27 14:14
多谢楼主/./.  很详细.
Hmily 发表于 2011-4-27 14:18
代码部分用上代码框那就更好了,会很美观.
gry8686 发表于 2011-4-27 14:24
支持楼主的分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-29 15:14

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表