How to hide yourself in Windows NT [转]

xiaoxiao2021-03-06  14

============================= [disappeared in the NT "box"] ============ ==================

How to hide yourself in Windows NT

----------------------------

Author: Holy_Father

Version: 1.2 English

Date: 05.08.2003

Translation: pker / cvc translation group

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

Directory

2. Introduction

3. File

3.1 NTQueryDirectoryFile

3.2 NTVDMControl

4. Process

5. Registration

5.1 nTenumerateKey

5.2 NTenumerateValueKey

6. System services and drivers

7. Hook and expand

7.1 Permissions

7.2 Global Hook

7.3 new process

7.4 DLL

8. Memory

9. Handle

9.1 Name your handle and get the type

10. Port

10.1 WinXP's NetStart, Opports, WinXP's FPORT

10.2 Opports of Win2K and NT4, Win2k's Fport

11. Conclusion

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

This document is a technology that hides objects, files, services, and processes in Windows NT. These methods are built

On the basis of the Windows API, see my "hook Windows API".

All of these are my research when writing rootkit code, all I have a high efficiency when writing this article.

And it is easy to write. This is due to my pay.

In this document, the hidden hidden to any object refers to this by changing the system of naming objects.

Object naming process. This object is just the return value of this process, as if it does not exist. Basic methods (excluding the differences on the description) are our use of original calls and original functions and then we change its output.

In this version of the document, we tell how to hide files, processes, keywords, and registry keys, system services, and drivers.

Allocated memory and handle.

===== [3. File] ======================================== =========================

There are many hidden files that make them impossible to system. We only target the technology that changes the API and does not involve those modifications.

Technical technology for system. This is also simpler because we don't need to know how many actual file systems work.

===== [3.1 ntQuerydirectoryFile] ========================================= ======

In Windows NT, looking for a file in the directory is obtained by looking for this directory and all its subdirectories. because

Enumerate files are used to use 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 is FileHandle, Fileinformation and FileinformationClass. File-

Handle is a handle of a directory object available from NTOPENFILE. FILEINFORMATION is a point pointing

The pointer of the memory has been allocated, and the function is written here to the user wants to get. FileInformationClass decided

The record type written in FileInformation.

FileInformationClass is a variable enumeration type, but we only need four values, these four values

To enumerate the contents of the directory.

#define fileDirectoryInformation 1

#define FileFullDirectoryInformation 2 # Define FileBothDirectoryInformation 3

#define filenamesinformation 12

The recording structure for the FileDirectoryInformation write fileInformation is:

Typedef struct _file_directory_information {

Ulong nextentryoffset;

Ulong unknown;

Large_integer credectime;

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 FILEFULDIRECTORYINFORMATION:

Typedef struct _file_full_directory_information {

Ulong nextentryoffset;

Ulong unknown;

Large_integer credectime;

Large_integer lastaccesstime;

Large_integer lastwritetime;

Large_integer changetime;

Large_integer endoffile;

Large_integer allocationsize;

Ulong FileAttributes;

Ulong filenamelength;

Ulong electionLength;

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 credectime;

Large_integer lastaccesstime;

Large_integer lastwritetime;

Large_integer changetime;

Large_integer endoffile;

Large_integer allocationsize;

Ulong FileAttributes;

Ulong filenamelength;

Ulong electionLength;

Uchar alternatenamelength;

Wchar alternatename [12];

Wchar filename [1];

} File_both_directory_information, * pfile_both_directory_information;

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 variables in these structural types are for me

It is important.

NEXTENTRYOFFSET is the length of the detailed list item. The first item can be found at the address fileinformation 0. Instant

The second item is at the offset of the first item Fileinformation NextentryOffset. The last item of NEXT-

EntryOffset field is 0.

FileName is the finished file name of the file.

FileNameLength is the length of the file name.

If we want to hide a file, we have to distinguish these four types of structures and record us for each return.

Need to compare the file names in the file name we have to hide. If we have to hide the first record, we will

It is necessary to move the structure according to the size of the first structure. This causes the first record to be rewritten. If we want to hide another

A record, we can easily rewrite the previous recorded NexTenTryOffset field. If we want to hide the last

Record, then the NEXTENTRYOFSET field in front of it should be 0, otherwise the value of this field should be

We want to hide the record and the next record of the next NEXTENTRYOFFSET field. Then we have to rewrive the previous record

The value of the unknown field, this value is the next record index number. The first record of the unknown value should be written as we want

The recorded unknown field value of the recorded record.

If you don't find visible records, we get a return value status_no_such_file that is incorrect.

#define status_no_such_file 0xc000000F

===== [3.2 ntvdmControl] =========================================== ==============

For some reasons, the DOS simulator NTVDM can use NTVDMControl call to obtain a list of files.

NTSTATUS NTVDMCONTROL

In Ulong Controlcode,

In Pvoid ​​ControlData

);

ControlCode specifies the sub-function that provides data to the ControlData buffer. If ControlCode is equal to VDMDirect-

ORYFILE, then this function fills FileBothDirectoryInformation with the fileinformationclass field

NTQueryDirectoryFile function is equivalent.

#define vdmdirectoryFile 6

Then ControlData uses the same as FileinFormation. The only difference here is that we don't know this buffer

the size of. So we have to calculate them manually. We must add NextentryOffset at the size of each record

There is also the size of FileNameLength on the last record, and the last record does not include the length of the file name.

The degree is 0x5E. Hidden methods and use NTQueryDirectoryFile.

===== [4. Process] ========================================= ======================== Many system information can be obtained by 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 we have to get, SystemInformation is a pointing function

The output buffer is the size of the buffer, and returngength is the number of bytes.

We can set the SystemInformationClass field to SystemProcessandThreadsinformation by setting the SystemInformationClassIndthreadsInformation

To enumerate the process in the line.

#define systemInformationClass 5

Returns the structure of the SystemInformation buffer as follows:

Typedef struct _system_processes {

Ulong nextentryDelta;

Ulong threadcount;

Ulong reserved1 [6];

Large_integer createtime;

Large_integer usertime;

Large_integer kernetime;

Unicode_string processname;

KPRIORITY BASEPRIORITY

Ulong processid;

Ulong inheritedFromProcessId;

Ulong handlecount;

Ulong reserved2 [2];

VM_Counters vmcounters;

IO_COUNTERS IOCOUNTERS; / / I only used for Windows 2000

System_threads throughs [1];

} System_processes, * psystem_processes;

The hidden process and hidden files are similar. We need to change the NEXTENTRYDATA field to hide the previous record of the process. usually

We won't hide the first record because it is usually an IDLE process.

===== [5. Registry] ======================================== ======================= Windows registry is a huge tree structure, which contains two important record types we can hide. First

The type is the key, the second is the key value. Since the structure of the registry, hidden registration keys are more complicated than hidden files and processes.

===== [5.1 nTenumerateKey] =========================================== ============

Due to the structure of the registry, we cannot get a list of all keys of a specified section of the registry. We can only pass

The index of the key is obtained. This has nTenumerateKey.

NTSTATUS NTENUMERATEKEY

In Handle KeyHandle,

In Ulong Index,

In key_information_class keyinformationclass,

Out pvoid keyInformation,

In Ulong KeyinformationLength,

Out Polong Resultlength

);

KeyHandle is the handle we want to be indexed by Index, we have to get information from this subkey. Return letter

The type of interest is specified by KeyinformationClass. The data is written to the KeyInformation buffer, and the size is made by key-

InformationLength is specified. The number of bytes written returns to ResultLength.

The most important thing we have to notice is if we hide a key, all keys have changed. And because I

We can get a high index record through a low index record, so we usually calculate before this record.

How many records we hide then return a correct value.

Let us look at an example. Assume that there are some keys in our registry called A, B, C, D, E and F. Coping from 0

No., that is, the index of the key E is 4. Now if we want to hide key B and then be hooked NTenumerateKey functions

We should return F when it is called 4, because the index changes are made here. The problem is that we don't know here.

You need to change. And if we don't care about this change and when the index is 4, we return E instead of f, then

What we will not return or return to C. when the index is 1 button. These two situations are wrong. This

Yes why we have to consider the change of the index.

Now if we calculate each key to calculate the offset for each key, we sometimes wait for a long time (at 1G Hz processor)

This will take 10 seconds for the standard registry. So we have to think about some strange methods.

We know that the key is sorted by alphabet (except for reference). If we ignore the reference (this we don't want to hide) we can calculate the offset with the following method. We sort the names of the keys we want to hide by alphabet (you can use RTL-

CompareUnicodeString function), then when the application call NTenumerateKey we don't have to use unchanged parameters

Re-call the function but find 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 that need to be compared. If we want to ignore the case of characters, you can put Caseinsensi-

TIVE is set.

Function return value describes the relationship between String1 and String2:

Return Value> 0: String1> String2

Return value = 0: String1 = string2

Return value <0: String1

Now we need to find a boundary. We must perform alphabetic comparison of key names specified by index and the key names in our list

Comparison. We know that the maximum offset is the number of miracies in our list. But it is not all items in our list.

The corresponding part of the registry is valid. So we have to see if every item in our list is in the registry.

Initial. We can use NTOPENKEY.

NTSTATUS NTOPENKEY

Out phaldle keyhandle,

IN Access_mask desidaccess,

In POBJECT_ATTRIBUTES OBJECTATTRIBUTES

);

KeyHandle is a master key handle. We can use NTenumerateKey to return the value returned. DesignedAccess is an interview

Question. You should fill in this field with key_enumerate_sub_keys. ObjectAttributes describes us to

Open subkey (including its name).

#define key_enumerate_sub_keys 8

If the result returned by NTOPENKEY is 0 Description Open success, indicating that this button in our list exists. Open key

After NTClose close.

NTSTATUS NTCLOSE

In Handle Handle

);

For each NTenumerateKey call, we must calculate the bias of the keys in the relative list.

shift. Then we add this offset to the index parameter and then call the original NTenumerateKey function.

In order to get the name of the key specified by INDEX, we can use KeyBasicInformation as a KeyInformation-

Class value.

#define KeybasicInformation 0

NTENUMERATEKEY Returns this structure in KeyInformation:

Typedef struct _key_basic_information {

Large_integer lastwritetime;

Ulong TitleIndex;

Ulong namelength;

Wchar Name [1];

} Key_basic_information, * pkey_basic_information;

Here we need only Name and its length Namelength.

If there is no entry corresponding to the offset INDEX, we have to return an error code status_ea_list_inconsis-

TENT.

#define status_ea_list_inconsistent 0x80000014

===== [5.2 nTenumerateValueKey] ========================================= ======= The key value of the registry is not sorted by alphabet. Fortunately, the key value under a key is not a lot, so we can pass

Re-calling method gets offset. The API that gets the key value is NTenumerateValueKey ..

NTSTATUS NTENUMERATEVALUEKEY

In Handle KeyHandle,

In Ulong Index,

In key_value_information_class keyvalueInformationClass,

Out pvoid keyvalueInformation,

In Ulong KeyValueInformationLength,

Out Polong Resultlength

);

KeyHandle or the handle of the primary key. Index is an index in a given key value list. KeyValueInformation-

Class describes the type of information to be stored in KeyValyeInFormate buffer, and its length is made from KeyValueInformation-

Length is specified. The number of bytes written returns to ResultLength.

We have to calculate the offset again, but this time is based on the number of key values ​​under one key and then recall from 0 serial number to INDEX.

This function. You can get the key when KeyValueInformationClass is set to KeyValueBasicInformation.

The name of the value.

#define keyvaluebasicinformation 0

Then we get the following structure in the KeyValueInformation buffer:

Typedef struct _key_value_basic_information {

Ulong TitleIndex;

Ulong Type;

Ulong namelength;

Wchar Name [1];

} Key_Value_basic_information, * pkey_value_basic_information;

Once again, we only care about the Name and NameLength fields.

If there is no entry corresponding to the offset INDEX, we have to return an error code status_no_more_entries.

#define status_no_more_entries 0x8000001A

===== [6. System service and driver] ====================================== ==================

System services and drivers can be enumerated by four separate APIs. Their contacts in each of the different versions of Windows systems

all different. So we must hook these four functions.

Bool EnumserviceSstatusa

SC_HANDLE HSCMANAGER,

DWORD DWSERVICEPE,

DWORD DWSERVICESTATE, LPENUM_SERVICE_STATUS LPSERVICES,

DWORD CBBUFSIZE,

LPDWORD PCBBYTESNEED,

LPDWORD LPSERVICESRETURNED,

LPDWORD LPRESUMEHANDLE

);

Bool EnumServiceGroupw

SC_HANDLE HSCMANAGER,

DWORD DWSERVICEPE,

DWORD DWSERVICESTATE,

Lpbyte lpservices,

DWORD CBBUFSIZE,

LPDWORD PCBBYTESNEED,

LPDWORD LPSERVICESRETURNED,

LPDWORD LPRESUMEHANDLE,

DWORD DWUNKNOWN

);

Bool EnumserviceSstatusexa (

SC_HANDLE HSCMANAGER,

SC_ENUM_TYPE INFOLEVEL,

DWORD DWSERVICEPE,

DWORD DWSERVICESTATE,

Lpbyte lpservices,

DWORD CBBUFSIZE,

LPDWORD PCBBYTESNEED,

LPDWORD LPSERVICESRETURNED,

LPDWORD LPRESUMEHANDLE,

LPCTSTR PSZGroupname

);

Bool EnumserviceSstusExw

SC_HANDLE HSCMANAGER,

SC_ENUM_TYPE INFOLEVEL,

DWORD DWSERVICEPE,

DWORD DWSERVICESTATE,

Lpbyte lpservices,

DWORD CBBUFSIZE,

LPDWORD PCBBYTESNEED,

LPDWORD LPSERVICESRETURNED,

LPDWORD LPRESUMEHANDLE,

LPCTSTR PSZGroupname

);

The most important thing here is LPService, pointing to the buffer of the listing of the service list. At the same time, LPSERVICESRETURNED point

Record the number, it is also important. The data structure output to the buffer depends on different functions. For EnumServiceSstatusa

And EnumServicesGroupw will return the following structure:

TYPEDEF STRUCT _ENUM_SERVICE_STATUS {

LPTSTR LPSERVICENAME;

LPTSTR LPDISPLAYNAME;

Service_status serviceArstatus;

} ENUM_SERVICE_STATUS, * LPENUM_SERVICE_STATUS;

Typedef struct _service_status {

DWORD DWSERVICEPE;

DWORD DWCURRENTATE;

DWORD DWCONTROLSACCEPTED;

DWORD dwin32exitcode;

DWORD DWSERVICESPECIFICEXITCODE;

DWORD dwcheckpoint;

DWORD dwaithint;

Service_status, * lpservice_status;

For EnumServicesSstatusexa and EnumServicesSstatusexws are:

Typedef struct _enum_service_status_process {

LPTSTR LPSERVICENAME;

LPTSTR LPDISPLAYNAME;

Service_status_process service service;

} ENUM_SERVICE_STATUS_PROCESS, * LPENUM_SERVICE_STATUS_PROCESS;

Typedef struct _service_status_process {dWord dwserviceType;

DWORD DWCURRENTATE;

DWORD DWCONTROLSACCEPTED;

DWORD dwin32exitcode;

DWORD DWSERVICESPECIFICEXITCODE;

DWORD dwcheckpoint;

DWORD dwaithint;

DWORD DWPROCESSID;

DWORD DWSERVICEFLAGS;

Service_status_process, * lpservice_status_process;

We refer to LPServicename, this is the name of the system service. Record a static size, so if we

Want to hide a record, we will move over all records according to the recorded size. Here we must distinguish

Service_status and service_status_process size.

===== [7. Hook and expand] ======================================= ====================

In order to achieve the effect we want, we must hook all running processes and all processs that will be generated. New process must

It is hooked before it runs its own first instruction, otherwise it can see our hidden object before it is hook.

===== [7.1 permission] ========================================== =====================================================================================================================================================

First, we should first know that we need at least administrator privileges to get access to all running processes. The best way is

Run our process with system service. To install the service, we also need special

Permission.

At the same time, it is useful to get sedebugprivilege. This can be through OpenProcessToken, Lookupprivilege-

Value and AdjustTokenPrivileges These APIs are reached.

Bool OpenProcesstoken

Handle ProcessHandle,

DWORD DESIREDACCESS,

Phandle tokenhandle

);

Bool LookuppprivilerageGevalue (

LPCTSTR LPSYSTEMNAME,

LPCTSTR LPNAME,

Pluid LPluid

);

Bool AdjustTokenPrivileges

Handle tokenhandle,

Bool DisableAllPrivileges,

Ptoken_Privileges NewState, DWORD BUFFERLENGTH,

Ptoken_Privileges PreviouState,

PDWord ReturnLength

);

Ignore the error, this code can be written as follows:

#define se_privilege_enabled 0x0002

#define token_Query 0x0008

#define token_adjust_privileges 0x0020

Handle htokeen;

Luid DebugnameValue;

Token_Privileges Privileges;

DWORD DWRET;

OpenProcessToken (GetCurrentProcess (),

Token_adjust_privileges | token_Query, HToken;

Lookuppprivilerage (Null, "Sedbugprivilege", & debugnameValue;

PRIVILEGES.PRIVILEGECOUNT = 1;

Privileges.privileges [0] .luid = DebugnameValue;

Privileges.privileges [0] .attributes = se_privilege_enabled;

AdjustTokenprivileges (HToken, False, & Privileges, Sizeof (Privileges),

NULL, & DWRET

CloseHandle (HTOKEN);

===== [7.2 global hook] ========================================== ====================

The problem of enumeration processes has been solved when NTQuerySystemInformation this API. There is one in the system

Some local processes, so we can hook them by rewriting the first instructions of the function. For each run

We must do this. We have to assign a memory in the target process, and write the functions we want to hook here.

New code. Then we use the JMP instruction to override the first instructions of these functions. This jump is relocated to

Our code. So this JMP instruction will be executed immediately when the hook is called. We must protect

Save each function's rewritten first instruction. We need them to call the original hooked function. Save the instruction

I have described in Section 3.2.3 of the article "Hook Windows API".

First we have to open the target process through NTOPROCESS and get the handle. If we don't have enough permissions, this will

failure.

NTSTATUS NTOPENPROCESS

Out phaldle processhandle,

IN Access_mask desidaccess,

In Pobject_Attributes Objectttributes,

In PClient_id ClientId Optional

);

ProcessHandle is a pointer to the return handle. DesignedAccess should be set to process_all_

Access. We can set the PID of the target process into a ClientID structure of the uniqueProcess value, and Unique-Thread should be 0. The open handle can always be shut down through the NTClose function.

#define process_all_access 0x001F0FFF

Now we have to assign memory for our code. This can be implemented by NTALLOCATEVIRTUALMEMORY.

NTSTATUS NTALLOCATEVIRTUALMEMORY

In Handle ProcessHandle,

In Out Pvoid ​​Baseaddress,

In Ulong ZeroBITS,

In Out Polong Allocationsize,

In Ulong AllocationType,

In Ulong Protect

);

ProcessHandle is the handle returned by NTOPROCESS. BaseAddress is a pointer to the beginning of memory.

The address of the assigned memory is stored here. The input value can be NULL. Allocationsize is a pointing to us to apply

Please have a memory size pointer. At the same time, it is also used to return the actual size of allocated memory. Best to set up allocationtype

Set MEM_TOP_DOWN and MEM_COMMIT, as this will be assigned to the high address as close as possible to the dynamic link library.

#define mem_commit 0x00001000

#define mem_top_down 0x00100000

Then we can write our code with NTWRITEVIRTUALMEMORY.

NTSTATUS NTWRITEVIRTUALMEMORY

In Handle ProcessHandle,

In Pvoid ​​Baseaddress,

In pvoid buffer,

In ulong bufferlength,

OUT Pulong ReturnLength Optional

);

BaseAddress is the address returned by NTallocateVirtualMemory. Buffer points to the number of bytes written by the function,

BufferLength is the number of bytes we have to write.

Now we have to hook a single function. Only NTDLL.DLL is loaded every process. So let us check us

The function in NTDLL.DLL to be hooked is introduced by the process. But this function (in other DLL) in memory

The place where the place is assignable, so rewriting on this address is easy to raise an error in the target process. What is this?

What we have to check this library (where we want to hook functions) is loaded by the target process.

We have to get the PEB (process environment block) of the target process through NTQueryInformationProcess.

NTSTATUS NTQUERYINFORMATIONPROCESS

In Handle ProcessHandle,

In ProcessInfoclass ProcessInformationClass,

Out Pvoid ​​ProcessInformation,

In Ulong ProcessInformationLength,

OUT Pulong ReturnLength Optional

);

We have to set ProcessInformationClass to ProcessBasicInformation. Then process_basic_

The Information structure returns to the ProcessInformation buffer with the size of ProcessInformationLength.

#define processbasicinformation 0

Typedef struct _process_basic_information {

NTSTATUS EXITSTATUS;

PPEB PebbaseAddress;

Kaffinity affinitymask;

KPRIORITY BASEPRIORITY

Ulong uniqueprocessid;

Ulong inheritedfromuniqueprocessid;

} Process_basic_information, * pprocess_basic_information;

Pebbaseaddress is what we want. Where the PEBASEADDRESS 0x0c is the address of PPEB_LDR_DATA.

This can be called via NTREADVIRTUALMEMORY.

NTSTATUS NTREADVIRTUALMEMORY

In Handle ProcessHandle,

In Pvoid ​​Baseaddress,

Out pvoid buffer,

In ulong bufferlength,

OUT Pulong ReturnLength Optional

);

The parameters are similar to the NTWRITEVIRTUALMEMORY function.

Where the PPEB_LDR_DATA 0x1c is the address of the INITIALIZATIONORDERMODULIST. This is the process loading

List of link libraries. We only care about this structure.

TYPEDEF STRUCT _IN_INITIALIZATION_ORDER_MODULE_LIST {

PVOID NEXT,

PVOID PREV,

DWORD ImageBase,

DWORD ImageEntry,

DWORD ImageSize,

...

);

Next is a pointer to the next record, the prev pointing forward a record, and the last record points to the first one.

ImageBase is the address of the module in memory. ImageEntry is the entry of the module. ImageSize is its size.

We have to get its imagebase for all we have linked libraries, such as getModuleHandle or Load-

Library). We use this imageBase and IninitializationOrderModuleList to perform each entrance

Comparison.

Now we have prepared it for hooks. Because we have to hook the process in the run, there is a possibility that we may be our code.

May be executed while being rewritten. This will happen, so we must first stop all threads in the target process.

You can pass the systemprocessandthreadsinformation of NTQuerySystemInformation described in Section IV.

The type gets the thread list. But we want to describe the SYSTEM_THREADS structure used to store thread information.

Typedef struct _system_threads {

Large_integer kernetime;

Large_integer usertime;

Large_integer createtime;

Ulong Waittime;

Pvoid ​​Startaddress;

Client_id clientid;

KPRIORITY PRIORITY

KPRIORITY BASEPRIORITY

Ulong contextswitchcount;

Thread_State State;

Kwait_reason waitreason;

} System_threads, * psystem_threads;

We have to get its handles through NTOPENTHREAD for each thread. We have to use ClientId.

NTSTATUS NTOPENTHREAD

Out phaldle threadhandle,

IN Access_mask desidaccess,

In Pobject_Attributes Objectttributes,

In PClient_id ClientID

)

The handle we have to be stored in ThreadHandle. We have to set DesiredAccess to thread_suspend_

RESUME. #define thread_suspend_resume 2

ThreadHandle is used to call NTSUSPENDTHREAD.

NTSTATUS NTSUSPENDHREAD (

In Handle Threadhandle,

OUT Pulong Previoussuspendcount Optional

);

The hangs can be prepared to rewrite. We will enter as "hook Windows API" in Section 3.2.2

Row. The only difference is this time we use other processes.

After the hook is completed, we wake up all threads of the process through the NTRESUMETHREAD.

NTSTATUS NTRESUMETHREAD

In Handle Threadhandle,

OUT Pulong Previoussuspendcount Optional

);

===== [7.3 new process] ======================================== ======================

The process for all running threads does not affect the processes running. We can get a list of processes and then get again

I have to compare them and infect those processes that appear in the second list without appearing in the first list. but

This method is very unreliable.

A better way is to hook the functions that will always be called when the new process begins. Because we hook the system in the system

There is a process, so we don't miss any new process with this approach. We can hook ntcreatethread but this

Not the earliest way. We can hook NTRESUMETHREAD, which is created whenever a new process is created

Waiting will also be called. It is called after ntcreatethread.

The only problem with NTRESUMETHREAD is called not just when creating a new process. But we can overcome it very easy

it. NTQueryInformationthread will give us a message about which process specifies a thread. we

The last thing to do is to check if this process has been hooked. This can be read by reading any of our needs

Function is completed.

NTSTATUS NTQUERYINFORMATIONTHREAD

In Handle Threadhandle,

In ThreadInfoclass ThreadInformationClass,

Out pvoid threadinformation,

In ulong threadinformationLength,

OUT Pulong ReturnLength Optional

);

ThreadInformationClass is an information class, we have to set it to threadbasicinformation. Thread-

Information is a buffer that returns a result of ThreadInformationLength.

#define threadbasicinformation 0

For ThreadBasicInformation, return the following structure:

Typedef struct _thread_basic_information {

NTSTATUS EXITSTATUS;

PNT_TIB TEBASEADDRESS;

Client_id clientid;

Kaffinity affinitymask;

KPRIORITY PRIORITY

Kpriority basepriority;} thread_basic_information, * pthread_basic_information;

ClientID is a PID with this thread. Now we have to infect a new process. The problem is this new process in memory

There is only NTDLL.DLL. Other modules are immediately loaded immediately after calling NTRESUMETHREAD. There are several ways to come

solve this problem. For example, we can hook the LDRINTILALIZETHUNK API, which is adjusted when the process is initialized

use.

NTSTATUS LDRINTIALIZETHUNK (

DWORD UNKNOWN1,

DWORD UNKNOWN2,

DWORD UNKNOWN3

);

First we run the original code, then we hook all the functions we have to hook in the new process. But it is best to release it

LDRINTILALIZETHUNK's hooks are called after this function, we don't want to reinite all.

function. We have completed all things before being linked. That's why it has no chance.

Call the enclosed function before being hooked.

Hook itself and hooks the execution process is the same. Here we don't consider performing threads.

===== [7.4 dll] ========================================= =========================

Each process in the system has a copy of NTDLL.DLL. This means that we can hook this when the process is initialized.

Any function in the module. But what other functions from kernel32.dll or advapi32.dll? And one

Some processes have only ntdll.dll. Other libraries can be dynamically loaded in the code after the process is hooked. That's why

We have to hook LDRLOADDLL, which is used to load new modules.

NTSTATUS LDRLOADDLL (

Pwstr szcwpath,

PDWORD PDWLDRERR,

Punicode_String PunimodulenAme,

Phinstance PRESULTINSTANCE

);

Here is the most important thing about us is Punimodulename, where the name of the module is stored. If calling successfully PRESULTIN-

Stance is filled with its memory address.

We can call the original LDRLOADDLL and hook all functions in the loaded module.

===== [8. Memory] ======================================== =========================

When we hook a function we change its first few bytes. By calling the function NTREADVIRTUALMEMORY, we

You can detect if a function is hooked. So we have to hook NTREADVIRTUALMEMORY to prevent being detected. NTSTATUS NTREADVIRTUALMEMORY

In Handle ProcessHandle,

In Pvoid ​​Baseaddress,

Out pvoid buffer,

In ulong bufferlength,

OUT Pulong ReturnLength Optional

);

We have changed the first few bytes we want to hook the function, and apply for memory for our code. We should check

Does the caller read these bytes. If we have us in BaseAddress to BaseAddress Bufferlength

The code we must change bytes in buffer.

If the user requests to read the data in the memory we apply, we have to return empty and a status_partial_copy error

code. This value shows that all requests are copied into the buffer. This value is used to describe the request is not divided

Space. This situation RETURNLENGTH should be set to 0.

#define status_partial_copy 0x8000000D

If the user requests to read the first few bytes of the hook function, we have to call the original code and copy the original byte to

In the buffer (these bytes, we save them in order to call the original function).

Now the process has not been detected by reading your own memory it has been hooked. And if there is a hooked process

It will also encounter difficulties. It presents the original code in front of you but executes our code.

In order to be more perfectly hidden, we can also hook NTQueryVirtualMemory. This function is used to get the virtual

Memory information. We can hook it to prevent the memory we apply from being detected.

NTSTATUS NTQUERYVIRTUALMEMORY

In Handle ProcessHandle,

In Pvoid ​​Baseaddress,

In Memory_Information_Class MemoryInformationClass,

Out pvoid memoryInformation,

In Ulong MemoryInformationLength,

OUT Pulong ReturnLength Optional

);

MemoryInformationClass Specifies the returned data class. We are interested in the previous types.

#define memorybasicinformation 0

#define memoryworkingsetlist 1

Returns the following structure for the MemoryBasicInformation class:

Typedef struct _Memory_basic_information {

Pvoid ​​Baseaddress;

PVOID AllocationBase;

Ulong allocationprotect;

Ulong Regionsize;

Ulong State;

Ulong protect;

Ulong Type;

Memory_basic_information, * pmemory_basic_information;

Each memory cell interval has its own RegionSize and its own type TYPE. The type of idle memory is MEM_FREE.

#define mem_free 0x10000

If we previous areas Mem_Free, we should add the size of our code intervals to its RegionSize.

If we follow the area of ​​Mem_Free, we should add the size of this section to the previous RegionSize.

If we have other types, we return to MEM_FREE for our interval. Its size is also based on

The interval properties of the face are determined.

For the MemoryworkingSetList class, it returns the following structure:

Typedef struct _memory_working_set_list {ulong numberofpages;

Ulong WorkingSetList [1];

} Memory_Working_Set_List, * PMemory_working_set_list;

NumberOfpages is the number of items in WorkingSetList. This number should be reduced. We want to be in WorkingSetList

Find our interval and then cover us with the records behind. WorkingSetList is a DWORD array, of which

The high 20 digits specify the high 20-bit address of the interval, and the bottom 12 is specified as a flag.

===== [9. Handle] ======================================== =========================

Call NTQuerySystemInformation through the SystemHandleinformation class We can get all open

Handle, which is stored in the _xystem_handle_information_ex structure.

#define systemhandleinformation 0x10

Typedef struct _system_handle_information {

Ulong processid;

Uchar ObjectTypenumber;

Uchar flags;

Ushort handle;

PVOID Object;

Access_mask grantedAccess;

} System_handle_information, * psystem_handle_information;

Typedef struct _system_handle_information_ex {

Ulong Numberofhandles;

System_handle_information information [1];

} System_handle_information_ex, * psystem_handle_information_ex;

ProcessID specifies the process that has the handle. ObjectTypenumber is a handle type. Numberofhandles store

It is the number of records in the information array. Hiding a handle is very simple. We have to put all the records behind

Early and reduce the value of NumberOfhandles. You must put all the items in advance, because this array is

Group of ProcessID. This means that all handles of a process are together. And for a process,

The number of handles is growing.

I now think about this function returned by the SystemProcesSandthreadsinformation class_system_process

structure. Here we can see that every process has a value about its handle, in HandleCount.

If we want to hide perfectly, we will also call this in the SystemProcesSistthreadsinformation class.

When the function is rewritten according to the number of hidden handles, HandleCount. But this change is very high for time requirements.

When the system is running normally, there will be a lot of handles to open and close during a short period of time. So this happens often,

The number of intermediate handles in this function changed, but we don't need to change the value of Handlecount. ===== [9.1 named handle and get type] ======================================== ============

The hidden handle is simple, but it is difficult to find the handle you want to hide. For example, if we hide a process, we must

Hide all the handles and all handles pointing to it. Hidden handles of this process is also very simple. We only need to compare

The processID of the handle and the PID of our process, we hide it when they are equal. But for other processes

Handle, it must first be named and then we can compare. The number of handles in the system is usually a lot, so I

It is best to compare the type of handle before comparing. Named types can save us many searches of our uncomfortable sentence

The time of the handle.

Named handles and naming types can be obtained by calling NTQueryObject.

NTSTATUS ZWQUERYOBJECT

In Handle ObjectHandle,

In object_information_class objectinformationclass,

Out pvoid ObjectInformation,

In Ulong ObjectInformationLength,

OUT Pulong ReturnLength Optional

);

ObjectHandle is a handle we have to get information, ObjectInformationClass is stored in Object-

The type of information in the Information buffer, its length is ObjectInformationLength byte length.

#define ObjectNameInformation 1

#define ObjectAllTypesinformation 3

Typedef struct _object_name_information {

Unicode_String Name;

} Object_name_information, * pObject_name_information;

The Name field indicates the name of the handle.

Typedef struct _object_type_information {

Unicode_String Name;

Ulong Objectcount;

Ulong handlecount;

Ulong reserved1 [4];

Ulong peakobjectcount;

Ulong peakhandlecount;

Ulong reserved2 [4];

Ulong invalidattribute;

Generic_mapping genericmapping;

Ulong validAccess;

Uchar unknown;

Boolean maintainhandaDatabase;

Pool_Type PoolType;

Ulong PagedPoolusage;

Ulong nonpagedpoolusage;

} Object_type_information, * pObject_type_information;

TYPEDEF STRUCT _Object_all_types_information {

Ulong NumberOfTypes;

Object_type_information typeInformation;

} Object_all_types_information, * pObject_all_types_information; Name field indicates the object type name of each Object_Type_information structure of the tight surface. Next Object_

The TYPE_INFORMATION structure is also this name, at the beginning of the four-byte boundary.

ObjectTypenumber in the System_Handle_information structure is an index of a TypeInformation array.

It is difficult to find a handle of other processes. There are two possible methods to name it. The first is to pass this handle through NTDUPLI-

CateObject is copied to our process and then naming it. This method does not work for some specific types of handles. but

This is just a few cases, so we can not be nervous.

NTDUPLICATEOBJECT

In Handle SourceProcessHandle,

In Handle SourceHandle,

In Handle TargetProcessHandle,

Out Phandle TargetHandle Optional,

IN Access_mask desidaccess,

In Ulong Attributes,

In Ulong Options

);

SourceProessHandle is a handle of a SourceHandle process, SourceHandle is what we have to copy

Handle. TargetProcessHandle is the handle of the process to be copied. In our case, this is our

Process handle. TargetHandle is a pointer to a copy of the original handle. DespedAccess should be set to Process

_Query_information, Attributes, and Options should be 0.

The second naming method is to use the system driver, which can function for any handle. This source code in the Ophaandle project

In the middle, you can be on my website

Http://rootkit.host.sk is found.

===== [10. Port] ============================================ =====================================================================================================================================================

The simplest way to open the handle is to use allocateandgettcptablefromstack and allocateandget-

UDPTableFromstack call, or call allocateandgettcpextablefromstack in iPhlpapi.dll

And AllocateAndgetudpextableFromstack. The EX function is valid from XP.

TypedEf struct _mib_tcprow {

DWORD DWSTATE;

DWORD DWLOCALADDR;

DWORD DWLOCALPORT;

DWORD DWREMOTEADDR;

DWORD dwremoteport;

} Mib_tcprow, * pmib_tcprow;

Typedef struct _mib_tcptable {

DWORD DWNUMENTRIES;

MIB_TCPROW TABLE [Any_SIZE];

} MIB_TCPTABLE, * PMIB_TCPTABLE;

Typedef struct _mib_udprow {dword dwlocaladdr;

DWORD DWLOCALPORT;

} MIB_UDPROW, * PMIB_UDPROW;

Typedef struct _mib_udptable {

DWORD DWNUMENTRIES;

MIB_UDPROW TABLE [Any_SIZE];

} Mib_udptable, * pmib_udptable;

TypedEf struct _mib_tcprow_ex

{

DWORD DWSTATE;

DWORD DWLOCALADDR;

DWORD DWLOCALPORT;

DWORD DWREMOTEADDR;

DWORD dwremoteport;

DWORD DWPROCESSID;

} MIB_TCPROW_EX, * PMIB_TCPROW_EX;

TypedEf struct _MIB_TCPTABLE_EX

{

DWORD DWNUMENTRIES;

MIB_TCPROW_EX TABLE [Any_SIZE];

} Mib_tcptable_ex, * pmib_tcptable_ex;

Typedef struct _MIB_UDPROW_EX

{

DWORD DWLOCALADDR;

DWORD DWLOCALPORT;

DWORD DWPROCESSID;

} MiB_udprow_ex, * pmib_udprow_ex;

Typedef struct _MIB_UDPTABLE_EX

{

DWORD DWNUMENTRIES;

MIB_UDPROW_EX TABLE [Any_SIZE];

} MiB_udptable_ex, * pmib_udptable_ex;

DWORD WINAPI AllocateandGetTcptableFromstack

OUT PMIB_TCPTABLE * PTCPTABLE,

In Bool Border,

In Handle Hallocheap,

In dword dwallocflags,

IN DWORD DWPROTOCOLVERSION;

);

DWORD WINAPI AllocateAndgetudPtableFromstack

Out pmib_udptable * pudptable,

In Bool Border,

In Handle Hallocheap,

In dword dwallocflags,

IN DWORD DWPROTOCOLVERSION;

);

DWORD WINAPI AllocateandGetTcPextableFromstack

OUT PMIB_TCPTABLE_EX * PTCPTABLEEX,

In Bool Border,

In Handle Hallocheap,

In dword dwallocflags,

IN DWORD DWPROTOCOLVERSION;

);

DWORD WINAPI AllocateAndgetudpextableFromstack

OUT PMIB_UDPTABLE_EX * PUDPTABLEEX,

In Bool Border,

In Handle Hallocheap,

In dword dwallocflags,

IN DWORD DWPROTOCOLVERSION;

);

There is also a way to do this. When a program creates a socket and start listening, it will get one

The handle is used to open the port. We can enumerate all open handles in the system and pass NTDeviceIocontrolfile

They send a special buffer field to detect if this handle is used to open the port. This can also give us about this

Port information. Because there are many open handles, we only need to detect types of file and name is / device / TCP

Or / Device / UDP. Opened ports have only this type and name.

When we look at the code in iPhlPapi.dll, we can learn that these functions also call the function NTDEVICEICONTROLFILE and send a special buffer field to get all the columns in the system.

table. This means that the only function that needs us to hook only NTDeviceiocontrolFile.

NTSTATUS NTDEVICEIOCONTROLFILE

In Handle FileHandle

In Handle Event Optional,

IN PIO_APC_ROUTINE APCROUTINE OPTIONAL,

In Pvoid ​​APCCONText Optional,

OUT PIO_STATUS_BLOCK IOSTATUSBLOCK,

In Ulong IoControlcode,

In Pvoid ​​InputBuffer Optional,

In Ulong InputBufferLength,

Out Pvoid ​​OutputBuffer Optional,

In Ulong OutputBufferlength

);

The parameters we are interested in are the specified device handle FileHandle, pointing to receiving completion status and request operation letter.

IOSTATUSBLOCK, specify IOCONTROLCODE, specified device type, method, access, and a function. InputBuffer

Contains input data for InputBufferLength, this and OutputBuffer and OutputBufferLength Class

like.

===== [10.1 WinXP NetStart, Opports, winxp's fport] =============================

The first way to get all open port lists is Opports and Fports of Windows XP, while there is Windows

XP's NetStat.

This process calls NTDEVICEIOCONTROLFILE for two IOCONTROLCODE = 0x000120003. OutputBuffer

Fill it after the second call. FileHandle's name is here for / device / tcp. InputBuffer according to call

The type is different and different.

1) In order to obtain the MIB_TCPROW array, the InputBuffer should be:

First call:

0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x00 0x00 0x00 0x00

Second call:

0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x00 0x00 0x00 0x00

2) Get a MIB_UDPROW array:

First call:

0x01 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x000x00 0x00 0x00 0x00

Second call:

0x01 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x00 0x00 0x00 0x00

3) Get a MIB_TCPROW_EX array:

First call:

0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x00 0x00 0x00 0x00

Second call:

0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x02 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x00 0x00 0x00 0x00

4) Get a MIB_UDPROW_EX array:

First call:

0x01 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x00 0x00 0x00 0x00

Second call:

0x01 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x01 0x00 0x00

0x02 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

0x00 0x00 0x00 0x00

You can see that there are only a few bytes in the data in the buffer. We can clearly summarize as follows:

Call requires inputbuffer [1] to 0x04 and most of the invutbuffer [17] is 0x01. Only in this way

Get the list of our hopes in OutputBuffer. If we have to get information about TCP ports, we have to put

InputBuffer [0] is set to 0x00, if you want to get information about UDP, set to 0x01. If we have to get

Extended output list (MIB_TCPROW_EX or MIB_UB_UDPROW_EX), we put inputbuffer in the second call

[16] is set to 0x02.

If we understand these parameters, we can change the output buffer. We can simmer

Single place in the IostatusBlock in the INFORMATION in addition to the size of the line. It is very simple to hide one line. Just use the latter

Cover it and delete the last line. Don't forget to change OutputBufferlength and iostatusblock.

===== [10.2 Win2K and NT4 Opports, win2k fport] ================================= We call NtDeviceiocontrolFile through IOCONTROLCODE = 0x00210012 to determine a type File, name

Words / Device / TCP or / Device / UDP handle is a open port handle.

So first we have to compare IOControlcode and then the type and name. If you still care about other, we can compare

The size of the buffer should be equal to the size of the TDI_CONNECTION_IN structure. This length is 0x18. OutputBuffer

Is TDI_CONNECTION_OUT.

Typedef struct _tdi_connetion_in

{

Ulong UserDarata,

Pvoid ​​Userdata,

Ulong OptionsLength,

PVOID OPTIONS,

Ulong RemoteaddressionLength,

Pvoid ​​RemoteAddress

} TDI_CONNETION_IN, * PTDI_CONNETION_IN;

Typedef struct _tdi_connetion_out

{

Ulong State,

Ulong Event,

Ulong Transmittedtsdus,

Ulong Receivedtsdus,

Ulong TransmissionerRors,

Ulong ReceiveErrorS,

Large_integer throughput

Large_integer delay,

Ulong Sendbuffersize,

Ulong ReceiveBuffersize,

Ulong unreliable,

Ulong unknown1 [5],

USHORT UNKNOWN2

} TDI_CONNETITON_OUT, * PTDI_CONNETION_OUT

Determine if a handle is a specific implementation that opens the port can be found in the opports code, it is

Http: // rookit.

Host.sk. We now interested in hiding a specified port. We compare InputBufferLength and IOCON-

Trolcode. RemoteAddressLength was also compared. This value is usually 3 or 4 for the open port. Finally we want

Do it is the RECEIVEDTSDUS in OutputBuffer, which contains the fracture in the network and the port we want to hide.

List. TCP and UDP can distinguish between the name of the handle. Change the IO- by deleting some values ​​in OutputBuffer

StatusBlock and returns status_invalid_address We can hide this port.

===== [11. Conclusion] ========================================== =====================

The specific implementation of the techniques described above can be found in the 1.0.0 version of HACKER Defender Rootkit, its homepage

Yes

http://rootkit.host.sk and

Http://www.rootkit.com.

I will also add some other hidden technologies under Windows NT. The new version of this document will contain

Improvement of technology and some new views.

Special gratitude to Ratter, he told me a lot of knowledge to help me complete this document and complete the HACKER Defender item.

Objective to write.

If you have any comments, you can send an email to holy_father@phreaker.net or to

Http://rootkit.host.sk

Message board message.

==================================== [end] =========== ===========================

转载请注明原文地址:https://www.9cbs.com/read-50223.html

New Post(0)