【標題:Tag&Rename 1.7 文章一 :跟蹤,並且製作Loader。(適合初學者)】

看雪資料發表於2000-11-11

【標題:Tag&Rename 1.7 文章一 :跟蹤,並且製作Loader。(適合初學者)】
========================================================================================
軟體      :Tag&Rename 1.7

軟體簡介  :一個可以修改MP3 和 VQF 音樂檔案中的TAG說明的程式。目前尚未支援MP3最新的ID3v2
            但是,仍然是一個很好用的編輯工具。

下載處    :軟體主頁: http://www.softpointer.com/tr.htm
          :版本1.7(若找不到)可以在我這裡下載:
            http://www.geocities.com/mcny_work/orgfile/2000/TagRename17.zip
            (888k bytes  不支援斷點續傳 )

註冊方法  :註冊碼(與名字無關,而且是不可逆演算法,無法計算出註冊碼)

反跟蹤保護 :Asprotect 1.0 加殼
========================================================================================
破解難度        :易 (這裡是指:找出關鍵跳轉,改變它)
去反跟蹤保護難度:易 (這裡是指:使用Loader,有現成的程式碼嘛,不用自己寫!
                      若要自動脫殼的話,有現成的脫殼機(SAC的,我還沒用過,不知效果如何)。
                      若要手工脫殼的話,可以參考http://toye.yeah.net
                      '破解教學'上的相關文章,難度:中)
使用工具        :1) Trw2000 v1.22
                  2) TASM32 5.0(需要3個檔案:import32.lib ,tasm32.exe, tlink32.exe)
目標檔案        :TagRename.exe
關鍵            :找出關鍵跳轉點,製作一個Loader來改變該跳轉(原因:因為軟體經過加殼,無
                  法直接修改目標檔案)
----------------------------------------------------------------------------------------
【注1】 :看雪論壇中,有人曾告訴我:破解是破解,脫殼是脫殼,不能混為一談。 覺得很有
          道理,所以這裡就分成兩個難度度量:破解、去反跟蹤。
【注2】 :編譯連線Loader時,本文沒有使用'資原始檔',所以製作出來Loader不會包含圖示。有
          興趣,你可以自己補上。
【注3】 :本文意在給予不曾製作Loader的朋友一個Loader的製作經驗。並不是說,製作Loader
          才是破解本軟體最佳方法。
========================================================================================
本文作者:McNy@Work
日期     :2000年11月09日
Email    :mcny_work@yahoo.com
        (郵件主題請以"WANTED:McNycn"開始,注意英文字母大小寫,否則我會收不到喔!)



                【目錄】
§====================§
§第一部分:初步追蹤                    §
§第二部分:進一步追蹤,找到關鍵比較點    §
§第三部分:製作Loader,附:程式原始碼    §
§====================§


-------------------------------【第一部分:初步追蹤】-----------------------------------

    首先執行 Trw2000 ,用它載入TagRename.exe 。按下'Load'健後,我們來到trw2000的除錯框中,
按F5,程式繼續執行。然後,TagRename 會出現一個提示框告述你已經使用了幾天,還叫你註冊。選擇
'Unlock',在Yourname中添入姓名,在Code中添入任意文字。(eg, Name: McNy@Work    Code:a )
暫時不要按下OK按鈕。

    然後,按Ctrl+N, 來到trw2000除錯框中。設定斷點,鍵入:bpx hmemcpy  ,回車。(<--這可是
經典動作喔!)按F5,讓程式繼續執行。我們會回到windows 中,按下剛才沒按下的OK鍵。

    程式又被中斷,我們又來到trw2000除錯框中。現在,我們不斷的按F10 ,一直到Error對話方塊出
現(F10 是逐步跟蹤)。其中一個ret處按下F10後會來到地址 00508B49。繼續跟蹤,當用F10越過
00508B76  call 004646EC 後,Error 框出現,告訴你註冊碼不對! 按OK ,會回到Trw2000除錯框。

    很明顯,00508B76 處的call 會顯示error對話方塊。要如何避開它呢?我們向上找,發現00508B80
處的JZ有機會避開Error框,條件是AL=1。(當然,我們到這裡時的AL<>1,因為註冊碼不對嘛!)
        
            ...
        ==>    017F:00508B49    MOV EAX,[EBP-08]        //某一個ret會返回到此。
        017F:00508B4C    LEA EDX,[EBP-04]
                017F:00508B4F    CALL 0408EBC
                017F:00508B54    MOV EAX,[EBP-04]
      **(A1)**  017F:00508B57    CALL 00456510          //處理、計算、比較註冊碼!!!
                                                        //註冊碼正確時,返回AL=1。
      **(A2)**  017F:00508B5C    CMP AL,01        
    ==>    017F:00508B5E    JZ 0508B80        //若AL=1,則可以避開error對話方塊!
                017F:00508B60    LEA ECX,[EBP-0C]
                017F:00508B63    MOV EAX,[00541A98]
                017F:00508B68    MOV EAX,[EAX]
                017F:00508B6A    MOV DX,01D9
                017F:00508B6E    CALL 0046DE40
                017F:00508B73    MOV EAX,[EBP-0C]
        ==>    017F:00508B76    CALL 004646EC          //會出現error對話方塊
                017F:00508B7B    JMP 00508C56
            ...


    聰明的你,一定會想到改變 00508B5C 的比較指令 或者 改變 00508B5E 的條轉指令來達到
避開error對話方塊的目的。但是,這樣做的話只對了一半!因為程式不止在一地方呼叫 call 00456510 。
(我當然是試過才知道嘛!)所以使 call 00456510 的返回結果必定 AL=01才是一勞永逸的方法。

    所以,我們也可以修改 00465610 處的程式碼,使之變成 mov al,01 。 ret。(置AL=1,並馬上返回)
但我們不這樣做,因為這樣做已改變了整個Call的作用,可能會帶來潛在的程式錯誤。我想對原始程
序用最少、最安全的修改來達到我們的目的。

    於是,我們本著這樣的思路來進行追蹤:是什麼造成AL=1?原來是地址xxxxxxxx 處的 EBX=1 時。
哪又是什麼造成 xxxxxxxx 時的EBX=1?原來是地址yyyyyyyy處的 EAX<>0 ,... 就這樣,一直到比較
註冊碼的地點。

---------------------------------第一部分完-----------------------------------------------



-------------------------------【第二部分:進一步追蹤,找到關鍵比較點】-------------------

    我們重新設定所有斷點,而新斷點設定在上述程式碼中有註明**(A1)**處,所call的地址。
即 bc * , 回車。bpx 00456510 ,回車 。 按下F5 。TagRename程式繼續執行。

    按'Unlock'鍵,'OK'鍵。程式又被中斷,我們來到除錯框中,地址是我們剛才設定的斷點處,即
00456510 。不斷按F10一直到過了第一個RET (下面程式碼的 **(A4)** 處)。由於第二個RET 才是真
正的RET,所以我們知道地址004565BD處的EBX 決定了即將返回的EAX值(我們要使EAX=1)!
    
    於是我們把注意力轉移到EBX。再往上面幾行看看,發現00456598 處將1 賦值給BL。但是為什麼
我們的是EBX=0 ? 這是因為 00456594 處的JZ 跳轉成功!(下面程式碼的**(A3)** )

    很明顯00456594就是我們要改的地方了。只要將 JZ 00456598 去掉即可(即,不管真正結果如
何,我們都令註冊碼正確(BL=1) )。鍵入 code on,回車。先用紙記下00456594處開始的10 Bytes
的程式碼(製作LOADER時會用到:即74 02 B3 01 8B 45 F8 E8 C8 C9)。
   
    現在,用兩個nop取代00456594的JZ 00456598。我們鍵入a 456594,回車。nop,回車。nop,兩
個回車。可以看見,00456594處的程式碼變成兩個nop 了。

    讓程式繼續執行前,我們應該清除所有斷點。故鍵入bc * ,回車。按下F5。TagRename程式繼續
執行。程式出現Error框(我們的修改在下一次才生效)。

    按'Unlock'鍵,'OK'鍵。出現一個對話方塊感謝我們註冊 8^)  。我們的追蹤也到此結束了。選擇
TagRename 程式中的HELP > ABOUT,出現的ABOUT對話方塊會顯示 Register to: McNy@Work 。


            ...
        ==>    017F:00456510    PUSH EBP                //此為斷點處,程式在這裡暫停。
                017F:00456511    MOV EBP,ESP
            ...
            ...
                017F:0045655F    MOV EAX,ESI
                017F:00456561    CALL 00402F68
                017F:00456566    LEA EDX,[EBP-04]
                017F:00456569    LEA EAX,[EBP-18]
                017F:0045656C    CALL 00456460          //由輸入S/N,產生"輸入碼生成串"的
                                                        //主要呼叫。
                017F:00456571    MOV DL,01
                017F:00456573    MOV EAX,[00410060]
                017F:0045657D    MOV [EBP-08],EAX
                017F:00456580    LEA EAX,[EBP-08]
                017F:00456583     CALL 00456404
                017F:00456588    MOV EDX,[EBP-04]
                017F:0045658B    MOV EAX,[EBP-08]
                017F:0045658E    MOV ECX,[EAX]
                017F:00456590    CALL NEAR [ECX+50]  //比較"註冊碼生成串'和兩百餘個
                                                    //"正確的串"。
                                                    //若全部不匹配返回EAX=FFFFFFFF
                                                    //(內部會呼叫 Kernel32!CompareStringA)
                017F:00456593    INC EAX            
      **(A3)**  017F:00456594    JZ 0456598              //EAX=0 時跳轉。我們改這裡!!!
        ==>    017F:00456598    MOV BL,01              //若上一行不跳轉,則註冊碼正確。
                017F:0045659B    CALL 00402F68
                017F:004565A0    XOR EAX,EAX
                017F:004565A2     POP EDX
                017F:004565A3    POP ECX
                017F:004565A4    POP ECX
                017F:004565A5    MOV [FS:EAX],EDX
                017F:004565A8    PUSH DWORD 004565BD
                017F:004565AD    LEA EAX,[EBP-04]
                017F:004565B0    CALL 00403CEC
        ==>    017F:004565B5    RET                    //去017f:004565BD  !!!
                017F:004565B6    JMP 004036C8
                017F:004565BB    JMP SHORT 004565AD
      **(A4)**  017F:004565BD    MOV EAX,EBX            //哈!原來是將EBX賦值給EAX。
                017F:004565BF    POP ESI
                017F:004565C0    POP EBX
                017F:004565C1    POP ESP,EBP
                017F:004565C3    POP EBP
                017F:004565C4    RET                    //返回到**(A2)**處


---------------------------------第二部分完-----------------------------------------------


-------------------------------【第三部分:製作Loader】-----------------------------------

本文采用R!SC 的Loader原始碼,並改變相應的地方:

(一)我們先整理由第一、二部分的跟蹤所得的一些資料:
    目標程式名:TAGRENAME.EXE
    修改的地址:00456594h         (h 代表十六進位制數)
    所作修改  :7402 ==> 9090        (nop的程式碼是90)
    修改位元組數:2             
    從00456594起的10個位元組為:74,02,B3,01,8B,45,F8,E8,C8,C9

(二)步驟:
        1)在TASM的目錄中,建立一個檔名為loader.asm 的文字檔案(.asm是副檔名)

        2)將下面兩行 ;+++++++++++++ 之間的程式碼全部複製貼上到loader.asm中,儲存檔案。
    
        3)將我們(一)中的所有資料填在loader.asm中**(B1)**處的相應位置。
        在**(B2)**處,填入延時,先假定1000 吧。若不能正常使用則在調整。
        (調整原則:Loader 可以載入TagRename,但程式依然沒註冊。 ==> 減少延時 (eg: 800)
                Loader 不能正常執行,出現ERROR框。          ==> 增加延時 (eg:1200)
         )    
    
        4)在DOS Prompt 中 ,進入TASM的目錄中(筆者的目錄為:e:\tasm5),依次鍵入以下
        兩行命令。
        tasm32 /ml loader.asm                        (編譯)
        tlink32 /Tpe /aa /c loader,loader,,e:\tasm5\import32.lib    (連線)
       
        5)成功的話,會在當前目錄產生一個名為loader.exe的檔案,將它複製到Tag&Rename的
        目錄中,即可。執行Loader,看看能不能正常使用,不能則再次調整延時,重新編譯。


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Requires Tasm 5.0 & import32.lib to compile

; tasm32 /ml loader.asm
; tlink32 /Tpe /aa /c loader,loader,, <path to> import32.lib
; replace <path to> with whatever...

.386P
Locals
jumps

.Model Flat ,StdCall


;Define the needed external functions and constants here.

Extrn      MessageBoxA:PROC 
Extrn      WaitForInputIdle:PROC

Extrn      WriteProcessMemory:PROC
Extrn      ReadProcessMemory:PROC
Extrn      CreateProcessA:PROC
Extrn      CloseHandle:PROC
Extrn      ExitProcess:PROC

;-=-Normal data-=-=-=-=-=-=-=-=-=-=-=-=-=
.Data                                       
CSiR_Tag            db 'Tag&Rename 1.7 (Loader),by McNy@Work ',0
CSiR_Error          db 'Error!!!',0
CSiR_Error1        db 'Something wrong!!...',0
OpenERR_txt        db 'CreateProcess Error :(',0
ReadERR_txt        db 'ReadProcessMemory Error :(',0
WriteERR_txt        db 'WriteProcessMemory Error :P',0
VersionERR_txt      db 'Incorrect Version of application :(',0
CSiR_ProcessInfo    dd 4 dup (0)        ;process handles
CSiR_StartupInfo    db 48h dup (0)      ;startup info for the process were opening
CSiR_RPBuffer      db 10h dup (0)      ;read buffer, for checking data

;-=-Patch datas-=-=-=-=-=-=-=-=-=-=-=-=-=

CSiR_AppName  db 'TAGRENAME.EXE',0          ; **(B1)**
mcny          dd 00456594h                  ; address to read data from for version checking
sizeof        dd 10                        ; in the new process

checkbytes    db 074h,002h,0b3h,001h,08bh  ; the bytes to check for
              db 045h,0f8h,0e8h,0c8h,0c9h  ; if there not there, we have the wrong version??
;-----
patch_data_1  db 90h,90h
patch_size_1  dd 2
patch_addr_1  dd 00456594h

.Code                                 
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Main:
    push    offset CSiR_Tag
    mov    dword ptr [CSiR_StartupInfo],44h ; (the size in bytes of the structure)
    push    offset CSiR_ProcessInfo          ; Typedef struct _PROCESS_INFORMATION
    push    offset CSiR_StartupInfo          ; Pointer to STARTUPINFO structure
    push    0
    push    0
    push    20h                              ; Creation flags
    push    0
    push    0
    push    0
    push    0
    push    offset CSiR_AppName              ; Pointer to name of executable mod
    call    CreateProcessA
    test    eax,eax
    jz      OpenERR

Wait4Depack:
    push    1000                            ; **(B2)**   
                                            ; Timeout (in milliseconds, -1 = infinate)
                                            ; 原作者為 LARGE-1
                                            ; 我的PC上可以用800到1500。你自己設一個數吧!
    push    dword ptr [CSiR_ProcessInfo]
    call    WaitForInputIdle
   
Check_Data:

    push    0                              ; BytesRead
    push    dword ptr [sizeof]              ; Length
    push    offset CSiR_RPBuffer            ; Destination (to read them to)
    push    dword ptr [mcny]                ; Source
    push    dword ptr [CSiR_ProcessInfo]    ; Process whose memory we are to read
    call    ReadProcessMemory
    test    eax,eax
    jz      ReadERR
    ;...
    ;int 03 ;-)
    cld
    lea    esi, CSiR_RPBuffer
    lea    edi, checkbytes
    mov    ecx, 10
    rep    cmpsb
    jnz    VersionERR 
    ;...
Patch_the_mother:
    push    0                              ; Pointer to byteswritten (i like null though)
    push    dword ptr [patch_size_1]        ; Length
    push    offset patch_data_1            ; Source
    push    dword ptr [patch_addr_1]        ; Destination
    push    dword ptr [CSiR_ProcessInfo]    ; Process whose memory we are to patch
    call    WriteProcessMemory              ; Call Kernel32!WriteProcessMenory
    test    eax,eax
    jz      WriteERR
   
Close_This_app:
    push    dword ptr [CSiR_ProcessInfo]
    call    CloseHandle
    push    dword ptr [CSiR_ProcessInfo+4]
    call    CloseHandle
   
Exit_Proc:
    Push LARGE-1
    Call ExitProcess

;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
VersionERR:
    lea    eax, VersionERR_txt
    jmp    abort
ReadERR:
    lea    eax, ReadERR_txt
    jmp    abort
OpenERR:
    lea    eax, OpenERR_txt
    jmp    abort
WriteERR:
    lea    eax, WriteERR_txt
abort:
    push 0
    push offset CSiR_Error                  ; Title
    push eax                                ; Message
    push 0
    call MessageBoxA

    jmp Close_This_app
   
End Main
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

---------------------------------第三部分完-----------------------------------------------

==========================================================================================
全文結束(這是我的處女作,有不對的地方,還望大家多多指正與包涵!)

相關文章