winamp V2.02 
                   程式猎人
简介:这个软件不用多说了,大家一定对它很熟悉了。
追踪:name:dahuilang
      RN:01234567
  以前追踪过这个程序,当时追踪的版本已经忘记了,但是那时记得追踪它很简单就将它追
踪出来了,因为只要设bpx hmemcpy后拦下后跳跃到程序中就可以了,没有想到这个版本的
程序无法跳跃到正常程序中,那么如何追踪这个程序呢?
  先使用反汇编软件W32对它进行反汇编吧。
:0041C11C 50                      push eax
:0041C11D 52                      push edx

* Possible StringData Ref from Data Obj ->"RegisteredTo"
                                  |
:0041C11E 683C504300              push 0043503C
:0041C123 FF35A43F4400            push dword ptr [00443FA4]

* Reference To: KERNEL32.GetPrivateProfileStringA, Ord:0111h
                                  |
:0041C129 FF1578754400            Call dword ptr [00447578]
:0041C12F 389D00FDFFFF            cmp byte ptr [ebp+FFFFFD00], bl
:0041C135 7467                    je 0041C19E

* Possible StringData Ref from Data Obj ->"!!!"
                                  |
:0041C137 6838504300              push 00435038
:0041C13C 8D8500FDFFFF            lea eaxdword ptr [ebp+FFFFFD00]
:0041C142 50                      push eax
:0041C143 E888AC0000              call 00426DD0
:0041C148 83C408                  add esp, 00000008
:0041C14B 85C0                    test eaxeax
:0041C14D 744F                    je 0041C19E
:0041C14F C745FCFFFFFFFF          mov [ebp-04], FFFFFFFF
:0041C156 8D4DFC                  lea ecxdword ptr [ebp-04]
:0041C159 8818                    mov byte ptr [eax], bl
:0041C15B 51                      push ecx
:0041C15C 83C003                  add eax, 00000003

* Possible StringData Ref from Data Obj ->"%d"
                                  |
:0041C15F 68C0234300              push 004323C0
:0041C164 50                      push eax
:0041C165 E8A6AD0000              call 00426F10
:0041C16A 83C40C                  add esp, 0000000C
:0041C16D 8D8D00FDFFFF            lea ecxdword ptr [ebp+FFFFFD00]
:0041C173 51                      push ecx
:0041C174 E83E670000              call 004228B7
:0041C179 83C404                  add esp, 00000004
:0041C17C 3945FC                  cmp dword ptr [ebp-04], eax
:0041C17F 751D                    jne 0041C19E
:0041C181 50                      push eax
:0041C182 8D8D00FDFFFF            lea ecxdword ptr [ebp+FFFFFD00]
:0041C188 51                      push ecx
:0041C189 8D9500F9FFFF            lea edxdword ptr [ebp+FFFFF900]

* Possible StringData Ref from Data Obj ->"----- 授 权 给 :   %s (%d) -----"
                                  |
:0041C18F 68D8514300              push 004351D8
:0041C194 52                      push edx

* Reference To: USER32.wsprintfA, Ord:0262h
                                  |
:0041C195 FF1554774400            Call dword ptr [00447754]
:0041C19B 83C410                  add esp, 00000010

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0041C135(C), :0041C14D(C), :0041C17F(C)
|
:0041C19E 80BD00F9FFFF00          cmp byte ptr [ebp+FFFFF900], 00
:0041C1A5 7515                    jne 0041C1BC
   我首先看到了这个字符串,"----- 授 权 给 :   %s (%d) -----",在它上面有一个比
较的地方,那么程序一定是比较注册码或注册旗标吧,GetPrivateProfileStringA大家看到
这个函数了吧,那么这个函数是调用ini文件的(通常是这样的),现在使用filemon来查看
一下程序调用了什么ini文件呢?
  查看后发现程序调用了在winamp.exe同目录下的winamp.ini文件,这里的内容如下:
[Winamp]
……
RegisteredTo=
  分析后可知,程序是这样将注册码和名字放在一起的,为name!!!RN。这个格式,因为可
以从上面看到程序使用了!!!。好了,现在是设在
RegisteredTo=dahuilang!!!01234567,然后在下面
:0041C17C 3945FC                  cmp dword ptr [ebp-04], eax
设断了,下bpx 0041C17C 后运行程序,结果发现在[ebp-04]=0012d687,而eax=4E0C8C6,
这样就可以得到注册码了。
  RN=4E0C8C6=81840326
  这个就是dahuilang的注册码了。OK,这个版本的注册码破解就算结束了。

 
Winamp 2.04
启动winamp.exe
1. 把开关于”wiamp”,选Shareware.
2. 按 Enter Registration Info
3. Name: Peter Reg#:78787878
4. Ctrl+N
5. bpx getdlgitemtexta
6. 按 x 返回 再输入一个数学(我用”9”)
7. 又被拦阻,到一个”User32!Getdlgitemtexta
8. F10,22次
9. 你会看见 0167:0041EF81 PUSH EAX
10. 我用 d eax 一看有 Peter我字眼,我就定比较地方一定在不远的地方。
11. 本人汇编不好,只是知道Push eax。大概是输入字符到eax中。要输入字符不
就是要用的名字,d了一下果然是。
12. 再往下看:
0167:0041EF82  CALL  0042218 (也许是比比较的地方)
0167:0041EF87  ADD   ESP,BYTE+04
0167:0041EF8A CMP EAX,ESI
0167:0041EF8C JNZ 0041EF97
13. 想一下刚才我破解winamp skin maker v1.2时,不是Sun Bird翻译了v1.05资料中的
14. ”CMP EAX,ESI” 不是用d而用?
15. 试一试:
16. ? EAX
17. DEC=67972642(会不会是注册码?)
18. HEX=40d2e22
19. ? EDI
20. DEC=787878789(不是我刚才用的假码?)
21. HEX=2ef61385
22. CMP EAX,ESI(不就是两个记存器比较?要比较就一定要有注册码吗?)
23. 好试一下,果然是。Yeah!
24. 我再试一下进入0167:0041EF82  CALL  0042218 (也许是比比较的地方)
25. 可能本人技术不行,只能白作工。
这才是本人自己破解的第一个软件,多谢我的师傅和Sun Bird大哥帮助!
我是用手打的,0167:0041EF82  CALL  0042218
                 ……….
                  0167:0041EF8C JNZ 0041EF97
用trw2000 or soft-ice,能不能copy出来和抓图?
说明一下这里的破解过程以后出现Peter也就是我本人PeterChen!当然这篇也
不列外?

WinAmp V2.11的注册机制分析(一)(初学者必读) 
    转载本文请注明出处,并保持文章的完整性。本文不得用于任何商业场合,仅供学习和参考。 
作者: Fpc (感谢直接和间接提供帮助的所有朋友) 
目的: 分析注册机制 
工具: SI 4.05, Wdasm 8.93, Hedit 2.0 

软件名称:WinAmp Ver 2.11 
作    者: Nullsoft,Inc.      Apr 13,1999 
文件大小:612KB 
编译器  :VC++ 6.0 
授权方式:共享软件 
使用平台:Win95/98 
软件简介:著名的MP3播放器 

软件来源:不清楚 
下载地址:请到各大专的下载网站自己查找。 


    首先引用 WinAmp (WA) 关于中的一段:“Winamp is shareware, and may be previewed for 14 days. Continued use of Winamp after 14 days requires that you register it. winamp will neither cease functioning nor warn you of the end of the 14 day trial period. It is your responsibility to register.”。说的很明白,也是说到做到。共享软件作成这样,都不忍心去CRAK,它也的确没有任何加密、干扰手段,真是不知该说些什么。所以本文仅限于CRAK教学之用。 
    这个程序我看了三天(“当兵的,你不看我了”,“我都看了三天了”),其中有二天是在跟踪。程序写的很规范,也没有加壳,所以需要的只是耐心。现在让我给各位分析一下*COUGH* 


    1、 在WA菜单中选择“Nullsoft Winamp....”,显示“About”对话框,选“Shareware”->“Enter Registration Info”进入注册页面。 
    2、 输入: Name = Fpc ,Reg# = 123456 。“OK”竟未被激活,应该是每输入一次就作一次判断。 
    3、 删除Reg#中的‘6’,^D到SI中,下 bpx hmemcpy(万能中断,也是我最常用的); 
    4、 F5回来,在Reg#后加‘6’,立刻中断到SI中,下 BD *阻断,按F12 N次,发现始终在USER中,最后直接就返回到WA中,有点奇怪; 
    5、 还是删除‘6’,^D到SI中,下 be hmemcpy 激活中断; 
    6、 再F5回来,仍输入‘6’,立刻中断到SI中。这次按F5,一次,二次,三次,返回到WA中。猜想第一次不知做什么,第二次取 RegisterName(Rn),第三次是取InputedRegisterCode(Irc),OK; 
    7、 重复上面5、6两步,不过这次在SI中按一次F5,N次F12,正确的回到WA领空,地址是 00401F28,向下看 @00401F2E是一个外部的 CALL调用(其实是GetDlgItemInt),是取 Irc的。再向下是一个 CallCmpJmp的程序段,这个 CALL 4252D1就是计算注册码的核心。要问我是怎么知道的,就是:静态分析+动态分析+尝试+耐心。 


    上面简要介绍了 SI动态拦截方式,若用 WDASM静态分析需要查找“Licensed to”字符串,它不在 String资源中 :-( ,而是在 DATA中找到。分析的角度不同,得到的结果是类似的,我们当然要多了解和尝试。这个串会在 @00401DA5 处找到,再向上还是对关键 Call 4252D1的调用。根据这一调用返回的注册成功与否,程序用 wsprintfA打印不同的字串:“LICENSED TO:%s(%d)”或“UNREGISTERED SHAREWARE ......”,最后显示在About对话框中。整个这一段代码是在选择菜单的第一项时执行,向上翻页,记下的它的入口地址:401CCE。 
    关闭WA,打开SI的 Symbol Loader,调入WA,然后 Load,这时在SI设断:Bpx 401CCE。^D执行 WA。注意SI不会被激活,除非你选择了菜单的第一项,下面借助“程式”作分析,希望大家耐心看下去。 


;程序段(1),在显示“About”时执行 

* Referenced by a CALL at Addresses: 
|:00401B9B  , :00401CB1  

:00401CCE 55                      push ebp 
:00401CCF 8BEC                    mov ebpesp 
:00401CD1 81EC00060000            sub esp, 00000600 
:00401CD7 A050914400              mov albyte ptr [00449150]        <== 0->al 
:00401CDC 53                      push ebx 
:00401CDD 56                      push esi 
:00401CDE 57                      push edi 
:00401CDF 888500FAFFFF            mov byte ptr [ebp+FFFFFA00], al        <== Ebp-600=6DC6F8-600 
:00401CE5 B9FF000000              mov ecx, 000000FF 
:00401CEA 33C0                    xor eaxeax 
:00401CEC 8DBD01FAFFFF            lea edidword ptr [ebp+FFFFFA01]    <== 准备将内存清0 
:00401CF2 F3                      repz 
:00401CF3 AB                      stosd 
:00401CF4 66AB                    stosw 

* Reference To: KERNEL32.GetPrivateProfileStringA, Ord:013Ah 
                                  | 
:00401CF6 8B3534E14300            mov esidword ptr [0043E134]        <== 准备功能调用 

* Possible StringData Ref from Data Obj ->"winamp.ini"            <== 文件名 
                                  | 
:00401CFC 687C214400              push 0044217C 
:00401D01 AA                      stosb                        <== 到此将Ebp-600到Ebp-200清为0 
:00401D02 8D8500FEFFFF            lea eaxdword ptr [ebp+FFFFFE00]    <== 缓冲区1 首址(句柄?) 
:00401D08 6800020000              push 00000200                    <== 缓冲区长度为200 
:00401D0D BB50914400              mov ebx, 00449150 
:00401D12 50                      push eax 

* Possible StringData Ref from Data Obj ->"RegisteredTo" 
                                  | 
:00401D13 BF6C214400              mov edi, 0044216C            <== 读内容 
:00401D18 53                      push ebx 
:00401D19 57                      push edi 

* Possible StringData Ref from Data Obj ->"WinampRegInfo" 
                                  | 
:00401D1A 685C214400              push 0044215C                <== 小节名 
:00401D1F FFD6                    call esi 

    这个Call将注册信息(RI)读到 Ebp-200处,后面以0补足至 Ebp。当然,WA没有注册时,RI是不存在的,自己输入的方式是: 
    在WIN9X系统目录下,找“winamp.ini”文件并打开(什么,没有?不会自己生成一个!),添加[WinampRegInfo]小节,输入RI。我的“winamp.ini”相关内容如下: 

[WinampRegInfo] 
RegisteredTo=Fpc!!!123456 

注意RI中,Fpc是Rn,123456是Irc,中间的“!!!”是必须的,在下面的分析中你会找到原因。 


:00401D21 80BD00FEFFFF00          cmp byte ptr [ebp+FFFFFE00], 00    <== 检查RI是否为空 
:00401D28 7524                    jne 00401D4E                <== 正确则向下跳 
:00401D2A 68A0794500              push 004579A0 
:00401D2F 8D8500FEFFFF            lea eaxdword ptr [ebp+FFFFFE00] 
:00401D35 6800020000              push 00000200 
:00401D3A 50                      push eax 
:00401D3B 53                      push ebx 
:00401D3C 57                      push edi 
:00401D3D FF35E0594500            push dword ptr [004559E0] 
:00401D43 FFD6                    call esi                <== 不用关心是在读什么 
:00401D45 80BD00FEFFFF00          cmp byte ptr [ebp+FFFFFE00], 00 
:00401D4C 7466                    je 00401DB4                <== 这里千万不能去 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00401D28(C) 

:00401D4E 8D8500FEFFFF            lea eaxdword ptr [ebp+FFFFFE00]<== 缓冲区1 首址 

* Possible StringData Ref from Data Obj ->"!!!" 
                                  | 
:00401D54 6858214400              push 00442158                <== 准备检查RI中是否含有"!!!" 
:00401D59 50                      push eax 
:00401D5A E8F1330300              call 00435150                <== 这个Call有意思,错误则eax=0,正确则eax指向RI的!!!123456,我这里返回值是6DC4FB 
:00401D5F 59                      pop ecx                    <== 对这个Call的分析见(二) 
:00401D60 85C0                    test eaxeax 
:00401D62 59                      pop ecx 
:00401D63 744F                    je 00401DB4                <== Eax=0就去死 
:00401D65 802000                  and byte ptr [eax], 00        <== 使得Rn以'\0'结束 
:00401D68 33F6                    xor esiesi 
:00401D6A 83C003                  add eax, 00000003            <== Eax指向Irc:123456 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00401D84(U) 

:00401D6D 8A08                    mov clbyte ptr [eax]        <== 取一个字符 
:00401D6F 80F930                  cmp cl, 30                <== 数字为有效字符,非数字表示完成 
:00401D72 7C12                    jl 00401D86 
:00401D74 80F939                  cmp cl, 39 
:00401D77 7F0D                    jg 00401D86 
:00401D79 0FBEC9                  movsx ecxcl                <== Ecx中无用位清0 
:00401D7C 8D14B6                  lea edxdword ptr [esi+4*esi]    <= Edx=5*Esi 
:00401D7F 40                      inc eax                    <== Edx的初始值为0,这三条指令将字符串变为数字 
:00401D80 8D7451D0                lea esidword ptr [ecx+2*edx-30]    <= 很有意思 
:00401D84 EBE7                    jmp 00401D6D 


  这一段以C来表示: 

  char Irc[6]="123456"        /* 当然注册码不止6位    */ 
  long Temp=0; 
  int i; 

  for( i=0; i<6; i++) 
  { 
      if( !isdigit( Irc[i] ) ) 
        break; 
    Temp*=10; 
    Temp+=Irc[i]-'0'; 
  } 


* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00401D72(C), :00401D77(C) 

:00401D86 8D8500FEFFFF            lea eaxdword ptr [ebp+FFFFFE00]<== Eax指向Rn 
:00401D8C 50                      push eax 
:00401D8D E83F350200              call 004252D1                <== !! 关键Call,由Rn计算得出Rc,保存在Eax。具体分析请看(三) 
:00401D92 3BC6                    cmp eaxesi                <== 比较Rc与Irc 
:00401D94 59                      pop ecx 
:00401D95 751D                    jne 00401DB4                <== 不相等则GAME OVER,大家将此处NOP掉,看会发生什么有趣的事情 
:00401D97 50                      push eax 
:00401D98 8D8500FEFFFF            lea eaxdword ptr [ebp+FFFFFE00] 
:00401D9E 50                      push eax 
:00401D9F 8D8500FAFFFF            lea eaxdword ptr [ebp+FFFFFA00] 

* Possible StringData Ref from Data Obj ->"----- LICENSED TO: %s (%d) -----" 
                                  | 
:00401DA5 6834214400              push 00442134 
:00401DAA 50                      push eax 

* Reference To: USER32.wsprintfA, Ord:02ACh 
                                  | 
:00401DAB FF1568E34300            Call dword ptr [0043E368]        <== 打印授权信息 
:00401DB1 83C410                  add esp, 00000010 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00401D4C(C), :00401D63(C), :00401D95(C) 

:00401DB4 80BD00FAFFFF00          cmp byte ptr [ebp+FFFFFA00], 00 
:00401DBB 5F                      pop edi 
:00401DBC 5E                      pop esi 
:00401DBD 5B                      pop ebx 
:00401DBE 751C                    jne 00401DDC 
:00401DC0 6A00                    push 00000000 
:00401DC2 6A00                    push 00000000 

* Possible Reference to String Resource ID=00018: "UNREGISTERED SHAREWARE VERSION - PLEASE REGISTER" 
                                  | 
:00401DC4 6A12                    push 00000012 
:00401DC6 E8C5A10200              call 0042BF90 
:00401DCB 50                      push eax 
:00401DCC 8D8500FAFFFF            lea eaxdword ptr [ebp+FFFFFA00] 
:00401DD2 50                      push eax 

* Reference To: USER32.wsprintfA, Ord:02ACh 
                                  | 
:00401DD3 FF1568E34300            Call dword ptr [0043E368]        <== 打印未授权信息 
:00401DD9 83C414                  add esp, 00000014            <== 向下很长一段与分析无关 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00401DBE(C) 

:00401DDC 8D8500FAFFFF            lea eaxdword ptr [ebp+FFFFFA00] 
:00401DE2 50                      push eax 

* Possible Reference to Dialog: DialogID_009C, CONTROL_ID:0483, "License" 
                                  | 
:00401DE3 6883040000              push 00000483 
:00401DE8 FF7508                  push [ebp+08] 

* Reference To: USER32.SetDlgItemTextA, Ord:022Ch 
                                  | 
:00401DEB FF1534E34300            Call dword ptr [0043E334] 
:00401DF1 C9                      leave 
:00401DF2 C3                      ret 

......... 


* Possible StringData Ref from Data Obj ->"!!!" 
                                  | 
:00401EAC 6858214400              push 00442158 
:00401EB1 50                      push eax 
:00401EB2 E829330300              call 004351E0 
:00401EB7 59                      pop ecx 
:00401EB8 8D8580FBFFFF            lea eaxdword ptr [ebp+FFFFFB80] 
:00401EBE 59                      pop ecx 
:00401EBF 57                      push edi 
:00401EC0 50                      push eax 
:00401EC1 E8FA330300              call 004352C0 
:00401EC6 59                      pop ecx 
:00401EC7 8D840580FBFFFF          lea eaxdword ptr [ebp+eax-00000480] 
:00401ECE 50                      push eax 
:00401ECF 53                      push ebx 
:00401ED0 FF7508                  push [ebp+08] 
:00401ED3 FFD6                    call esi 
:00401ED5 8D8580FBFFFF            lea eaxdword ptr [ebp+FFFFFB80] 

* Possible StringData Ref from Data Obj ->"winamp.ini" 
                                  | 
:00401EDB 687C214400              push 0044217C 
:00401EE0 50                      push eax 

* Possible StringData Ref from Data Obj ->"RegisteredTo" 
                                  | 
:00401EE1 686C214400              push 0044216C 

* Possible StringData Ref from Data Obj ->"WinampRegInfo" 
                                  | 
:00401EE6 685C214400              push 0044215C 

* Reference To: KERNEL32.WritePrivateProfileStringA, Ord:02E5h 
                                  | 
:00401EEB FF1530E14300            Call dword ptr [0043E130]            <== 这一段会在点击“OK”时执行,向ini文件写RI 

* Possible Reference to String Resource ID=00001: "You must first exit Winamp before uninstalling." 
                                  | 
:00401EF1 6A01                    push 00000001 
:00401EF3 FF7508                  push [ebp+08] 

* Reference To: USER32.EndDialog, Ord:00B9h 
                                  | 
:00401EF6 FF151CE44300            Call dword ptr [0043E41C] 
:00401EFC 8B7D10                  mov edidword ptr [ebp+10] 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00401E6C(C) 

* Possible Reference to Dialog: DialogID_00BF, CONTROL_ID:048B, "" 
                                  | 
:00401EFF B88B040000              mov eax, 0000048B 
:00401F04 663BF8                  cmp diax 
:00401F07 7405                    je 00401F0E 
:00401F09 663BFB                  cmp dibx 
:00401F0C 7552                    jne 00401F60 

对关键 Call 004252D1的分析请见(三) 
WinAmp V2.11的注册机制分析(二)(初学者必读) 
    转载本文请注明出处,并保持文章的完整性。本文不得用于任何商业场合,仅供学习和参考。 
作者: Fpc (感谢直接和间接提供帮助的所有朋友) 
目的: 分析注册机制 
工具: SI 4.05, Wdasm 8.93, Hedit 2.0 


    程序段(2),输入注册信息的每次输入时执行:根据Rn计算Rc,若Irc=Rc则激活“OK”表示可以将RI写入“winamp.ini”文件中 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00401F07(C) 

:00401F0E C1EF10                  shr edi, 10 
:00401F11 6681FF0003              cmp di, 0300 
:00401F16 7548                    jne 00401F60 
:00401F18 8B7D08                  mov edidword ptr [ebp+08] 
:00401F1B 8D4D80                  lea ecxdword ptr [ebp-80] 
:00401F1E 6880000000              push 00000080 
:00401F23 51                      push ecx 
:00401F24 50                      push eax 
:00401F25 57                      push edi 
:00401F26 FFD6                    call esi                <== 读Name文本框,将取得的Rn保存在 Ebp-80处 
:00401F28 6A00                    push 00000000 
:00401F2A 6A00                    push 00000000 
:00401F2C 53                      push ebx 
:00401F2D 57                      push edi 

* Reference To: USER32.GetDlgItemInt, Ord:0103h 
                                  | 
:00401F2E FF152CE34300            Call dword ptr [0043E32C]        <== 读Reg#文本框,返回值在 Eax中 
:00401F34 8BF0                    mov esieax 
:00401F36 8D4580                  lea eaxdword ptr [ebp-80] 
:00401F39 50                      push eax 
:00401F3A E892330200              call 004252D1                <== !! 关键Call,由Rn计算得出Rc,保存在Eax。具体分析请看(三) 
:00401F3F 3BC6                    cmp eaxesi                <== 比较Rc与Irc 
:00401F41 59                      pop ecx 
:00401F42 750A                    jne 00401F4E 
:00401F44 807D8000                cmp byte ptr [ebp-80], 00 
:00401F48 7404                    je 00401F4E 

* Possible Reference to String Resource ID=00001: "You must first exit Winamp before uninstalling." 
                                  | 
:00401F4A 6A01                    push 00000001                <== “OK”为Enable 
:00401F4C EB02                    jmp 00401F50 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00401F42(C), :00401F48(C) 

:00401F4E 6A00                    push 00000000                <== “OK”为Disable 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00401F4C(U) 

* Possible Reference to String Resource ID=00001: "You must first exit Winamp before uninstalling." 
                                  | 
:00401F50 6A01                    push 00000001 
:00401F52 57                      push edi 

* Reference To: USER32.GetDlgItem, Ord:0102h 
                                  | 
:00401F53 FF1574E34300            Call dword ptr [0043E374] 
:00401F59 50                      push eax 

* Reference To: USER32.EnableWindow, Ord:00B7h 
                                  | 
:00401F5A FF1530E34300            Call dword ptr [0043E330]        <== 修改按钮状态 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00401E43(C), :00401F0C(C), :00401F16(C) 

:00401F60 33C0                    xor eaxeax 
:00401F62 5B                      pop ebx 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00401E36(U) 

:00401F63 5F                      pop edi 
:00401F64 5E                      pop esi 
:00401F65 C9                      leave 
:00401F66 C21000                  ret 0010 


    Call 435150 比较在RI中是否含有"!!!" 

入口:Ecx指向"!!!"+'\0' 
出口:错误则eax=0,正确则eax指向RI的!!!123456, 

* Referenced by a CALL at Addresses: 
|    有N处调用,我用了 Echo y|Format C:/u 

:00435150 8B4C2408                mov ecxdword ptr [esp+08]    <== Ecx=442158,指向"!!!"+'\0' 
:00435154 57                      push edi 
:00435155 53                      push ebx 
:00435156 56                      push esi 
:00435157 8A11                    mov dlbyte ptr [ecx]        <== Dl取得第一个'!' 
:00435159 8B7C2410                mov edidword ptr [esp+10]    <== Edi=Ebp-200=6DC4F8,即RI首址 
:0043515D 84D2                    test dldl 
:0043515F 7469                    je 004351CA                <== Dl=0证明比较完成,跳下去准备返回(怎么可能?!) 
:00435161 8A7101                  mov dhbyte ptr [ecx+01]        <== 第二个'!'到Dh 
:00435164 84F6                    test dhdh 
:00435166 744F                    je 004351B7 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:004351A2(C), :004351B5(U) 

:00435168 8BF7                    mov esiedi 
:0043516A 8B4C2414                mov ecxdword ptr [esp+14]    <== Ecx=442158,指向"!!!"+'\0' 
:0043516E 8A07                    mov albyte ptr [edi
:00435170 46                      inc esi 
:00435171 38D0                    cmp aldl                <== 看Al是否为'!' 
:00435173 7415                    je 0043518A 
:00435175 84C0                    test alal 
:00435177 740B                    je 00435184                <== Al为空则失败 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00435182(C) 

:00435179 8A06                    mov albyte ptr [esi
:0043517B 46                      inc esi 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:0043518F(C) 

:0043517C 38D0                    cmp aldl 
:0043517E 740A                    je 0043518A                <== 向下跳检查RI中是否含三个'!' 
:00435180 84C0                    test alal 
:00435182 75F5                    jne 00435179                <== 直到Al取到'!';若不跳则说明在遇到"!!!"之前,RI已经结束(RI中不含!!!),失败 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00435177(C) 

:00435184 5E                      pop esi 
:00435185 5B                      pop ebx 
:00435186 5F                      pop edi 
:00435187 33C0                    xor eaxeax 
:00435189 C3                      ret 


* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00435173(C), :0043517E(C) 

:0043518A 8A06                    mov albyte ptr [esi]        <== 从RI中!之后再读一字节 
:0043518C 46                      inc esi 
:0043518D 38F0                    cmp aldh 
:0043518F 75EB                    jne 0043517C                <== 若不等, 则在Rn中含'!' 
:00435191 8D7EFF                  lea edidword ptr [esi-01] 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:004351B3(C) 

:00435194 8A6102                  mov ahbyte ptr [ecx+02] 
:00435197 84E4                    test ahah 
:00435199 7428                    je 004351C3 
:0043519B 8A06                    mov albyte ptr [esi]        <== 从Rn中取第三个'!' 
:0043519D 83C602                  add esi, 00000002 
:004351A0 38E0                    cmp alah 
:004351A2 75C4                    jne 00435168 
:004351A4 8A4103                  mov albyte ptr [ecx+03]        <== Al应取到0 
:004351A7 84C0                    test alal 
:004351A9 7418                    je 004351C3                <== Al为空表示正常结束 
:004351AB 8A66FF                  mov ahbyte ptr [esi-01] 
:004351AE 83C102                  add ecx, 00000002            <== 若正确,这里不会被执行 
:004351B1 38E0                    cmp alah 
:004351B3 74DF                    je 00435194 
:004351B5 EBB1                    jmp 00435168 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00435166(C) 

:004351B7 33C0                    xor eaxeax                <== 跳到这里则RI形式错误 
:004351B9 5E                      pop esi 
:004351BA 5B                      pop ebx 
:004351BB 5F                      pop edi 
:004351BC 8AC2                    mov aldl 
:004351BE E933210000              jmp 004372F6 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00435199(C), :004351A9(C) 

:004351C3 8D47FF                  lea eaxdword ptr [edi-01]    <== 正确的出口,我是这里返回的 
:004351C6 5E                      pop esi 
:004351C7 5B                      pop ebx 
:004351C8 5F                      pop edi 
:004351C9 C3                      ret 


* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:0043515F(C) 

:004351CA 8BC7                    mov eaxedi                <== 也是正确出口 
:004351CC 5E                      pop esi 
:004351CD 5B                      pop ebx 
:004351CE 5F                      pop edi 
:004351CF C3                      ret 

上面跳来跳去的有些乱(上跳下跳,左跳右跳,原来每个条件都不一般),不知大家看懂没有,找源码跟一跟就明白啦! 

对关键 Call 004252D1的分析请见(三) 

WinAmp V2.11的注册机制分析(三)(初学者必读) 
    转载本文请注明出处,并保持文章的完整性。本文不得用于任何商业场合,仅供学习和参考。 
作者: Fpc (感谢直接和间接提供帮助的所有朋友) 
目的: 分析注册机制 
工具: SI 4.05, Wdasm 8.93, Hedit 2.0 

    下面是CALL  004252D1的核心程序,00401D8D是打开菜单“Nullsoft WinAmp...”(即“关于”)时的调用,第二次是输入注册信息时的调用,第三次我也不清楚。 
这段程序负责由RegisterName(Rn)计算出RegisterCode(Rc),放到Eax中。 

* Referenced by a CALL at Addresses: 
|:00401D8D  , :00401F3A  , :004254FE  

:004252D1 55                      push ebp 
:004252D2 8BEC                    mov ebpesp 
:004252D4 81EC00010000            sub esp, 00000100 
:004252DA 53                      push ebx 
:004252DB 56                      push esi 
:004252DC 57                      push edi 

:004252DD 6A3F                    push 0000003F 
:004252DF 33DB                    xor ebxebx 
:004252E1 59                      pop ecx                <== Ecx=3F 
:004252E2 209D00FFFFFF            and byte ptr [ebp+FFFFFF00], bl 
:004252E8 33C0                    xor eaxeax 
:004252EA 8DBD01FFFFFF            lea edidword ptr [ebp+FFFFFF01] 
:004252F0 6800010000              push 00000100 
:004252F5 F3                      repz 
:004252F6 AB                      stosd 
:004252F7 FF7508                  push [ebp+08] 
:004252FA 66AB                    stosw 
:004252FC AA                      stosb                    <== 从4252E2到此将 Ebp-100到Ebp处清0 
:004252FD 8D8500FFFFFF            lea eaxdword ptr [ebp+FFFFFF00] 
:00425303 50                      push eax 
:00425304 E8E7010100              call 004354F0                <== 这次调用将Rn复制到Ebp-100,见分析。 
:00425309 83C40C                  add esp, 0000000C 
:0042530C 389D00FFFFFF            cmp byte ptr [ebp+FFFFFF00], bl 
:00425312 7428                    je 0042533C 
:00425314 8DB500FFFFFF            lea esidword ptr [ebp+FFFFFF00] 
:0042531A 33FF                    xor ediedi 
                                    <== 至此,入口: Edi=Ebx=0 
* Referenced by a (U)nconditional or (C)onditional Jump at Address:    <== !! 这个循环计算中间结果,很关键 
|:0042533A(C) 

:0042531C 56                      push esi 
:0042531D E861000000              call 00425383                <== 从Esi开始取4字节,作运算,结果在Eax中。请看下面 
:00425322 59                      pop ecx 
:00425323 8BCF                    mov ecxedi                <== 随着循环,Edi=0、2,4,6,8,A... 
:00425325 83E10F                  and ecx, 0000000F 
:00425328 D3E0                    shl eaxcl                <== 左移位 
:0042532A 85C0                    test eaxeax 
:0042532C 7C04                    jl 00425332                <== 是负数则向下跳 
:0042532E 03D8                    add ebxeax                <== 很少被执行到 
:00425330 EB02                    jmp 00425334                <== 循环次数为Rn长度 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:0042532C(C) 

:00425332 2BD8                    sub ebxeax                <== Ebx放累加结果 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00425330(U) 

:00425334 47                      inc edi 
:00425335 47                      inc edi                <== Edi=Edi+2 
:00425336 46                      inc esi                <== Esi取Rn的下一个字节 
:00425337 803E00                  cmp byte ptr [esi], 00    <== 检查是否结束 
:0042533A 75E0                    jne 0042531C            <== 未完则继续,循环次数为Rn长度 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00425312(C) 

:0042533C 8BC3                    mov eaxebx                <== 中间结果送 Eax 
:0042533E B940420F00              mov ecx, 000F4240            <== Ecx= 1,000,000(Dec
:00425343 6BC025                  imul eax, 00000025            <== EaxEax*37(Dec
:00425346 99                      cdq 
:00425347 F7F9                    idiv ecx 
:00425349 8BCA                    mov ecxedx                <== 余数送Ecx保存,很重要(我跟到下面要返回的语句,向回找了半天才找到) 
:0042534B 8BF2                    mov esiedx                <== 余数送Esi,到 425352继续处理 
:0042534D 6BC964                  imul ecx, 00000064            <== Ecx=Ecx*100(Dec
:00425350 33FF                    xor ediedi 

* Referenced by a (U)nconditional or (C)onditional Jump at Address:    <== 到 425369的这个循环会被执行几次 
|:00425369(U) 

:00425352 85F6                    test esiesi                <== Esi是否为0 
:00425354 7415                    je 0042536B                <== 是则跳出这一循环 
:00425356 8BC6                    mov eaxesi            <== Esi->Eax,作处理准备 
                                  
:00425358 6A64                    push 00000064 
:0042535A 99                      cdq 
:0042535B 5B                      pop ebx             
:0042535C F7FB                    idiv ebx            <== 被100(Dec)除 
:0042535E 8BC6                    mov eaxesi 
:00425360 53                      push ebx 
:00425361 5E                      pop esi 
:00425362 03FA                    add ediedx            <== Edi放余数累加和 
:00425364 99                      cdq 
:00425365 F7FE                    idiv esi 
:00425367 8BF0                    mov esieax            <== 商被送到Esi 
:00425369 EBE7                    jmp 00425352 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00425354(C) 

:0042536B 8D047F                  lea eaxdword ptr [edi+2*edi]    <== Eax=Edi*3 

                                  | 
:0042536E 6A04                    push 00000004 
:00425370 99                      cdq 
:00425371 5E                      pop esi 
:00425372 F7FE                    idiv esi                <== 再被4除 

                                  | 
:00425374 6A64                    push 00000064 
:00425376 5E                      pop esi 
:00425377 5F                      pop edi 
:00425378 99                      cdq 
:00425379 F7FE                    idiv esi                <== 再被100除 
:0042537B 5E                      pop esi 
:0042537C 5B                      pop ebx 
:0042537D 8BC2                    mov eaxedx                <== 余数送 Eax 
:0042537F 03C1                    add eaxecx                <== EaxEax+Ecx (看42534D),这是最终结果 
:00425381 C9                      leave 
:00425382 C3                      ret 


* Referenced by a CALL at Address: 
|:0042531D  

:00425383 55                      push ebp 
:00425384 8BEC                    mov ebpesp 
:00425386 51                      push ecx 
:00425387 8065FC00                and byte ptr [ebp-04], 00 
:0042538B 57                      push edi 
:0042538C 33C0                    xor eaxeax 
:0042538E 8D7DFD                  lea edidword ptr [ebp-03] 
:00425391 66AB                    stosw 
:00425393 6A04                    push 00000004 
:00425395 FF7508                  push [ebp+08]                <== 源字符串地址压栈 
:00425398 AA                      stosb                    <== 从Ebp-04处建立了4字节的临时缓冲区 

:00425399 8D45FC                  lea eaxdword ptr [ebp-04]        <== 
:0042539C 50                      push eax                <== 目标区地址压栈 
:0042539D E84E010100              call 004354F0                <== 又一次对这个CALL的调用,不过这次是从Esi处取 4 字节到临时缓冲区,我在这里转的头晕,大家可以看一看。 
:004253A2 0FB645FE                movzx eaxbyte ptr [ebp-02]        <== 相当于 al=[Esi+2],高位是0,下同 
:004253A6 0FB64DFC                movzx ecxbyte ptr [ebp-04]        <==        cl=[Esi
:004253AA 0FB655FD                movzx edxbyte ptr [ebp-03]        <==        dl=[Esi+1] 
:004253AE 33C1                    xor eaxecx            <== Al^=Cl 
:004253B0 83C40C                  add esp, 0000000C 
:004253B3 0FB64DFF                movzx ecxbyte ptr [ebp-01]        <==        cl=[Esi+3] 
:004253B7 F7D1                    not ecx                <== !Ecx 
:004253B9 F7D0                    not eax                <== !Eax 
:004253BB 33CA                    xor ecxedx            <== Cl^=Dl 
:004253BD 5F                      pop edi 
:004253BE 03C1                    add eaxecx            <== Eax+=Ecx 
:004253C0 C9                      leave 
:004253C1 C3                      ret 


    call 004354F0,这个CALL是从源字符串区向目标缓冲区复制字串,长度由调用前的压栈决定;出口:将目标缓冲区地址送 Eax。 
里面跳转太多,看不明白关系不大,它没有别的功能。 


* Referenced by a CALL at Addresses: 
|:00403EF8  , :00410333  , :00410517  , :00425304  , :0042539D  
|:00425B3F  , :00425BF1  , :004294AF  , :0042951D  , :00439DCA  

:004354F0 8B4C240C                mov ecxdword ptr [esp+0C]        <== 调用此Call前的倒数第三次Push,为100或4 
:004354F4 57                      push edi 
:004354F5 85C9                    test ecxecx 
:004354F7 747A                    je 00435573                <== 两处调用都不跳 
:004354F9 56                      push esi 
:004354FA 53                      push ebx 
:004354FB 8BD9                    mov ebxecx                <== 
:004354FD 8B742414                mov esidword ptr [esp+14]        <== !! Esi为源字串地址,注意 @42539D调用时,每次都有Esi=Esi+1 

:00435501 F7C603000000            test esi, 00000003            <== Esi低字节是否为03 
:00435507 8B7C2410                mov edidword ptr [esp+10]        <== !! 调用此Call前的最后一次Push,均为Eax,是目标地址 
:0043550B 7507                    jne 00435514                <== 大多数情况下不会跳 
:0043550D C1E902                  shr ecx, 02 
:00435510 756F                    jne 00435581                <== 会跳走 
:00435512 EB21                    jmp 00435535 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:0043550B(C), :00435527(C) 

:00435514 8A06                    mov albyte ptr [esi
:00435516 46                      inc esi 
:00435517 8807                    mov byte ptr [edi], al 
:00435519 47                      inc edi 
:0043551A 49                      dec ecx 
:0043551B 7425                    je 00435542 
:0043551D 84C0                    test alal 
:0043551F 7429                    je 0043554A 

* Possible Reference to String Resource ID=00003: "Uninstall canceled." 
                                  | 
:00435521 F7C603000000            test esi, 00000003 
:00435527 75EB                    jne 00435514 
:00435529 8BD9                    mov ebxecx 
:0043552B C1E902                  shr ecx, 02 
:0043552E 7551                    jne 00435581 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:0043557F(C) 

:00435530 83E303                  and ebx, 00000003 
:00435533 740D                    je 00435542 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00435512(U), :00435540(C) 

:00435535 8A06                    mov albyte ptr [esi
:00435537 46                      inc esi 
:00435538 8807                    mov byte ptr [edi], al 
:0043553A 47                      inc edi 
:0043553B 84C0                    test alal 
:0043553D 742F                    je 0043556E 
:0043553F 4B                      dec ebx 
:00435540 75F3                    jne 00435535 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:0043551B(C), :00435533(C) 

:00435542 8B442410                mov eaxdword ptr [esp+10] 
:00435546 5B                      pop ebx 
:00435547 5E                      pop esi 
:00435548 5F                      pop edi 
:00435549 C3                      ret 


* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:0043551F(C) 

:0043554A F7C703000000            test edi, 00000003 
:00435550 7412                    je 00435564 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00435562(C) 

:00435552 8807                    mov byte ptr [edi], al 
:00435554 47                      inc edi 
:00435555 49                      dec ecx 
:00435556 0F848A000000            je 004355E6 
:0043555C F7C703000000            test edi, 00000003 
:00435562 75EE                    jne 00435552 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00435550(C) 

:00435564 8BD9                    mov ebxecx 
:00435566 C1E902                  shr ecx, 02 
:00435569 756C                    jne 004355D7 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:0043556F(C), :004355E4(C) 

:0043556B 8807                    mov byte ptr [edi], al 
:0043556D 47                      inc edi 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:0043553D(C) 

:0043556E 4B                      dec ebx 
:0043556F 75FA                    jne 0043556B 
:00435571 5B                      pop ebx 
:00435572 5E                      pop esi 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:004354F7(C) 

:00435573 8B442408                mov eaxdword ptr [esp+08] 
:00435577 5F                      pop edi 
:00435578 C3                      ret 


* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:00435599(C), :004355B1(C) 

:00435579 8917                    mov dword ptr [edi], edx 
:0043557B 83C704                  add edi, 00000004 
:0043557E 49                      dec ecx 
:0043557F 74AF                    je 00435530                <== 处理完成则跳上去 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:     
        <== 从这里到返回处是将字串从[Esi]处复制到[Edi],长度与Ecx有关,不够则在[Edi]后面补0 
|:00435510(C), :0043552E(C) 

:00435581 BAFFFEFE7E              mov edx, 7EFEFEFF        <-- 
:00435586 8B06                    mov eaxdword ptr [esi]    <-- 
:00435588 03D0                    add edxeax 
:0043558A 83F0FF                  xor eax, FFFFFFFF 
:0043558D 33C2                    xor eaxedx 
:0043558F 8B16                    mov edxdword ptr [esi
:00435591 83C604                  add esi, 00000004 
:00435594 A900010181              test eax, 81010100        <-- 检查 Eax取到的是否为0,手法很是怪异?! 
:00435599 74DE                    je 00435579 
:0043559B 84D2                    test dldl 
:0043559D 742C                    je 004355CB 
:0043559F 84F6                    test dhdh 
:004355A1 741E                    je 004355C1 
:004355A3 F7C20000FF00            test edx, 00FF0000 
:004355A9 740C                    je 004355B7 
:004355AB F7C2000000FF            test edx, FF000000 
:004355B1 75C6                    jne 00435579                <== 跳走表示edx取到的各字节均为非0 
:004355B3 8917                    mov dword ptr [edi], edx 
:004355B5 EB18                    jmp 004355CF 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:004355A9(C) 

:004355B7 81E2FFFF0000            and edx, 0000FFFF 
:004355BD 8917                    mov dword ptr [edi], edx 
:004355BF EB0E                    jmp 004355CF 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:004355A1(C) 

:004355C1 81E2FF000000            and edx, 000000FF 
:004355C7 8917                    mov dword ptr [edi], edx 
:004355C9 EB04                    jmp 004355CF 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:0043559D(C) 

:004355CB 33D2                    xor edxedx 
:004355CD 8917                    mov dword ptr [edi], edx 

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 
|:004355B5(U), :004355BF(U), :004355C9(U) 

:004355CF 83C704                  add edi, 00000004 
:004355D2 33C0                    xor eaxeax 
:004355D4 49                      dec ecx 
:004355D5 740A                    je 004355E1 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00435569(C) 

:004355D7 33C0                    xor eaxeax 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:004355DF(C) 

:004355D9 8907                    mov dword ptr [edi], eax 
:004355DB 83C704                  add edi, 00000004 
:004355DE 49                      dec ecx 
:004355DF 75F8                    jne 004355D9 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:004355D5(C) 

:004355E1 83E303                  and ebx, 00000003 
:004355E4 7585                    jne 0043556B 

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 
|:00435556(C) 

:004355E6 8B442410                mov eaxdword ptr [esp+10] 
:004355EA 5B                      pop ebx 
:004355EB 5E                      pop esi 
:004355EC 5F                      pop edi 
:004355ED C3                      ret 

注册机 
    转载本文请注明出处,并保持文章的完整性。本文不得用于任何商业场合,仅供学习和参考。 
作者: Fpc (感谢直接和间接提供帮助的所有朋友) 
工具: BC++ Builder 5.0(对ASM的兼容性非常不错,可惜我用的不熟) 

    写教程真是很累的一件事,想起众多前辈的妙文,就知道他们付出了什么。不过在这过程中是学到了一些,尤其是那些自己原来不太明白之处,要去想清楚,否则错误连连,走在街上肯定被痛扁。有意把这一篇写的很罗嗦,只是希望大家从中学到知识,如果再写,一定会是很简练。当然水平还是基础级的,需要的只是耐心!! 
下面是注册机: 

//--------------------------------------------------------------------------- 
// KeyGen for WinAmp 2.11 by Fpc 
// edtName为输入注册姓名的文本框,edtCode为显示注册码的文本框(只读) 

void __fastcall TForm1::edtNameChange(TObject *Sender) 

char name[255], code[255] = " "; 
int i; 
long value = 0; 
for(i=0;i<255;i++) 
        name[i]='\0x0'; 

if(edtName->Text.IsEmpty()){ 
        edtCode->Text = ""; 
        return; 
        } 
strcpy(name, edtName->Text.c_str()); 

_asm 

    lea esi, name 
    xor ediedi 
    xor ebxebx 
loop1: 
    movzx eaxbyte ptr [Esi+2] 
    movzx ecxbyte ptr [Esi
    movzx edxbyte ptr [Esi+1] 
    xor eaxecx 
    movzx ecxbyte ptr [Esi+3] 
    not ecx 
    not eax 
    xor ecxedx 
    add eaxecx 
    mov ecxedi 
    and ecx, 0x0000000F 
    shl eaxcl 
    test eaxeax 
    jl iflittle 
    add ebxeax 
    jmp nextchar 

iflittle: 
    sub ebxeax 

nextchar: 
    inc edi 
    inc edi 
    inc esi 
    cmp byte ptr [esi], 00 
    jne loop1            // the first loop 

    mov eaxebx 
    mov ecx, 0x000F4240 
    imul eax, 0x00000025 
    cdq 
    idiv ecx 
    mov ecxedx 
    mov esiedx 
    imul ecx, 0x00000064 
    xor ediedi 

loop2: 
    test esiesi 
    je over 
    mov eaxesi 
                                  
    push 0x00000064 
    cdq 
    pop ebx             
    idiv ebx 
    mov eaxesi 
    push ebx 
    pop esi 
    add ediedx 
    cdq 
    idiv esi 
    mov esieax 
    jmp loop2                // the second loop 

over: 
    lea eaxdword ptr [edi+2*edi
    push 0x00000004 
    cdq 
    pop esi 
    idiv esi 
    push 0x00000064 
    pop esi 
    cdq 
    idiv esi 
    mov eaxedx 
    add eaxecx 
      mov value,eax 

  wsprintf(code, "%ld", value); 
  edtCode->Text = code; 

//--------------------------------------------------------------------------- 
// 以上经编译通过,没有问题 


                                    Fpc @2001/03/26

<DIV ALIGN='right'>----------------------------------------------
没有最好,只有最差!
希望FCG不会最差!DIV>