⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 29a-7.024

📁 从29A上收集的病毒源码
💻 024
📖 第 1 页 / 共 4 页
字号:

=========================[ Invisibility on NT boxes ]===========================

                      How to become unseen on Windows NT
                      ----------------------------------

                       Author:  Holy_Father <holy_father@phreaker.net>
                       Version: 1.2 english
                       Date:    05.08.2003


=====[ 1. Contents ]============================================================

 1. Contents
 2. Introduction
 3. Files
	3.1 NtQueryDirectoryFile
	3.2 NtVdmControl
 4. Processes
 5. Registry
	5.1 NtEnumerateKey
	5.2 NtEnumerateValueKey
 6. System services and drivers
 7. Hooking and spreading
	7.1 Rights
	7.2 Global hook
	7.3 New processes
	7.4 DLL
 8. Memory
 9. Handle
	9.1 Naming handle and getting type
10. Ports
	10.1 Netstat, OpPorts on WinXP, FPort on WinXP
	10.2 OpPorts on Win2k and NT4, FPort on Win2k
11. Ending



=====[ 2. Introduction ]========================================================

	This document is about technics	of hiding objects, files, services, 
processes etc. on OS Windows NT. These methods are based on hooking Windows API 
functions which are described in my document "Hooking Windows API".
        Everything here was get from my own research during writing rootkit 
code, so there is a chance it can be written more effectively or it can be 
written much more easily. This also involve my implementation.
        Hiding arbitrary object in this document mean to change some system 
functions which name this object in the way they would skip its naming. In 
the case this object is only return value of that function we would return 
value as the object does not exist.
        Basic method (excluding cases of telling different) is that we would 
call original function with original arguments and then we would change its 
output.
        In this version of this text are described methods of hiding files, 
processes, keys and values in registry, system services and drivers, allocated 
memory and handles.



=====[ 3. Files ]===============================================================

        There are serveral possibilities of hiding files in the way OS would 
not see it. We would aim only changing API and leave out technics like those
which play on features of filesystem. It also is much easier because we dont 
need to know how particular filesystem works.


=====[ 3.1 NtQueryDirectoryFile ]===============================================

        Looking for a file on wNT in some directory is based on searching in 
all its files and files in all its subdirectories. For file enumeration is used 
function NtQueryDirectoryFile.

	NTSTATUS 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 FileInformationLength,
		IN FILE_INFORMATION_CLASS FileInformationClass,
		IN BOOLEAN ReturnSingleEntry,
		IN PUNICODE_STRING FileName OPTIONAL,
		IN BOOLEAN RestartScan
	);


        Important parameters for us are FileHandle, FileInformation 
and FileInformationClass. FileHandle is a handle of directory object which 
can be get from NtOpenFile. FileInformation is a pointer on allocated memory, 
where this function write wanted data to. FileInformationClass determines type 
of record written in FileInformation.
        FileInformationClass is varied enumerative type, but we need only 
four values which are used for enumerating directory content:
 
	#define FileDirectoryInformation 1
	#define FileFullDirectoryInformation 2
	#define FileBothDirectoryInformation 3
	#define FileNamesInformation 12


structure of recoed written in FileInformation for FileDirectoryInformation:

	typedef struct _FILE_DIRECTORY_INFORMATION { 
		ULONG NextEntryOffset;
		ULONG Unknown;
		LARGE_INTEGER CreationTime;
		LARGE_INTEGER LastAccessTime;
		LARGE_INTEGER LastWriteTime;
		LARGE_INTEGER ChangeTime;
		LARGE_INTEGER EndOfFile;
		LARGE_INTEGER AllocationSize; 
		ULONG FileAttributes;
		ULONG FileNameLength;
		WCHAR FileName[1];
	} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;


for FileFullDirectoryInformation:

	typedef struct _FILE_FULL_DIRECTORY_INFORMATION {
		ULONG NextEntryOffset;
		ULONG Unknown;
		LARGE_INTEGER CreationTime;
		LARGE_INTEGER LastAccessTime;
		LARGE_INTEGER LastWriteTime;
		LARGE_INTEGER ChangeTime;
		LARGE_INTEGER EndOfFile;
		LARGE_INTEGER AllocationSize;
		ULONG FileAttributes;
		ULONG FileNameLength;
		ULONG EaInformationLength;
		WCHAR FileName[1];
	} FILE_FULL_DIRECTORY_INFORMATION, *PFILE_FULL_DIRECTORY_INFORMATION;


for FileBothDirectoryInformation:

	typedef struct _FILE_BOTH_DIRECTORY_INFORMATION { 
		ULONG NextEntryOffset;
		ULONG Unknown;
		LARGE_INTEGER CreationTime;
		LARGE_INTEGER LastAccessTime;
		LARGE_INTEGER LastWriteTime;
		LARGE_INTEGER ChangeTime;
		LARGE_INTEGER EndOfFile;
		LARGE_INTEGER AllocationSize;
		ULONG FileAttributes;
		ULONG FileNameLength;
		ULONG EaInformationLength;
		UCHAR AlternateNameLength;
		WCHAR AlternateName[12];
		WCHAR FileName[1];
	} FILE_BOTH_DIRECTORY_INFORMATION, *PFILE_BOTH_DIRECTORY_INFORMATION; 


and for FileNamesInformation:

	typedef struct _FILE_NAMES_INFORMATION {
		ULONG NextEntryOffset;
		ULONG Unknown;
		ULONG FileNameLength;
		WCHAR FileName[1];
	} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;


        This function writes a list of these structures in FileInformation. 
Only three vairiables are important for us in any of these structure types.
        NextEntryOffset is the length of particular list item. First item 
can be found on address FileInformation + 0. So the second item is on address 
FileInformation + NextEntryOffset of first one. Last item has NextEntryOffset 
set on zero.
        FileName is a full name of the file.
        FileNameLength is a length of file name.

        If we want to hide a file, we need to tell apart these four types 
and for each returned record we need to compare its name with the one which 
we want to hide. If we want to hide first record, we have to move following 
structures by the size of the first. This will cause the first record would 
be rewritten. If we want to hide another record, we can easily change the value 
of NextEntryOffset of previous record. New value of NextEntryOffset would be 
zero if we want to hide the last record, otherwise the value would be the sum 
of NextEntryOffset of the record we want to hide and of previous record.
Then we should change the value of Unknown of previous record which is prolly 
an index for next search. The value of Unknown of previous record should have 
a value of Unknown of the record we want hide.
        If no record which should be seen was found, we will return error 
STATUS_NO_SUCH_FILE.

	#define STATUS_NO_SUCH_FILE 0xC000000F


=====[ 3.2 NtVdmControl ]=======================================================

	From unknown reason DOS emulation NTVDM can get a list of files also 
with function NtVdmContol.

	NTSTATUS NtVdmControl(        
		IN ULONG ControlCode,
		IN PVOID ControlData
	);

	ControlCode specifies the subfunction which is applied on data in 
ControlData buffer. If ControlCode equals to VdmDirectoryFile this function 
does the same as NtQueryDirectoryFile with FileInformationClass set on 
FileBothDirectoryInformation.

	#define VdmDirectoryFile 6

	Then ControlData is used like FileInformation. The only difference here 
is that we do not know the length of this buffer. So we have to count it 
manually. We have to add NextEntryOffset of all records and FileNameLength 
of the last record and 0x5E as a length of the last record excluding the name 
of the file. Hiding methods are the same as in NtQueryDirectoryFile then.



=====[ 4. Processes ]===========================================================

	Various system info is available using NtQuerySystemInformation.

	NTSTATUS NtQuerySystemInformation(
		IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
		IN OUT PVOID SystemInformation,
		IN ULONG SystemInformationLength,
		OUT PULONG ReturnLength OPTIONAL
	);

	
	SystemInformationClass specifies the type of information which we want 
to get, SystemInformation is a pointer to the function output buffer, 
SystemInformationLength is the length of this buffer and ReturnLength is 
number of written bytes.
	For the enumeration of running processes we use SystemInformationClass 
set on SystemProcessesAndThreadsInformation.

	#define SystemInformationClass 5


	Returned structure in SystemInformation buffer is:

	typedef struct _SYSTEM_PROCESSES { 
		ULONG NextEntryDelta;
		ULONG ThreadCount;
		ULONG Reserved1[6];
		LARGE_INTEGER CreateTime;
		LARGE_INTEGER UserTime;
		LARGE_INTEGER KernelTime;
		UNICODE_STRING ProcessName; 
		KPRIORITY BasePriority;
		ULONG ProcessId;
		ULONG InheritedFromProcessId;
		ULONG HandleCount;
		ULONG Reserved2[2];
		VM_COUNTERS VmCounters;
		IO_COUNTERS IoCounters;  // Windows 2000 only
		SYSTEM_THREADS Threads[1];
	} SYSTEM_PROCESSES, *PSYSTEM_PROCESSES;


	Hiding processes is similiar as in the case of hiding files.
We have to change NextEntryDelta of previous record of that we want to hide. 
Usually we will not want to hide the first record here because it is Idle 
process.



=====[ 5. Registry ]============================================================

	Windows registry is quite big tree structure containing two important 
types of records for us which we could want to hide. First type is registry 
keys, second is values. Owing to registry structure hiding registry keys is 
not as trivial as hiding file or process.


=====[ 5.1 NtEnumerateKey ]=====================================================

	Owing to its structure we are not able to ask for a list of all keys 
in the specific part of registry. We can get only information about one key 
specified by its index in some part of registry. This provides NtEnumerateKey.

	NTSTATUS NtEnumerateKey(
		IN HANDLE KeyHandle,
		IN ULONG Index,
		IN KEY_INFORMATION_CLASS KeyInformationClass, 
		OUT PVOID KeyInformation,
		IN ULONG KeyInformationLength,
		OUT PULONG ResultLength
	);


	KeyHandle is a handle to a key in which we want to get information 
about a subkey specified by Index. Type of returned information is specified 
by KeyInformationClass. Data are written to KeyInformation buffer which length 
is KeyInformationLength. Number of written bytes is returned in ResultLength.
	The most important think we need to perceive is that if we hide a key, 
indexes of all following keys woould be shifted. And because we are able to get 
information about a key with higher index with asking for key with lower index 
we always have to count how many records before were hidden and then return 
the right one.
	Let's have a look on the example. Assume we have some keys called A, B, 
C, D, E and F in any part of registry. Indexing starts from zero which mean 
index 4 match E key. Now if we want to hide B key and the hooked application 
call NtEnumerateKey with Index 4 we should return information about F key 
because there is an index shift. The problem is that we don't know that there 
is a shift. And if we didn't care about shifting and return E instead of F when 
asking for key with index 4 we would return nothing when asking for key with 
index 1 or we would return C. Both cases are errors. This is why we have to 
care about shifting.
	Now if we counted the shift by recalling the function for each index 
from 0 to Index we would sometimes wait for ages (on 1GHz processor it could 
take up to 10 seconds with standard registry which is too much). So we have to 
think out more sophisticated method.
	We know that keys are (except of references) sorted alphabetically.
If we neglect references (which we don't want to hide) we can count the shift 
by following method. We will sort alphabetically our list of key names which we 
want to hide (RtlCompareUnicodeString can be used), then when application calls 
NtEnumerateKey we will not recall it with unchanged arguments but we will find 
out the name of the record specified by Index. 

	NTSTATUS RtlCompareUnicodeString(       
		IN PUNICODE_STRING String1, 
		IN PUNICODE_STRING String2, 
		IN BOOLEAN  CaseInSensitive  
	);

	String1 and String2 are strings which will be compared, CaseInSensitive 
is True if we want to compare with neglecting character case. 
	Function result describes relation between String1 and String2:

		result > 0:	String1 > String2
		result = 0:	String1 = String2
		result < 0:	String1 < String2


Now we have to find a border. We will compare alphabetically the name of 
the key specified by Index with the names in our list. The border would be 
the last lesser name from our list. We know that the shift is at most 
the number of the border in our list. But not all items from our list have to 
be a valid key in the part of registry we are in. So we have to ask for all 
items from our list up to border if they are in this part of the registry. 
This can be done using NtOpenKey.

	NTSTATUS NtOpenKey(

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -