yijun 发表于 2005-4-5 10:28:45

一个比较有代表的虚拟方法保护软件

【软件名称】:互联网点歌台 V3.91
【软件大小】:1.46M
【下载地址】:http://mpt.zj.com/
【软件简介】:随着宽带网的普及,网速越来越快,网上听音乐已不成问题。使用互联网点歌台,只用鼠标轻轻一“点歌”,就能让您听遍全世界的音乐,免去寻找下载歌曲的麻烦。
  互联网点歌台是国内第一款高度集成歌曲搜索及播放功能的音乐软件。把自己想要听的歌曲输入,就能一下子听到你想要的歌曲,看你想要的歌词。支持几乎所有歌曲类型,如mp3、wma、rm等,可编程播放。音质媲美winamp。

第19届全国科技创新大赛(CASTIC Computer Science)获奖作品   中国·成都

【功能介绍】:
1.搜索播放网络歌曲,支持mp3、wma等搜索,广泛的歌曲搜索量(“全部”类型歌曲更多,更强大),支持Windows Media Player格式、Real Player格式。
2.最新版本完全采用了MPT-Link第二代技术,最大限度保证了搜索的成功率,支持同名歌曲的智能区分,点歌率>97%。
3.支持点歌单系统,可编程搜索播放,并能保存点歌单。点歌单文件具有地址自动记忆功能,可直接双击启动互联网点歌台顺序播放。
4.歌曲同步批量下载(断点续传)。
5.自动搜索权威音乐排行榜TOP100,搜索播放歌手与专辑。
6.同步显示歌词。
7.能最小化至托盘播放,悬浮窗显示,方便快捷。

【软件限制】:

V3.9 未注册版与注册版的区别:
1.全部类型选择(更多的歌曲数量,更快的点歌速度).
2.享受歌手与专辑/网络广播电台/历史记录导入/候选地址导入功能.
3.未注册版在搜索歌词后歌词不能保存,且会在歌词底部增加注册信息.
4.未注册版不具有批量下载功能.
5.注册版可查看全部排行榜.
6.注册版可以享有所有售后服务.

【保护方式】:注册码保护
【破解声明】:初学Crack,只是感兴趣,失误之处敬请诸位大侠赐教!
【破解工具】:OllyDbg.V1.10聆风听雨汉化第二版、PeID 0.93

--------------------------------------------------------------------------------------------------------------

【破解过程】:
先用PEID 0.93汉化增强版查壳,Borland Delphi 6.0 - 7.0,无壳?OD 直接载入MusicPoint.exe,查找参考字符串"感谢你的注册..."双击后向上查找,来到这里:
005189B5    55            push ebp
005189B6    68 6B8A5100   push <MusicPoi.->System.@HandleFinally>
005189BB    64:FF30         push dword ptr fs:
005189BE    64:8920         mov dword ptr fs:,esp
005189C1    8D55 FC         lea edx,dword ptr ss:
005189C4 >8B83 F8020000   mov eax,dword ptr ds:         ; *Tfrmreg.Edit1:TLabeledEdit
005189CA >E8 AD49F4FF   call MusicPoi.0045D37C               ; ->Controls.TControl.GetText(TControl):TCaption;
005189CF    837D FC 00      cmp dword ptr ss:,0             ; 机器码不能为空
005189D3    74 11         je short MusicPoi.005189E6
005189D5 >8B83 04030000   mov eax,dword ptr ds:         ; *Tfrmreg.btnget:TBitBtn
005189DB    66:BE EBFF      mov si,0FFEB
005189DF >E8 0CB6EEFF   call MusicPoi.00403FF0               ; ->System.@CallDynaInst 本破文关键所在!!!
005189E4    EB 0C         jmp short MusicPoi.005189F2
005189E6    B8 808A5100   mov eax,MusicPoi.00518A80            ; 机器码为空提示"请生成机器码"
005189EB >E8 FCD0F1FF   call MusicPoi.00435AEC               ; ->Dialogs.ShowMessage(AnsiString);
005189F0    EB 5E         jmp short MusicPoi.00518A50
005189F2    8D55 F8         lea edx,dword ptr ss:
005189F5 >8B83 FC020000   mov eax,dword ptr ds:         ; *Tfrmreg.Edit2:TLabeledEdit
005189FB >E8 7C49F4FF   call MusicPoi.0045D37C               ; ->Controls.TControl.GetText(TControl):TCaption;
00518A00    8B45 F8         mov eax,dword ptr ss:         ; 注册码
00518A03    8B15 3C415200   mov edx,dword ptr ds:          ; 计算后的机器码
00518A09 >E8 42C6EEFF   call MusicPoi.00405050               ; ->System.@LStrCmp;
00518A0E    75 2C         jnz short MusicPoi.00518A3C            ; 明码比较,可以爆破或制作内存注册机 ^_^
00518A10    6A 40         push 40
00518A12    68 908A5100   push MusicPoi.00518A90
00518A17    68 A08A5100   push MusicPoi.00518AA0               ; 感谢你的注册...
00518A1C    8BC3            mov eax,ebx
00518A1E >E8 A5B2F4FF   call MusicPoi.00463CC8               ; ->QForms.TCustomForm.GetClientHandle(TCustomForm):QWorkspaceH;
00518A23    50            push eax
00518A24 >E8 5BF1EEFF   call <jmp.&user32.MessageBoxA>         ; ->user32.MessageBoxA()
00518A29    8BC3            mov eax,ebx                            ; 提示注册成功。
00518A2B    E8 AC000000   call MusicPoi.00518ADC               ; 保存注册信息到注册表中
00518A30    A1 38415200   mov eax,dword ptr ds:
00518A35 >E8 1A13F6FF   call MusicPoi.00479D54               ; ->Forms.TCustomForm.Close(TCustomForm);
00518A3A    EB 14         jmp short MusicPoi.00518A50
00518A3C    B8 D08A5100   mov eax,MusicPoi.00518AD0
00518A41 >E8 A6D0F1FF   call MusicPoi.00435AEC               ; ->Dialogs.ShowMessage(AnsiString);
00518A46    A1 38415200   mov eax,dword ptr ds:
00518A4B >E8 0413F6FF   call MusicPoi.00479D54               ; ->Forms.TCustomForm.Close(TCustomForm);
00518A50    33C0            xor eax,eax
00518A52    5A            pop edx
00518A53    59            pop ecx
00518A54    59            pop ecx
00518A55    64:8910         mov dword ptr fs:,edx
00518A58    68 728A5100   push MusicPoi.00518A72
00518A5D    8D45 F8         lea eax,dword ptr ss:
00518A60    BA 02000000   mov edx,2
00518A65 >E8 FEC1EEFF   call MusicPoi.00404C68               ; ->System.@LStrArrayClr(void;void;Integer);
00518A6A    C3            retn
00518A6B >^ E9 18BBEEFF   jmp MusicPoi.00404588                  ; ->System.@HandleFinally;
00518A70^ EB EB         jmp short MusicPoi.00518A5D
00518A72    5E            pop esi
00518A73    5B            pop ebx
00518A74    59            pop ecx
00518A75    59            pop ecx
00518A76    5D            pop ebp
00518A77    C3            retn

一看是明码比较,晕。本想注册一下能用就行了,但发现作者使用虚拟方法保护,兴趣来了……


从互联网上查的有关System.@CallDynaInst 函数的一些资料,方便大家参考:


                                          虚拟方法表格和动态方法表格

   Delphi 中虚方法是通过类的虚拟方法表格(Virtul Method Table,简称 VMT)或者动态方法表格(Dynamic Method Table,简称 DMT)实现的。VMT 中存放着类及其基类声明的所有虚方法的指针。每个类都具有一个唯一的 VMT,并且是在编译期间就确定的,所有由该类创建的对象都共享同一个 VMT,VMT 中除了一个虚方法表外,还包括其他有关一个类的信息。

   DMT 是 Delphi 中实现虚方法的另一种方式。利用 DMT 可以有效减小 VMT 的体积,但执行效率稍差。
   DMT 中存有类所声明的动态方法和消息句柄,但并不包括从祖先类继承的方法。用关键字 dynamic 或者 message 声明的方法都会以动态方法实现。从 VMT + vmtDynamicTable 偏移处取出的 DWORD 值就是指向类的 DMT 指针。DMT 的结构在 Delphi 中是 Undocumented 的,但通过阅读 VCL 源码和 Debug 很容易写出 DMT 在内存中的逻辑布局:

type
TDynmethodTable = packed record
    Count: Word;
    Indexes: packed array of SmallInt;
    Addresses: packed array of Pointer;
end;
   假如我们声明了如下的类:
TMyObject = class
private
    procedure DM1; dynamic;
    procedure DM2; dynamic;
    procedure WMCommand(var Message); message WM_COMMAND;
public
    procedure DM3; dynamic;
end;

   凡是带 dynamic 的关键字的方法都会被编译器按照在它们在类中声明的顺序赋予一个编号,或者说 ID,编号用一个 SmallInt 值表示,顺序为 $FFFF,$FFFE,$FFFD...当编译器遇到 message 时,方法的编号则用消息 ID 表示,例如 WM_COMMAND 代表 $0111,有了这些分析我们很容易把这个类的 DMT 按照上面的内存布局描述出来:

4   // Count =4,即包括4个动态方法
$FFFF // DM1 的编号
$FFFE // DM2 的编号
$0111 // WMCommand 的消息 ID
$FFFD // DM3 的编号
DM1 入口地址
DM2 入口地址
WMCommand 入口地址
DM3 入口地址

   这些方法是如何被调用的呢?对于带 dynamic 关键字的方法是通过调用 System._CallDynaInst 实现的。通常这样:

mov eax,ebx      ; eax = point to current object
mov si,$ffff       ; si 为方法编号
call @CallDynaInst

而System._CallDynaInst 继而会调用 System.GetDynaMethod 获得对应方法编号的方法入口地址,并直接跳到方法入口地址,执行该方法:

procedure _CallDynaInst;
asm
      PUSH    EAX
      PUSH    ECX
      MOV   EAX, ;注意调用时传递的是 VMT
      CALL    GetDynaMethod
      POP   ECX
      POP   EAX
      JE      @@Abstract
      JMP   ESI ; ESI 指向动态方法入口地址
@@Abstract:
      POP   ECX
      JMP   _AbstractError
end;


   System.GetDynaMethod 则在 DMT 中寻找该动态方法的编号,如果找到了,就从 DMT 中取得该方法的入口地址;如果找不到,则继续在父类的 DMT 中寻找该方法编号直至 TObject 的 DMT(TObject 中指向 DMT 的指针为 nil,循环到这里自然会停止):
procedure GetDynaMethod;
{       function      GetDynaMethod(vmt: TClass; selector: Smallint) : Pointer;       }
asm
      { ->    EAX   vmt of class            }
      {       SI      dynamic method index    }
      { <-    ESI pointer to routine}
      {       ZF = 0 if found         }
      {       trashes: EAX, ECX               }

      PUSH    EDI
      XCHG    EAX,ESI
      JMP   @@haveVMT
@@outerLoop:
      MOV   ESI,
@@haveVMT:
      MOV   EDI,.vmtDynamicTable
      TEST    EDI,EDI
      JE      @@parent
      MOVZX   ECX,word ptr
      PUSH    ECX
      ADD   EDI,2
      REPNE   SCASW
      JE      @@found
      POP   ECX
@@parent:
      MOV   ESI,.vmtParent
      TEST    ESI,ESI
      JNE   @@outerLoop
      JMP   @@exit

@@found:
      POP   EAX
      ADD   EAX,EAX
      SUB   EAX,ECX         { this will always clear the Z-flag ! }
      MOV   ESI,

@@exit:
      POP   EDI
end;


大家再看看上面的注册验证代码中的几行代码:
--------------------------------------------------------------------------------------------------------------
005189D5 >8B83 04030000   mov eax,dword ptr ds:         ; *Tfrmreg.btnget:TBitBtn
005189DB    66:BE EBFF      mov si,0FFEB
005189DF >E8 0CB6EEFF   call MusicPoi.00403FF0               ; ->System.@CallDynaInst
--------------------------------------------------------------------------------------------------------------


跟进005189DF >E8 0CB6EEFF   call MusicPoi.00403FF0   
--------------------------------------------------------------------------------------------------------------
00403FF0    50            push eax
00403FF1    51            push ecx
00403FF2    8B00            mov eax,dword ptr ds:
00403FF4    E8 C7FFFFFF   call MusicPoi.00403FC0      //这就是 GetDynaMethod 啦
00403FF9    59            pop ecx
00403FFA    58            pop eax
00403FFB    74 02         je short MusicPoi.00403FFF
00403FFD    FFE6            jmp esi                      //看牢这里,它可是指向动态方法入口地址哦
00403FFF    59            pop ecx
00404000^ E9 53ECFFFF   jmp MusicPoi.00402C58
00404005    C3            retn
--------------------------------------------------------------------------------------------------------------
和上面的理论一一对应了,继续……


0043CDB0    53            push ebx                               ; 动态方法入口地址
0043CDB1    8BD8            mov ebx,eax
0043CDB3    8A83 21020000   mov al,byte ptr ds:
0043CDB9    2C 03         sub al,3
0043CDBB    74 1F         je short MusicPoi.0043CDDC
0043CDBD    2C 03         sub al,3
0043CDBF    75 52         jnz short MusicPoi.0043CE13
0043CDC1    8BC3            mov eax,ebx
0043CDC3    E8 80790300   call MusicPoi.00474748
0043CDC8    85C0            test eax,eax
0043CDCA    74 07         je short MusicPoi.0043CDD3
0043CDCC    E8 83CF0300   call MusicPoi.00479D54
0043CDD1    EB 47         jmp short MusicPoi.0043CE1A
0043CDD3    8BC3            mov eax,ebx
0043CDD5    E8 5E710100   call MusicPoi.00453F38
0043CDDA    5B            pop ebx
0043CDDB    C3            retn
0043CDDC    8BC3            mov eax,ebx
0043CDDE    EB 03         jmp short MusicPoi.0043CDE3
0043CDE0    8B40 30         mov eax,dword ptr ds:
0043CDE3    85C0            test eax,eax
0043CDE5    74 09         je short MusicPoi.0043CDF0
0043CDE7    83B8 58010000 0>cmp dword ptr ds:,0
0043CDEE^ 74 F0         je short MusicPoi.0043CDE0
0043CDF0    85C0            test eax,eax
0043CDF2    74 16         je short MusicPoi.0043CE0A
0043CDF4    8B15 0C2C5200   mov edx,dword ptr ds:          ; MusicPoi.00523BF0
0043CDFA    8B12            mov edx,dword ptr ds:
0043CDFC    8B80 58010000   mov eax,dword ptr ds:
0043CE02    92            xchg eax,edx
0043CE03    E8 2C0C0400   call MusicPoi.0047DA34
0043CE08    EB 10         jmp short MusicPoi.0043CE1A
0043CE0A    8BC3            mov eax,ebx
0043CE0C    E8 27710100   call MusicPoi.00453F38
0043CE11    5B            pop ebx
0043CE12    C3            retn
0043CE13    8BC3            mov eax,ebx
0043CE15    E8 1E710100   call MusicPoi.00453F38               ; 注册算法,关键跟进
0043CE1A    5B            pop ebx
0043CE1B    C3            retn



call MusicPoi.00453F38函数,注册码关键算法:
--------------------------------------------------------------------------------------------------------------
005188D0 >55            push ebp                               ; <-Tfrmreg@btngetClick
005188D1    8BEC            mov ebp,esp
005188D3    6A 00         push 0
005188D5    6A 00         push 0
005188D7    53            push ebx
005188D8    56            push esi
005188D9    57            push edi
005188DA    8BD8            mov ebx,eax
005188DC    33C0            xor eax,eax
005188DE    55            push ebp
005188DF    68 8B895100   push <MusicPoi.->System.@HandleFinally>
005188E4    64:FF30         push dword ptr fs:
005188E7    64:8920         mov dword ptr fs:,esp
005188EA    B8 3C415200   mov eax,MusicPoi.0052413C
005188EF >E8 50C3EEFF   call MusicPoi.00404C44               ; ->System.@LStrClr(void;void);
005188F4    8D55 FC         lea edx,dword ptr ss:
005188F7 >8B83 F8020000   mov eax,dword ptr ds:         ; *Tfrmreg.Edit1:TLabeledEdit
005188FD >E8 7A4AF4FF   call MusicPoi.0045D37C               ; ->Controls.TControl.GetText(TControl):TCaption;
00518902    8B45 FC         mov eax,dword ptr ss:         ; 机器码 MachineCode
00518905 >E8 FAC5EEFF   call MusicPoi.00404F04               ; ->System.@LStrLen(String):Integer;<+>
0051890A    8BF0            mov esi,eax                            ; 机器码长度 Length
0051890C    85F6            test esi,esi
0051890E    7E 4B         jle short MusicPoi.0051895B            ; 如果长度<=0 则Over!
00518910    BF 01000000   mov edi,1                              ; i=1
00518915    8B45 FC         mov eax,dword ptr ss:         ; 机器码
00518918    33DB            xor ebx,ebx
0051891A    8A5C38 FF       mov bl,byte ptr ds:         ; MachineCode
0051891E    83FB 41         cmp ebx,41                           ; 假如MachineCode<'A' 则MachineCode+1E
00518921    7C 14         jl short MusicPoi.00518937
00518923    83FB 5A         cmp ebx,5A                           ; 假如MachineCode>'Z' 则MachineCode+1E
00518926    7F 0F         jg short MusicPoi.00518937
00518928    83FB 49         cmp ebx,49                           ; 假如MachineCode>='I' 则MachineCode-5
0051892B    7D 05         jge short MusicPoi.00518932
0051892D    83C3 07         add ebx,7                              ; 假如MachineCode<'I'则MachineCode+7
00518930    EB 08         jmp short MusicPoi.0051893A
00518932    83EB 05         sub ebx,5
00518935    EB 03         jmp short MusicPoi.0051893A
00518937    83C3 1E         add ebx,1E
0051893A    8D45 F8         lea eax,dword ptr ss:
0051893D    8BD3            mov edx,ebx
0051893F >E8 E8C4EEFF   call MusicPoi.00404E2C               ; ->System.@LStrFromChar(String;String;Char);<+>
00518944    8B55 F8         mov edx,dword ptr ss:
00518947    B8 3C415200   mov eax,MusicPoi.0052413C
0051894C    8B0D 3C415200   mov ecx,dword ptr ds:
00518952 >E8 F9C5EEFF   call MusicPoi.00404F50               ; 字符串的连接->System.@LStrCat3;注意是倒序
00518957    47            inc edi
00518958    4E            dec esi
00518959^ 75 BA         jnz short MusicPoi.00518915            ; 循环
0051895B    B8 3C415200   mov eax,MusicPoi.0052413C
00518960    8B0D 3C415200   mov ecx,dword ptr ds:          ; 连接后的字符串
00518966    BA A4895100   mov edx,MusicPoi.005189A4            ; 字符 '8'
0051896B >E8 E0C5EEFF   call MusicPoi.00404F50               ; ->System.@LStrCat3;
00518970    33C0            xor eax,eax                            ; '8'+连接后的字符串,即为有效注册码
00518972    5A            pop edx
00518973    59            pop ecx
00518974    59            pop ecx
00518975    64:8910         mov dword ptr fs:,edx
00518978    68 92895100   push MusicPoi.00518992
0051897D    8D45 F8         lea eax,dword ptr ss:
00518980    BA 02000000   mov edx,2
00518985 >E8 DEC2EEFF   call MusicPoi.00404C68               ; ->System.@LStrArrayClr(void;void;Integer);
0051898A    C3            retn
0051898B >^ E9 F8BBEEFF   jmp MusicPoi.00404588                  ; ->System.@HandleFinally;
00518990^ EB EB         jmp short MusicPoi.0051897D
00518992    5F            pop edi
00518993    5E            pop esi
00518994    5B            pop ebx
00518995    59            pop ecx
00518996    59            pop ecx
00518997    5D            pop ebp
00518998    C3            retn
--------------------------------------------------------------------------------------------------------------

【算法总结】:

注册算法很简单,虚拟方法保护这方法不错,我也会了!

Delphi 7.0 注册机源代码如下:
Procedure TForm1.btn1Click(Sender: TObject);
Var
i: Integer;
SN, MachineCode: String;
Begin
MachineCode := edt1.Text;
SetLength(SN, Length(MachineCode));
For i := 1 To Length(MachineCode) Do
Begin
    If (Ord(MachineCode) < $41) Or (Ord(MachineCode) > $5A) Then
      SN := Char(Ord(MachineCode) + $1E)
    Else If (Ord(MachineCode) >= $49) Then
      SN := Char(Ord(MachineCode) - 5)
    Else
      SN := Char(Ord(MachineCode) + 7);
End;
edt2.Text := '8' + ReverseString(SN);
End;


我的机器码='14      60-206'    (不包括引号)
    注册码=8TNPKNT>>>>>>RO

yygx 发表于 2005-4-6 11:22:55

好文章!!!
楼主能不能再说说这种虚拟动态方法如果没有正确的注册码,就得不到正确的地址,
那要爆破该怎么作?

yijun 发表于 2005-4-6 12:59:32

那就需要继续努力学习了^_^^_^

yygx 发表于 2005-4-6 13:56:49

^_^,这么说爆破没活路了。
呜呜呜,偶碰到的东东怎么都是用这个虚拟动态方法,难道都要算出注册码才能获的正确的资源,苦啊。

yijun 发表于 2005-4-7 13:43:42

对啊,学习算法才是正道,以前我都是太依奈爆破了~~~~~~~
至少你现在对明码比较的应该能搞定啊~~~
关于算法建议你从飘云兄的算法第一课学起,过几天我也发几篇我以前学习过的简单算法~~~

hyd009 发表于 2005-4-9 00:22:39

啊,高手
在看学看过

阿毛 发表于 2005-4-9 12:49:37

^_^,这么说爆破没活路了

yijun 发表于 2005-4-9 19:29:29

Originally posted by hyd009 at 2005-4-9 12:22 AM:
啊,高手
在看学看过


我只是觉得这个软件比较有代表性所以发来大家学习,我没有说是原创啊;)~~~~~

xbb[DFCG] 发表于 2005-4-11 21:27:02

Crack的目的就是学习别人的代码。当然附带着做出精美的算法注册机也是非常不错的。:)
要想做出算法注册机,弄懂软件的注册算法是必然。
我正在向这个目的努力前进。
页: [1]
查看完整版本: 一个比较有代表的虚拟方法保护软件