欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

WinAmp V2.11的注册机制分析(一)(初学者必读) (12千字)

WinAmp V2.11的注册机制分析(一)(初学者必读) (12千字)

WinAmp V2.11的注册机制分析(一)(初学者必读)
    转载本文请注明出处,并保持文章的完整性。本文不得用于任何商业场合,仅供学习和参考。

目的: 分析注册机制
工具: 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的。再向下是一个 Call+ Cmp+ Jmp的程序段,这个 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 ebp, esp
:00401CD1 81EC00060000            sub esp, 00000600
:00401CD7 A050914400              mov al, byte 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 eax, eax
:00401CEC 8DBD01FAFFFF            lea edi, dword ptr [ebp+FFFFFA01]    <== 准备将内存清0
:00401CF2 F3                      repz
:00401CF3 AB                      stosd
:00401CF4 66AB                    stosw
* Reference To: KERNEL32.GetPrivateProfileStringA, Ord:013Ah
                                  |
:00401CF6 8B3534E14300            mov esi, dword 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 eax, dword 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 eax, dword 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 eax, dword 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 eax, eax
:00401D62 59                      pop ecx
:00401D63 744F                    je 00401DB4                <== Eax=0就去死
:00401D65 802000                  and byte ptr [eax], 00        <== 使得Rn以'\0'结束
:00401D68 33F6                    xor esi, esi
:00401D6A 83C003                  add eax, 00000003            <== Eax指向Irc:123456
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401D84(U)
|
:00401D6D 8A08                    mov cl, byte ptr [eax]        <== 取一个字符
:00401D6F 80F930                  cmp cl, 30                <== 数字为有效字符,非数字表示完成
:00401D72 7C12                    jl 00401D86
:00401D74 80F939                  cmp cl, 39
:00401D77 7F0D                    jg 00401D86
:00401D79 0FBEC9                  movsx ecx, cl                <== Ecx中无用位清0
:00401D7C 8D14B6                  lea edx, dword ptr [esi+4*esi]    <= Edx=5*Esi
:00401D7F 40                      inc eax                    <== Edx的初始值为0,这三条指令将字符串变为数字
:00401D80 8D7451D0                lea esi, dword 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 eax, dword ptr [ebp+FFFFFE00]<== Eax指向Rn
:00401D8C 50                      push eax
:00401D8D E83F350200              call 004252D1                <== !! 关键Call,由Rn计算得出Rc,保存在Eax。具体分析请看(三)
:00401D92 3BC6                    cmp eax, esi                <== 比较Rc与Irc
:00401D94 59                      pop ecx
:00401D95 751D                    jne 00401DB4                <== 不相等则GAME OVER,大家将此处NOP掉,看会发生什么有趣的事情
:00401D97 50                      push eax
:00401D98 8D8500FEFFFF            lea eax, dword ptr [ebp+FFFFFE00]
:00401D9E 50                      push eax
:00401D9F 8D8500FAFFFF            lea eax, dword 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 eax, dword 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 eax, dword 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 eax, dword 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 eax, dword ptr [ebp+eax-00000480]
:00401ECE 50                      push eax
:00401ECF 53                      push ebx
:00401ED0 FF7508                  push [ebp+08]
:00401ED3 FFD6                    call esi
:00401ED5 8D8580FBFFFF            lea eax, dword 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 edi, dword 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 di, ax
:00401F07 7405                    je 00401F0E
:00401F09 663BFB                  cmp di, bx
:00401F0C 7552                    jne 00401F60
对关键 Call 004252D1的分析请见(三)

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功