• 标 题:转:Patching of Packed/Protected files...(Writing a Loader) (13千字)
  • 作 者:dm955
  • 时 间:2002-3-14 3:04:21
  • 链 接:http://bbs.pediy.com

Patching of Packed/Protected files...(Writing a Loader) - by R!SC - With Loader-Source (Assembler)
Posted on Wednesday, March 13 @ 15:37:26 CET    [  |  ] 



There are three ways to defeat packed/protected files

#1:Unpack them, then patch the 'exe
#2:Writing a loader, that waits for the program to unpack, then patches the memory
#3:Patching the packed file to patch itself when unpacked :)





In my eyes, they are like patching a reg code(#1), ripping a reg code(#2), and writing a
keygen(#3), well, i never knew how to write a loader, so i decided to reverse engineer another
crackers(Hayras's) loader/memory patcher, and re-write it in win32asm. It seemed like a good
idea at the time :) and proves to be very useful indeed, more leet than ripping a reg code, as
you may see....

aND sO tHE tUTORIAL bEGINS!
-=-=-=-=-=-=-=-=-=-=-=-=-=-

Target Program: NeoTrace v1.22
Url: http://www.neoworx.com
Protection: Packed with Neolite & a little NAG when u want to exit

Ok, as i dont really like tutorials on cracking as such, and to make a long story short, run
NeoTrace, enter softice

bpx DialogBoxParamA

Click on quit, BOOM, back into softice...hit F11, click on the OK button BOOM?, in softice
again, note the cmp eax, 01, and eax is zero? the jnz 40A67F gets taken if eax was not '1', ok,
for killing this, we skip the call to DialogBoxParamA, so in softice, bpx DialogBoxParamA again,
hit F11 when it breaks, click 'OK', use ctrl + cursor up to move up a few lines...


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040A5FF(C)
|
:0040A60F 8B0DF4404200            mov ecx, dword ptr [004240F4]
:0040A615 8B15543F4200            mov edx, dword ptr [00423F54]
:0040A61B 6A00                    push 00000000
:0040A61D 68E08C4000              push 00408CE0
:0040A622 51                      push ecx

* Possible Reference to Dialog: DialogID_00A4
                                  |
:0040A623 68A4000000              push 000000A4
:0040A628 52                      push edx

* Reference To: USER32.DialogBoxParamA, Ord:008Eh
                                  |
:0040A629 FF15D8B24100            Call dword ptr [0041B2D8]
:0040A62F 83F801                  cmp eax, 00000001
:0040A632 754B                    jne 0040A67F

See the first push? at 40A61B? Thats the first paramater for the function, so we want to jump
from there to 40A67F, where we would be if OK was pressed? in softice, type in 'a 40A61B', then
'jmp 40A67F', write dowm the codes for the jump instruction (EB62), and the address of it
(40A61B). Just a quick test that it works...

Run NeoTrace again, bpx getwindowtexta, type in an address to trace, click on the trace button,
hi softice :), Hit F11, make sure your inside of Neotrace, then type in 'e 40a61b eb,62' to do
our patch. 'bc *','x', click on quit, no NAG! kewl...

Right oh, easy crack, lets see a loader for it then :)


;-=-Loader.asm-=-=-cut & paste me :)=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

; based on original loader.exe by Hayras [tNO '98] used in
; Hayras's Neolite v1.22 memory patcher.
;
; Special thanks to TNO for graciously allowing me to use this
; source on behalf of Hayras, who has now retired from the scene.

; Yes, Hayras's loader reversed by R!SC, then totally re-written
; & released to the public, so everyone can learn this shit :)

; Requires Tasm 5.0 & import32.lib to compile

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

; (c)1999 R!SC (see what i do instead of cracking...duh) yey Prophecy!


.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 ' PE LOADER & CRACKER---R!SC 1999 ',0
CSiR_Error          db 'Error!!!',0
CSiR_Error1        db 'Something fucked up...',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 'NEOTRACE.EXE',0
fuck          dd 40a61bh        ; address to read data from for version checking
sizeof        dd 10            ; in the new process

checkbytes    db 06ah,0,068h,0e0h,08ch  ; the bytes to check for
              db 040h,0,051h,068h,0a4h  ; if there not there, we have the wrong version??

patch_data_1  db 0ebh,62h
patch_size_1  dd 2
patch_addr_1  dd 40a61bh

.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    LARGE-1                        ; Timeout (in milliseconds, -1 = infinate)
    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 [fuck]                ; 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
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


This basically loads the 'exe, the WaitForInputIdle function waits until the given process is
waiting for user input with no input pending, then patches the memory, then carrys on running
the process :)

Its pretty easy code to follow, and with just alterations of the 'patch datas' section, can be
fixed to patch almost any program :)

If you fancy reversing a patch for neotrace, to make the packed version patch itself, get mine
from http://www.gz.ee/cracks/n.htm, if you fancy reversing Hayras's loader yourself, thats
availble from http://zor:code58@www.zor.org/tno/n.html


I know that WaitForInputIdle is not the best way to tell when a program has
depacked/deprotected itself, and if your having problems with it patching the memory after it
should have done, you can change the timeout value.

With this loader, i have patched neolite & pecrypt so far, i know others will work, but i havent
tested them yet...


love R!SC








Note:
;-=-Loader.asm-=-=-cut & paste me :)=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

; based on original loader.exe by Hayras [tNO '98] used in
; Hayras's Neolite v1.22 memory patcher.
;
; Special thanks to TNO for graciously allowing me to use this
; source on behalf of Hayras, who has now retired from the scene.

; Yes, Hayras's loader reversed by R!SC, then totally re-written
; & released to the public, so everyone can learn this shit :)

; Requires Tasm 5.0 & import32.lib to compile

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

; (c)1999 R!SC (see what i do instead of cracking...duh) yey Prophecy!


.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 ' PE LOADER & CRACKER---R!SC 1999 ',0
CSiR_Error          db 'Error!!!',0
CSiR_Error1        db 'Something fucked up...',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 'NEOTRACE.EXE',0
fuck          dd 40a61bh        ; address to read data from for version checking
sizeof        dd 10            ; in the new process

checkbytes    db 06ah,0,068h,0e0h,08ch  ; the bytes to check for
              db 040h,0,051h,068h,0a4h  ; if there not there, we have the wrong version??

patch_data_1  db 0ebh,62h
patch_size_1  dd 2
patch_addr_1  dd 40a61bh

.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    LARGE-1                        ; Timeout (in milliseconds, -1 = infinate)
    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 [fuck]                ; 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
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-