【破文标题】Guetta's R-KeyGenMe 算法分析
【破文作者】XXNB
【作者邮箱】
【作者主页】http://free.ys168.com/?binbinbin7456
【破解工具】OD
【破解平台】xpsp2
【软件名称】Guetta's R-KeyGenMe
【软件大小】25kb
【软件简介】
Hello everybody, a little keygenme in asm :
Stuff: anti-xxx, layers...
Protection: U will see by yourself ;-)
Solution : Keygen & little solution.
Good luck,
Guetta.
Difficulty: 3 - Getting harder
Platform: Windows
Language: Assembler
Published: 07. Dec, 2006
【破解声明】向大侠们学习!!!只为学习!请尊重作者的劳动成功!
------------------------------------------------------------------------
【破解过程】
今天才在 http://www.crackmes.de/users/guetta/r_keygenme/ 发现了个好东西。分析了下,算法还挺简单的。当然如果要用asm写出这个
keygenme我是万万不可能的(我很菜)。
这个keygenme是只有输入正确的注册信息,灰色按钮才是有效的。而且如果用激活按钮的工具的话直接可以看到结果。有不错的音乐听哦。 1、字符串查找可以轻松定位。
004010A4 $ 55 push ebp
004010A5 . 8BEC mov ebp, esp
004010A7 . 53 push ebx
004010A8 . 56 push esi
004010A9 . 57 push edi
004010AA . 6A 20 push 20 ; /Count = 20 (32.)
004010AC . 68 48624000 push 00406248 ; |binbin
004010B1 . 68 94010000 push 194 ; |ControlID = 194 (404.)
004010B6 . FF75 08 push dword ptr [ebp+8] ; |hWnd
004010B9 . E8 FC070000 call <jmp.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
004010BE . 83F8 04 cmp eax, 4 ; 用户名不能小于4位数
004010C1 . 72 4A jb short 0040110D
004010C3 . 6A 20 push 20 ; /Count = 20 (32.)
004010C5 . 68 80604000 push 00406080 ; |123456888
004010CA . 68 95010000 push 195 ; |ControlID = 195 (405.)
004010CF . FF75 08 push dword ptr [ebp+8] ; |hWnd
004010D2 . E8 E3070000 call <jmp.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
004010D7 . 83F8 1D cmp eax, 1D ; 输入的注册码要1D(29位数)
004010DA . 75 31 jnz short 0040110D
004010DC . E8 1F9F0100 call 0041B000 ; 这里是算法call。跟进《《《《《《《《《《《-----
004010E1 . 50 push eax
004010E2 . 68 65604000 push 00406065 ; /Registered !
004010E7 . 68 95010000 push 195 ; |ControlID = 195 (405.)
004010EC . FF75 08 push dword ptr [ebp+8] ; |hWnd
004010EF . E8 0E080000 call <jmp.&user32.SetDlgItemTextA> ; \SetDlgItemTextA
004010F4 . B8 01000000 mov eax, 1
004010F9 . EB 17 jmp short 00401112
004010FB . 68 4C 60 40 0>ascii "hL`@",0 ; You should enter a name.
00401100 . 68 95010000 push 195 ; |ControlID = 195 (405.)
00401105 . FF75 08 push dword ptr [ebp+8] ; |hWnd
00401108 . E8 F5070000 call <jmp.&user32.SetDlgItemTextA> ; \SetDlgItemTextA
0040110D > B8 00000000 mov eax, 0
00401112 > 5F pop edi
00401113 . 5E pop esi
00401114 . 5B pop ebx
00401115 . C9 leave
00401116 . C2 0400 retn 4 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2、跟进算法call可以得到下面关键代码。 0041B000 33DB xor ebx, ebx
0041B002 8D35 84604000 lea esi, dword ptr [406084]
0041B008 8A06 mov al, byte ptr [esi] ; 判断 第五位、第十位、第十五位、第二十位、第二十五位是
否是分隔符
0041B00A 83FB 14 cmp ebx, 14
0041B00D 74 25 je short 0041B034
0041B00F 83C6 05 add esi, 5
0041B012 83C3 05 add ebx, 5
0041B015 34 7F xor al, 7F ; 第五位和7F异或
0041B017 3C 52 cmp al, 52 ; 然后和 52H“R” 比较
0041B019 75 14 jnz short 0041B02F ; 这里说明了每隔四位一定要是分隔符“-”
0041B01B ^ EB EB jmp short 0041B008 ; 跳回循环
0041B01D 33C0 xor eax, eax
0041B01F 53 push ebx
0041B020 3C 52 cmp al, 52
0041B022 75 0B jnz short 0041B02F
0041B024 83C6 05 add esi, 5
0041B027 8A06 mov al, byte ptr [esi]
0041B029 34 7F xor al, 7F
0041B02B 3C 52 cmp al, 52
0041B02D 74 05 je short 0041B034
0041B02F - E9 D960FEFF jmp 0040110D
0041B034 8D35 80604000 lea esi, dword ptr [406080] ; 把整个输入的假码放到esi
0041B03A 8A06 mov al, byte ptr [esi] ; 取第一位
0041B03C 3C 00 cmp al, 0 ; 第一位不能为0
0041B03E 74 19 je short 0041B059
0041B040 3C 2D cmp al, 2D ; 第一位不能为“-”
0041B042 74 12 je short 0041B056
0041B044 3C 30 cmp al, 30
0041B046 72 06 jb short 0041B04E
0041B048 3C 39 cmp al, 39
0041B04A 77 02 ja short 0041B04E ; 第一位要求是数字1~9
0041B04C EB 08 jmp short 0041B056
0041B04E 3C 41 cmp al, 41
0041B050 ^ 72 DD jb short 0041B02F
0041B052 3C 46 cmp al, 46
0041B054 ^ 77 D9 ja short 0041B02F
0041B056 46 inc esi ; 继续下一位判断,
0041B057 ^ EB E1 jmp short 0041B03A ; 循环回去判断。这个循环是检测输入的注册码是否都是数字的
1~9
0041B059 33C9 xor ecx, ecx
0041B05B 8D35 D7614000 lea esi, dword ptr [4061D7]
0041B061 BB 10000000 mov ebx, 10 ; 常数10H(16)
0041B066 0FBE81 80604000 movsx eax, byte ptr [ecx+406080] ; 第一位
0041B06D 3C 00 cmp al, 0
0041B06F 74 3C je short 0041B0AD
0041B071 3C 2D cmp al, 2D
0041B073 74 2A je short 0041B09F
0041B075 3C 40 cmp al, 40 ; 和“@”比较
0041B077 72 04 jb short 0041B07D
0041B079 2C 37 sub al, 37
0041B07B EB 02 jmp short 0041B07F
0041B07D 2C 30 sub al, 30
0041B07F F7E3 mul ebx ; 乘以常数
0041B081 86E0 xchg al, ah ; 掉换高低位
0041B083 8A81 81604000 mov al, byte ptr [ecx+406081] ; 第二位
0041B089 3C 40 cmp al, 40
0041B08B 72 04 jb short 0041B091
0041B08D 2C 37 sub al, 37
0041B08F EB 02 jmp short 0041B093
0041B091 2C 30 sub al, 30
0041B093 02C4 add al, ah ; 高位低位相加
0041B095 8806 mov byte ptr [esi], al ; 存储加的结果
0041B097 83C6 01 add esi, 1
0041B09A 83C1 02 add ecx, 2
0041B09D ^ EB C7 jmp short 0041B066 ; 循环回去。每次循环取两位
0041B09F 83C6 02 add esi, 2
0041B0A2 83C1 01 add ecx, 1 ; 这里是跳过分隔符
0041B0A5 ^ EB BF jmp short 0041B066 ; 循环回去。这上面的循环只是对输入注册码的检测
0041B0A7 33DB xor ebx, ebx
0041B0A9 33D2 xor edx, edx
0041B0AB 33F6 xor esi, esi
0041B0AD 33C0 xor eax, eax
0041B0AF 33DB xor ebx, ebx
0041B0B1 A1 D7614000 mov eax, dword ptr [4061D7] ; 3412
0041B0B6 35 37130000 xor eax, 1337 ; 和1337异或
0041B0BB 83C0 77 add eax, 77 ; 再加上常数77。记为A
0041B0BE 8B1D DB614000 mov ebx, dword ptr [4061DB] ; 8967
0041B0C4 81F3 31730000 xor ebx, 7331 ; 异或
0041B0CA 83EB 44 sub ebx, 44 ; 减44。 记为B
0041B0CD 83E8 77 sub eax, 77 ; A-77
0041B0D0 83C3 44 add ebx, 44 ; B+44
0041B0D3 35 37130000 xor eax, 1337 ; 异或。又得回3412
0041B0D8 81F3 31730000 xor ebx, 7331 ; 异或。得回8967
0041B0DE A3 29624000 mov dword ptr [406229], eax
0041B0E3 891D 2B624000 mov dword ptr [40622B], ebx ; 存储
0041B0E9 33C0 xor eax, eax ; 清空
0041B0EB 33DB xor ebx, ebx
0041B0ED A1 DF614000 mov eax, dword ptr [4061DF] ; 3412
0041B0F2 35 FC000000 xor eax, 0FC ; 异或
0041B0F7 2D 5EA10F00 sub eax, 0FA15E ; 减常量
0041B0FC 8B1D E3614000 mov ebx, dword ptr [4061E3] ; 8967
0041B102 81F3 33030000 xor ebx, 333 ; 异或
0041B108 81C3 FC000000 add ebx, 0FC
0041B10E 05 5EA10F00 add eax, 0FA15E
0041B113 81EB FC000000 sub ebx, 0FC
0041B119 35 FC000000 xor eax, 0FC
0041B11E 81F3 33030000 xor ebx, 333
0041B124 A3 2F624000 mov dword ptr [40622F], eax
0041B129 891D 31624000 mov dword ptr [406231], ebx
0041B12F 33C0 xor eax, eax
0041B131 33DB xor ebx, ebx
0041B133 A1 E7614000 mov eax, dword ptr [4061E7]
0041B138 83F0 64 xor eax, 64
0041B13B 8B1D EB614000 mov ebx, dword ptr [4061EB] ; 上面那堆东西目的是为了:
0041B141 83F3 32 xor ebx, 32 ; 把“1234-6789”转化成“89673412”。以后的依此类推
0041B144 A3 35624000 mov dword ptr [406235], eax
0041B149 891D 37624000 mov dword ptr [406237], ebx ; 我跟完算法后发现这里这堆代码
0041B14F 8335 35624000 6>xor dword ptr [406235], 64 ; 用处不是很大,可能是我水平菜
0041B156 8335 37624000 3>xor dword ptr [406237], 32
0041B15D 833D 29624000 0>cmp dword ptr [406229], 0
0041B164 - 0F84 A35FFEFF je 0040110D
0041B16A 833D 2F624000 0>cmp dword ptr [40622F], 0
0041B171 - 0F84 965FFEFF je 0040110D
0041B177 833D 35624000 0>cmp dword ptr [406235], 0
0041B17E - 0F84 895FFEFF je 0040110D
0041B184 33C0 xor eax, eax
0041B186 33D2 xor edx, edx
0041B188 8D35 48624000 lea esi, dword ptr [406248] ; 用户名到esi
0041B18E 8A06 mov al, byte ptr [esi] ; 取第一位ascii
0041B190 3C 00 cmp al, 0
0041B192 74 05 je short 0041B199
0041B194 03D0 add edx, eax ; 这个循环得到用户名ascii码累加值
0041B196 46 inc esi
0041B197 ^ EB F5 jmp short 0041B18E
0041B199 8915 AD614000 mov dword ptr [4061AD], edx ; 存储累加值
0041B19F FF35 AD614000 push dword ptr [4061AD] ; 累加值入栈
0041B1A5 68 7A604000 push 0040607A ; ASCII "%d"
0041B1AA 68 80624000 push 00406280
0041B1AF E8 B866FEFF call <jmp.&user32.wsprintfA>
0041B1B4 FF35 AD614000 push dword ptr [4061AD]
0041B1BA 68 7D604000 push 0040607D ; ASCII "%x"
0041B1BF 68 85624000 push 00406285
0041B1C4 E8 A366FEFF call <jmp.&user32.wsprintfA>
0041B1C9 33C0 xor eax, eax
0041B1CB 33C9 xor ecx, ecx
0041B1CD 33D2 xor edx, edx
0041B1CF A1 A5A14100 mov eax, dword ptr [41A1A5] ; A8AFA785 这个是固定值
0041B1D4 8B0D 29624000 mov ecx, dword ptr [406229] ; 89673412 这里是前两段
0041B1DA 8B15 80624000 mov edx, dword ptr [406280] ; 00363236 这个是用户名Ascii码 十进制
0041B1E0 33C2 xor eax, edx ; eax 异或 edx
0041B1E2 3BC1 cmp eax, ecx ; 比较。
0041B1E4 - 0F85 235FFEFF jnz 0040110D ; 前两段是=固定值 异或 用户名的Ascii码
0041B1EA 33C0 xor eax, eax
0041B1EC 33C9 xor ecx, ecx
0041B1EE 33D2 xor edx, edx
0041B1F0 A1 ABA14100 mov eax, dword ptr [41A1AB] ; 63366437 固定值
0041B1F5 8B0D 2F624000 mov ecx, dword ptr [40622F] ; 第三、第四段
0041B1FB 8B15 85624000 mov edx, dword ptr [406285] ; 00323732 十六进制
0041B201 33C2 xor eax, edx
0041B203 3BC1 cmp eax, ecx ; 在这里看信息框,然后一一对应就可以得到真码。
0041B205 - 0F85 025FFEFF jnz 0040110D ; 参考上面同理,第三、第四段也可以得出了,
0041B20B 33C0 xor eax, eax
0041B20D 33C9 xor ecx, ecx
0041B20F 33D2 xor edx, edx
0041B211 A1 56A14100 mov eax, dword ptr [41A156] ; F5166011 这个值在你注册成功后会变的。
0041B216 8B0D 35624000 mov ecx, dword ptr [406235] ; 最后两段
0041B21C 8B15 48624000 mov edx, dword ptr [406248] ; 直接使用用户名的十六进制字符串
0041B222 33C2 xor eax, edx
0041B224 3BC1 cmp eax, ecx ; 同理,在这里看信息框一一对应就可以得到真码。
0041B226 - 0F85 E15EFEFF jnz 0040110D
0041B22C - E9 C35EFEFF jmp 004010F4
0041B231 68 65604000 push 00406065 ; ASCII "Registered !"
0041B236 68 95010000 push 195
0041B23B FF75 08 push dword ptr [ebp+8]
0041B23E E8 BF66FEFF call <jmp.&user32.SetDlgItemTextA>
0041B243 68 9F144000 push 0040149F
0041B248 C3 retn ------------------------------------------------------------------------
【破解总结】 1、这个keygenme写的好啊,算法虽然简单,但它包含了一般注册所需要的方法。
2、首先它就规定了输入的注册码要1D,就是29位数的。不够29位数,它一点反映都没有。然后规定“第五位、第十位、第十五位、第二十位、
第二十五位一定要是分隔符”。所以我一开始输入的假码是:1234-6789-8888-9999-5555-6666。
3、它把我们输入的假码分三段,第一段“1234-6789”转化为“89673412”;第二段“8888-9999”转化为“99998888”;第三段“5555-6666
”转化为“66665555”。
4、得到用户名binbin的ascii码累加值。10进制(626)转成“00363236”;16进制(272)转成“00323732”;还有用户名本身前四位(binb
)转成“626E6962”
5、然后对应每段共有3个固定值“A8AFA785”“63366437”“F5166011”。这三个固定值分别异或上面用户名的三个值。就得到相应段的真注
册码了。
有个技巧就是在每次“cmp eax, ecx”真假比较的时候推算出注册码。
这个注册机难写哦。我不会。那位大叔贴出来让我们见识下吧。 +++++++++++++++++++++++++++++++++++++++++++++++++++++
刚才想放出可以的注册信息的时候发现了这个keygenme是有记忆和自修改功能的,就是说但你注册成功一次后,它会改变注册信息,同样是binbin这个用户名,但是那三个固定值中的第三个是变动的。
所以,我暂时没有发现固定的能用的注册信息,大家试试也发表下看法啊。 我又跟了下,发现我还有很多东西没有发现的。这个keygenme真牛。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: