PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [MASM]Loaders/Memorypatcher (N0iseTools, PixelStealer und Codesoft)



EBFE
14.08.2010, 18:18
Quellcode von Loadern/Memorypatchern:

N0iseTools - ein Beispiel für Codeinjection + EAT Hook von Funktionen.
Oder: wie man .NET Protections umgeht, ohne .NET auch nur anzufassen :D



;#############################
;N0ise Tools Loader
;autor: EBFE
;mail: ebfe@inbox.ru
;#############################
.386
.model flat, stdcall
option casemap :none

include windows.inc
include masm32.inc

include user32.inc
include kernel32.inc
include psapi.inc
includelib psapi.lib
include advapi32.inc
includelib advapi32.lib
includelib masm32.lib
includelib user32.lib
includelib kernel32.lib



.data
kernel32 db "kernel32.dll",0
crypt_get_hash_param db "CryptGetHashParam",0
Error_starting db "Exe konnte nicht gefunden/gestartet werden!",0
Error_alloc db "Speicher konnte nicht reserviert werden!",0
Error_injection db "Konnte Code nicht injecten!",0

count dd 0

.data?
process PROCESS_INFORMATION <>
procstart STARTUPINFO <>
injmem dd ?
buffer db(256) ?

.code
;#### eigentliche Injection ####
Injection::
;db 0ebh,0feh
call inj_delta
mydata:
temp dd 0
advapi32 db "advapi32.dll",0
cryptGetHashParamEAT dd 0

loadlib_addr dd 0
virtual_protect dd 0
exit_thread dd 0

hook:
db 90h, 090h
;call original func
push [esp + 14h]
push [esp + 14h]
push [esp + 14h]
push [esp + 14h]
push [esp + 14h]
db 0e8h ;CALL Opcode
original_func: ;
dd 00000000 ;Distanz muss vor der Ausführung reingepatcht werden
test eax, eax ; return on error
jnz @f
ret 14h
@@:
pushad
call delta
hook_data:
original_hwid db 48h,0d3h,0cbh,0c8h,0cah,0b8h,2ah,0b6h
db 0dah,8ah,00,0a6h,69h,20h,34h,73h ;db(32) dup (0)
user_hwid db 0f9h,00h,30h,58h,0a8h,0cch
db 0b1h,3ah,34h,66h,1ch,4fh,1bh,45h,82h,48h;(16) dup (0)
delta:
pop edi
;param 3 holen, pushad beachten
mov edx,[esp + 20h + 0Ch]
test edx, edx
jz ende
lea ebx, [edi + (user_hwid - hook_data)]
; vergleiche den Buffer mit HWID
mov eax, dword ptr[ebx]
cmp [edx],eax
jne ende

mov eax, dword ptr[ebx + 4]
cmp [edx + 4], eax
jne ende

mov eax, dword ptr[ebx + 8]
cmp [edx + 8], eax
jne ende

mov eax, dword ptr[ebx + 12]
cmp [edx + 12], eax
jne ende
;ok, beide gleich, schreibe nun original ID in den Buffer rein
lea ebx, [edi + (original_hwid - hook_data)]
mov eax, [ebx]
mov [edx], eax
mov eax, [ebx + 4]
mov [edx+4], eax
mov eax, [ebx + 8]
mov [edx+8], eax
mov eax, [ebx + 12]
mov [edx+12], eax

ende:
popad
ret 14h

db 0ebh,0feh
db 5eh,05h,73h,21h
inj_delta:
pop edi ; mydata Address
;call LoadLibraryA(Advapi32)
lea eax, [edi + (advapi32 - mydata)]
push eax
call dword ptr [edi + (loadlib_addr - mydata)]
; in eax ImageBase of ADVAPI32 DLL
mov esi, [edi + (cryptGetHashParamEAT - mydata)]
mov ebx, eax ; ebx = ImageBase of ADVAPI32 DLL
add esi, eax ; in eax = EAT Address of cryptGetHashParam
; set EAT writeable:
;invoke VirtualProtectEx,process.hProcess,lstrcmpEAT,4,PAG E_EXECUTE_READWRITE,offset procstart ;procstart==temp Variable
push edi ; temp
push PAGE_EXECUTE_READWRITE
push 4
push esi
call dword ptr[edi + (virtual_protect - mydata)]
;backup original address:
mov eax, [esi]
add eax, ebx
;berechne JMP distanz von inj code zur API Function
lea edx, [edi + (original_func - mydata + 4)]
sub eax, edx
mov [edi + (original_func - mydata)], eax
;patch EAT
lea eax, [edi + (hook - mydata)];
sub eax, ebx ; EAT Hookaddr = hook addr - ImageBase
mov [esi], eax
; done !:)
call dword ptr[edi + (exit_thread - mydata)]
db 0, 0, 0, 0
Injection_end::

;#### main
start:

invoke GetCL,1,offset buffer
cmp eax,1
jne Exit
;##### Starte Exe ####
invoke CreateProcess,offset buffer,0,0,0,FALSE,CREATE_SUSPENDED,0,0,offset procstart,offset process
test eax,eax
jnz @f
mov eax,offset Error_starting
jmp Error
@@:
; LoadLibrary und VirtualProtect Adressen über eigene IAT bestimmen
mov eax, LoadLibrary
mov eax, [eax+2]
mov eax, [eax]
mov loadlib_addr, eax
mov eax, VirtualProtect
mov eax, [eax+2]
mov eax, [eax]
mov virtual_protect, eax
mov eax, ExitThread
mov eax, [eax + 2]
mov eax, [eax]
mov exit_thread, eax
;##### hole cryptGetHashParam Adresse in EAT
invoke LoadLibrary,offset advapi32
mov ebx, eax
mov esi,offset crypt_get_hash_param
mov ecx,sizeof crypt_get_hash_param
call getproc ;
; get RVA only!
sub eax, ebx
mov cryptGetHashParamEAT,eax
invoke LoadLibrary, offset kernel32
mov ebx, eax

;#### warte, bis kernel32 verfügbar ist ####
wait_loop:
add count,1
cmp count,10000 ;max. 10 Sek warten
jb @f
mov eax, offset Error_injection
jmp Error
@@:
invoke ResumeThread,process.hThread
invoke Sleep,1
invoke SuspendThread,process.hThread
invoke GetModuleInformation,process.hProcess,ebx,offset procstart,sizeof procstart;procstart=TEMP Var
test eax,eax
jz wait_loop



;##### Alloziere Speicher in ZielExe ####
invoke VirtualAllocEx,process.hProcess,0,offset Injection_end-offset Injection,MEM_COMMIT,PAGE_EXECUTE_READWRITE
test eax,eax
jnz @f
mov eax,offset Error_alloc
jmp Error
@@:
mov injmem,eax


;##### Schreibe Injection
invoke WriteProcessMemory,process.hProcess,injmem,offset Injection,Injection_end-Injection,offset procstart
test eax,eax
jnz @f
inj_error:
mov eax,offset Error_injection
jmp Error
@@:

invoke CreateRemoteThread,process.hProcess,0,0,injmem,0,0 ,0
test eax,eax
jz inj_error

;##### Setze Zielexe fort:
invoke ResumeThread,process.hThread

Exit::
invoke ExitProcess,0
ret


;###########################
Error:
invoke MessageBox,0,eax,0,MB_ICONERROR
;eigentlich müsste noch ein VirtualFreeEx rein, aber da der Prozess
;eher terminiert wird, verzichte ich auf den Aufwand
invoke TerminateProcess,process.hProcess,0

jmp Exit

;##########################



;##### Parst die Export Table und gibt Adresse der Funktion in EAT zurück
getproc:
;erwartet: DLL Base in EAX,in ECX Stringlänge, in ESI string adresse
;rückgabe: Export Adresse in EAX
push ebp
push edi
mov edx,[eax+3ch]
lea edx,dword ptr [eax+edx+78h]
;nun EDX=Exportdirektory VA
mov edx,[edx] ;RVA holen
add edx,eax ;VA zeiger auf ExportDirectory Eintrag
push edx
mov ebp,[edx+18h] ;Anzahl der Namen
mov edx,[edx+20h] ;in EDX: zeiger auf *AdressOfNames
add edx,eax ;Erster Eintrag des AdressOfNames Arrays
cld
search:
mov edi,dword ptr [edx+ebp*4-4]
add edi,eax
push ecx
push esi
repe cmpsb
pop esi
pop ecx
jz found
dec ebp
jnz search
;nicht gefunden:
mov eax,-1
pop ebp
pop ebp ;ebp wiederherstellen+Stackframe
ret
found:
;nun in EBP Funktionsnummer

pop edx ;zeiger auf ExportDirectory Eintrag
push edx
mov edx,dword ptr [edx+24h] ;*AdressOfOrdinals RVA

add edx,eax ;AdressOfOrdinals VA
movzx ecx,word ptr [ebp*2-2+edx]; lese index der Funktion aus der *AdressOfOrdinals
pop edx
mov edx,dword ptr [edx+1ch]
add edx,eax
lea eax,dword ptr [ecx*4+edx] ;VA Adresse in exporttable
;add eax,edx ;+ImageBase=VA
pop edi
pop ebp
ret

end start
make.bat


SET INCLUDE=C:\masm32\include
SET LIB=C:\masm32\lib
SET PATH=C:\masm32\bin
SET NAME=loader


if exist %NAME%.obj del %NAME%.obj
if exist %NAME%.exe del %NAME%1.exe

ml /c /coff /nologo %NAME%.asm
Link /SUBSYSTEM:WINDOWS /FILEALIGN:512 /MERGE:.data=.text /MERGE:.rdata=.text /SECTION:.text,RWE %NAME%.obj

pause

der Code des Builders wird nicht gepostet, da dieser nur 3 (durchaus wichtige) Aufgaben hatte: NFO anzeigen, Musik abspielen und die eingegebene HWID in den "hwid_user" Byte-Array (Zeile 74) zu schreiben (vorher natürlich Str2Hex Umwandlung durchzuführen). Das kann man eigentlich auch gut per Hand machen. D.h nichts wirklich interessantes ;)

PíxelStealer - im wesentlichen interessant, weil PixelStealer 1.5.5 mit Themida geschützt ist:



;#############################
;Pixelloader
;autor: EBFE
;mail: ebfe@inbox.ru
;#############################
.386
.model flat, stdcall
option casemap :none

include windows.inc
include masm32.inc
include user32.inc
include kernel32.inc
include psapi.inc
include advapi32.inc
includelib psapi.lib

includelib advapi32.lib
includelib masm32.lib
includelib user32.lib
includelib kernel32.lib



.data
filename db "pixel Stealer.exe",0
Error_starting db "'Pixel Stealer.exe' konnte nicht"
db " gefunden/gestartet werden!",0
Error_patch db "Konnte den Code nicht patchen!",0
count dd 0
BUFFER dd 0
;# Format: DWORD: Adresse
;4Bytes: Patch

; HWID "build" Funktion
patch dd 4BA570h
db 0b8h,0a0h,92h,40h
dd 4BA574h
db 00, 0c3h,90h,90h
;protector antis
dd 6B1E9Fh
db 0EBh,53h, 90h, 90h
;erster vbaCmp
dd 4b9ef3h
db 33h, 0ffh, 0f7h,0dfh
;überspringe den HTTP check
dd 4b9519h
db 0e9h,88h,00,00
dd 4b951ch
db 00,00,90h,90h
;überspringe sicherheitshalber den ersten "error" Check
dd 4b95c8h
db 0ebh,06h,90h,90h
;überspringe den zweiten "error" Check
dd 4b9689h
db 0ebh,08h,90h,90h
;dritter Check, muss genoppt werden
dd 4b96edh
db 90h,90h,68h,20h
;weiterer "error" Check:
dd 4b9732h
db 0ebh, 06h,90h,90h
;noch ein "error" Check, langsam wird es lästig
dd 4b9762h
db 74h,04h, 90h,90h

;und den Namen nicht zu vergessen:
dd 42ed6eh
db "Olly"
dd 42ed72h
db "Dbg",0

PATCH_SIZE EQU ($ -patch)/8
%echo @CatStr(<PATCH_SIZE = >,%(PATCH_SIZE))



.data?
process PROCESS_INFORMATION <>
procstart STARTUPINFO <>
TIME equ 1
TEMP dd ?

.code


;#### main
start:

;##### Starte Exe ####
invoke CreateProcess,offset filename,0,0,0,FALSE,
CREATE_SUSPENDED,0,0,offset procstart,offset process
test eax,eax
jnz @f
mov eax,offset Error_starting
jmp Error
@@:

;#### warte, bis Exe entpackt wurde ####
wait_loop:
add count,TIME
cmp count,10000 ;max. 10 Sek warten
jb @f
mov eax, offset Error_patch
jmp Error
@@:
invoke ResumeThread, process.hThread
invoke Sleep,TIME
invoke SuspendThread, process.hThread
; lese Code an der ersten Patchstelle
invoke ReadProcessMemory, process.hProcess, [patch],
offset BUFFER, 4, offset TEMP

; wenn eingelesene Bytes gleich 0 sind, dann wurde der Code
; von Themida noch nicht entpack
cmp DWORD PTR[BUFFER], 0
je wait_loop

;#### setze Codebereich auf Beschreibbar+Ausführbar
;#### sonst schlägt der Patchversuch fehl
invoke VirtualProtectEx,process.hProcess, 0401000h, 01E5000h,
PAGE_EXECUTE_READWRITE,
offset TEMP
test eax,eax
jnz @f
mov eax, offset Error_patch
jmp Error
@@:


;##### Patchen ####
mov edi, offset patch
mov esi, PATCH_SIZE
patch_loop:
lea eax,[edi+4]
invoke WriteProcessMemory,process.hProcess,
[edi], eax ,4,
offset TEMP
add edi,8
dec esi
jnz patch_loop

test eax,eax
jnz @f
mov eax,offset Error_patch
jmp Error
@@:


;##### Setze Zielexe fort:
invoke ResumeThread,process.hThread

Exit::
invoke ExitProcess,0
ret


;###########################
Error:
invoke MessageBox,0,eax,0,MB_ICONERROR
invoke TerminateProcess,process.hProcess,0
jmp Exit

;##########################

end start

make.bat
die gleiche, wie oben gepostet
CodeSoft PW Stealer 0.5 - ein generischer Loader, einfach mal vollständigkeitshalber mitgeliefert (zudem verwendete CodeSoft ASProtect zum Schutz) ;)



;Autor: EBFE
;mail: ebfe@inbox.ru
.386
.model flat, stdcall
option casemap :none

include windows.inc
include masm32.inc

include user32.inc
include kernel32.inc
include psapi.inc
includelib psapi.lib
include advapi32.inc
includelib advapi32.lib

includelib masm32.lib

includelib user32.lib
includelib kernel32.lib



.data
kernel32 db "kernel32.dll",0
filename db "codesoft.exe",0
lstrcmp_ db "lstrcmpA",0
Error_starting db "Codesoft.exe konnte nicht gefunden/gestartet werden!",0
Error_alloc db "Speicher konnte nicht reserviert werden!",0
Error_protect db "Konnte Kernel32.dll nicht patchen!",0
Error_injection db "Konnte Code nicht injecten!",0
count dd 0

.data?
process PROCESS_INFORMATION <>
procstart STARTUPINFO <>
lstrcmpEAT dd ?
injmem dd ?
newEAT dd ?
.code
;#### eigentliche Injection ####
Injection::
;db 0ebh,0feh
call @f
original_lstrcmp dd 0
@@:
;esp+4 = 2 Parameter auf ESP+12
;heuristik: prüfe ob 2 Parameter aus Exebereich:
mov eax,[esp+12]
cmp eax,400000h
jl @f
cmp eax,500000h
jg @f
;ok, prüfe ob in beiden Parameter mindestens 4 dezimale Zahlen stehen:
mov edx,[eax]
and edx, 0c0c0c0c0h
jnz @f
mov ecx,[esp+8]
mov edx,[ecx]
and edx,0c0c0c0c0h
jnz @f
;suche noch nach einem -
searchloop:
movzx ecx,byte ptr[eax]
inc eax
cmp cl,'-'
je serial
test ecx,ecx
jz @f
jmp searchloop
serial:
;ok, es wird die Serial geprüft: 0 zurückgeben
pop eax
xor eax,eax
ret 8

;sonst: irgendwas anderes - rufe original auf
@@:
pop eax
jmp dword ptr[eax]
Injection_end::

;#### main
start:

;##### Starte Exe ####
invoke CreateProcess,offset filename,0,0,0,FALSE,CREATE_SUSPENDED,0,0,offset procstart,offset process
test eax,eax
jnz @f
mov eax,offset Error_starting
jmp Error
@@:
;##### hole lstrcmpA Adresse in EAT
invoke LoadLibrary,offset kernel32
mov ebx,eax
mov esi,offset lstrcmp_
mov ecx,sizeof lstrcmp_
call getproc ;
mov lstrcmpEAT,eax

mov eax,[eax] ;eigentliche RVA der Funktion
add eax,ebx ;+ImageBase=VA (äquivalent zum GetProcAddr Aufruf)
mov original_lstrcmp,eax

;#### warte, bis kernel32 verfügbar ist ####
wait_loop:
add count,1
cmp count,10000 ;max. 10 Sek warten
jb @f
mov eax, offset Error_injection
jmp Error
@@:
invoke ResumeThread,process.hThread
invoke Sleep,1
invoke SuspendThread,process.hThread
invoke GetModuleInformation,process.hProcess,ebx,offset procstart,sizeof procstart;procstart=TEMP Var
test eax,eax
jz wait_loop

;#### setze EAT auf "beschreibbar"
invoke VirtualProtectEx,process.hProcess,lstrcmpEAT,4,PAG E_EXECUTE_READWRITE,offset procstart ;procstart==temp Variable
test eax,eax
jnz @f
mov eax, offset Error_injection
jmp Error
@@:

;##### Alloziere Speicher in ZielExe ####
invoke VirtualAllocEx,process.hProcess,0,offset Injection_end-offset Injection,MEM_COMMIT,PAGE_EXECUTE_READWRITE
test eax,eax
jnz @f
mov eax,offset Error_alloc
jmp Error
@@:
mov injmem,eax

;##### Patche EAT ####
sub eax,ebx ;Adresse der Injection - ImageBase der Kernel32 == Differenz für EAT Patch
mov newEAT,eax
invoke WriteProcessMemory,process.hProcess,lstrcmpEAT,off set newEAT,4,offset procstart
test eax,eax
jnz @f
mov eax,offset Error_protect
jmp Error
@@:

;##### Schreibe Injection
invoke WriteProcessMemory,process.hProcess,injmem,offset Injection,Injection_end-Injection-4,offset procstart
test eax,eax
jnz @f
mov eax,offset Error_injection
jmp Error
@@:

;##### Setze Zielexe fort:
invoke ResumeThread,process.hThread

Exit::
invoke ExitProcess,0
ret


;###########################
Error:
invoke MessageBox,0,eax,0,MB_ICONERROR
invoke TerminateProcess,process.hProcess,0
jmp Exit

;##########################



;##### Parst die Export Table und gibt Adresse der Funktion in EAT zurück
getproc:
;erwartet: DLL Base in EAX,in ECX Stringlänge, in ESI string adresse
;rückgabe: Export Adresse in EAX
push ebp
push edi
mov edx,[eax+3ch]
lea edx,dword ptr [eax+edx+78h]
;nun EDX=Exportdirektory VA
mov edx,[edx] ;RVA holen
add edx,eax ;VA zeiger auf ExportDirectory Eintrag
push edx
mov ebp,[edx+18h] ;Anzahl der Namen
mov edx,[edx+20h] ;in EDX: zeiger auf *AdressOfNames
add edx,eax ;Erster Eintrag des AdressOfNames Arrays
cld
search:
mov edi,dword ptr [edx+ebp*4-4]
add edi,eax
push ecx
push esi
repe cmpsb
pop esi
pop ecx
jz found
dec ebp
jnz search
;nicht gefunden:
mov eax,-1
pop ebp
pop ebp ;ebp wiederherstellen+Stackframe
ret
found:
;nun in EBP Funktionsnummer

pop edx ;zeiger auf ExportDirectory Eintrag
push edx
mov edx,dword ptr [edx+24h] ;*AdressOfOrdinals RVA

add edx,eax ;AdressOfOrdinals VA
movzx ecx,word ptr [ebp*2-2+edx]; lese index der Funktion aus der *AdressOfOrdinals
pop edx
mov edx,dword ptr [edx+1ch]
add edx,eax
lea eax,dword ptr [ecx*4+edx] ;VA Adresse in exporttable
;add eax,edx ;+ImageBase=VA
pop edi
pop ebp
ret

end start

make.bat:
die gleiche wie oben