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 <dd	?>
	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 <dd	?>
	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 <dd	0>		; streams as it would be on file we must
	@pushvar <dd	0>		; 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 <victim_file>: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 <victim_file>: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	<dd	?>
	push	eax
	push	eax
	push	4
	@pushvar	<dd	1>		;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	<dd	?>
	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 <dd	8>
	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.