【文章标题】: GIFMovieGear4.2注册码算法分析+注册机
【文章作者】: VIDEN
【作者QQ号】: 38352959
【作者邮箱】: viden@live.cn
【操作系统】: Windows 7
【生产日期】: 20100712
【软件名称】: GIFMovieGear4.2
【软件介绍】: 一个gif格式图片制作软件
【加壳方式】: PECompact 2.x -> Jeremy Collake
【保护方式】: 注册码
【编写语言】: Microsoft Visual C++ 7.0
【使用工具】: OD+PEID+UNPECompact_2.x_by_mirz(脱壳机)
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!第一次分析程序注册码算法,写的第一个KeyGen。不足之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
 GIFMovieGear4.2该程序原本带破解补丁,没注册机,心想原来只是爆破,从没分析过算法。心血来潮挑战一下。

PEID查壳PECompact 2.x -> Jeremy Collake,脱壳机搞定。脱壳后查壳Microsoft Visual C++ 7.0。
运行程序,找到注册位置输入姓名111111,注册码222222。提交后弹出出错信息。
OD载入,字符串参考,没找到出错信息。接着查找二进制字符串FF25,查看输入表函数。发现USER32.GetWindowTextA和USER32.GetDlgItemTextA,都给他硬件访问断点,概率大点。运行程序,找到注册位置填入假注册信息,提交,断在USER32.GetWindowTextA。这样另一个断点就没用了。

断在此处,F8向下运行
00433C1A   .  50            PUSH EAX                                               ; |hWnd = 00160554 (class='Edit',parent=001704F6)
00433C1B   .  FFD3          CALL EBX                                               ; \GetWindowTextA
00433C1D   .  6A 64         PUSH 64                                                ; /Count = 64 (100.)
00433C1F   .  8D8424 C80000>LEA EAX,DWORD PTR SS:[ESP+C8]                          ; |
00433C26   .  50            PUSH EAX                                               ; |Buffer
00433C27   .  68 50040000   PUSH 450                                               ; |/ControlID = 450 (1104.)
00433C2C   .  57            PUSH EDI                                               ; ||hWnd
00433C2D   .  FFD6          CALL ESI                                               ; |\GetDlgItem
00433C2F   .  50            PUSH EAX                                               ; |hWnd
00433C30   .  FFD3          CALL EBX                                               ; \GetWindowTextA
00433C32   .  8D8C24 C40000>LEA ECX,DWORD PTR SS:[ESP+C4]
00433C39   .  51            PUSH ECX
00433C3A   .  8D5424 64     LEA EDX,DWORD PTR SS:[ESP+64]
00433C3E   .  52            PUSH EDX                                               ;运行到此处,看堆栈出现假的注册信息
00433C3F   .  E8 FCFBFFFF   CALL unpacked.00433840                                 ;开始验证,F7进去

到此处,下面这段是检验用户名前四个字符是否为"mg37",一般没人会乱猜一个注册码前四位是"mg37吧"?呵呵,直接跳走
00433840  /$  53            PUSH EBX
00433841  |.  55            PUSH EBP
00433842  |.  8B6C24 10     MOV EBP,DWORD PTR SS:[ESP+10]
00433846  |.  807D 00 6D    CMP BYTE PTR SS:[EBP],6D
0043384A  |.  56            PUSH ESI
0043384B  |.  57            PUSH EDI
0043384C  |.  0F85 AD000000 JNZ unpacked.004338FF                                  ;从这就跳走,继续往下
00433852  |.  807D 01 67    CMP BYTE PTR SS:[EBP+1],67
00433856  |.  0F85 A3000000 JNZ unpacked.004338FF
0043385C  |.  807D 02 33    CMP BYTE PTR SS:[EBP+2],33
00433860  |.  0F85 99000000 JNZ unpacked.004338FF
00433866  |.  807D 03 37    CMP BYTE PTR SS:[EBP+3],37
0043386A  |.  0F85 8F000000 JNZ unpacked.004338FF

跳到此处
004338FF  |>  8B5C24 14     MOV EBX,DWORD PTR SS:[ESP+14]
00433903  |>  55            PUSH EBP
00433904  |.  53            PUSH EBX
00433905  |.  E8 16FCFFFF   CALL unpacked.00433520                                 ;F7进去

到此处
00433520  /$  8B4424 04     MOV EAX,DWORD PTR SS:[ESP+4]
00433524  |.  8D9424 38FFFF>LEA EDX,DWORD PTR SS:[ESP-C8]
0043352B  |.  81EC D8000000 SUB ESP,0D8
00433531  |.  2BD0          SUB EDX,EAX
00433533  |>  8A08          /MOV CL,BYTE PTR DS:[EAX]
00433535  |.  880C02        |MOV BYTE PTR DS:[EDX+EAX],CL
00433538  |.  40            |INC EAX
00433539  |.  84C9          |TEST CL,CL
0043353B  |.^ 75 F6         \JNZ SHORT unpacked.00433533
0043353D  |.  53            PUSH EBX
0043353E  |.  55            PUSH EBP
0043353F  |.  56            PUSH ESI
00433540  |.  57            PUSH EDI
00433541  |.  8D4424 20     LEA EAX,DWORD PTR SS:[ESP+20]
00433545  |.  50            PUSH EAX                                               ; /StringOrChar
00433546  |.  FF15 1CF34700 CALL DWORD PTR DS:[<&user32.CharUpperA>]               ; \CharUpperA                ;CharUpperA函数将用户名全部转换为大写
0043354C  |.  8A4424 20     MOV AL,BYTE PTR SS:[ESP+20]
00433550  |.  84C0          TEST AL,AL
00433552  |.  8D7424 20     LEA ESI,DWORD PTR SS:[ESP+20]
00433556  |.  8D7C24 20     LEA EDI,DWORD PTR SS:[ESP+20]
0043355A  |.  74 26         JE SHORT unpacked.00433582
0043355C  |.  8D6424 00     LEA ESP,DWORD PTR SS:[ESP]
00433560  |>  0FBE0E        /MOVSX ECX,BYTE PTR DS:[ESI]
00433563  |.  51            |PUSH ECX
00433564  |.  68 78F44800   |PUSH unpacked.0048F478                                ;  hkrwqv2958dwntqrgnscfsxazpyk    ;这里是程序自带的一个字符串,先全部转换为大写,把这个字符串记为①,用它经过换算生成注册码的
00433569  |.  E8 B2C00300   |CALL unpacked.0046F620                                ;F7进去
0043356E  |.  83C4 08       |ADD ESP,8
00433571  |.  85C0          |TEST EAX,EAX
00433573  |.  74 05         |JE SHORT unpacked.0043357A
00433575  |.  8A16          |MOV DL,BYTE PTR DS:[ESI]
00433577  |.  8817          |MOV BYTE PTR DS:[EDI],DL
00433579  |.  47            |INC EDI
0043357A  |>  8A46 01       |MOV AL,BYTE PTR DS:[ESI+1]
0043357D  |.  46            |INC ESI
0043357E  |.  84C0          |TEST AL,AL
00433580  |.^ 75 DE         \JNZ SHORT unpacked.00433560

进去后到这,这个CAll的调用目的是检查全部为大写的用户名的每个字符,是否包含在字符串①里面,若存在,返回EAX为该字符在字符串①中的地址,若不存在EAX置0
0046F620  |$  33C0          XOR EAX,EAX
0046F622  |.  8A4424 08     MOV AL,BYTE PTR SS:[ESP+8]
0046F626  |.  53            PUSH EBX
0046F627  |.  8BD8          MOV EBX,EAX
0046F629  |.  C1E0 08       SHL EAX,8
0046F62C  |.  8B5424 08     MOV EDX,DWORD PTR SS:[ESP+8]
0046F630  |.  F7C2 03000000 TEST EDX,3
0046F636  |.  74 15         JE SHORT unpacked.0046F64D
0046F638  |>  8A0A          /MOV CL,BYTE PTR DS:[EDX]
0046F63A  |.  83C2 01       |ADD EDX,1
0046F63D  |.  38D9          |CMP CL,BL
0046F63F  |.^ 74 CF         |JE SHORT unpacked.0046F610
0046F641  |.  84C9          |TEST CL,CL
0046F643  |.  74 51         |JE SHORT unpacked.0046F696
0046F645  |.  F7C2 03000000 |TEST EDX,3
0046F64B  |.^ 75 EB         \JNZ SHORT unpacked.0046F638
0046F64D  |>  0BD8          OR EBX,EAX
0046F64F  |.  57            PUSH EDI
0046F650  |.  8BC3          MOV EAX,EBX
0046F652  |.  C1E3 10       SHL EBX,10
0046F655  |.  56            PUSH ESI
0046F656  |.  0BD8          OR EBX,EAX
0046F658  |>  8B0A          /MOV ECX,DWORD PTR DS:[EDX]                            ;运行到这,看到EBX的值,就知道从这向上这段代码的作用了
0046F65A  |.  BF FFFEFE7E   |MOV EDI,7EFEFEFF
0046F65F  |.  8BC1          |MOV EAX,ECX
0046F661  |.  8BF7          |MOV ESI,EDI
0046F663  |.  33CB          |XOR ECX,EBX
0046F665  |.  03F0          |ADD ESI,EAX
0046F667  |.  03F9          |ADD EDI,ECX
0046F669  |.  83F1 FF       |XOR ECX,FFFFFFFF
0046F66C  |.  83F0 FF       |XOR EAX,FFFFFFFF
0046F66F  |.  33CF          |XOR ECX,EDI
0046F671  |.  33C6          |XOR EAX,ESI
0046F673  |.  83C2 04       |ADD EDX,4
0046F676  |.  81E1 00010181 |AND ECX,81010100
0046F67C  |.  75 1C         |JNZ SHORT unpacked.0046F69A
0046F67E  |.  25 00010181   |AND EAX,81010100
0046F683  |.^ 74 D3         |JE SHORT unpacked.0046F658
0046F685  |.  25 00010101   |AND EAX,1010100
0046F68A  |.  75 08         |JNZ SHORT unpacked.0046F694
0046F68C  |.  81E6 00000080 |AND ESI,80000000
0046F692  |.^ 75 C4         \JNZ SHORT unpacked.0046F658      
0046F694  |>  5E            POP ESI
0046F695  |.  5F            POP EDI
0046F696  |>  5B            POP EBX
0046F697  |.  33C0          XOR EAX,EAX
0046F699  |.  C3            RETN                                                    ;不存在时从这里返回,明显EAX被置0
0046F69A  |> \8B42 FC       MOV EAX,DWORD PTR DS:[EDX-4]
0046F69D  |.  38D8          CMP AL,BL
0046F69F  |.  74 36         JE SHORT unpacked.0046F6D7
0046F6A1  |.  84C0          TEST AL,AL
0046F6A3  |.^ 74 EF         JE SHORT unpacked.0046F694
0046F6A5  |.  38DC          CMP AH,BL
0046F6A7  |.  74 27         JE SHORT unpacked.0046F6D0
0046F6A9  |.  84E4          TEST AH,AH
0046F6AB  |.^ 74 E7         JE SHORT unpacked.0046F694
0046F6AD  |.  C1E8 10       SHR EAX,10
0046F6B0  |.  38D8          CMP AL,BL
0046F6B2  |.  74 15         JE SHORT unpacked.0046F6C9
0046F6B4  |.  84C0          TEST AL,AL
0046F6B6  |.^ 74 DC         JE SHORT unpacked.0046F694
0046F6B8  |.  38DC          CMP AH,BL
0046F6BA  |.  74 06         JE SHORT unpacked.0046F6C2
0046F6BC  |.  84E4          TEST AH,AH
0046F6BE  |.^ 74 D4         JE SHORT unpacked.0046F694
0046F6C0  |.^ EB 96         JMP SHORT unpacked.0046F658
0046F6C2  |>  5E            POP ESI
0046F6C3  |.  5F            POP EDI
0046F6C4  |.  8D42 FF       LEA EAX,DWORD PTR DS:[EDX-1]
0046F6C7  |.  5B            POP EBX
0046F6C8  |.  C3            RETN                                    ;第一个
0046F6C9  |>  8D42 FE       LEA EAX,DWORD PTR DS:[EDX-2]
0046F6CC  |.  5E            POP ESI
0046F6CD  |.  5F            POP EDI
0046F6CE  |.  5B            POP EBX
0046F6CF  |.  C3            RETN                                    ;第二个
0046F6D0  |>  8D42 FD       LEA EAX,DWORD PTR DS:[EDX-3]
0046F6D3  |.  5E            POP ESI
0046F6D4  |.  5F            POP EDI
0046F6D5  |.  5B            POP EBX
0046F6D6  |.  C3            RETN                                    ;第三个
0046F6D7  |>  8D42 FC       LEA EAX,DWORD PTR DS:[EDX-4]
0046F6DA  |.  5E            POP ESI
0046F6DB  |.  5F            POP EDI
0046F6DC  |.  5B            POP EBX
0046F6DD  \.  C3            RETN                                    ;第四个;若存在就从这4个RETN中返回,虽然有4个,但是目的是为了返回匹配字符在字符串①中的地址

返回后回到这里,看这个循环,目的是将用户名里在字符串①里存在的字符保存下来,组成一组新的字符串,这里记为②
00433560  |> /0FBE0E        /MOVSX ECX,BYTE PTR DS:[ESI]
00433563  |. |51            |PUSH ECX
00433564  |. |68 78F44800   |PUSH unpacked.0048F478                                ;  hkrwqv2958dwntqrgnscfsxazpyk
00433569  |. |E8 B2C00300   |CALL unpacked.0046F620
0043356E  |. |83C4 08       |ADD ESP,8                              ;返回后回到这里
00433571  |. |85C0          |TEST EAX,EAX                           ;测试EAX的值,若为0则跳走,若不为0,则将存在的那个字符保存下来
00433573  |. |74 05         |JE SHORT unpacked.0043357A
00433575  |. |8A16          |MOV DL,BYTE PTR DS:[ESI]
00433577  |. |8817          |MOV BYTE PTR DS:[EDI],DL               ;在这里把字符保存下来
00433579  |. |47            |INC EDI
0043357A  |> |8A46 01       |MOV AL,BYTE PTR DS:[ESI+1]
0043357D  |. |46            |INC ESI
0043357E  |. |84C0          |TEST AL,AL
00433580  |.^\75 DE         \JNZ SHORT unpacked.00433560            ;循环,直到用户名所有字符全部检查完毕

继续向下看
00433582  |> \8D4424 20     LEA EAX,DWORD PTR SS:[ESP+20]
00433586  |.  C607 00       MOV BYTE PTR DS:[EDI],0                  ;这里,是在新字符串②末尾添加一个00
00433589  |.  8D50 01       LEA EDX,DWORD PTR DS:[EAX+1]
0043358C  |.  8D6424 00     LEA ESP,DWORD PTR SS:[ESP]
00433590  |>  8A08          /MOV CL,BYTE PTR DS:[EAX]
00433592  |.  40            |INC EAX
00433593  |.  84C9          |TEST CL,CL
00433595  |.^ 75 F9         \JNZ SHORT unpacked.00433590
00433597  |.  2BC2          SUB EAX,EDX                              ;上面的小循环到这里是算出新字符串②的个数
00433599  |.  83F8 18       CMP EAX,18
0043359C  |.  7D 1E         JGE SHORT unpacked.004335BC              ;字符串②个数大于24就跳走,虽然跳走不会挂,但是一般输入的用户名都会比较短,不会弄个24位以上吧,呵呵,继续往下看
0043359E  |.  B9 18000000   MOV ECX,18
004335A3  |.  2BC8          SUB ECX,EAX                                            ;这里24减去②的长度
004335A5  |.  8D7C04 20     LEA EDI,DWORD PTR SS:[ESP+EAX+20]
004335A9  |.  8BC1          MOV EAX,ECX
004335AB  |.  C1E9 02       SHR ECX,2                                              ;得到的差逻辑右移2位,可以认为得到的差去除以4,得到结果给ECX
004335AE  |.  BE 78F44800   MOV ESI,unpacked.0048F478                              ;  hkrwqv2958dwntqrgnscfsxazpyk
004335B3  |.  F3:A5         REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]         ;到这里,把这个字符串从左向右4个字符为一组,分成7组。取前ECX组字符,我们记做③吧,剩下的7-ECX组字符我们记为④。这里是把③接在了②的后面,保存下来。
004335B5  |.  8BC8          MOV ECX,EAX                                            ;这里ECX就是24减去②的长度的结果
004335B7  |.  83E1 03       AND ECX,3                                              ;这里把ECX换算成二进制,取最低2位的值给ECX
004335BA  |.  F3:A4         REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]           ;到这里,取④字符串的前ECX个字符接在②③的后面。不知道我这样说大家觉得乱不乱。。。。这样就组成了一组新的字符串,我们记为⑤吧
004335BC  |>  B8 78F44800   MOV EAX,unpacked.0048F478                              ;  hkrwqv2958dwntqrgnscfsxazpyk
004335C1  |.  C64424 39 00  MOV BYTE PTR SS:[ESP+39],0
004335C6  |.  C68424 840000>MOV BYTE PTR SS:[ESP+84],0
004335CE  |.  33ED          XOR EBP,EBP                                            ;注意此时的EBP为0,下面会用到
004335D0  |.  8D48 01       LEA ECX,DWORD PTR DS:[EAX+1]
004335D3  |>  8A10          /MOV DL,BYTE PTR DS:[EAX]
004335D5  |.  40            |INC EAX
004335D6  |.  84D2          |TEST DL,DL
004335D8  |.^ 75 F9         \JNZ SHORT unpacked.004335D3
004335DA  |.  2BC1          SUB EAX,ECX                                            ;这句加上上面的小循环是算字符串①的字符数
004335DC  |.  894424 10     MOV DWORD PTR SS:[ESP+10],EAX
004335E0  |.  B8 01000000   MOV EAX,1
004335E5  |.  2D 78F44800   SUB EAX,unpacked.0048F478                              ;  ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"  这里用1减去字符串首的地址这里把结果记做a,下面用到
004335EA  |.  894424 18     MOV DWORD PTR SS:[ESP+18],EAX                          ;保存起来
004335EE  |.  33DB          XOR EBX,EBX
004335F0  |.  B8 78F44800   MOV EAX,unpacked.0048F478                              ;  hkrwqv2958dwntqrgnscfsxazpyk
004335F5  |.  48            DEC EAX                                                ;字符串①首地址减去1,这里把结果记做b,下面用到
004335F6  |.  894424 14     MOV DWORD PTR SS:[ESP+14],EAX                          ;保存起来
004335FA  |.  8D4424 20     LEA EAX,DWORD PTR SS:[ESP+20]                          ;取新字符串⑤的首地址给EAX
004335FE  |.  48            DEC EAX                                                ;也减去1
004335FF  |.  8DBC24 840000>LEA EDI,DWORD PTR SS:[ESP+84]
00433606  |.  894424 1C     MOV DWORD PTR SS:[ESP+1C],EAX
0043360A  |.  EB 04         JMP SHORT unpacked.00433610                            ;进下面这个循环,关键时候到了,这个循环是算注册码的地方
0043360C  |>  8B4424 1C     /MOV EAX,DWORD PTR SS:[ESP+1C]
00433610  |>  0FBE4C18 01    MOVSX ECX,BYTE PTR DS:[EAX+EBX+1]                      ;字符串⑤的一个字符给ECX
00433615  |.  8D73 01       |LEA ESI,DWORD PTR DS:[EBX+1]
00433618  |.  51            |PUSH ECX
00433619  |.  68 78F44800   |PUSH unpacked.0048F478                                ;  hkrwqv2958dwntqrgnscfsxazpyk
0043361E  |.  E8 FDBF0300   |CALL unpacked.0046F620                                 ;这里跟上面00433569地址的那个一样,自己向上看,不多解释了
00433623  |.  8B5424 20     |MOV EDX,DWORD PTR SS:[ESP+20]                         ;取a的值给EDX,a是什么向上看
00433627  |.  8BC8          |MOV ECX,EAX                                           ;上面那个CALL返回的EAX给ECX
00433629  |.  03CA          |ADD ECX,EDX                                           ;实际结果是字符串①里,第ECX个字符与字符串⑤的那个字符匹配
0043362B  |.  8D41 FF       |LEA EAX,DWORD PTR DS:[ECX-1]                          ;ECX-1
0043362E  |.  0FAFC1        |IMUL EAX,ECX                                          ;ECX*(ECX-1)
00433631  |.  03C5          |ADD EAX,EBP                                           ;ECX*(ECX-1)+EBP 上面提到初始EBP为0
00433633  |.  99            |CDQ                                                   ;EDX置0
00433634  |.  F77C24 18     |IDIV DWORD PTR SS:[ESP+18]                            ;(ECX*(ECX-1)+EBP)/28,商给EAX,余数给EDX
00433638  |.  83C4 08       |ADD ESP,8
0043363B  |.  B9 06000000   |MOV ECX,6                                             ;ECX=6,目的是生成的注册码每6个之间用'-'符号隔开
00433640  |.  42            |INC EDX                                               ;余数+1
00433641  |.  8BEA          |MOV EBP,EDX                                           ;余数+1给EBP
00433643  |.  8B5424 14     |MOV EDX,DWORD PTR SS:[ESP+14]                         ;取b给EDX,b是什么请向上看
00433647  |.  8A042A        |MOV AL,BYTE PTR DS:[EDX+EBP]                          ;取字符串①中第EBP个字符作为注册码!!!!注册码出现!
0043364A  |.  8807          |MOV BYTE PTR DS:[EDI],AL                              ;找了个地存起来了
0043364C  |.  8BC6          |MOV EAX,ESI                                           ;这里的ESI是来计数用的
0043364E  |.  99            |CDQ
0043364F  |.  F7F9          |IDIV ECX
00433651  |.  47            |INC EDI
00433652  |.  85D2          |TEST EDX,EDX
00433654  |.  75 09         |JNZ SHORT unpacked.0043365F
00433656  |.  83FB 17       |CMP EBX,17
00433659  |.  7D 04         |JGE SHORT unpacked.0043365F
0043365B  |.  C607 2D       |MOV BYTE PTR DS:[EDI],2D                              ;这里到上面是注册码每6个用'-'隔开
0043365E  |.  47            |INC EDI
0043365F  |>  8BDE          |MOV EBX,ESI
00433661  |.  83FB 18       |CMP EBX,18
00433664  |.^ 7C A6         \JL SHORT unpacked.0043360C                             ;循环生成注册码。注册码为24个,6个为一组,共四组
00433666  |.  8B8424 F00000>MOV EAX,DWORD PTR SS:[ESP+F0]                           ;到这是取我们输入得注册码给EAX
0043366D  |.  C607 00       MOV BYTE PTR DS:[EDI],0
00433670  |.  8DB424 840000>LEA ESI,DWORD PTR SS:[ESP+84]                           ;取计算出的真实注册码给ESI,大家应该都想到了,下面就是比较了
00433677  |>  8A10          /MOV DL,BYTE PTR DS:[EAX]                              ;  (初始 cpu 选择)
00433679  |.  8A1E          |MOV BL,BYTE PTR DS:[ESI]
0043367B  |.  8ACA          |MOV CL,DL
0043367D  |.  3AD3          |CMP DL,BL
0043367F  |.  75 1E         |JNZ SHORT unpacked.0043369F                            ;这里!可以将这里改为JMP 0043369B来实现爆破!!!
00433681  |.  84C9          |TEST CL,CL
00433683  |.  74 16         |JE SHORT unpacked.0043369B
00433685  |.  8A50 01       |MOV DL,BYTE PTR DS:[EAX+1]
00433688  |.  8A5E 01       |MOV BL,BYTE PTR DS:[ESI+1]
0043368B  |.  8ACA          |MOV CL,DL
0043368D  |.  3AD3          |CMP DL,BL
0043368F  |.  75 0E         |JNZ SHORT unpacked.0043369F
00433691  |.  83C0 02       |ADD EAX,2
00433694  |.  83C6 02       |ADD ESI,2
00433697  |.  84C9          |TEST CL,CL
00433699  |.^ 75 DC         \JNZ SHORT unpacked.00433677
0043369B  |>  33C0          XOR EAX,EAX                                             ;这里如果注册码正确,则EAX置0,然后直接跳下去
0043369D  |.  EB 05         JMP SHORT unpacked.004336A4
0043369F  |>  1BC0          SBB EAX,EAX
004336A1  |.  83D8 FF       SBB EAX,-1                                               ;这里注册码不正确,EAX置1,然后测试EAX的值
004336A4  |>  85C0          TEST EAX,EAX
004336A6  |.  5F            POP EDI
004336A7  |.  5E            POP ESI
004336A8  |.  5D            POP EBP
004336A9  |.  5B            POP EBX
004336AA  |.  75 0C         JNZ SHORT unpacked.004336B8                              ;这个程序是以EAX的值来判断是否正确,这里正确EAX为1,错误EAX为0。
004336AC  |.  B8 01000000   MOV EAX,1
004336B1  |.  81C4 D8000000 ADD ESP,0D8
004336B7  |.  C3            RETN
004336B8  |>  33C0          XOR EAX,EAX
004336BA  |.  81C4 D8000000 ADD ESP,0D8
004336C0  \.  C3            RETN                                                     ;分析还没结束,F8单步向下运行

返回到此处
00433C44   .  83C4 08       ADD ESP,8
00433C47   .  85C0          TEST EAX,EAX                                                                       ;这里测试EAX的值
00433C49   .  0F84 B6000000 JE unpacked.00433D05                                                               ;当注册码正确,EAX为1时,下面就将注册信息写入注册表,否则跳走出错
00433C4F   .  8D4424 10     LEA EAX,DWORD PTR SS:[ESP+10]
00433C53   .  50            PUSH EAX                                      ; /pDisposition
00433C54   .  8D4C24 10     LEA ECX,DWORD PTR SS:[ESP+10]                 ; |
00433C58   .  51            PUSH ECX                                      ; |pHandle
00433C59   .  6A 00         PUSH 0                                        ; |pSecurity = NULL
00433C5B   .  68 3F000F00   PUSH 0F003F                                   ; |Access = KEY_ALL_ACCESS
00433C60   .  6A 00         PUSH 0                                        ; |Options = REG_OPTION_NON_VOLATILE
00433C62   .  68 85F64700   PUSH unpacked.0047F685                        ; |Class = ""
00433C67   .  6A 00         PUSH 0                                        ; |Reserved = 0
00433C69   .  68 84E44800   PUSH unpacked.0048E484                        ; |software\gamani\gifmoviegear\2.0
00433C6E   .  68 02000080   PUSH 80000002                                 ; |hKey = HKEY_LOCAL_MACHINE
00433C73   .  FF15 0CF04700 CALL DWORD PTR DS:[<&ADVAPI32.RegCreateKeyExA>; \RegCreateKeyExA
00433C79   .  8D4424 60     LEA EAX,DWORD PTR SS:[ESP+60]
00433C7D   .  8D50 01       LEA EDX,DWORD PTR DS:[EAX+1]
00433C80   >  8A08          MOV CL,BYTE PTR DS:[EAX]
00433C82   .  40            INC EAX
00433C83   .  84C9          TEST CL,CL
00433C85   .^ 75 F9         JNZ SHORT unpacked.00433C80
00433C87   .  8B35 00F04700 MOV ESI,DWORD PTR DS:[<&ADVAPI32.RegSetValueE>;  ADVAPI32.RegSetValueExA
00433C8D   .  2BC2          SUB EAX,EDX
00433C8F   .  40            INC EAX
00433C90   .  50            PUSH EAX                                      ; /BufSize
00433C91   .  8B4424 10     MOV EAX,DWORD PTR SS:[ESP+10]                 ; |
00433C95   .  8D5424 64     LEA EDX,DWORD PTR SS:[ESP+64]                 ; |
00433C99   .  52            PUSH EDX                                      ; |Buffer
00433C9A   .  6A 01         PUSH 1                                        ; |ValueType = REG_SZ
00433C9C   .  6A 00         PUSH 0                                        ; |Reserved = 0
00433C9E   .  68 C8F34800   PUSH unpacked.0048F3C8                        ; |regname3
00433CA3   .  50            PUSH EAX                                      ; |hKey
00433CA4   .  FFD6          CALL ESI                                      ; \RegSetValueExA
00433CA6   .  8D8424 C40000>LEA EAX,DWORD PTR SS:[ESP+C4]
00433CAD   .  8D48 01       LEA ECX,DWORD PTR DS:[EAX+1]
00433CB0   >  8A10          MOV DL,BYTE PTR DS:[EAX]
00433CB2   .  40            INC EAX
00433CB3   .  84D2          TEST DL,DL
00433CB5   .^ 75 F9         JNZ SHORT unpacked.00433CB0
00433CB7   .  8B5424 0C     MOV EDX,DWORD PTR SS:[ESP+C]
00433CBB   .  2BC1          SUB EAX,ECX
00433CBD   .  40            INC EAX
00433CBE   .  50            PUSH EAX
00433CBF   .  8D8C24 C80000>LEA ECX,DWORD PTR SS:[ESP+C8]
00433CC6   .  51            PUSH ECX
00433CC7   .  6A 01         PUSH 1
00433CC9   .  6A 00         PUSH 0
00433CCB   .  68 D4F34800   PUSH unpacked.0048F3D4                        ;  regcode3
00433CD0   .  52            PUSH EDX
00433CD1   .  FFD6          CALL ESI
00433CD3   .  8B4424 0C     MOV EAX,DWORD PTR SS:[ESP+C]
00433CD7   .  50            PUSH EAX                                      ; /hKey
00433CD8   .  FF15 18F04700 CALL DWORD PTR DS:[<&ADVAPI32.RegCloseKey>]   ; \RegCloseKey
00433CDE   .  68 E0F34800   PUSH unpacked.0048F3E0                        ; /software\loani\mg4
00433CE3   .  68 02000080   PUSH 80000002                                 ; |hKey = HKEY_LOCAL_MACHINE
00433CE8   .  FF15 14F04700 CALL DWORD PTR DS:[<&ADVAPI32.RegDeleteKeyA>] ; \RegDeleteKeyA
00433CEE   .  6A 01         PUSH 1                                        ; /Result = 1
00433CF0   .  57            PUSH EDI                                      ; |hWnd
00433CF1   .  FF15 A4F34700 CALL DWORD PTR DS:[<&user32.EndDialog>]       ; \EndDialog
00433CF7   .  5F            POP EDI
00433CF8   .  5E            POP ESI
00433CF9   .  33C0          XOR EAX,EAX
00433CFB   .  5B            POP EBX
00433CFC   .  81C4 1C010000 ADD ESP,11C
00433D02   .  C2 1000       RETN 10


程序开始时也会读取注册表进行验证。

至此注册码分析完毕。第一次分析,不知道大家看着乱不乱。。。。呵呵,让大家见笑了。



总结一下算法过程:
主要字符串"HKRWQV2958DWNTQRGNSCFSXAZPYK",记为①。
1.先将用户名转换为大写。
2.检验用户名的每个字符在字符串"HKRWQV2958DWNTQRGNSCFSXAZPYK"里是否存在,并把存在的保存下来。记为②。
3.(24-②的长度)/4=C,把字符串"HKRWQV2958DWNTQRGNSCFSXAZPYK"每4个分为一组,共7组。取前C组字符,记为③。剩下的7-C组记为④。把③接在②后面。
4.24-②的长度,转换为二进制,取最低2位的值N,取④前N个字符,接在②③后面,组成一组新的字符串⑤。
5.初始EBP=0,用⑤每个字符与字符串"HKRWQV2958DWNTQRGNSCFSXAZPYK"每个比较,设为第M个匹配。EBP=(M*(M-1)+EBP)/28+1。
6.找出字符串"HKRWQV2958DWNTQRGNSCFSXAZPYK"第EBP个字符即为注册码。每得到6个字符用'-'隔开。重复5,6步。




另外贴上第一个注册机代码,VB写的,毕竟学的还不是很专业,不足之处敬请诸位大侠赐教!

2个文本框,(t1,t2),一个按钮(默认),已测试可以正常使用。


Private Sub Command1_Click()
t2.Text = ""
Dim s As String
Dim c(77) As String
Dim i As Integer
Dim j As Integer
Dim t As Integer
Dim p As Integer
Dim temp As Integer
Dim r(26) As String
s = "HKRWQV2958DWNTQRGNSCFSXAZPYK"
t = 0

'If Len(t1.Text) > 23 Then
'MsgBox "姓名要小于24位"
't1.SetFocus
'Command1.Value = False
'End If
If Len(t1.Text) = 0 Then
MsgBox "姓名不能为空"
t1.SetFocus
Else



For i = 0 To Len(t1.Text) - 1
c(i) = Mid(t1.Text, i + 1, 1)
If Asc(c(i)) > 96 And Asc(c(i)) < 123 Then
c(i) = Chr(Asc(c(i)) - 32)
End If
Next i

For i = 0 To Len(t1.Text) - 1
 For j = 0 To 27
   If Asc(c(i)) = Asc(Mid(s, j + 1, 1)) Then
   c(t) = c(i)
   t = t + 1
   GoTo nn:
   End If
 Next j
nn:
Next i

temp = t

For p = 0 To Int((24 - t) / 4) - 1
 j = 4 * p + 1
 For i = 0 To 3
  c(t) = Mid(s, j + i, 1)
  t = t + 1
  Next i
Next p



For i = 0 To (24 - temp) And &H3 - 1
c(t) = Mid(s, j + 4 + i, 1)
t = t + 1
Next i



temp = 0
For i = 0 To 23
 For j = 0 To 27
  If Asc(c(i)) = Asc(Mid(s, j + 1, 1)) Then
  temp = ((j + 1) * j + temp) Mod 28 + 1
  r(i) = Mid(s, temp, 1)
  GoTo nnn:
  End If
  Next j
nnn:
Next i

For i = 0 To 23
t2.Text = t2.Text + r(i)
If (i + 1) Mod 6 = 0 And i <> 23 Then
t2.Text = t2.Text + "-"
End If

Next i

End If

End Sub


Private Sub Form_Load()
On Error Resume Next
End Sub