GIF Movie Gear逆向实战+注册代码+补丁

2023-03-15,,

GIF Movie Gear逆向实战+注册代码+补丁

    准备

我是在windows 8.1 x64上进行的操作。有不足之处,还望大虾指出。

    获取资源

网站下载:http://www.gamani.com/gmgdown.htm,国内站点是汉化破解好的。

GIF Movie Gear4.2.3是一款GIF动画制作软件,几乎有需要 制作GIF动画的编辑功能它都有,无须再用其它的图型软件辅助。GIF Movie Gear可以处理背景透明化而且做法容易,做好的图片可以做最佳化处理使图片减肥,另外它除了可 以把做好的图片存成GIF的动画图外,还可支援PSD,JPEG,AVI,BMP,GIF,与AVI格式输出。

    受限预先查看

    运行

确实受限了,其实在推出时也恼人,弹窗不然直接退出要等下出现个按钮,点ok关闭。

    查看pe信息

貌似没有欺骗我们,没加壳

    找看看有无注册窗口Version 4.2.3

    定位

      程序要判断注册的对不对,首先获取输入值。

回到od,查找一些符号,这里找GetDlgItemText或者GetWindowText,这里直接找GetWindowText(因为GetDlgItemText=GetDlgItem+GetWindowText,没有找到也没关系(如LoadLibary),直接到User2.dll模块找)并且是ASCII版的。方便点的有cmdBar插件直接入下图方式下断。

    回到界面点ok按钮,断点起作用了,和预想的一样。

看看堆栈,或者直接Alt+F9执行到程序模块。

可以看到两次调用GetWindowTextA,后面一个call,入参是EDX和ECX,来自于获取到编辑框里的值的缓冲区[LOCAL.49]和[LOCAL.24]。控件1103是Name,1104是Code。

后面还有一个根据返回值来jz的,并且有创建注册表项的字符串。这也太明显了,太快了,怎么这个就不设防。。。

注册信息保存在注册表HKEY_LOCAL_MACHINE \Software\gamani\GIFMovieGear\2.0下的两个键SubKey = "RegName3"和SubKey = "RegCode3" ,过期时间来自HKLM\SOFTWARE\Wow6432Node\Loani\MG4\stamp,保存的是秒数。

new Date(0x540b1713 * 1000) = Sat Jan 17 1970 15:40:12 GMT+0800 (China Standard Time)

需要注意x64位,这里的调用,注册表会被重定向:

::    RegQueryValue    HKCU\Software\Classes\VirtualStore\MACHINE\SOFTWARE\Wow6432Node\gamani\GIFMovieGear\, Data: 苏北小麦

::    RegQueryValue    HKCU\Software\Classes\VirtualStore\MACHINE\SOFTWARE\Wow6432Node\gamani\GIFMovieGear\, Data: mg37sfhh4045

::    RegQueryValue    HKLM\SOFTWARE\Wow6432Node\Loani\MG4\stamp    SUCCESS    Type: REG_BINARY, Length: , Data:   0B 

    注册获取窗口信息

CPU Disasm

地址十六进制数据指令注释

] ; 事例 1 of switch movgear.4344D1

 |. 8B35 D0F44700 MOV ESI,DWORD PTR DS:[<&USER32.GetDlgIte

 |. 6A   ; /MaxCount = 100.

 |. 8D5424  ] ; |

 PUSH EDX ; |String => OFFSET LOCAL.49

 4F040000 PUSH 44F ; |/ItemID = 1103.

 |.  PUSH EDI ; ||hDialog => [ARG.1]

 |. FFD6 CALL ESI ; |\USER32.GetDlgItem

 |. 8B1D 4CF34700 MOV EBX,DWORD PTR DS:[<&USER32.GetWindow ; |

 PUSH EAX ; |hWnd

0043451C |. FFD3 CALL EBX ; \USER32.GetWindowTextA

  ; /MaxCount = 100.

 |. 8D8424 C80000 ] ; |

 |.  PUSH EAX ; |String => OFFSET LOCAL.24

 |.    ; |/ItemID = 1104.

 PUSH EDI ; ||hDialog => [ARG.1]

0043452E |. FFD6 CALL ESI ; |\USER32.GetDlgItem

 |.  PUSH EAX ; |hWnd

 |. FFD3 CALL EBX ; \USER32.GetWindowTextA

 |. 8D8C24 C40000 ]

 PUSH ECX ; /Arg2 => OFFSET LOCAL.24

 ] ; |

 PUSH EDX ; |Arg1 => OFFSET LOCAL.49

 |. E8 EBFBFFFF  ; \movgear.00434130

 |. 83C4  

 |. 85C0 TEST EAX,EAX

 |. 8D4424  ]

 |.  PUSH EAX ; /pDisposition => OFFSET LOCAL.69

 |. 8D4C24  ] ; |

 |.  PUSH ECX ; |pResult => OFFSET LOCAL.70

  ; |pSecurity = NULL

 3F000F00 PUSH 0F003F ; |DesiredAccess = KEY_ALL_ACCESS

 |. 6A   ; |Options = REG_OPTION_NON_VOLATILE

 |.  85F64700 PUSH OFFSET 0047F685 ; |Class

 |. 6A   ; |Reserved = 0

 84E44800 PUSH OFFSET 0048E484 ; |Subkey = "Software\gamani\GIFMovieGear\2.0"

   ; |hKey = HKEY_LOCAL_MACHINE

 |. FF15 0CF04700 CALL DWORD PTR DS:[<&ADVAPI32.RegCreateK ; \ADVAPI32.RegCreateKeyExA

 ]

 ]

 |> 8A08 /MOV CL,BYTE PTR DS:[EAX]

 |.  |INC EAX

 |. 84C9 |TEST CL,CL

 |.^  F9 \

 |. 8B35 00F04700 MOV ESI,DWORD PTR DS:[<&ADVAPI32.RegSetV

0043458E |. 2BC2 SUB EAX,EDX

 |.  INC EAX

 |.  PUSH EAX ; /DataSize

 |. 8B4424  ] ; |

 |. 8D5424  ] ; |

 PUSH EDX ; |Data => OFFSET LOCAL.49

  ; |Type = REG_SZ

  ; |Reserved = 0

 C8F34800 PUSH OFFSET 0048F3C8 ; |SubKey = "RegName3"

 PUSH EAX ; |hKey => [LOCAL.70]

004345A5 |. FFD6 CALL ESI ; \ADVAPI32.RegSetValueExA

]

 ]

004345B1 |> 8A10 /MOV DL,BYTE PTR DS:[EAX]

 |INC EAX

004345B4 |. 84D2 |TEST DL,DL

 F9 \JNZ SHORT 004345B1

]

004345BC |. 2BC1 SUB EAX,ECX

 INC EAX

 PUSH EAX ; /DataSize

] ; |

 PUSH ECX ; |Data => OFFSET LOCAL.24

  ; |Type = REG_SZ

  ; |Reserved = 0

 D4F34800 PUSH OFFSET 0048F3D4 ; |SubKey = "RegCode3"

 PUSH EDX ; |hKey => [LOCAL.70]

004345D2 |. FFD6 CALL ESI ; \ADVAPI32.RegSetValueExA

]

 PUSH EAX ; /hKey => [LOCAL.70]

004345D9 |. FF15 18F04700 CALL DWORD PTR DS:[<&ADVAPI32.RegCloseKe ; \ADVAPI32.RegCloseKey

 E0F34800 PUSH OFFSET 0048F3E0 ; /Subkey = "Software\Loani\MG4"

   ; |hKey = HKEY_LOCAL_MACHINE

004345E9 |. FF15 14F04700 CALL DWORD PTR DS:[<&ADVAPI32.RegDeleteK ; \ADVAPI32.RegDeleteKeyA

  ; /Result = 1

 PUSH EDI ; |hDialog => [ARG.1]

004345F2 |. FF15 A4F34700 CALL DWORD PTR DS:[<&USER32.EndDialog>] ; \USER32.EndDialog

004345F8 |. 5F POP EDI

004345F9 |. 5E POP ESI

004345FA |. 33C0 XOR EAX,EAX

004345FC |. 5B POP EBX

004345FD |. 81C4 1C010000 ADD ESP,11C

 |. C2  

 |> 6A   ; /Arg4 = 30

 |.  159D0000 PUSH 9D15 ; |Arg3 = 9D15

 149D0000 PUSH 9D14 ; |Arg2 = 9D14

 |.  PUSH EDI ; |Arg1 => [ARG.1]

 |. E8 F8D8FDFF CALL 00411F10 ; \movgear.00411F10

 |. 83C4  

 4F040000 PUSH 44F ; /ItemID = 1103.

 |.  PUSH EDI ; |hDialog => [ARG.1]

 |. FFD6 CALL ESI ; \USER32.GetDlgItem

 |.  PUSH EAX ; /hWnd

 |. FF15 A8F44700 CALL DWORD PTR DS:[<&USER32.SetFocus>] ; \USER32.SetFocus

0043462A |. 5F POP EDI

0043462B |. 5E POP ESI

0043462C |. 33C0 XOR EAX,EAX

0043462E |. 5B POP EBX

0043462F |. 81C4 1C010000 ADD ESP,11C

 |. C2  

    失败弹窗走

    CPU Disasm
    地址        十六进制数据            指令                                       注释
         ]             ; movgear.00411EE0(推测 Arg1)
    00411EE4  |.  8B0D C4C24A00 MOV ECX,DWORD PTR DS:[4AC2C4]
                                         ; /Count = 512.
     80BF4A00   PUSH OFFSET 004ABF80                     ; |Buffer = "The information you have provided is invalid. Please be sure that you typed it exactly as it was given to you."
                PUSH EAX                                 ; |StringID => [ARG.1]
                PUSH ECX                                 ; |hInst => [4AC2C4] = 00400000 ('movgear')
    00411EF6  |.  FF15 C0F44700 CALL DWORD PTR DS:[<&USER32.LoadStringA> ; \USER32.LoadStringA
    00411EFC  |.  85C0          TEST EAX,EAX
     0D         JZ SHORT 00411F0D
    
             JGE SHORT 00411F0D
    00411F07  |.  B8 80BF4A00   MOV EAX,OFFSET 004ABF80                  ; ASCII "The information you have provided is invalid. Please be sure that you typed it exactly as it was given to you."
    00411F0C  |.  C3            RETN
    00411F0D  |>  33C0          XOR EAX,EAX
    00411F0F  \.  C3            RETN 
    
    ]             ; movgear.00411F10(推测 Arg1,Arg2,Arg3,Arg4)
    00411F14  |.  8B15 C4C24A00 MOV EDX,DWORD PTR DS:[4AC2C4]
    
     FF000000   PUSH 0FF                                 ; /Count = 255.
         ]                       ; |
                PUSH EAX                                 ; |Buffer => OFFSET LOCAL.63
                PUSH ECX                                 ; |StringID = 40213. => 'Invalid Registration Info'
                PUSH EDX                                 ; |hInst => [4AC2C4] = 00400000 ('movgear')
    00411F2C  |.  FF15 C0F44700 CALL DWORD PTR DS:[<&USER32.LoadStringA> ; \USER32.LoadStringA
     ]
     ]
    
                PUSH EAX                                 ; /Type
         ]                       ; |
                PUSH ECX                                 ; |Caption => OFFSET LOCAL.63
                PUSH EDX                                 ; |/Arg1 => [ARG.2]
    00411F4C  |.  E8 8FFFFFFF   CALL 00411EE0                            ; |\movgear.00411EE0
                                           ; |
                PUSH EAX                                 ; |Text
     ]             ; |
                PUSH EAX                                 ; |hOwner => [ARG.1]
    00411F5D  |.  FF15 C4F44700 CALL DWORD PTR DS:[<&USER32.MessageBoxA> ; \USER32.MessageBoxA
    
    00411F69  \.  C3            RETN

    关键

      看注册过程

我们来看看0048F3F8偏移处的值,32个黑名单

    第一种注册码验证过程,Code是mg37开头就是走这种的。

CPU Disasm
地址        十六进制数据            指令                                               注释
  /$              PUSH EBX                                         ; movgear.00434130(推测 Arg1,Arg2)
  |.              PUSH EBP
  |.  8B6C24      ]                     ; EBP指向Code,ASCII "12345678"
  |.  8 6D    CMP BYTE PTR SS:[EBP],6D                         ; Code的第一字节,和'm'比较
            PUSH ESI
            PUSH EDI
0043413C  |.  0F85 AD000000 JNE 004341EF
  |.  8     ],                       ; Code的第2字节,和'g'比较
  |.  0F85 A3000000 JNE 004341EF
     ],                       ; Code的第3字节,和'3'比较
  |.   JNE 004341EF
  |.  8     ],                       ; Code的第4字节,和'7'比较
0043415A  |.  0F85 8F000000 JNE 004341EF
  |.  33DB          XOR EBX,EBX                                      ; 和黑名单库里的比较
  |>  8BBB F8F34800 /MOV EDI,DWORD PTR DS:[EBX+48F3F8]               ; 到 PTR ASCII "mvg21951736"
  |.  8BC7          |MOV EAX,EDI                                     ; strlen开始
       |]
       |LEA ECX,[ECX]
  |>  8A08          |/MOV CL,BYTE PTR DS:[EAX]
  |.              ||INC EAX
  |.  84C9          ||TEST CL,CL
  |.^  F9         |\
  |.  2BC2          |SUB EAX,EDX                                     ; EAX = strlen()
  |.  8BC8          |MOV ECX,EAX                                     ; blackLengthECX = blackLengthEAX,比较次数
0043417B  |.  8BF5          |MOV ESI,EBP                                     ; pszchESI = pszchEBP
0043417D  |.  33C0          |XOR EAX,EAX
0043417F  |.  F3:A6         |REPE CMPS BYTE PTR DS:[ESI],BYTE PTR ES:[EDI]
  |.            |JE SHORT 004341E8                               ; 黑名单直接返回FALSE
  |.  83C3        |
  |.  81FB  |
 D4         \
     ],                       ; Code的第5字节,和's'比较
  |.
  |.              INC EBP
  |>  8D4D        ]                                  ; pszchECX = pszchCode + 7或8
  |.              PUSH ECX
  |.  E8 56BE0300   CALL 0046FFF4
     ]                     ; pszchNameEBX指向Name
004341A2  |.  8A13          MOV DL,BYTE PTR DS:[EBX]                         ; EDX_DL = *pszchNameEBX

004341A7  |.  33C9          XOR ECX,ECX
004341A9  |.  84D2          TEST DL,DL                                       ; 判断是否空串
004341AB  |.  8BFB          MOV EDI,EBX                                      ; pszchCodeEDI = pszchCodeEBX
004341AD  |.  BE DF0B0000   MOV ESI,0BDF                                     ; ESI = 0BDF=3039
          JZ SHORT 004341DA                                ;
004341B4  |>  0FBED2        /MOVSX EDX,DL
            |INC ECX
004341B8  |.  0FAFD1        |IMUL EDX,ECX
004341BB  |.  03F2          |ADD ESI,EDX                                     ; ESI += *pszchEDI * ECX
004341BD  |.  81FE BE170000 |CMP ESI,17BE
         |JLE SHORT 004341CB
004341C5  |.  81EE BE170000 |SUB ESI,17BE                                    ; ESI += *pszchEDI * ECX - 6078.
004341CB  |>  83F9 0A       |CMP ECX,0A
         |JLE SHORT 004341D2
004341D0  |.  33C9          |XOR ECX,ECX
       |]
            |INC EDI
004341D6  |.  84D2          |TEST DL,DL
 DA         \JNZ SHORT 004341B4
004341DA  |>  3BF0          CMP ESI,EAX
          JNE SHORT 004341F3
004341DE  |.  5F            POP EDI
004341DF  |.  5E            POP ESI
004341E0  |.  5D            POP EBP

004341E6  |.  5B            POP EBX
004341E7  |.  C3            RETN
004341E8  |>  5F            POP EDI
004341E9  |.  5E            POP ESI
004341EA  |.  5D            POP EBP
004341EB  |.  33C0          XOR EAX,EAX
004341ED  |.  5B            POP EBX
004341EE  |.  C3            RETN
     ]                     ; EBX指向Name,ASCII "Fang"
            PUSH EBP
            PUSH EBX
004341F5  |.  E8 16FCFFFF   CALL 00433E10

004341FD  |.  5F            POP EDI
004341FE  |.  5E            POP ESI
004341FF  |.  5D            POP EBP
  |.  5B            POP EBX
  \.  C3            RETN
 

    第二种注册码生成过程,直接比较Code == Func(Name)形式,这是最初级方式,容易点。

EBP = EDX

= ((EAX + (1 - pszHKRWQ) -1) * (EAX + (1 - pszHKRWQ)) + EBP) % strlen(pszHKRWQ)

= ((EAX - pszHKRWQ) * (EAX - pszHKRWQ + 1) +EBP) % 28

= (indexOf(pszHKRWQ, pszOkName[i]) * (indexOf(pszHKRWQ, pszOkName[i]) + 1) +EBP) % 28


CPU Disasm

地址十六进制数据指令注释

 ]

]

00433E1B |. 81EC D8000000 SUB ESP,0D8 ; 0D8=216.分配空间

00433E21 |. 2BD0 SUB EDX,EAX

00433E23 |> 8A08 /MOV CL,BYTE PTR DS:[EAX] ; 拷贝Name倒Local.49缓冲区

00433E25 |. 880C02 |MOV BYTE PTR DS:[EAX+EDX],CL

 |INC EAX

00433E29 |. 84C9 |TEST CL,CL

 F6 \JNZ SHORT 00433E23

 PUSH EBX

 PUSH EBP

 PUSH ESI

 PUSH EDI

 ]

 PUSH EAX ; /String => OFFSET LOCAL.49

00433E36 |. FF15 1CF34700 CALL DWORD PTR DS:[<&USER32.CharUpperA>] ; \USER32.CharUpperA

 ] ; Local.49里全是大写了

00433E40 |. 84C0 TEST AL,AL ; 判断Local.49是否为空串

 ]

 ]

  JZ SHORT 00433E72

 ] ; Name里在"HKRWQV2958DWNTQRGNSCFSXAZPYK"的字符拷贝到pszEDIBuffer里,既写回LOCAL.49缓冲区

00433E50 |> 0FBE0E /MOVSX ECX,BYTE PTR DS:[ESI] ; char chECX = *pszESI

 |PUSH ECX

 78F44800 |PUSH OFFSET 0048F478 ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"

 ; 查找字符

 |

00433E61 |. 85C0 |TEST EAX,EAX ; 判断是否找到,返回值非空为找到

  |JZ SHORT 00433E6A

00433E65 |. 8A16 |MOV DL,BYTE PTR DS:[ESI] ; char chDL = *pszESI

 |MOV BYTE PTR DS:[EDI],DL ; *pszEDI = chDL

 |INC EDI ; pszEDI++

 |] ; char chAL = *(pszESI+1)

 |INC ESI ; pszESI++

00433E6E |. 84C0 |TEST AL,AL

 DE \JNZ SHORT 00433E50 ; while(0! = chAL)

 ]

  ; LOCAL.49弄成0结尾字符串

 ] ; 获取LOCAL.49长度,开始

 ]

00433E80 |> 8A08 /MOV CL,BYTE PTR DS:[EAX]

 |INC EAX

00433E83 |. 84C9 |TEST CL,CL

 F9 \JNZ SHORT 00433E80

00433E87 |. 2BC2 SUB EAX,EDX ; 获取LOCAL.49长度,结束,EAX=EAX-EDX

  ; 名字长度和18=24.比较

00433E8C |. 7D 1E JGE SHORT 00433EAC ; 大于0x18=24.就跳转

00433E93 |. 2BC8 SUB ECX,EAX ; ECX=ECX-EAX=24.-NameLength_EAX

 ]

00433E99 |. 8BC1 MOV EAX,ECX

00433E9E |. BE 78F44800 MOV ESI,OFFSET 0048F478 ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"

00433EA3 |. F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ; strcat(LOCAL.49, strchr("HKRW...", LOCAL.49[0]))

00433EA5 |. 8BC8 MOV ECX,EAX

00433EAA |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]

00433EAC |> B8 78F44800 MOV EAX,OFFSET 0048F478 ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"

  +],

 ],

00433EBE |. 33ED XOR EBP,EBP ; EBP = 0

 ] ; 计算"HKRWQV2958DWNTQRGNSCFSXAZPYK"长度

00433EC3 |> 8A10 /MOV DL,BYTE PTR DS:[EAX]

 |INC EAX

00433EC6 |. 84D2 |TEST DL,DL

 F9 \JNZ SHORT 00433EC3

00433ECA |. 2BC1 SUB EAX,ECX ; 计算"HKRWQV2958DWNTQRGNSCFSXAZPYK"结束

  ],EAX ; LOCAL53 = 长度24

00433ED5 |. 2D 78F44800 SUB EAX,OFFSET 0048F478 ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"

  ],EAX ; LOCAL51 = 1 - 0048F478 = FFB70B89

00433EDE |. 33DB XOR EBX,EBX ; EBX = 0

00433EE0 |. B8 78F44800 MOV EAX,OFFSET 0048F478 ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"

 DEC EAX ; EAX = 0048F478-1=0048F477

  ],EAX ; LOCAL52 = 0048F477

 ] ; pszchEAX = pszchOkName

 DEC EAX ; pszchEAX--

 ]

 1C ],EAX ; pszchLOCAL50 = pszchEAX = pszchOkName - 1

 JMP SHORT 00433F00

]

 |] ; pszchECX = pszchOkName[EBX + 1]

 |] ; ESI = EBX + 1

 |PUSH ECX

 78F44800 |PUSH OFFSET 0048F478 ; ASCII "HKRWQV2958DWNTQRGNSCFSXAZPYK"

 |] ; EDX = FFB70B89

00433F17 |. 8BC8 |MOV ECX,EAX

00433F19 |. 03CA |ADD ECX,EDX ; ECX = EAX + FFB70B89

] ; EAX = EAX + FFB70B89 - 1

00433F1E |. 0FAFC1 |IMUL EAX,ECX ; EAX = (ECX - 1) * ECX = FFB70B88 * ECX

00433F21 |. 03C5 |ADD EAX,EBP ; EAX = EAX + EBP

 |CDQ ; 双字数据扩展为四字类型 EDX = EAX < 80000000 ? 00000000 : FFFFFFFF

 |] ; 商=(EAX)=(EDX,EAX)/(LOCAL53)(长度),余数=(EDX)=(EDX,EAX)%(LOCAL53)(长度)

 |

 |

 |INC EDX

00433F31 |. 8BEA |MOV EBP,EDX ; EBP = EDX = ((EAX + (1 - pszHKRWQ) -1) * (EAX + (1 - pszHKRWQ)) + EBP) % strlen(pszHKRWQ)

 |]

00433F37 |. 8A042A |MOV AL,BYTE PTR DS:[EBP+EDX] ; AL = pszHKRWQ[EBP]

 |MOV BYTE PTR DS:[EDI],AL ; *pszchEDI = AL = pszHKRWQ[EBP]

00433F3C |. 8BC6 |MOV EAX,ESI

 |CDQ

00433F3F |. F7F9 |IDIV ECX

 |INC EDI

00433F42 |. 85D2 |TEST EDX,EDX

  |JNZ SHORT 00433F4F

 | ; EBC 和 17=23.比较

 |JGE SHORT 00433F4F

00433F4B |. C607 2D |MOV BYTE PTR DS:[EDI],2D ; *pszchEDI = '-'

 |INC EDI

00433F4F |> 8BDE |MOV EBX,ESI

 | ; 和长度18=24.比较

00433F54 |.^ 7C A6 \JL SHORT 00433EFC ; 小于继续循环,否则结束循环

] ; pszEAX = pszCode

 ] ; pszESI=pszRealCode; 一段序列,如HSDWQ9-QKFADW-H92C5A-GAGVNK

00433F67 |> 8A10 /MOV DL,BYTE PTR DS:[EAX]

00433F69 |. 8A1E |MOV BL,BYTE PTR DS:[ESI]

00433F6B |. 8ACA |MOV CL,DL

00433F6D |. 3AD3 |CMP DL,BL

 1E |JNE SHORT 00433F8F

00433F71 |. 84C9 |TEST CL,CL

  |JZ SHORT 00433F8B

 |]

 |]

00433F7B |. 8ACA |MOV CL,DL

00433F7D |. 3AD3 |CMP DL,BL

 0E |JNE SHORT 00433F8F

 |

 |

00433F87 |. 84C9 |TEST CL,CL

 DC \JNZ SHORT 00433F67

00433F8B |> 33C0 XOR EAX,EAX

 JMP SHORT 00433F94

00433F8F |> 1BC0 SBB EAX,EAX ; Calculates sign(EAX)

00433F94 |> 85C0 TEST EAX,EAX

00433F96 |. 5F POP EDI

00433F97 |. 5E POP ESI

00433F98 |. 5D POP EBP

00433F99 |. 5B POP EBX

 0C JNZ SHORT 00433FA8 ; Code和Func(Name)的值不等,就跳,返回假

00433FA1 |. 81C4 D8000000 ADD ESP,0D8

00433FA7 |. C3 RETN

00433FA8 |> 33C0 XOR EAX,EAX

00433FAA |. 81C4 D8000000 ADD ESP,0D8

00433FB0 \. C3 RETN

    顺便

      程序打开时验证模块代码

刚打开也会断到验证里,看了下堆栈,写在这。

读取注册表注册信息,位置HKEY_LOCAL_MACHINE \Software\gamani\GIFMovieGear\2.0下的两个键SubKey = "RegName3"和SubKey = "RegCode3",,过期时间来自HKLM\SOFTWARE\Wow6432Node\Loani\MG4\stamp,保存的是秒数。

 Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\gamani\GIFMovieGear\2.0]
"RegName3"="Fang"
"RegCode3"="HSDWQ9-QKFADW-H92C5A-GAGVNK"
CPU Disasm
地址        十六进制数据            指令                                               注释
  /$  81EC D0000000 SUB ESP,0D0                                      ; movgear.00434210(推测 Arg1,Arg2)
  |.              PUSH EBX
  |.              PUSH ESI
  |.  8B35 04F04700 MOV ESI,DWORD PTR DS:[<&ADVAPI32.RegOpenKeyExA>]
     ]
  |.              PUSH EAX                                         ; /pResult => OFFSET LOCAL.51
  |.                                             ; |DesiredAccess = KEY_READ
  |.  6A                                                     ; |Reserved = 0
 84E44800   PUSH OFFSET 0048E484                             ; |SubKey = "Software\gamani\GIFMovieGear\2.0"
                                        ; |hKey = HKEY_LOCAL_MACHINE
  |.  83CB FF       OR EBX,FFFFFFFF                                  ; |
  |.  FFD6          CALL ESI                                         ; \ADVAPI32.RegOpenKeyExA
  |.  85C0          TEST EAX,EAX
          JZ SHORT 0043425D
     ]
  |.              PUSH ECX                                         ; /pResult => OFFSET LOCAL.51
  |.                                             ; |DesiredAccess = KEY_READ
  |.  6A                                                     ; |Reserved = 0
  |.   84E44800   PUSH OFFSET 0048E484                             ; |SubKey = "Software\gamani\GIFMovieGear\2.0"
                                        ; |hKey = HKEY_CURRENT_USER
  |.  FFD6          CALL ESI                                         ; \ADVAPI32.RegOpenKeyExA
  |.  85C0          TEST EAX,EAX
  |.  0F85 AF000000 JNZ 0043430C
     ]
  |.  8B35 08F04700 MOV ESI,DWORD PTR DS:[<&ADVAPI32.RegQueryValueEx
  |.  8D5424 ]
            PUSH EDX                                         ; /pDataLen => OFFSET LOCAL.50
     ]                               ; |
  |.              PUSH EAX                                         ; |pData => OFFSET LOCAL.49
  |.  6A                                                     ; |pType = NULL
  |.  6A                                                     ; |Reserved = 0
  |.   C8F34800   PUSH OFFSET 0048F3C8                             ; |Name = "RegName3"
            PUSH ECX                                         ; |hKey => [LOCAL.51]
  ],                   ; |
  |.  FFD6          CALL ESI                                         ; \ADVAPI32.RegQueryValueExA
  |.  85C0          TEST EAX,EAX
  |.  0F85 7F000000 JNZ 0043430C ;没有找到注册名字信息
     ]
  |.  8D5424 ]
  |.              PUSH EDX                                         ; /pDataLen => OFFSET LOCAL.50
  |.  8D4424      ]                               ; |
            PUSH EAX                                         ; |pData => OFFSET LOCAL.24
                                                    ; |pType = NULL
                                                    ; |Reserved = 0
 D4F34800   PUSH OFFSET 0048F3D4                             ; |Name = "RegCode3"
            PUSH ECX                                         ; |hKey => [LOCAL.51]
  ],                   ; |
004342AD  |.  FFD6          CALL ESI                                         ; \ADVAPI32.RegQueryValueExA
004342AF  |.  85C0          TEST EAX,EAX
          JNZ SHORT 0043430C ;没有找到注册码信息
     ]
            PUSH EDX                                         ; /Arg2 => OFFSET LOCAL.24
     ]                               ; |
            PUSH EAX                                         ; |Arg1 => OFFSET LOCAL.49
                                    ; \movgear.00434130        ;注册验证

004342C5  |.  85C0          TEST EAX,EAX
          JZ SHORT 0043430C  ;验证失败
]
004342D0  |.  85D2          TEST EDX,EDX

          JZ SHORT 004342ED
     ]
     ]
004342E1  |.  2BD1          SUB EDX,ECX
004342E3  |>  8A08          /MOV CL,BYTE PTR DS:[EAX]
004342E5  |.  880C02        |MOV BYTE PTR DS:[EAX+EDX],CL
            |INC EAX
004342E9  |.  84C9          |TEST CL,CL
 F6         \JNZ SHORT 004342E3
]
004342F4  |.  85D2          TEST EDX,EDX
          JZ SHORT 0043430C
     ]
     ]
  |.  2BD1          SUB EDX,ECX
  |>  8A08          /MOV CL,BYTE PTR DS:[EAX]
  |.  880C02        |MOV BYTE PTR DS:[EAX+EDX],CL
  |.              |INC EAX
  |.  84C9          |TEST CL,CL
 F6         \
     ]
  |.              PUSH EDX                                         ; /hKey => [LOCAL.51]
  |.  FF15 18F04700 CALL DWORD PTR DS:[<&ADVAPI32.RegCloseKey>]      ; \ADVAPI32.RegCloseKey
  |.  5E            POP ESI
  |.  8BC3          MOV EAX,EBX
0043431A  |.  5B            POP EBX
0043431B  |.  81C4 D0000000 ADD ESP,0D0
  \.  C3            RETN

    REPE CMPS

OD Shift+F1帮助命令,放在一起说明了

Command: REPE CMPS BYTE PTR DS:[ESI],BYTE PTR ES:[EDI]

Hex dump: F3:A6

Searches strings for the first non-matching byte.

On each iteration, processor compares byte at address [ESI] with the byte at address [EDI] and sets flags C, O, S, Z, A and P

according to the difference [ESI]-[EDI]. The operands themselves are not modified. After the comparison, registers ESI and

EDI are incremented by 1 (if flag D is cleared) or decremented by 1 (if flag D is set). Register ECX is always decremented

by 1. If ECX after decrement is zero, or if compared operands were different (flag Z was cleared), search stops; otherwise,

processor repeats the whole cycle again and again, until count exhausts or non-matching pair will be found.

Note that if ECX initially contains zero, this instruction does nothing.

REPE :repeat equal,意思是相等的时候重复,

REPNE repeat not equal,不等的时候重复;

他们每循环一次ECX自动减一。

/**正常使用等价于*/

//准备int rECX = 循环次数;        

//指令开始

bool bZF = true;//比较标志位,由指令REPE决定

while (bZF && !rECX)//循环条件,由指令REPE决定bZF,REPNE决定!bZF

{

    bZF = *pbyteESI++ == *pbyteEDI++;// DF位决定++还是--,根据结果设置标志位bZF

    rECX--;//总是--

}

字符串比较指令(Compare String Instruction)

该指令是把指针DS:SI和ES:DI所指向字节、字或双字的值相减,并用所得到的差来设置有关的标志位。与此同时,变址寄存器SI和DI也将根据标志位DF的值作相应增减。

指令的格式:CMPS 地址表达式1, 地址表达式2
CMPSB/CMPSW
CMPSD      ;80386+

受影响的标志位:AF、CF、OF、PF、SF和ZF

    注册代码

特别写了个js的代码,涉及中文名字时的gbk 在内存中的摆放。

    Javascript(在线查看 http://runjs.cn/code/npiizz88)

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>GIFMovieGear KeyGen</title>

<style type="text/css">

p {

font-family: 'Lucida Console', Monaco, monospace;

}

button {

width: 150px;

}

.bg {

font-style: italic;

color: gray;

}

</style>

<script language="javascript" type="text/javascript">

//Fang = HSDWQ9-QKFADW-H92C5A-GAGVNK CB D5 B1 B1|D0 A1 C2 F3| = 苏北小麦

function Generate() {

var inputs = document.getElementsByTagName("input");

//var addrHKRW = 0x48F478, local51 = 1 - 0x48F478, local52 = 0x48F478 - 1;

//local51 = 0xFFB70B89;//0xFFFFFFFF - 0x48F478 + 2

var idx, i, ch;

var name = inputs[0].value, rName = [], resTab = "HKRWQV2958DWNTQRGNSCFSXAZPYK";

var letterTable = "0123456789abcdefghijklmnopqrstuvwxyz"

var ediRCode = [], ebp = 0;//, eax, ecx;

var codeTypes = document.getElementsByName("codetype");

//两种注册码,mg37开头的和不是这开头的短横线分割的

if (!codeTypes[2].checked) {

do {

ediRCode = "mg37";

idx = name.length;

if (codeTypes[0].checked)

ediRCode += 's';

ediRCode += randomLetter(letterTable) + randomLetter(letterTable) + randomLetter(letterTable);

var esi = 3039, ecx = 0, edx;

//每一项0x00 - 0xFF

var codes = GB2312CodeArray(name);

for (i = 0; i < codes.length; i++) {

++ecx;

edx = codes[i];

if (edx > 0x7F)

edx = -(~(edx - 1) & 0xff);

esi += ecx * edx;

if (esi > 6078)

esi -= 6078;

if (ecx > 10)

ecx = 0;

}

ediRCode += esi;

} while (isBlackCode(ediRCode));

} else {

name = name.toUpperCase()

for (i = 0; i < name.length; i++) {

ch = name.charAt(i);

idx = resTab.indexOf(ch);

if (-1 != idx)//有才压入

rName.push(ch);

}

//rName每一个字符都存在于resTab中

rName = rName.join("");

//不足24位补齐

if (rName.length < 24)

rName = rName + resTab.substring(0, 24 - rName.length);

i = 0;

//Code长度为24

while (i < 24) {

idx = resTab.indexOf(rName.charAt(i));

//eax = addrHKRW + idx;

//ecx = (eax + local51) & 0xFFFFFFFF;//rAdd(eax, local51);

//ebp = rAdd(ebp, (ecx - 1)* ecx) % resTab.length;

ebp = (idx * (idx + 1) + ebp) % resTab.length;

ediRCode.push(resTab.charAt(ebp++));

if (!(++i % 6) && i < 24)

ediRCode.push('-');

}

ediRCode = ediRCode.join("");

}

inputs[1].value = ediRCode;

};

//模拟32位寄存器值相加

/*function rAdd(v1, v2){

var v = v1 + v2;

if(v > 0xFFFFFFFF)

v &= 0xFFFFFFFF;

return v;

}*/

var blackCodes = ["mvg21951736", "mg374604342", "mg370534035", "mg373465241", "mg37NTi", "mg372503958", "mg379843149", "mg370151347", "mg370353008", "mg372021424", "mg375953248", "mg379223953", "mg373473759", "mg378542544", "mg370473710", "mg37064348", "mg378822469", "mg374394987", "mg371073478", "mg379773651", "mg371895266", "mg373223554", "mg377583454", "mg37644957", "mg370342692", "mg376484039", "mg376871434", "mg370704788", "mg377643863", "mg377753931", "mg379342689", "mg374344777"];

function isBlackCode(code) {

for (i = blackCodes.length; i > 0; i--) {

if (code == blackCodes[--i]) {

return true;

}

}

return false;

}

function randomLetter(letterTable) {

return letterTable.charAt(Math.floor(Math.random() * letterTable.length));

}

function codeChange() {

var testCode = document.getElementsByName("testCode");

var raw = testCode[0].value;

var charCodes = [];

for (var i = 0; i < raw.length; i++) {

charCodes.push(raw.charCodeAt(i).toString(16));

}

testCode[1].value = charCodes.join();

//

charCodes.length = 0;

var encodeArray = encodeURI(raw).split("%");

for (var i = 1; i < encodeArray.length; i += 3) {

charCodes.push(encodeArray[i] + encodeArray[i + 1] + encodeArray[i + 2]);

}

testCode[2].value = charCodes.join();

charCodes.length = 0;

//

var gb2312Codes = GB2312CodeArray(raw);

for (var i = 0; i < gb2312Codes.length; i += 2) {

charCodes.push(gb2312Codes[i].toString(16) + gb2312Codes[i + 1].toString(16));

}

testCode[3].value = charCodes.join();

}

function init() {

Generate();

codeChange();

var c = document.getElementById("c");

var ctx = c.getContext("2d");

c.height = 100;

c.width = 300;

var txts = "CRACK".split("");

var font_size = 12;

var columns = c.width / font_size;

var drops = [];

for (var x = 0; x < columns; x++)

drops[x] = 1;

function draw() {

ctx.fillStyle = "rgba(0, 0, 0, 0.05)";

ctx.fillRect(0, 0, c.width, c.height);

ctx.fillStyle = "#0F0";

ctx.font = font_size + "px arial";

for (var i = 0; i < drops.length; i++) {

var text = txts[Math.floor(Math.random() * txts.length)];

ctx.fillText(text, i * font_size, drops[i] * font_size);

if (drops[i] * font_size > c.height || Math.random() > 0.8)

drops[i] = 0;

drops[i]++;

}

}

setInterval(draw, 66);

}

/** 返回[] http://blog.csdn.net/yimengqiannian/article/details/7016720 */

function GB2312CodeArray(str) {

/*********改自<a href="http://blog.csdn.net/qiushuiwuhen/article/details/14112">qiushuiwuhen(2002-9-16)</a>********/

var ch, pos, cod, gbkCode = [];

for (var i = 0; i < str.length; i++) {

ch = str.charAt(i);

cod = str.charCodeAt(i);

//汉字字符

if (cod >= 0x4e00 && cod < 0x9FA5) {

if (-1 != (pos = GBhz.indexOf(ch))) {

gbkCode.push(0xB0 + parseInt(pos / 94));

gbkCode.push(0xA1 + pos % 94);

}

} else if ((pos = GBfh.indexOf(ch)) != -1) {

gbkCode.push(0xA1 + parseInt(pos / 94));

gbkCode.push(0xA1 + pos % 94);

}

else gbkCode.push(parseInt(cod));

}

return gbkCode;

}

//采录的只是GB2312编码

var GBfh = " 、。•ˉˇ¨〃々—~‖…''""〔〕〈〉《》「」『』〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇①②③④⑤⑥⑦⑧⑨⑩㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ̄ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψω︵︶︹︺︿﹀︽︾﹁﹂﹃﹄︻︼︷︸︱︳︴АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяāáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüêɑńňɡㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋";

var GBhz = "啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏百摆佰败拜稗斑班搬扳般颁板版扮拌伴瓣半办绊邦帮梆榜膀绑棒磅蚌镑傍谤苞胞包褒剥薄雹保堡饱宝抱报暴豹鲍爆杯碑悲卑北辈背贝钡倍狈备惫焙被奔苯本笨崩绷甭泵蹦迸逼鼻比鄙笔彼碧蓖蔽毕毙毖币庇痹闭敝弊必辟壁臂避陛鞭边编贬扁便变卞辨辩辫遍标彪膘表鳖憋别瘪彬斌濒滨宾摈兵冰柄丙秉饼炳病并玻菠播拨钵波博勃搏铂箔伯帛舶脖膊渤泊驳捕卜哺补埠不布步簿部怖擦猜裁材才财睬踩采彩菜蔡餐参蚕残惭惨灿苍舱仓沧藏操糙槽曹草厕策侧册测层蹭插叉茬茶查碴搽察岔差诧拆柴豺搀掺蝉馋谗缠铲产阐颤昌猖场尝常长偿肠厂敞畅唱倡超抄钞朝嘲潮巢吵炒车扯撤掣彻澈郴臣辰尘晨忱沉陈趁衬撑称城橙成呈乘程惩澄诚承逞骋秤吃痴持匙池迟弛驰耻齿侈尺赤翅斥炽充冲虫崇宠抽酬畴踌稠愁筹仇绸瞅丑臭初出橱厨躇锄雏滁除楚础储矗搐触处揣川穿椽传船喘串疮窗幢床闯创吹炊捶锤垂春椿醇唇淳纯蠢戳绰疵茨磁雌辞慈瓷词此刺赐次聪葱囱匆从丛凑粗醋簇促蹿篡窜摧崔催脆瘁粹淬翠村存寸磋撮搓措挫错搭达答瘩打大呆歹傣戴带殆代贷袋待逮怠耽担丹单郸掸胆旦氮但惮淡诞弹蛋当挡党荡档刀捣蹈倒岛祷导到稻悼道盗德得的蹬灯登等瞪凳邓堤低滴迪敌笛狄涤翟嫡抵底地蒂第帝弟递缔颠掂滇碘点典靛垫电佃甸店惦奠淀殿碉叼雕凋刁掉吊钓调跌爹碟蝶迭谍叠丁盯叮钉顶鼎锭定订丢东冬董懂动栋侗恫冻洞兜抖斗陡豆逗痘都督毒犊独读堵睹赌杜镀肚度渡妒端短锻段断缎堆兑队对墩吨蹲敦顿囤钝盾遁掇哆多夺垛躲朵跺舵剁惰堕蛾峨鹅俄额讹娥恶厄扼遏鄂饿恩而儿耳尔饵洱二贰发罚筏伐乏阀法珐藩帆番翻樊矾钒繁凡烦反返范贩犯饭泛坊芳方肪房防妨仿访纺放菲非啡飞肥匪诽吠肺废沸费芬酚吩氛分纷坟焚汾粉奋份忿愤粪丰封枫蜂峰锋风疯烽逢冯缝讽奉凤佛否夫敷肤孵扶拂辐幅氟符伏俘服浮涪福袱弗甫抚辅俯釜斧脯腑府腐赴副覆赋复傅付阜父腹负富讣附妇缚咐噶嘎该改概钙盖溉干甘杆柑竿肝赶感秆敢赣冈刚钢缸肛纲岗港杠篙皋高膏羔糕搞镐稿告哥歌搁戈鸽胳疙割革葛格蛤阁隔铬个各给根跟耕更庚羹埂耿梗工攻功恭龚供躬公宫弓巩汞拱贡共钩勾沟苟狗垢构购够辜菇咕箍估沽孤姑鼓古蛊骨谷股故顾固雇刮瓜剐寡挂褂乖拐怪棺关官冠观管馆罐惯灌贯光广逛瑰规圭硅归龟闺轨鬼诡癸桂柜跪贵刽辊滚棍锅郭国果裹过哈骸孩海氦亥害骇酣憨邯韩含涵寒函喊罕翰撼捍旱憾悍焊汗汉夯杭航壕嚎豪毫郝好耗号浩呵喝荷菏核禾和何合盒貉阂河涸赫褐鹤贺嘿黑痕很狠恨哼亨横衡恒轰哄烘虹鸿洪宏弘红喉侯猴吼厚候后呼乎忽瑚壶葫胡蝴狐糊湖弧虎唬护互沪户花哗华猾滑画划化话槐徊怀淮坏欢环桓还缓换患唤痪豢焕涣宦幻荒慌黄磺蝗簧皇凰惶煌晃幌恍谎灰挥辉徽恢蛔回毁悔慧卉惠晦贿秽会烩汇讳诲绘荤昏婚魂浑混豁活伙火获或惑霍货祸击圾基机畸稽积箕肌饥迹激讥鸡姬绩缉吉极棘辑籍集及急疾汲即嫉级挤几脊己蓟技冀季伎祭剂悸济寄寂计记既忌际妓继纪嘉枷夹佳家加荚颊贾甲钾假稼价架驾嫁歼监坚尖笺间煎兼肩艰奸缄茧检柬碱硷拣捡简俭剪减荐槛鉴践贱见键箭件健舰剑饯渐溅涧建僵姜将浆江疆蒋桨奖讲匠酱降蕉椒礁焦胶交郊浇骄娇嚼搅铰矫侥脚狡角饺缴绞剿教酵轿较叫窖揭接皆秸街阶截劫节桔杰捷睫竭洁结解姐戒藉芥界借介疥诫届巾筋斤金今津襟紧锦仅谨进靳晋禁近烬浸尽劲荆兢茎睛晶鲸京惊精粳经井警景颈静境敬镜径痉靖竟竞净炯窘揪究纠玖韭久灸九酒厩救旧臼舅咎就疚鞠拘狙疽居驹菊局咀矩举沮聚拒据巨具距踞锯俱句惧炬剧捐鹃娟倦眷卷绢撅攫抉掘倔爵觉决诀绝均菌钧军君峻俊竣浚郡骏喀咖卡咯开揩楷凯慨刊堪勘坎砍看康慷糠扛抗亢炕考拷烤靠坷苛柯棵磕颗科壳咳可渴克刻客课肯啃垦恳坑吭空恐孔控抠口扣寇枯哭窟苦酷库裤夸垮挎跨胯块筷侩快宽款匡筐狂框矿眶旷况亏盔岿窥葵奎魁傀馈愧溃坤昆捆困括扩廓阔垃拉喇蜡腊辣啦莱来赖蓝婪栏拦篮阑兰澜谰揽览懒缆烂滥琅榔狼廊郎朗浪捞劳牢老佬姥酪烙涝勒乐雷镭蕾磊累儡垒擂肋类泪棱楞冷厘梨犁黎篱狸离漓理李里鲤礼莉荔吏栗丽厉励砾历利傈例俐痢立粒沥隶力璃哩俩联莲连镰廉怜涟帘敛脸链恋炼练粮凉梁粱良两辆量晾亮谅撩聊僚疗燎寥辽潦了撂镣廖料列裂烈劣猎琳林磷霖临邻鳞淋凛赁吝拎玲菱零龄铃伶羚凌灵陵岭领另令溜琉榴硫馏留刘瘤流柳六龙聋咙笼窿隆垄拢陇楼娄搂篓漏陋芦卢颅庐炉掳卤虏鲁麓碌露路赂鹿潞禄录陆戮驴吕铝侣旅履屡缕虑氯律率滤绿峦挛孪滦卵乱掠略抡轮伦仑沦纶论萝螺罗逻锣箩骡裸落洛骆络妈麻玛码蚂马骂嘛吗埋买麦卖迈脉瞒馒蛮满蔓曼慢漫谩芒茫盲氓忙莽猫茅锚毛矛铆卯茂冒帽貌贸么玫枚梅酶霉煤没眉媒镁每美昧寐妹媚门闷们萌蒙檬盟锰猛梦孟眯醚靡糜迷谜弥米秘觅泌蜜密幂棉眠绵冕免勉娩缅面苗描瞄藐秒渺庙妙蔑灭民抿皿敏悯闽明螟鸣铭名命谬摸摹蘑模膜磨摩魔抹末莫墨默沫漠寞陌谋牟某拇牡亩姆母墓暮幕募慕木目睦牧穆拿哪呐钠那娜纳氖乃奶耐奈南男难囊挠脑恼闹淖呢馁内嫩能妮霓倪泥尼拟你匿腻逆溺蔫拈年碾撵捻念娘酿鸟尿捏聂孽啮镊镍涅您柠狞凝宁拧泞牛扭钮纽脓浓农弄奴努怒女暖虐疟挪懦糯诺哦欧鸥殴藕呕偶沤啪趴爬帕怕琶拍排牌徘湃派攀潘盘磐盼畔判叛乓庞旁耪胖抛咆刨炮袍跑泡呸胚培裴赔陪配佩沛喷盆砰抨烹澎彭蓬棚硼篷膨朋鹏捧碰坯砒霹批披劈琵毗啤脾疲皮匹痞僻屁譬篇偏片骗飘漂瓢票撇瞥拼频贫品聘乒坪苹萍平凭瓶评屏坡泼颇婆破魄迫粕剖扑铺仆莆葡菩蒲埔朴圃普浦谱曝瀑期欺栖戚妻七凄漆柒沏其棋奇歧畦崎脐齐旗祈祁骑起岂乞企启契砌器气迄弃汽泣讫掐恰洽牵扦钎铅千迁签仟谦乾黔钱钳前潜遣浅谴堑嵌欠歉枪呛腔羌墙蔷强抢橇锹敲悄桥瞧乔侨巧鞘撬翘峭俏窍切茄且怯窃钦侵亲秦琴勤芹擒禽寝沁青轻氢倾卿清擎晴氰情顷请庆琼穷秋丘邱球求囚酋泅趋区蛆曲躯屈驱渠取娶龋趣去圈颧权醛泉全痊拳犬券劝缺炔瘸却鹊榷确雀裙群然燃冉染瓤壤攘嚷让饶扰绕惹热壬仁人忍韧任认刃妊纫扔仍日戎茸蓉荣融熔溶容绒冗揉柔肉茹蠕儒孺如辱乳汝入褥软阮蕊瑞锐闰润若弱撒洒萨腮鳃塞赛三叁伞散桑嗓丧搔骚扫嫂瑟色涩森僧莎砂杀刹沙纱傻啥煞筛晒珊苫杉山删煽衫闪陕擅赡膳善汕扇缮墒伤商赏晌上尚裳梢捎稍烧芍勺韶少哨邵绍奢赊蛇舌舍赦摄射慑涉社设砷申呻伸身深娠绅神沈审婶甚肾慎渗声生甥牲升绳省盛剩胜圣师失狮施湿诗尸虱十石拾时什食蚀实识史矢使屎驶始式示士世柿事拭誓逝势是嗜噬适仕侍释饰氏市恃室视试收手首守寿授售受瘦兽蔬枢梳殊抒输叔舒淑疏书赎孰熟薯暑曙署蜀黍鼠属术述树束戍竖墅庶数漱恕刷耍摔衰甩帅栓拴霜双爽谁水睡税吮瞬顺舜说硕朔烁斯撕嘶思私司丝死肆寺嗣四伺似饲巳松耸怂颂送宋讼诵搜艘擞嗽苏酥俗素速粟僳塑溯宿诉肃酸蒜算虽隋随绥髓碎岁穗遂隧祟孙损笋蓑梭唆缩琐索锁所塌他它她塔獭挞蹋踏胎苔抬台泰酞太态汰坍摊贪瘫滩坛檀痰潭谭谈坦毯袒碳探叹炭汤塘搪堂棠膛唐糖倘躺淌趟烫掏涛滔绦萄桃逃淘陶讨套特藤腾疼誊梯剔踢锑提题蹄啼体替嚏惕涕剃屉天添填田甜恬舔腆挑条迢眺跳贴铁帖厅听烃汀廷停亭庭挺艇通桐酮瞳同铜彤童桶捅筒统痛偷投头透凸秃突图徒途涂屠土吐兔湍团推颓腿蜕褪退吞屯臀拖托脱鸵陀驮驼椭妥拓唾挖哇蛙洼娃瓦袜歪外豌弯湾玩顽丸烷完碗挽晚皖惋宛婉万腕汪王亡枉网往旺望忘妄威巍微危韦违桅围唯惟为潍维苇萎委伟伪尾纬未蔚味畏胃喂魏位渭谓尉慰卫瘟温蚊文闻纹吻稳紊问嗡翁瓮挝蜗涡窝我斡卧握沃巫呜钨乌污诬屋无芜梧吾吴毋武五捂午舞伍侮坞戊雾晤物勿务悟误昔熙析西硒矽晰嘻吸锡牺稀息希悉膝夕惜熄烯溪汐犀檄袭席习媳喜铣洗系隙戏细瞎虾匣霞辖暇峡侠狭下厦夏吓掀锨先仙鲜纤咸贤衔舷闲涎弦嫌显险现献县腺馅羡宪陷限线相厢镶香箱襄湘乡翔祥详想响享项巷橡像向象萧硝霄削哮嚣销消宵淆晓小孝校肖啸笑效楔些歇蝎鞋协挟携邪斜胁谐写械卸蟹懈泄泻谢屑薪芯锌欣辛新忻心信衅星腥猩惺兴刑型形邢行醒幸杏性姓兄凶胸匈汹雄熊休修羞朽嗅锈秀袖绣墟戌需虚嘘须徐许蓄酗叙旭序畜恤絮婿绪续轩喧宣悬旋玄选癣眩绚靴薛学穴雪血勋熏循旬询寻驯巡殉汛训讯逊迅压押鸦鸭呀丫芽牙蚜崖衙涯雅哑亚讶焉咽阉烟淹盐严研蜒岩延言颜阎炎沿奄掩眼衍演艳堰燕厌砚雁唁彦焰宴谚验殃央鸯秧杨扬佯疡羊洋阳氧仰痒养样漾邀腰妖瑶摇尧遥窑谣姚咬舀药要耀椰噎耶爷野冶也页掖业叶曳腋夜液一壹医揖铱依伊衣颐夷遗移仪胰疑沂宜姨彝椅蚁倚已乙矣以艺抑易邑屹亿役臆逸肄疫亦裔意毅忆义益溢诣议谊译异翼翌绎茵荫因殷音阴姻吟银淫寅饮尹引隐印英樱婴鹰应缨莹萤营荧蝇迎赢盈影颖硬映哟拥佣臃痈庸雍踊蛹咏泳涌永恿勇用幽优悠忧尤由邮铀犹油游酉有友右佑釉诱又幼迂淤于盂榆虞愚舆余俞逾鱼愉渝渔隅予娱雨与屿禹宇语羽玉域芋郁吁遇喻峪御愈欲狱育誉浴寓裕预豫驭鸳渊冤元垣袁原援辕园员圆猿源缘远苑愿怨院曰约越跃钥岳粤月悦阅耘云郧匀陨允运蕴酝晕韵孕匝砸杂栽哉灾宰载再在咱攒暂赞赃脏葬遭糟凿藻枣早澡蚤躁噪造皂灶燥责择则泽贼怎增憎曾赠扎喳渣札轧铡闸眨栅榨咋乍炸诈摘斋宅窄债寨瞻毡詹粘沾盏斩辗崭展蘸栈占战站湛绽樟章彰漳张掌涨杖丈帐账仗胀瘴障招昭找沼赵照罩兆肇召遮折哲蛰辙者锗蔗这浙珍斟真甄砧臻贞针侦枕疹诊震振镇阵蒸挣睁征狰争怔整拯正政帧症郑证芝枝支吱蜘知肢脂汁之织职直植殖执值侄址指止趾只旨纸志挚掷至致置帜峙制智秩稚质炙痔滞治窒中盅忠钟衷终种肿重仲众舟周州洲诌粥轴肘帚咒皱宙昼骤珠株蛛朱猪诸诛逐竹烛煮拄瞩嘱主著柱助蛀贮铸筑住注祝驻抓爪拽专砖转撰赚篆桩庄装妆撞壮状椎锥追赘坠缀谆准捉拙卓桌琢茁酌啄着灼浊兹咨资姿滋淄孜紫仔籽滓子自渍字鬃棕踪宗综总纵邹走奏揍租足卒族祖诅阻组钻纂嘴醉最罪尊遵昨左佐柞做作坐座亍丌兀丐廿卅丕亘丞鬲孬噩丨禺丿匕乇夭爻卮氐囟胤馗毓睾鼗丶亟鼐乜乩亓芈孛啬嘏仄厍厝厣厥厮靥赝匚叵匦匮匾赜卦卣刂刈刎刭刳刿剀剌剞剡剜蒯剽劂劁劐劓冂罔亻仃仉仂仨仡仫仞伛仳伢佤仵伥伧伉伫佞佧攸佚佝佟佗伲伽佶佴侑侉侃侏佾佻侪佼侬侔俦俨俪俅俚俣俜俑俟俸倩偌俳倬倏倮倭俾倜倌倥倨偾偃偕偈偎偬偻傥傧傩傺僖儆僭僬僦僮儇儋仝氽佘佥俎龠汆籴兮巽黉馘冁夔勹匍訇匐凫夙兕亠兖亳衮袤亵脔裒禀嬴蠃羸冫冱冽冼凇冖冢冥讠讦讧讪讴讵讷诂诃诋诏诎诒诓诔诖诘诙诜诟诠诤诨诩诮诰诳诶诹诼诿谀谂谄谇谌谏谑谒谔谕谖谙谛谘谝谟谠谡谥谧谪谫谮谯谲谳谵谶卩卺阝阢阡阱阪阽阼陂陉陔陟陧陬陲陴隈隍隗隰邗邛邝邙邬邡邴邳邶邺邸邰郏郅邾郐郄郇郓郦郢郜郗郛郫郯郾鄄鄢鄞鄣鄱鄯鄹酃酆刍奂劢劬劭劾哿勐勖勰叟燮矍廴凵凼鬯厶弁畚巯坌垩垡塾墼壅壑圩圬圪圳圹圮圯坜圻坂坩垅坫垆坼坻坨坭坶坳垭垤垌垲埏垧垴垓垠埕埘埚埙埒垸埴埯埸埤埝堋堍埽埭堀堞堙塄堠塥塬墁墉墚墀馨鼙懿艹艽艿芏芊芨芄芎芑芗芙芫芸芾芰苈苊苣芘芷芮苋苌苁芩芴芡芪芟苄苎芤苡茉苷苤茏茇苜苴苒苘茌苻苓茑茚茆茔茕苠苕茜荑荛荜茈莒茼茴茱莛荞茯荏荇荃荟荀茗荠茭茺茳荦荥荨茛荩荬荪荭荮莰荸莳莴莠莪莓莜莅荼莶莩荽莸荻莘莞莨莺莼菁萁菥菘堇萘萋菝菽菖萜萸萑萆菔菟萏萃菸菹菪菅菀萦菰菡葜葑葚葙葳蒇蒈葺蒉葸萼葆葩葶蒌蒎萱葭蓁蓍蓐蓦蒽蓓蓊蒿蒺蓠蒡蒹蒴蒗蓥蓣蔌甍蔸蓰蔹蔟蔺蕖蔻蓿蓼蕙蕈蕨蕤蕞蕺瞢蕃蕲蕻薤薨薇薏蕹薮薜薅薹薷薰藓藁藜藿蘧蘅蘩蘖蘼廾弈夼奁耷奕奚奘匏尢尥尬尴扌扪抟抻拊拚拗拮挢拶挹捋捃掭揶捱捺掎掴捭掬掊捩掮掼揲揸揠揿揄揞揎摒揆掾摅摁搋搛搠搌搦搡摞撄摭撖摺撷撸撙撺擀擐擗擤擢攉攥攮弋忒甙弑卟叱叽叩叨叻吒吖吆呋呒呓呔呖呃吡呗呙吣吲咂咔呷呱呤咚咛咄呶呦咝哐咭哂咴哒咧咦哓哔呲咣哕咻咿哌哙哚哜咩咪咤哝哏哞唛哧唠哽唔哳唢唣唏唑唧唪啧喏喵啉啭啁啕唿啐唼唷啖啵啶啷唳唰啜喋嗒喃喱喹喈喁喟啾嗖喑啻嗟喽喾喔喙嗪嗷嗉嘟嗑嗫嗬嗔嗦嗝嗄嗯嗥嗲嗳嗌嗍嗨嗵嗤辔嘞嘈嘌嘁嘤嘣嗾嘀嘧嘭噘嘹噗嘬噍噢噙噜噌噔嚆噤噱噫噻噼嚅嚓嚯囔囗囝囡囵囫囹囿圄圊圉圜帏帙帔帑帱帻帼帷幄幔幛幞幡岌屺岍岐岖岈岘岙岑岚岜岵岢岽岬岫岱岣峁岷峄峒峤峋峥崂崃崧崦崮崤崞崆崛嵘崾崴崽嵬嵛嵯嵝嵫嵋嵊嵩嵴嶂嶙嶝豳嶷巅彳彷徂徇徉後徕徙徜徨徭徵徼衢彡犭犰犴犷犸狃狁狎狍狒狨狯狩狲狴狷猁狳猃狺狻猗猓猡猊猞猝猕猢猹猥猬猸猱獐獍獗獠獬獯獾舛夥飧夤夂饣饧饨饩饪饫饬饴饷饽馀馄馇馊馍馐馑馓馔馕庀庑庋庖庥庠庹庵庾庳赓廒廑廛廨廪膺忄忉忖忏怃忮怄忡忤忾怅怆忪忭忸怙怵怦怛怏怍怩怫怊怿怡恸恹恻恺恂恪恽悖悚悭悝悃悒悌悛惬悻悱惝惘惆惚悴愠愦愕愣惴愀愎愫慊慵憬憔憧憷懔懵忝隳闩闫闱闳闵闶闼闾阃阄阆阈阊阋阌阍阏阒阕阖阗阙阚丬爿戕氵汔汜汊沣沅沐沔沌汨汩汴汶沆沩泐泔沭泷泸泱泗沲泠泖泺泫泮沱泓泯泾洹洧洌浃浈洇洄洙洎洫浍洮洵洚浏浒浔洳涑浯涞涠浞涓涔浜浠浼浣渚淇淅淞渎涿淠渑淦淝淙渖涫渌涮渫湮湎湫溲湟溆湓湔渲渥湄滟溱溘滠漭滢溥溧溽溻溷滗溴滏溏滂溟潢潆潇漤漕滹漯漶潋潴漪漉漩澉澍澌潸潲潼潺濑濉澧澹澶濂濡濮濞濠濯瀚瀣瀛瀹瀵灏灞宀宄宕宓宥宸甯骞搴寤寮褰寰蹇謇辶迓迕迥迮迤迩迦迳迨逅逄逋逦逑逍逖逡逵逶逭逯遄遑遒遐遨遘遢遛暹遴遽邂邈邃邋彐彗彖彘尻咫屐屙孱屣屦羼弪弩弭艴弼鬻屮妁妃妍妩妪妣妗姊妫妞妤姒妲妯姗妾娅娆姝娈姣姘姹娌娉娲娴娑娣娓婀婧婊婕娼婢婵胬媪媛婷婺媾嫫媲嫒嫔媸嫠嫣嫱嫖嫦嫘嫜嬉嬗嬖嬲嬷孀尕尜孚孥孳孑孓孢驵驷驸驺驿驽骀骁骅骈骊骐骒骓骖骘骛骜骝骟骠骢骣骥骧纟纡纣纥纨纩纭纰纾绀绁绂绉绋绌绐绔绗绛绠绡绨绫绮绯绱绲缍绶绺绻绾缁缂缃缇缈缋缌缏缑缒缗缙缜缛缟缡缢缣缤缥缦缧缪缫缬缭缯缰缱缲缳缵幺畿巛甾邕玎玑玮玢玟珏珂珑玷玳珀珉珈珥珙顼琊珩珧珞玺珲琏琪瑛琦琥琨琰琮琬琛琚瑁瑜瑗瑕瑙瑷瑭瑾璜璎璀璁璇璋璞璨璩璐璧瓒璺韪韫韬杌杓杞杈杩枥枇杪杳枘枧杵枨枞枭枋杷杼柰栉柘栊柩枰栌柙枵柚枳柝栀柃枸柢栎柁柽栲栳桠桡桎桢桄桤梃栝桕桦桁桧桀栾桊桉栩梵梏桴桷梓桫棂楮棼椟椠棹椤棰椋椁楗棣椐楱椹楠楂楝榄楫榀榘楸椴槌榇榈槎榉楦楣楹榛榧榻榫榭槔榱槁槊槟榕槠榍槿樯槭樗樘橥槲橄樾檠橐橛樵檎橹樽樨橘橼檑檐檩檗檫猷獒殁殂殇殄殒殓殍殚殛殡殪轫轭轱轲轳轵轶轸轷轹轺轼轾辁辂辄辇辋辍辎辏辘辚軎戋戗戛戟戢戡戥戤戬臧瓯瓴瓿甏甑甓攴旮旯旰昊昙杲昃昕昀炅曷昝昴昱昶昵耆晟晔晁晏晖晡晗晷暄暌暧暝暾曛曜曦曩贲贳贶贻贽赀赅赆赈赉赇赍赕赙觇觊觋觌觎觏觐觑牮犟牝牦牯牾牿犄犋犍犏犒挈挲掰搿擘耄毪毳毽毵毹氅氇氆氍氕氘氙氚氡氩氤氪氲攵敕敫牍牒牖爰虢刖肟肜肓肼朊肽肱肫肭肴肷胧胨胩胪胛胂胄胙胍胗朐胝胫胱胴胭脍脎胲胼朕脒豚脶脞脬脘脲腈腌腓腴腙腚腱腠腩腼腽腭腧塍媵膈膂膑滕膣膪臌朦臊膻臁膦欤欷欹歃歆歙飑飒飓飕飙飚殳彀毂觳斐齑斓於旆旄旃旌旎旒旖炀炜炖炝炻烀炷炫炱烨烊焐焓焖焯焱煳煜煨煅煲煊煸煺熘熳熵熨熠燠燔燧燹爝爨灬焘煦熹戾戽扃扈扉礻祀祆祉祛祜祓祚祢祗祠祯祧祺禅禊禚禧禳忑忐怼恝恚恧恁恙恣悫愆愍慝憩憝懋懑戆肀聿沓泶淼矶矸砀砉砗砘砑斫砭砜砝砹砺砻砟砼砥砬砣砩硎硭硖硗砦硐硇硌硪碛碓碚碇碜碡碣碲碹碥磔磙磉磬磲礅磴礓礤礞礴龛黹黻黼盱眄眍盹眇眈眚眢眙眭眦眵眸睐睑睇睃睚睨睢睥睿瞍睽瞀瞌瞑瞟瞠瞰瞵瞽町畀畎畋畈畛畲畹疃罘罡罟詈罨罴罱罹羁罾盍盥蠲钅钆钇钋钊钌钍钏钐钔钗钕钚钛钜钣钤钫钪钭钬钯钰钲钴钶钷钸钹钺钼钽钿铄铈铉铊铋铌铍铎铐铑铒铕铖铗铙铘铛铞铟铠铢铤铥铧铨铪铩铫铮铯铳铴铵铷铹铼铽铿锃锂锆锇锉锊锍锎锏锒锓锔锕锖锘锛锝锞锟锢锪锫锩锬锱锲锴锶锷锸锼锾锿镂锵镄镅镆镉镌镎镏镒镓镔镖镗镘镙镛镞镟镝镡镢镤镥镦镧镨镩镪镫镬镯镱镲镳锺矧矬雉秕秭秣秫稆嵇稃稂稞稔稹稷穑黏馥穰皈皎皓皙皤瓞瓠甬鸠鸢鸨鸩鸪鸫鸬鸲鸱鸶鸸鸷鸹鸺鸾鹁鹂鹄鹆鹇鹈鹉鹋鹌鹎鹑鹕鹗鹚鹛鹜鹞鹣鹦鹧鹨鹩鹪鹫鹬鹱鹭鹳疒疔疖疠疝疬疣疳疴疸痄疱疰痃痂痖痍痣痨痦痤痫痧瘃痱痼痿瘐瘀瘅瘌瘗瘊瘥瘘瘕瘙瘛瘼瘢瘠癀瘭瘰瘿瘵癃瘾瘳癍癞癔癜癖癫癯翊竦穸穹窀窆窈窕窦窠窬窨窭窳衤衩衲衽衿袂袢裆袷袼裉裢裎裣裥裱褚裼裨裾裰褡褙褓褛褊褴褫褶襁襦襻疋胥皲皴矜耒耔耖耜耠耢耥耦耧耩耨耱耋耵聃聆聍聒聩聱覃顸颀颃颉颌颍颏颔颚颛颞颟颡颢颥颦虍虔虬虮虿虺虼虻蚨蚍蚋蚬蚝蚧蚣蚪蚓蚩蚶蛄蚵蛎蚰蚺蚱蚯蛉蛏蚴蛩蛱蛲蛭蛳蛐蜓蛞蛴蛟蛘蛑蜃蜇蛸蜈蜊蜍蜉蜣蜻蜞蜥蜮蜚蜾蝈蜴蜱蜩蜷蜿螂蜢蝽蝾蝻蝠蝰蝌蝮螋蝓蝣蝼蝤蝙蝥螓螯螨蟒蟆螈螅螭螗螃螫蟥螬螵螳蟋蟓螽蟑蟀蟊蟛蟪蟠蟮蠖蠓蟾蠊蠛蠡蠹蠼缶罂罄罅舐竺竽笈笃笄笕笊笫笏筇笸笪笙笮笱笠笥笤笳笾笞筘筚筅筵筌筝筠筮筻筢筲筱箐箦箧箸箬箝箨箅箪箜箢箫箴篑篁篌篝篚篥篦篪簌篾篼簏簖簋簟簪簦簸籁籀臾舁舂舄臬衄舡舢舣舭舯舨舫舸舻舳舴舾艄艉艋艏艚艟艨衾袅袈裘裟襞羝羟羧羯羰羲籼敉粑粝粜粞粢粲粼粽糁糇糌糍糈糅糗糨艮暨羿翎翕翥翡翦翩翮翳糸絷綦綮繇纛麸麴赳趄趔趑趱赧赭豇豉酊酐酎酏酤酢酡酰酩酯酽酾酲酴酹醌醅醐醍醑醢醣醪醭醮醯醵醴醺豕鹾趸跫踅蹙蹩趵趿趼趺跄跖跗跚跞跎跏跛跆跬跷跸跣跹跻跤踉跽踔踝踟踬踮踣踯踺蹀踹踵踽踱蹉蹁蹂蹑蹒蹊蹰蹶蹼蹯蹴躅躏躔躐躜躞豸貂貊貅貘貔斛觖觞觚觜觥觫觯訾謦靓雩雳雯霆霁霈霏霎霪霭霰霾龀龃龅龆龇龈龉龊龌黾鼋鼍隹隼隽雎雒瞿雠銎銮鋈錾鍪鏊鎏鐾鑫鱿鲂鲅鲆鲇鲈稣鲋鲎鲐鲑鲒鲔鲕鲚鲛鲞鲟鲠鲡鲢鲣鲥鲦鲧鲨鲩鲫鲭鲮鲰鲱鲲鲳鲴鲵鲶鲷鲺鲻鲼鲽鳄鳅鳆鳇鳊鳋鳌鳍鳎鳏鳐鳓鳔鳕鳗鳘鳙鳜鳝鳟鳢靼鞅鞑鞒鞔鞯鞫鞣鞲鞴骱骰骷鹘骶骺骼髁髀髅髂髋髌髑魅魃魇魉魈魍魑飨餍餮饕饔髟髡髦髯髫髻髭髹鬈鬏鬓鬟鬣麽麾縻麂麇麈麋麒鏖麝麟黛黜黝黠黟黢黩黧黥黪黯鼢鼬鼯鼹鼷鼽鼾齄";

</script>

</head>

<body onload="init()">

<canvas id="c"></canvas><br>

<p>Name:<input value="Fang" size="36" /></p>

<p>Code:<input size="36" readonly="true" /></p>

<p>

<input type="radio" name="codetype" checked="checked" />Site License<br>

<input type="radio" name="codetype" />Register Code N<br>

<input type="radio" name="codetype" />Register Code A

</p>

<p><button onclick="Generate()">Generate</button><button onclick="window.close();">Close</button></p>

<p>

<span class="bg">"HKRWQV2958DWNTQRGNSCFSXAZPYK"</span><br>

<span class="bg">[Provided by Fang3s]</span>

</p>

<table>

<tr><td>Input Here:</td><td><input name="testCode" onchange="codeChange()" value="苏北小麦" size="36" /></td></tr>

<tr><td>charCodeAt:</td><td><input name="testCode" value="" size="36" /></td></tr>

<tr><td>encodeURI:</td><td><input name="testCode" value="" size="36" /></td></tr>

<tr><td>GB2312:</td><td><input name="testCode" value="" size="36" /></td></tr>

</table>

</body>

</html>

    C++

const char *psBlackCodes[] = { "mvg21951736", "mg374604342", "mg370534035", "mg373465241", "mg37NTi", "mg372503958", "mg379843149",

"mg370151347", "mg370353008", "mg372021424", "mg375953248", "mg379223953", "mg373473759", "mg378542544", "mg370473710", "mg37064348",

"mg378822469", "mg374394987", "mg371073478", "mg379773651", "mg371895266", "mg373223554", "mg377583454", "mg37644957", "mg370342692",

"mg376484039", "mg376871434", "mg370704788", "mg377643863", "mg377753931", "mg379342689", "mg374344777" };

const char* pszRandomCharTable = "0123456789abcdefghijklmnopqrstuvwxyz";

const int lengthOfCharTable = lstrlenA(pszRandomCharTable);

const char *pResourceTable = "HKRWQV2958DWNTQRGNSCFSXAZPYK";

inline char randomChar(void){

     - ) + ];

}

bool keygen(const char *pszchName, int keygenType, char *pchCodeBuffer, size_t sizeOfBuffer)

{

    if (NULL == pszchName || !*pszchName)

    {

        return false;

    }

     == keygenType)

    {

        )

        {

            ], *pNameCursor, *pOkNameCursor, *pchCodeCursor;

            int length, indexOfTable, ebp, idx;

            const int lengthOfTable = lstrlenA(pResourceTable);

            pNameCursor = buffer;

            pOkNameCursor = buffer;

            lstrcpynA(buffer, pszchName, _countof(buffer));

            CharUpperA(buffer);

            //在资源表pResourceTable中的名字才合法

            while (*pNameCursor)

            {

                if (strchr(pResourceTable, *pNameCursor))

                {

                    *pOkNameCursor++ = *pNameCursor;

                }

                pNameCursor++;

            }

            *pOkNameCursor = '\0';

            length = lstrlenA(buffer);

            //名字不足24位补齐

            ){

                lstrcpynA(buffer, pResourceTable,  - length);//'\0'算在第三个参数长度

            }

            //buffer全是pResourceTable里的字符, 长度为24

            ebp = ;

            idx = ;

            pchCodeCursor = pchCodeBuffer;

            )

            {

                indexOfTable = strchr(pResourceTable, buffer[idx]) - pResourceTable;

                ebp = (indexOfTable * (indexOfTable + ) + ebp) % lengthOfTable;

                *pchCodeCursor++ = pResourceTable[ebp++];

                ) && idx < )

                    *pchCodeCursor++ = '-';

            }

            *pchCodeCursor = '\0';

        }

        else

            return false;

    }

    else{

        //

         +  +  + ){

            ];

            , ecx = ;

            srand((unsigned ));

            pchCodeBuffer[] = 'm';

            pchCodeBuffer[] = 'g';

            pchCodeBuffer[] = ';

            pchCodeBuffer[] = ';

            pchCodeBuffer[] = randomChar();

            pchCodeBuffer[] = randomChar();

            ){

                pchCodeBuffer[] = 's';

                pchCodeBuffer[] = randomChar();

                pchCodeAppend = pchCodeBuffer+;

            }

            else{

                pchCodeBuffer[] = randomChar();

                pchCodeAppend = pchCodeBuffer + ;

            }

            pNameCursor = const_cast<char *>(pszchName);

            while (*pNameCursor)

            {

                ++ecx;

                esi += ecx * *pNameCursor++;

                )

                    esi -= ;

                )

                    ecx = ;

            }

            _itoa_s(esi, buffer, );

            lstrcpynA(pchCodeAppend, buffer, sizeOfBuffer - (pchCodeBuffer - pchCodeAppend));

        }

        else{

            return false;

        }

    }

    return true;

}

int _tmain(int argc, _TCHAR* argv[])

{

    ], code[] = {};

    while (true){

        printf("Input Name :\t");

        lstrcpynA(name, "苏北小麦", _countof(name));

        scanf_s("%s", name);

        printf("%s\n", name);

        keygen(name, , code, _countof(code));

        printf("Site License :\t\t%s\n", code);

        keygen(name, , code, _countof(code));

        printf("Register Code N :\t%s\n", code);

        keygen(name, , code, _countof(code));

        printf("Register Code A :\t%s\n", code);

    }

    //getchar();

    ;

}

如果dump代码,怎么搞都没搞成,不用ebp的。。

//see ).aspx ).aspx

//#pragma optimize( "y", off ) // 对下面的代码使用 /Oy 优化 Generate frame pointers on the program stack.

int keygen_dump(const char *arg_0, const char *arg_4){

    //框架指针寄存器"ebp"被内联程序集代码修改

    _asm{

        mov ebp, arg_4    //就乱了。。。。

        ], 6Dh

        jnz loc_4341EF

        ], 67h

        jnz loc_4341EF

        ], 33h

        jnz loc_4341EF

        ], 37h

        jnz loc_4341EF

        xor ebx, ebx

    loc_434162 :

        mov edi, psBlackCodes

        mov eax, edi

        ]

        ]

    loc_434170 :

             mov cl, [eax]

             inc eax

             test cl, cl

             jnz short loc_434170

             sub eax, edx

             mov ecx, eax

             mov esi, ebp

             xor eax, eax

             repe cmpsb

             jz short loc_4341E8

             cmp ebx, 80h

             jb short loc_434162

             ], 73h

             jnz short loc_434195

             inc ebp

         loc_434195 :

    ]

        push ecx

        push    ecx

        call codekeygen //----------------------------------

        pop ecx

        pop ecx

        push ecx

        call atol

        mov ebx, arg_0

        mov dl, [ebx]

        xor ecx, ecx

        test dl, dl

        mov edi, ebx

        mov esi, 0BDFh

        jz short loc_4341DA

    loc_4341B4 :

    movsx edx, dl

        inc ecx

        imul edx, ecx

        add esi, edx

        cmp esi, 17BEh

        jle short loc_4341CB

        sub esi, 17BEh

    loc_4341CB:

    cmp ecx, 0Ah

        jle short loc_4341D2

        xor ecx, ecx

    loc_4341D2 :

    ]

        inc edi

        test dl, dl

        jnz short loc_4341B4

    loc_4341DA :

    push esi

    cmp esi, eax

        jnz short loc_4341F3

        pop ebp

        pop ebx

        retn//移除pop esi和pop ebp

    loc_4341E8 :

    pop edi

        xor eax, eax

        pop ebx

        retn //移除pop esi和pop ebp

    loc_4341EF :

    mov ebx, arg_0

    loc_4341F3 :

    push ebp

        push ebx

        call codekeygen //移除两参数

             pop ebp

             pop ebx

             retn//移除pop esi和pop ebp

}

}

//#pragma optimize("", on) // 恢复到编译器 /O 选项指定的优化

    汇编(跃然纸上)

注册时让注册码跃然纸上,这招貌似叫内嵌补丁。

个人觉得算是个费时的活儿,又写汇编,又要了解PE等,知识点散。而且只适用于程序把注册码计算出来和输入的Code直接比较,即Code == Func(Name)???型。避免了写注册机算法等等,如果很复杂这很适合,当然也可以远程调用。

为了便于好看,有大量截图,也是用心写的证明,就想发点有价值的东西,不然不好。

    第一处改写。

主要获取Code窗口句柄HWND和保存,如果是局部变量就好了,但是我没看看它是不是,直接保存到代码区的。

修改前两处

修改前后

    目标代码。

来到我们预定的空隙处,这里也是准备些代码的地方,这里call api暂时是拷贝的,后面修改。

设置访问方式

修改访问后,再执行此条指令,如下图我们看到地址0x0047EA94值变了,共4字节。注意这里是临时修改,要实际修改,还要保存。君子善假于物也。使用论坛工具LordPE。

继续执行到原来PUSH EAX后的指令CALL EBX时,即此处的寄存器状态和之前未修改的图是一致的。这里要说下,原来未修改的截图还未执行PUSH EAX,所以原ESP比这里的大4,截得不好。

    第二处改写

来到注册码已经出来的地方,然后我们想在界面Code编辑框里打印显示出来。

说明下,由于ESP寻找局部变量,所以只要找到ESP+84(十六进制)处看看就可,右下角堆栈窗口就可以看;或者直接点击代码行右键-数据窗口中跟随-内存地址,即可左小角查看。

这条指令大于5字节,直接线程替换为我们的跳转JMP 0047EA9E,剩余的90填充然后F7或F8跟随进去。

当我们获取原来LEA ESI, [LOCAL.24]里的[LOCAL.24]=[ESP + 84]时,堆栈和原来不一样的差了8.*4 = 32. = 20h,从右下角的图也可以看出,当时记录的ESP和此时ESP相差$-20。所以取值时多加了这个差值。

我们走一步,通过赋值给ESI看下这时的值,OllyDbg会提示的。

再看看第一个入参,[Alt+W]打开当前可预见的窗口。

    这里call API有一定讲究。

导入API

首先看它导入了没有,OK。

OllyDbg的查找所有模块中的名称(Ctrl+N)

call地址计算

目标进程右键-载入PE编辑器-目录-输入表一行左边省略号按钮上面ListView点选USER32.dll-下面输入SetWindowTextA搜索自动定位。

注意未勾选总是查看FisrtThunk时值时,ThunkRVA按照函数列表计算的值是不一样的。

未勾选时,第一个函数SystemParametersInfoA的ThunkRVA是0008BCC8和USER32.dll的OrigianlFirstThunk一样的,以后相差+4。

勾选后,地址为0007F30C,记下它,后面会眼熟的。

我们来拿个现成例子看看地址间关系。

回到OllyDbg,在程序模块movgear.exe,右键查找-所有模块间调用

搜索System看到

点击进入

我们看看SystemParametersInfoA的调用方式不是CALL xx,而是CALL DWORD PTR DS:[xx],即call机器码不一样。

再看看地址关系,可以看出CALL DWORD PTR DS:[xx]的xx是0047F30C,后4位是不是很眼熟。是的,和前面看到的ThunkRVA = 0047F30C,是一致的,只是多了个400000,其实40万(十六进制)就是我们在前面一起看到的,基本PE头信息里的镜像基址(BaseImage)400000。

接下来看我们的SetWindowTextA,以此类推,调用写法,400000 + 0007F448 = 0047F448 ,48F44700,CALL DWORD PTR DS:[ 0047F448],OllyDbg自动解析为对应符号。

    修改的代码

CPU Disasm
地址        十六进制数据            指令                                       注释
     /E9 68A50400   JMP 0047EA9E

CPU Disasm
地址        十六进制数据            指令                                       注释
00433F60     /E9 39AB0400   JMP 0047EA9E

CPU Disasm
地址        十六进制数据            指令                                       注释
            DB                                     ; 原来.text区是不可写,这也证明了足够
            DB                                     ; 安全性,而且原是0映射后还是0,
            DB                                     ; 不用搞检测看这段是否可能被修改。
            DB                                     ; 一般程序也不会调用API来改吧,又没壳。
            DB
            DB
            DB
            PUSHAD                                   ; /Arg1_4, >>保存8大寄存器状态,也可仅push使用的
   CALL 0047EAA4                            ; \movgear.0047EAA4, 随意搞吧,不管你怎么使用寄存器,只要栈操作平衡。
            POP ECX                                  ; 获取EIP,即ECX = EIP = 0047EAA4
]            ; 这里把.text区地址0047EA94上DWORD大小给了EDX
0047EAA8  |.  85D2          TEST EDX,EDX
          JNZ SHORT 0047EABE
 F0       ],EAX
            POPAD                                    ; <<恢复8大寄存器状态
0047EAB0  |.  FFD3          CALL EBX                                 ; >>恢复原指令的调用流程
]                       ; <<恢复原指令的调用流程
0047EAB9  |.^ E9 7C5AFBFF   JMP 0043453A                             ; 回去并执行接下来的指令
 ],
]                       ; 这里使用ESP的局部变量要注意。
            PUSH ESI                                 ; /Text
            PUSH EDX                                 ; |hWnd
0047EACE  |.  FF15 48F44700 CALL DWORD PTR DS:[<&USER32.SetWindowTex ; \USER32.SetWindowTextA, call xx 需要计算xx = ImageBase + ThunkRVAOfAPI
            POPAD                                    ; <<恢复8大寄存器状态
 ]                       ; >><<恢复原指令的调用流程
0047EADC  \.^ E9 8654FBFF   JMP 00433F67                             ; 回去并执行接下来的指令
0047EAE1      E8 6B25EB74   CALL SetWindowTextA                        ;直接修改为CALL SetWindowTextA,错,仅临时偏移对
 

    最后看下效果图:

在弹窗前注册码已经写入了Code编辑框内了。。。

    总结

LoadPE使用,熟练OllyDbg,Call API

    附件

CPU Disasm
地址        十六进制数据            指令                                       注释
00434531     /E9 68A50400   JMP0047EA9E
 
CPU Disasm
地址        十六进制数据            指令                                       注释
00433F60     /E9 39AB0400   JMP0047EA9E
CPU Disasm
地址        十六进制数据            指令                                       注释
0047EA97      00            DB 00                                    ; 原来.text区是不可写,这也证明了足够
0047EA98      00            DB 00                                    ; 安全性,而且原是0映射后还是0,
0047EA99      00            DB 00                                    ; 不用搞检测看这段是否可能被修改。
0047EA9A      00            DB 00                                    ; 一般程序也不会调用API来改吧,又没壳。
0047EA9B      00            DB 00
0047EA9C      00            DB 00
0047EA9D      00            DB 00
0047EA9E  />  60            PUSHAD                                   ; /Arg1_4, >>保存8大寄存器状态,也可仅push使用的
0047EA9F  |.  E8 00000000   CALL0047EAA4                            ; \movgear.0047EAA4, 随意搞吧,不管你怎么使用寄存器,只要栈操作平衡。
0047EAA4  |$  59            POP ECX                                  ; 获取EIP,即ECX = EIP = 0047EAA4
0047EAA5  |.  8B51 F0       MOV EDX,DWORD PTR DS:[ECX-10]            ; 这里把.text区地址0047EA94上DWORD大小给了EDX
0047EAA8  |.  85D2          TEST EDX,EDX
0047EAAA  |.  7512         JNZ SHORT 0047EABE
0047EAAC  |.  8941 F0       MOV DWORD PTR DS:[ECX-10],EAX
0047EAAF  |.  61            POPAD                                    ; <<恢复8大寄存器状态
0047EAB0  |.  FFD3          CALL EBX                                 ; >>恢复原指令的调用流程
0047EAB2  |.  8D8CE4 C40000 LEA ECX,[LOCAL.24]                       ; <<恢复原指令的调用流程
0047EAB9  |.^ E9 7C5AFBFF   JMP0043453A                             ; 回去并执行接下来的指令
0047EABE  |>  C741 F0 00000MOV DWORD PTR DS:[ECX-10],0
0047EAC5  |.  8DB4E4 A40000 LEA ESI,[LOCAL.24]                       ; 这里使用ESP的局部变量要注意。
0047EACC  |.  56            PUSH ESI                                 ; /Text
0047EACD  |.  52            PUSH EDX                                 ; |hWnd
0047EACE  |.  FF15 48F44700 CALL DWORD PTR DS:[<&USER32.SetWindowTex ; \USER32.SetWindowTextA, call xx 需要计算xx = ImageBase + ThunkRVAOfAPI
0047EAD4  |.  61            POPAD                                    ; <<恢复8大寄存器状态
0047EAD5  |.  8DB4E4 840000LEA ESI,[LOCAL.24]                       ; >><<恢复原指令的调用流程
0047EADC  \.^ E9 8654FBFF   JMP00433F67                             ; 回去并执行接下来的指令
0047EAE1      E8 6B25EB74   CALL SetWindowTextA                        ;直接修改为CALL SetWindowTextA,错,仅临时偏移对

    教训特别修改(已测)

没有测试打开验证,由于只走验证,代码区本来想保存HWND一直为0,走了保存窗口句柄的,导致CALL失败。需要拆分为两个独立的过程比较好,如下,修改第二个验证跳转和内嵌代码。丑大了,没有思考过只走验证和没有再次打开测试。。。

地址 十六进制数据 指令 注释

00433F60 E9 59AB0400 JMP 0047EABE

CPU Disasm

地址 十六进制数据 指令 注释

 PUSHAD

 CALL 0047EAA4

 POP ECX ; movgear_crack.0047EAA4(推测 Arg1,Arg2,Arg3,Arg4)

]

0047EAA8 85D2 TEST EDX,EDX

  JNZ SHORT 0047EAAF

 F0 ],EAX

 POPAD

0047EAB0 FFD3 CALL EBX

0047EAB2 8D8CE4 C40000 LEA ECX,[ESP+0C4]

0047EAB9 ^ E9 7C5AFBFF JMP 0043453A

 PUSHAD

 CALL 0047EAC4

 POP ECX

]

0047EAC8 85D2 TEST EDX,EDX

  JE SHORT 0047EAE2

 ],

0047EAD3 8DB4E4 A40000 LEA ESI,[ESP+0A4]

 PUSH ESI

 PUSH EDX

0047EADC FF15 48F44700 CALL DWORD PTR DS:[<&USER32.SetWindowTex

 POPAD

 ]

0047EAEA ^ E9 7854FBFF JMP 00433F67

0047EAEF E8 5D25EB74 CALL SetWindowTextA

插件编写比较方便

<0047EA9E>

@L00000001:

PUSHAD

CALL @L00000002

@L00000002:

POP ECX

]

TEST EDX,EDX

JNE SHORT @L00000003

],EAX

@L00000003:

POPAD

CALL EBX

LEA ECX,[ESP+0C4]

JMP 0043453A

PUSHAD

CALL @L00000004

@L00000004:

POP ECX

]

TEST EDX,EDX

JE SHORT @L00000005

],

LEA ESI,[ESP+0A4]

PUSH ESI

PUSH EDX

CALL DWORD PTR DS:[47F448]

@L00000005:

POPAD

]

JMP 00433F67

GIF Movie Gear逆向实战+注册代码+补丁的相关教程结束。

《GIF Movie Gear逆向实战+注册代码+补丁.doc》

下载本文的Word格式文档,以方便收藏与打印。