• 标 题:第一篇破文,请各位老大指教。 (11千字)
  • 作 者:hyzhang001
  • 时 间:2001-10-17 0:22:04
  • 链 接:http://bbs.pediy.com

知道这个论坛也将近一年了,经常来这里听各位的高论,受益匪浅,看了论坛精华2和3之后,禁不住手痒,也学着破软件,可功力浅,只好专捏“软柿子”了。(这是我第一次写破解,有言不达意之处,请多多包涵。^O^)

软件:股霸5.0
功能:通视卡用户接收东方上证信息工具,有通视卡的兄弟可以试试,可能我不会用,算出注册码注册成功后仍就接收不到股市信息(不过拿来练练手倒不错)。
下载地址:http://stockhot.my.west163.com/down/Gb50SHM.exe
软件保护:加壳,代码采用花指令法加密,使用了cih的技术(使TRW2000在某些地址不能中断),注册码在DLL文件中计算对比(注册码算法中使用了硬件信息)。
工具:TRW2000,WinHex9.5,caspr1.011(一个非常好的脱壳软件,我喜欢,感谢作者的不懈努力),fs2k55(也是一个很好的侦测加壳类型的软件),w32dasm8.93。
过程:
    运行主程序sdlzc.exe后,输入注册码“787878787878787878”一共十六位,按现在注册按钮后,出现“对不起,注册失败!!!”注册错误消息窗口,至此,通常破解方法为设断bpx  MessageBoxA,然后采用逆推法,寻找能跳过CALL MessageBoxA的地方,这样可以尽快找到核心比较代码(大部分程序是这样的吧)。
    用fs2k55侦测文件,发现有加壳,用caspr让它一丝不挂吧。
    用w32dasm反汇编,寻找“对不起,注册失败!!!”的错误信息,Ok!,w32dasm总是不会让人失望,在0040129A地址找到了这个错误信息,好!,往上找,原来是从00401266跳来的,看来0040125F的call 00401822必有问题,追进去看看。
:00401249 817D0C11010000          cmp dword ptr [ebp+0C], 00000111
:00401250 0F8584000000            jne 004012DA
:00401256 817D10E8030000          cmp dword ptr [ebp+10], 000003E8
:0040125D 7550                    jne 004012AF
:0040125F E8BE050000              call 00401822
:00401264 0BC0                    or eax, eax        *eax如果为0则死,不为0则注册成功。
:00401266 752A                    jne 00401292
:00401268 6A00                    push 00000000
:0040126A FF35FF684000            push dword ptr [004068FF]

* Possible StringData Ref from Data Obj ->"恭喜您,注册成功!"
                                  |
:00401270 68CD624000              push 004062CD
:00401275 FF358A644000            push dword ptr [0040648A]

* Reference To: USER32.MessageBoxA, Ord:01BBh
                                  |
:0040127B E8560D0000              Call 00401FD6
:00401280 6A00                    push 00000000
:00401282 FF358A644000            push dword ptr [0040648A]

* Possible StringData Ref from Data Obj ->"对不起,注册失败!!!"
                                  |
:0040129A 68E0624000              push 004062E0
:0040129F FF358A644000            push dword ptr [0040648A]

* Reference To: USER32.MessageBoxA, Ord:01BBh
                                  |
:004012A5 E82C0D0000              Call 00401FD6
:004012AA E9B9000000              jmp 00401368


0040125F的call 00401822果然有问题,以下见代码中注解。

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040101E(U)
|
:00401822 55                      push ebp
:00401823 8BEC                    mov ebp, esp
:00401825 83C4F8                  add esp, FFFFFFF8
:00401828 60                      pushad
:00401829 B805000000              mov eax, 00000005
:0040182E 8945FC                  mov dword ptr [ebp-04], eax
:00401831 6A1E                    push 0000001E
:00401833 68A5624000              push 004062A5
:00401838 6A64                    push 00000064
:0040183A FF358A644000            push dword ptr [0040648A]

* Reference To: KERNEL32.lstrlenA, Ord:02E2h
                                  |
:00401865 E890070000              Call 00401FFA
:0040186A 83F810                  cmp eax, 00000010    *这里比较注册码长度,不等于16位则死
:0040186D 7516                    jne 00401885
:0040186F 6857634000              push 00406357
:00401874 6853634000              push 00406353
:00401879 68A5624000              push 004062A5

* Reference To: sdldll.GetDateInKJMReg, Ord:000Ah
                                  |
:0040187E E8430B0000              Call 004023C6        *按f10到这里后,再按f10则直接出现注册
:00401883 EB0C                    jmp 00401891        *失败的错误信息,这里也有问题,追吧。

sdldll.dll也有加壳,直接用caspr脱。
Exported fn(): GetDateInKJMReg - Ord:000Bh
:10007FFA 55                      push ebp
:10007FFB 8BEC                    mov ebp, esp
:10007FFD 83C4F8                  add esp, FFFFFFF8
:10008000 60                      pushad
:10008001 8B7D08                  mov edi, dword ptr [ebp+08]
:10008004 8D35BEF80010            lea esi, dword ptr [1000F8BE]
:1000800A 56                      push esi
:1000800B 57                      push edi
:1000800C 6A09                    push 00000009
:1000800E 57                      push edi
:1000800F 68AAF80010              push 1000F8AA

* Reference To: KERNEL32.lstrcpynA, Ord:02DFh
                                  |
:10008037 E806070000              Call 10008742
:1000803C 68AAF80010              push 1000F8AA
:10008041 E86E050000              call 100085B4
:10008046 5F                      pop edi
:10008047 5E                      pop esi
:10008048 8906                    mov dword ptr [esi], eax
:1000804A 8D35BEF80010            lea esi, dword ptr [1000F8BE]
:10008050 8B06                    mov eax, dword ptr [esi]
:10008052 8945FC                  mov dword ptr [ebp-04], eax

* Reference To: sdldll.GetJQZW
                                  |
:10008055 E866FEFFFF              call 10007EC0        *此call获得硬件信息
:1000805A 50                      push eax
:1000805B FF1590F80010            call dword ptr [1000F890]    *此F(1)对EAX中硬件信息作复杂转换
:10008061 83C404                  add esp, 00000004
:10008064 A38FF90010              mov dword ptr [1000F98F], eax
:10008069 3345FC                  xor eax, dword ptr [ebp-04]    *[ebp-4]中为注册码前8位
:1000806C 50                      push eax
:1000806D FF158CF80010            call dword ptr [1000F88C]    *此F(2)对EAX作复杂转换(看的头都:10008073 83C404                  add esp, 00000004        *大了还是不明白算法)
:10008076 6652                    push dx
:10008078 6650                    push ax
:1000807A 58                      pop eax            *EAX为上call结果
:1000807B EB02                    jmp 1000807F
:1000807D EA3360EB026967          jmp 6769:02EB6033    ***这里以后采用了“花指令”法。***
:10008084 EB02                    jmp 10008088
我倒,用trw2000追到1000807B后,按一下F8,代码变一变,再按几下F8,前后代码都不对了(挂在半空的滋味真不错,你也来尝尝。),原来作者用了“花指令”,经仔细分析后,祭出了winHex,修改后代码如下。
:1000807D 90                      nop
:1000807E 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000807B(U)
|
:1000807F 60                      pushad
:10008080 EB02                    jmp 10008084
:10008082 90                      nop
:10008083 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10008080(U)
|
:10008084 EB02                    jmp 10008088

这样看起来顺眼多了。
噫!追着追着怎么出现了......
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10008089(U)
|
:1000808D B903000000              mov ecx, 00000003
:10008092 8D05BB550010            lea eax, dword ptr [100055BB]    **这里为修改int 3入口作准备
:10008098 8B1D02A00010            mov ebx, dword ptr [1000A002]
:1000809E EB02                    jmp 100080A2
:100080A0 90                      nop
:100080A1 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000809E(U)
|
:100080A2 8D1CCB                  lea ebx, dword ptr [ebx+8*ecx]
:100080A5 668903                  mov word ptr [ebx], ax      **这里修改int 3入口
:100080A8 EB02                    jmp 100080AC
:100080AA 90                      nop
:100080AB 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100080A8(U)
|
:100080AC C1E810                  shr eax, 10
:100080AF EB02                    jmp 100080B3
:100080B1 90                      nop
:100080B2 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100080AF(U)
|
:100080B3 66894306                mov word ptr [ebx+06], ax
:100080B7 EB02                    jmp 100080BB
:100080B9 90                      nop
:100080BA 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100080C0(U)
|
:100080C4 CC                      int 03    **这里是cih病毒的技术,获得了0级特权,它想做什么                            **呢??自己U 100055BB看看吧。
                        **这里F8、F10都死,只好在100055BB中作作手脚了。


继续追吧......
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10008111(U)
|
:10008115 BB34122989              mov ebx, 89291234
:1000811A 81E3FFFF0000            and ebx, 0000FFFF
:10008120 EB02                    jmp 10008124
:10008122 90                      nop
:10008123 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10008120(U)
|
* Reference To: sdldll.NewKjmSuanFa
                                  |
:10008124 E824D0FFFF              call 1000514D    **关键,开机码(注册码前8位)算法,算法很简单
:10008129 EB02                    jmp 1000812D **(大概为eax xor 1234h,eax xor 52071197,eax xor                         **12345678)但不容易找到计算子程序,此子程序代替了                            **int 1处理程序,trw2000没办法追。

来到了......
:100081C3 80FC09                  cmp ah, 09    **eax为注册码前8位经计算后内容,看来此程序只允许
:100081C6 7704                    ja 100081CC    **用到2009年12月,程序中另有一处比较当前日期。
:100081C8 3C12                    cmp al, 12
:100081CA 7606                    jbe 100081D2

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100081C6(C)
|
:100081CC EB02                    jmp 100081D0
:100081CE 90                      nop
:100081CF 90                      nop

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100081CC(U)
|
:100081D0 33C0                    xor eax, eax    **EAX为0则注册错误。

以下比较计算注册码后8位。
:10008271 8D35BEF80010            lea esi, dword ptr [1000F8BE] *注册码前8位地址
:10008277 FC                      cld
:10008278 AD                      lodsd
:10008279 33058FF90010            xor eax, dword ptr [1000F98F]    *经转换后硬件信息地址
:1000827F 8945F8                  mov dword ptr [ebp-08], eax
:10008282 AD                      lodsd
:10008283 33058FF90010            xor eax, dword ptr [1000F98F]    *注册码后8位地址
:10008289 50                      push eax
:1000828A FF158CF80010            call dword ptr [1000F88C]    *同前面:1000806D之F(2)
:10008290 83C404                  add esp, 00000004
:10008293 6652                    push dx
:10008295 6650                    push ax
:10008297 58                      pop eax        *注册码后8位经转换后内容
:10008298 3345F8                  xor eax, dword ptr [ebp-08]
:1000829B 66B90800                mov cx, 0008
:1000829F 8BD8                    mov ebx, eax
:100082A1 53                      push ebx
:100082A2 83E30F                  and ebx, 0000000F
:100082A5 83FB09                  cmp ebx, 00000009
:100082A8 7602                    jbe 100082AC
:100082AA 33C0                    xor eax, eax        *EAX为0注册失败,必须跳过。

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:100082A8(C)
|
:100082AC 5B                      pop ebx
:100082AD C1EB04                  shr ebx, 04
:100082B0 E2EF                    loop 100082A1
:100082B2 8B7510                  mov esi, dword ptr [ebp+10]
:100082B5 8906                    mov dword ptr [esi], eax
:100082B7 61                      popad
:100082B8 C9                      leave
:100082B9 C20C00                  ret 000C


至此程序注册算法基本上已弄明白,有兴趣的朋友可写注册机了(函数F(1)和F(2)互逆)。