一个简单的keygen me算法分析
潜水吾爱很久了,第一次发帖,有什么错误的欢迎指正!!!这个文章是自己原创的,如有雷同纯属巧合!!
上面的check hardecoded 这个就不跟了,非常的简单我们要跟的是下面那个 name/serial check
这个程序应该是用汇编写的,因为入口是push 0
BP GetWindowTextA下这个断点可以跟踪到关键算法
004015E5|.8BEC mov ebp,esp
004015E7|.6A 20 push 0x20 ; /Count = 20 (32.)
004015E9|.68 42324000 push Splish.00403242 ; |Buffer = Splish.00403242
004015EE|.FF75 0C push ; |hWnd = 000102F0 (class='Edit',parent=000202E4)
004015F1|.E8 34010000 call <jmp.&USER32.GetWindowTextA> ; \GetWindowTextA
004015F6|.85C0 test eax,eax ;获取注册码长度
004015F8|.0F84 95000000 je Splish.00401693 ;如果注册码码等于空则跳
004015FE|.A3 67344000 mov dword ptr ds:,eax ;注册码长度
00401603|.6A 0B push 0xB ; /Count = B (11.)
00401605|.68 36324000 push Splish.00403236 ; |name
0040160A|.FF75 08 push ; |hWnd = 000202E8 (class='Edit',parent=000202E4)
0040160D|.E8 18010000 call <jmp.&USER32.GetWindowTextA> ; \GetWindowTextA
00401612|.85C0 test eax,eax ;获取name长度
00401614|.74 68 je short Splish.0040167E
00401616|.A3 63344000 mov dword ptr ds:,eax ;name长度
0040161B|.33C9 xor ecx,ecx
0040161D|.33DB xor ebx,ebx
0040161F|.33D2 xor edx,edx
00401621|.8D35 36324000 lea esi,dword ptr ds: ;name
00401627|.8D3D 58324000 lea edi,dword ptr ds:
我们先看程序最后的比较, 它循环判断的次数是name的长度
004016A8|> \8D35 4D324000 lea esi,dword ptr ds: 指向name得出的结果Y
004016AE|.8D3D 58324000 lea edi,dword ptr ds: 指向serial得出的结果T
004016B4|.33DB xor ebx,ebx
004016B6|>3B1D 63344000 /cmp ebx,dword ptr ds: ;对比name长度
004016BC|.74 0F |je short Splish.004016CD
004016BE|.0FBE041F |movsx eax,byte ptr ds:
004016C2|.0FBE0C1E |movsx ecx,byte ptr ds:
004016C6|.3BC1 |cmp eax,ecx Y和T对比
004016C8|.75 18 |jnz short Splish.004016E2 不相等就挂
004016CA|.43 |inc ebx ebx+1
004016CB|.^ EB E9 \jmp short Splish.004016B6
00401632|> /0FBE041E /movsx eax,byte ptr ds: ;逐个指向name
00401636|. |99 |cdq
00401637|. |F7F9 |idiv ecx ;name的16进制除以ecxecx=10 49/10=4....9
00401639|. |33D3 |xor edx,ebx edx和ebx异或
0040163B|. |83C2 02 |add edx,0x2 ;余数+2
0040163E|. |80FA 0A |cmp dl,0xA
00401641|. |7C 03 |jl short Splish.00401646 ;少于A
00401643|. |80EA 0A |sub dl,0xA ;dl-A
00401646|> |88141F |mov byte ptr ds:,dl ;余数1
00401649|. |43 |inc ebx
0040164A|. |3B1D 63344000 |cmp ebx,dword ptr ds: ;循环name的长度次数
00401650|.^\75 E0 \jnz short Splish.00401632
小结:
name指向每个字符串记为namestr
namestr÷10 余数记为X
xor edx,ebx这里的ebx 每次自增1 ebx设为S
X和 S+1 异或
X+2 =Y
如果Y少于10
则直接跳向
mov byte ptr ds:,Y
否则
Y-10
↓
mov byte ptr ds:,Y
例子:
name第一个为ASCII “1”hex数据是3110进制就是49
49/10=4......9
9和0异或 还是等于9
9+2=11
11》10
∴ 11-10=1
S=S+1
最后1 给
00401669|> /0FBE041E /movsx eax,byte ptr ds: ;逐个指向假码
0040166D|. |99 |cdq
0040166E|. |F7F9 |idiv ecx ;假码的16进制除以ecxecx=10 49/10=4....9
00401670|. |88141F |mov byte ptr ds:,dl ;余数2
00401673|. |43 |inc ebx
00401674|. |3B1D 67344000 |cmp ebx,dword ptr ds: ;循环假码的长度
0040167A|.^\75 ED \jnz short Splish.00401669
假码指向每个字符串记为 Serialstr
Serialstr÷10余数记为 T
movsx byte ptr ds:,T
所以要符合 Y=T 》》》注册成功
例子:
因为现在我们要计算得出Y=T
上面得出Y=1所以T也是等于1
然后就有以下算式
10T+T=11
11/10=1....1
刚好符合,这个条件有很多
例如: 51/10=5....1
是吧,这个公式成立的条件有很多,自己发挥想象。。。
所以 51/10=5...1这个得出51记住51是 10进制转换成16进制是3333是字符串 “3”
所以得出 namne 的1对应 serial 的3
name :12345678
1 3 5 3 9 3 5 3 Y
3 + 7 ! c ! 7 ! T
所以
name:12345678
注册码为:3+7!c!7!
附上易语言源码,代码写的很挫,将就看着吧{:1_936:}
最后附上 keygenme和算法的易语言源码
楼主分析得不错 附件下来学习下。。 Hmily 发表于 2016-7-19 17:42
@Sendige 文章我给你编辑了下,多用代码框方便阅读,第一篇技术文章给予精华鼓励,期待更多分析。
下次记得精华帖回复下。 这个.......没看懂!!!支持一下!!! 本帖最后由 hahacker 于 2016-7-17 22:42 编辑
膜拜师傅。学习了。楼主可否用C写个注册机? E不会。 @Sendige 文章我给你编辑了下,多用代码框方便阅读,第一篇技术文章给予精华鼓励,期待更多分析。 打注释是个好习惯,分析的很详细 Hmily 发表于 2016-7-19 17:42
@Sendige 文章我给你编辑了下,多用代码框方便阅读,第一篇技术文章给予精华鼓励,期待更多分析。
谢谢老大 Sound 发表于 2016-7-20 11:45
下次记得精华帖回复下。
{:1_937:}我又忘了。。。 分析的很详细。