Invisibility on NT boxes

国央企创新负责人如何通过平台提升技术需求挖掘与资源配置的精准性?.docx 国央企创新负责人如何通过平台提升技术需求挖掘与资源配置的精准性? 立即下载
=========================[ 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
                           Web: http://www.hxdef.org, http://hxdef.net.ru,
                                http://hxdef.czweb.org, http://rootkit.host.sk
                          Link: http://www.rootkit.com


=====[ 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(
                OUT PHANDLE KeyHandle,
                IN ACCESS_MASK DesiredAccess,
                IN POBJECT_ATTRIBUTES ObjectAttributes
        );

        KeyHandle is a handle of superordinate key. We will use the value from 
NtEnumerateKey for it. DesiredAccess are access rights. KEY_ENUMERATE_SUB_KEYS 
is the right value for it. ObjectAttributes describes subkey which we want to 
open (including its name).

        #define KEY_ENUMERATE_SUB_KEYS 8

        If the result of NtOpenKey is 0 opening was successful which mean this 
key from our list exists. Opened key should be closed via NtClose.

        NTSTATUS NtClose(
                IN HANDLE Handle
        );

        
        For each call of NtEnumareteKey we will count the shift as a number of 
keys from our list which exist in the given part of registry. Then we will add 
this shift to Index argument and finally call the original NtEnumerateKey.
        For getting name of the key specified by Index we will use the value 
KeyBasicInformation as a KeyInformationClass.

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

        Only thing we need here is Name and its length NameLength.
        If there is no entry for shifted Index we will return error 
STATUS_EA_LIST_INCONSISTENT.

        #define STATUS_EA_LIST_INCONSISTENT 0x80000014


=====[ 5.2 NtEnumerateValueKey ]================================================

        Registry values are not alphabetically sorted. Luckily the number 
of values in one key is quite small, so we can use recall method to get 
the shift. API for getting info about one value is called NtEnumerateValueKey.

        NTSTATUS NtEnumerateValueKey(
                IN HANDLE KeyHandle,
                IN ULONG Index,
                IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
                OUT PVOID KeyValueInformation,
                IN ULONG KeyValueInformationLength,
                OUT PULONG ResultLength
        );

        KeyHandle is again a handle of superordinate key. Index is an index 
to the list of values in given key. KeyValueInformationClass describes a type 
of information which will be stored into KeyValueInformation buffer which 
is long KeyValueInformationLength bytes. Number of written bytes is returned 
in ResultLength.
        Again we have to count the shift but according to the number of values 
in one key we can recall this function for all indexes from 0 to Index. 
The name of the value can be get when KeyValueInformationClass is set to 
KeyValueBasicInformation.
        
        #define KeyValueBasicInformation 0


        Then we will get following structure in 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;

        Again we are interested only in Name and NameLength.

        
        If there is no entry for shifted Index we will return error 
STATUS_NO_MORE_ENTRIES.

        #define STATUS_NO_MORE_ENTRIES 0x8000001A



=====[ 6. System services and drivers ]=========================================

        System services and drivers are enumerated by four independent API
functions. Their connections is different in each Windows version. That's why 
we have to hook all four functions. 

        BOOL EnumServicesStatusA(
                SC_HANDLE hSCManager,
                DWORD dwServiceType,
                DWORD dwServiceState,
                LPENUM_SERVICE_STATUS lpServices,
                DWORD cbBufSize,
                LPDWORD pcbBytesNeeded,
                LPDWORD lpServicesReturned,
                LPDWORD lpResumeHandle
        );

        BOOL EnumServiceGroupW(
                SC_HANDLE hSCManager,
                DWORD dwServiceType,
                DWORD dwServiceState,
                LPBYTE lpServices,
                DWORD cbBufSize,
                LPDWORD pcbBytesNeeded,
                LPDWORD lpServicesReturned,
                LPDWORD lpResumeHandle,
                DWORD dwUnknown
        );

        BOOL EnumServicesStatusExA(
                SC_HANDLE hSCManager,
                SC_ENUM_TYPE InfoLevel,
                DWORD dwServiceType,
                DWORD dwServiceState,
                LPBYTE lpServices,
                DWORD cbBufSize,
                LPDWORD pcbBytesNeeded,
                LPDWORD lpServicesReturned,
                LPDWORD lpResumeHandle,
                LPCTSTR pszGroupName
        );

        BOOL EnumServicesStatusExW(
                SC_HANDLE hSCManager,
                SC_ENUM_TYPE InfoLevel,
                DWORD dwServiceType,
                DWORD dwServiceState,
                LPBYTE lpServices,
                DWORD cbBufSize,
                LPDWORD pcbBytesNeeded,
                LPDWORD lpServicesReturned,
                LPDWORD lpResumeHandle,
                LPCTSTR pszGroupName
        );


        The most important here is lpServices which points on the buffer where 
the list of services would be stored. And also lpServicesReturned pointing on 
the number of records in result is important. Structure of data in the output 
buffer depends on the type of function. For functions EnumServicesStatusA 
and EnumServicesGroupW is returned structure 

        typedef struct _ENUM_SERVICE_STATUS {
                LPTSTR lpServiceName;
                LPTSTR lpDisplayName;
                SERVICE_STATUS ServiceStatus;
        } ENUM_SERVICE_STATUS, *LPENUM_SERVICE_STATUS;

        typedef struct _SERVICE_STATUS {
                DWORD dwServiceType;
                DWORD dwCurrentState;
                DWORD dwControlsAccepted;
                DWORD dwWin32ExitCode;
                DWORD dwServiceSpecificExitCode;
                DWORD dwCheckPoint;
                DWORD dwWaitHint;
        } SERVICE_STATUS, *LPSERVICE_STATUS;

for EnumServicesStatusExA a EnumServicesStatusExW it it

        typedef struct _ENUM_SERVICE_STATUS_PROCESS {
                LPTSTR lpServiceName;
                LPTSTR lpDisplayName;
                SERVICE_STATUS_PROCESS ServiceStatusProcess;
        } ENUM_SERVICE_STATUS_PROCESS, *LPENUM_SERVICE_STATUS_PROCESS;

        typedef struct _SERVICE_STATUS_PROCESS {
                DWORD dwServiceType;
                DWORD dwCurrentState;
                DWORD dwControlsAccepted;
                DWORD dwWin32ExitCode;
                DWORD dwServiceSpecificExitCode;
                DWORD dwCheckPoint;
                DWORD dwWaitHint;
                DWORD dwProcessId;
                DWORD dwServiceFlags;
        } SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;


        We are interested only in lpServiceName which is the name of system 
service. Records have static size, so if we want to hide one we will move all 
following records by its size. Here we have to differentiate between the size 
of SERVICE_STATUS and SERVICE_STATUS_PROCESS.



=====[ 7. Hooking and spreading ]===============================================

        To get the desiderative efect we have to hook all running processes 
and also all processes which would be created later. New processes should be 
hooked before running their first instruction of their own code otherwise 
they would be able to see our hidden objects in the time before they would be 
hooked.
        

=====[ 7.1 Rights ]=============================================================

        At first it is good to know that we need at least administrators rights
to get access to all running processes. The best possibility is to run our 
process as system service which run on user SYSTEM. To install the service we 
also need special rights. 
        Also getting SeDebugPrivilege is very useful. This can be done using 
API OpenProcessToken, LookupPrivilegeValue and AdjustTokenPrivileges.

        BOOL OpenProcessToken(
                HANDLE ProcessHandle,
                DWORD DesiredAccess,
                PHANDLE TokenHandle
        );

        BOOL LookupPrivilegeValue(
                LPCTSTR lpSystemName,
                LPCTSTR lpName,
                PLUID lpLuid
        );

        BOOL AdjustTokenPrivileges(
                HANDLE TokenHandle,
                BOOL DisableAllPrivileges,
                PTOKEN_PRIVILEGES NewState,
                DWORD BufferLength,
                PTOKEN_PRIVILEGES PreviousState,
                PDWORD ReturnLength
        );


        Neglecting errors the code can look like this:

        #define SE_PRIVILEGE_ENABLED    0x0002
        #define TOKEN_QUERY             0x0008
        #define TOKEN_ADJUST_PRIVILEGES 0x0020

        HANDLE hToken;
        LUID DebugNameValue;
        TOKEN_PRIVILEGES Privileges;
        DWORD dwRet;

        OpenProcessToken(GetCurrentProcess(),
                         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,hToken);
        LookupPrivilegeValue(NULL,"SeDebugPrivilege",&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 ]========================================================

        Enumeration of processes is done by already metioned API function 
NtQuerySystemInformation. There are few native processes in the system, so we 
will use the method of rewriting first instructions of the function to hook 
them. For each running process we will do the same. We will allocate a part 
of memory in target process where we will write our new code for functions 
we want to hook. Then we will change the first five bytes of these functions 
with jmp instruction. This jump will redirect the execution to our code. 
So the jmp instruction will be executed immediately when the hooked function is 
called. We have to save first instructions of each function which is rewritten. 
We need them to call original code of the hooked function. Saving instructions 
is described in chapter 3.2.3 in the document "Hooking Windows API".
        At first we have to open target process via NtOpenProcess and get 
the handle. This will fail if we don't have enough rights. 

        NTSTATUS NtOpenProcess(
                OUT PHANDLE ProcessHandle,
                IN ACCESS_MASK DesiredAccess,
                IN POBJECT_ATTRIBUTES ObjectAttributes,
                IN PCLIENT_ID ClientId OPTIONAL
        );

        ProcessHandle is a pointer on a handle where the result will be stored. 
DesiredAccess should be set on PROCESS_ALL_ACCESS. We will set PID of target 
process to UniqueProcess part of ClientId structure, UniqueThread should be 0.
Open handle can be always closed via NtClose.

        #define PROCESS_ALL_ACCESS 0x001F0FFF

        Now we are going to allocate the part of memory for our code. This can 
be done using NtAllocateVirtualMemory.

        NTSTATUS NtAllocateVirtualMemory(
                IN HANDLE ProcessHandle,
                IN OUT PVOID BaseAddress,
                IN ULONG ZeroBits,
                IN OUT PULONG AllocationSize,
                IN ULONG AllocationType,
                IN ULONG Protect
        );

        ProcessHandle is the one from NtOpenProcess. BaseAddress is a pointer 
on a pointer on the beginning where we want to allocate. Here will be stored 
the address of the allocated memory. Input value can be NULL. AllocationSize 
is a pointer on number of bytes we want to allocate. And again it is also used 
as output value for the real number of allocated bytes. It is good to set 
AllocationType to MEM_TOP_DOWN in addition to MEM_COMMIT because the memory 
would be allocated on the highest possible address near DLLs.

        #define MEM_COMMIT      0x00001000
        #define MEM_TOP_DOWN    0x00100000      


        Then we can write our code there using NtWriteVirtualMemory.

        NTSTATUS NtWriteVirtualMemory(
                IN HANDLE ProcessHandle,
                IN PVOID BaseAddress,
                IN PVOID Buffer,
                IN ULONG BufferLength,
                OUT PULONG ReturnLength OPTIONAL
        );

        BaseAddress will be that address returned by NtAllocateVirtualMemory. 
Buffer points on bytes we want to write, BufferLength is number of bytes we 
want to write.

        Now we have to hook single functions. Only library which is loaded to 
all processes is ntdll.dll. So we have to check if function we want to hook is 
imported to the process if it is not from ntdll.dll. But the memory where would 
this function (from another DLL) be could be allocated, so rewriting bytes on 
its address could easily cause error in target process. This is why we have to 
check whether library (where function we want to hook is) is loaded to target 
process.
        We need to get PEB (Process Environment Block) of target process via 
NtQueryInformationProcess.

        NTSTATUS NtQueryInformationProcess(
                IN HANDLE ProcessHandle,
                IN PROCESSINFOCLASS ProcessInformationClass,
                OUT PVOID ProcessInformation,
                IN ULONG ProcessInformationLength,
                OUT PULONG ReturnLength OPTIONAL
        );

        We will set ProcessInfromationClass to ProcessBasicInformation. Then 
the PROCESS_BASIC_INFORMATION structure would be returned to ProcessInformation 
buffer which size is given by 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 were looking for. On PebBaseAddress+0x0C is 
address PPEB_LDR_DATA. This would be get calling NtReadVirtualMemory.

        NTSTATUS NtReadVirtualMemory(
                IN HANDLE ProcessHandle,
                IN PVOID BaseAddress,
                OUT PVOID Buffer,
                IN ULONG BufferLength,
                OUT PULONG ReturnLength OPTIONAL
        );

        Parameters are similar like in NtWriteVirtualMemory. 
        On PPEB_LDR_DATA+0x1C is address InInitializationOrderModuleList. It is 
the list of libraries loaded to the process. We are interested only in a part 
of this structure.

        typedef struct _IN_INITIALIZATION_ORDER_MODULE_LIST {
                PVOID Next,
                PVOID Prev,
                DWORD ImageBase,
                DWORD ImageEntry,
                DWORD ImageSize,
                ...
        );

        Next is a pointer on next record, Prev on previous, last record points 
on first. ImageBase is an address of module in the memory, ImageEntry is 
the EntryPoint of the module, ImageSize is its size.
        
        For all libraries in which we want to hook we will get their ImageBase 
(e.g. using GetModuleHandle or LoadLibrary). This ImageBase we will compare 
with ImageBase of each entry in InInitializationOrderModuleList.
        Now we are ready for hooking. Because we are hooking running processes 
there is a possibility that the code we would be executed in the moment we will 
be rewriting it. This can cause error, so at first we will stop all threads 
in target process. The list of its threads can get via NtQuerySystemInformation 
with SystemProcessesAndThreadsInformation class. Result of this function is 
described in chapter 4. But we have to add the description of SYSTEM_THREADS 
structure where the information about thread is.

        typedef struct _SYSTEM_THREADS {
                LARGE_INTEGER KernelTime;
                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; 

        For each thread we have to get its handle using NtOpenThread. We will 
use ClientId for it.

        NTSTATUS NtOpenThread(
                OUT PHANDLE ThreadHandle,
                IN ACCESS_MASK DesiredAccess,
                IN POBJECT_ATTRIBUTES ObjectAttributes,
                IN PCLIENT_ID ClientId
        );

        The handle we want will be stored to ThreadHandle. We will set 
DesiredAccess to THREAD_SUSPEND_RESUME.

        #define THREAD_SUSPEND_RESUME 2

        ThreadHandle will be used for calling NtSuspendThread.

        NTSTATUS NtSuspendThread(
                IN HANDLE ThreadHandle,
                OUT PULONG PreviousSuspendCount OPTIONAL
        );


        Suspended process is ready for rewriting. We will proceed as it is 
described in chapter 3.2.2 in "Hooking Windows API". Only difference will be 
in using functions for other processes.

        After a hook we will revive all process threads calling NtResumeThread.

        NTSTATUS NtResumeThread(
                IN HANDLE ThreadHandle,
                OUT PULONG PreviousSuspendCount OPTIONAL
        );


=====[ 7.3 New processes ]======================================================

        Infection of all running processes does not affect processes which 
would be run later. We could get the process list and after a while get a new 
one and compare them and then infect those processes which are in second list 
but not in first. But this method is very unreliable.
        Much better is to hook function which is always called when new process 
starts. Because of hooking all running processes on the system we can't miss 
any new with this method. We can hook NtCreateThread but it is not the easiest 
way. We will hook NtResumeThread which is also called everytime after the new 
process is created. It is called after NtCreateThread.
        The only problem with NtResumeThread is that it is called not only when 
new process starts. But we can easily get over this. NtQueryInformationThread 
will give us an information about which process owns the specific thread. 
The last thing we have to do is to check whether this process is already hooked 
or not. This can be done by reading first byte of any function we are hooking.

        NTSTATUS NtQueryInformationThread(
                IN HANDLE ThreadHandle,
                IN THREADINFOCLASS ThreadInformationClass,
                OUT PVOID ThreadInformation,
                IN ULONG ThreadInformationLength, 
                OUT PULONG ReturnLength OPTIONAL
        );

        ThreadInformationClass is information class and it should be set in our 
case to ThreadBasicInformation. ThreadInformation is the buffer for result 
which size is ThreadInformationLength bytes.

        #define ThreadBasicInformation 0

        For class ThreadBasicInformation is this structure returned: 

        typedef struct _THREAD_BASIC_INFORMATION {
                NTSTATUS ExitStatus;
                PNT_TIB TebBaseAddress;
                CLIENT_ID ClientId;
                KAFFINITY AffinityMask;
                KPRIORITY Priority;
                KPRIORITY BasePriority;
        } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;

        In ClientId is the PID of which owns the thread.

        Now we have to infect the new process. The problem is that the new 
process has only ntdll.dll in its memory. All others modules are loaded 
immediately after calling NtResumeThread. There are several ways how to handle 
this problem. E.g. we can hook API called LdrInitializeThunk which is called 
during process init.

        NTSTATUS LdrInitializeThunk(
                DWORD Unknown1,
                DWORD Unknown2,
                DWORD Unknown3
        );

        At first we will run original code and then we will hook all functions 
we want in this new process. But it will be better to unhook LdrInitializeThunk 
because it is called many times later and we don't want to rehook all functions 
again. Everything here is done before execution of the first instruction of 
hooked application. That's why there is no chance it would call any of hooked 
functions before we hook it.
        The hooking in itself is the same as when hooking running process 
but here we don't care about running threads.


=====[ 7.4 DLL ]================================================================

        In each process in the system is the copy of ntdll.dll. That mean we 
can hook any function from this module in the process init. But how about 
functions from other modules like kernel32.dll or advapi32.dll? And there are 
also several processes which has only ntdll.dll. All other modules can be 
loaded dynamically in the middle of the code after the process hook. That's why 
we have to hook LdrLoadDll which loades new modules.
        
        NTSTATUS LdrLoadDll( 
                PWSTR szcwPath,
                PDWORD pdwLdrErr,      
                PUNICODE_STRING pUniModuleName,
                PHINSTANCE pResultInstance
        );

        The most important for us here is pUniModuleName which is the name of 
the module. pResultInstance will be filled with its address if the call is 
successful.
        We will call original LdrLoadDll and then hook all functions in loaded 
module.



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

        When we are hooking a function we modify its first bytes. Via calling 
NtReadVirtualMemory anyone can detect that a function is hooked. So we have to 
hook NtReadVirtualMemory to prevent detecting.

        NTSTATUS NtReadVirtualMemory(
                IN HANDLE ProcessHandle,
                IN PVOID BaseAddress,
                OUT PVOID Buffer,
                IN ULONG BufferLength,
                OUT PULONG ReturnLength OPTIONAL
        );

        We have changed bytes on the begining of all functions we hooked and 
we have also allocated memory for our new code. We should check whether caller 
reads some of these bytes. If we have our bytes in the range from BaseAddress 
to BaseAddress + BufferLength we have to change some bytes in Buffer.
        If one ask for bytes from our allocated memory we should return empty 
Buffer and an error STATUS_PARTIAL_COPY. This value says not all requested 
bytes were copied to the Buffer. It is also used when asking for unallocated 
memory. ReturnLength should be set to 0 in this case.

        #define STATUS_PARTIAL_COPY 0x8000000D

        If one ask for first bytes of hooked function we have to call original 
code and than we should copy original bytes (we have saved them for original 
calls) to Buffer. 
        Now the process is not able to detect he is hooked via reading its 
memory. Also if you debug hooked process debugger will have a problem. It will 
show original bytes but it will execute our code.

        To make hiding perfect we can also hook NtQueryVirtualMemory. This 
function is used to get information about virtual memory. We can hook it to 
prevent detecting our allocated memory.

        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 class of data which are returned. 
First two types are interesting for us.

        #define MemoryBasicInformation 0
        #define MemoryWorkingSetList 1

        For class MemoryBasicInformation is returned this structure:

        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 section has its size RegionSize and its type Type. Free 
memory has type MEM_FREE.

        #define MEM_FREE 0x10000

        If a section before ours has type MEM_FREE we should add the size of 
ours section to its RegionSize. If the following section is also MEM_FREE we 
should add following section size again that RegionSize.
        If a section before ours has another type we will return MEM_FREE 
for our section. Its size is counted again according to following section.

        For class MemoryWorkingSetList is returned 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 decreased. We should find ours section in WorkingSetList and move 
following records over ours. WorkingSetList is an array of DWORDs where higher 
20 bits specifies higher 20 bits of section address and lower 12 bits specifies 
flags.



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

        Calling NtQuerySystemInformation with SystemHandleInformation class
gives us array of all open handles in _SYSTEM_HANDLE_INFORMATION_EX strucure.

        #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 which owns the handle. ObjectTypeNumber 
is handle type. NumberOfHandles is number of records in Information array. 
Hiding one item is trivial. We have to remove all following records by one 
and decrease NumberOfHandles. Removing all following is needed because handles 
in array are grouped by ProcessId. That mean all handles from one single 
process are together. And for one process the number Handle is growing.
        Now remember structure _SYSTEM_PROCESSES which is returned by this 
function with SystemProcessesAndThreadsInformation class. Here we can see that 
each process has an information about its number of handles in HandleCount. 
If we want to be perfect we should modify HandleCount owing to how many handles 
we hide when calling this function with SystemProcessesAndThreadsInformation
class. But this correction would be very time-consuming. There are many handles 
opening and closing in very short time during normal system running. So it can 
easily happend that number of handles is changed in between two calls of this 
function and we don't need to change HandleCount.


=====[ 9.1 Naming handle and getting type ]=====================================

        Handle hiding is trivial but find out which handle to hide is little 
bit harder. If we have e.g. hidden process we should hide all its handles and 
all handles which are connected with it. Hiding handles of this process is 
again trivial. We are only comparing ProcessId of handle and PID of our process 
and when they equals we hide it. But handles of other processes have to be 
named before we can compare something. The number of handles in the system is 
usually very big, so the best we can do is to compare handle type first before 
trying to name it. Naming types will save a lot of time for handles we are not 
interested in. 
        Naming handle and handle type can be done via 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 want to get info about, 
ObjectInformationClass is the type of information which will be stored into 
ObjectInformation buffer which is ObjectInformationLength bytes long.
        We will use class ObjectNameInformation and ObjectAllTypesInformation.
ObjectNameInfromation class will fill the buffer with OBJECT_NAME_INFORMATION 
structure, ObjectAllTypesInformation class with OBJECT_ALL_TYPES_INFORMATION 
structure then.

        #define ObjectNameInformation 1
        #define ObjectAllTypesInformation 3

        typedef struct _OBJECT_NAME_INFORMATION {
                UNICODE_STRING Name;
        } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;

        Name determines 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 InvalidAttributes;
                GENERIC_MAPPING GenericMapping;
                ULONG ValidAccess;
                UCHAR Unknown;
                BOOLEAN MaintainHandleDatabase;
                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 determines the name of type object which immediately follows 
each OBJECT_TYPE_INFORMATION structure. The next OBJECT_TYPE_INFORMATION 
structure follows this Name, starting on the first four-byte boundary.
        
        ObjectTypeNumber from SYSTEM_HANDLE_INFORMATION structure is an index 
to TypeInformation array.

        Harder is to get the name of handle from other process. There are two 
possibilities how to name it. First is to copy the handle via NtDuplicateObject 
to our process and then to name it. This method will fail for some specific 
types of handles. But it will fail only for few, so we can stay calm and use 
this.

        NtDuplicateObject(
                IN HANDLE SourceProcessHandle,
                IN HANDLE SourceHandle,
                IN HANDLE TargetProcessHandle,
                OUT PHANDLE TargetHandle OPTIONAL,
                IN ACCESS_MASK DesiredAccess,
                IN ULONG Attributes,
                IN ULONG Options
        );

        SourceProcessHandle is a handle of process which owns SourceHandle 
which is the handle we want to copy. TargetProcessHandle is handle of process 
where to copy. This will be handle to our process in our case. TargetHandle 
is the pointer on handle where to save a copy of original handle. DesiredAccess 
should be set to PROCESS_QUERY_INFORMATION, Attribures and Options to 0.

        Second naming method which works with any handle is to use system 
driver. Source code for this is available in OpHandle project on my site. 



=====[ 10. Ports ]==============================================================

        The easiest way to enumarate open ports is to use functions called 
AllocateAndGetTcpTableFromStack and AllocateAndGetUdpTableFromStack, and or
AllocateAndGetTcpExTableFromStack and AllocateAndGetUdpExTableFromStack from
iphlpapi.dll. The Ex functions are available since Windows 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 another way to do this stuff. When program creates a socket
and starts listening it surely has an open handle for it and for open port.
We can enumerate all open handles in the system and send them special buffer 
via NtDeviceIoControlFile to find out whether the handle is for open port 
or not. This will also give us information about the port. Because there are 
a lot of open handles we will test only handles which type is File and name 
is /Device/Tcp or /Device/Udp. Open ports have only this type and name.

        When we look to the code of iphlpapi.dll functions above we find out 
that these functions also calls NtDeviceIoControlFile and sends special buffer 
to get a list of all open ports in the system. That mean only functions we 
need to hook for hiding ports is 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
        );      

        Interesting agruments for us now are FileHandle which specify a handle 
of device to communicate with, IoStatusBlock which points to a variable that 
receives the final completion status and information about the requested 
operation, IoControlCode that is a number specifying type of the device, 
method, file access and a function. InputBuffer contains input data that are 
InputBufferLength bytes long and similarly OutputBuffer and OutputbufferLength.

       
=====[ 10.1 Netstat, OpPorts on WinXP, FPort on WinXP ]=========================

        Getting a list of all open ports is the first way which is used by e.g. 
OpPorts and FPort on Windows XP and also Netstat.
        Programs calls here NtDeviceIoControlFile twice with IoControlCode 
0x000120003. OutputBuffer is filled after a second call. Name of FileHandle is 
here alwats /Device/Tcp. InputBuffer differs for different types of call:

        1) To get an array of MIB_TCPROW InputBuffer looks as follows:

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) To get an array of MIB_UDPROW:

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 
0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x00 0x00 0x00 


        3) To get an array of MIB_TCPROW_EX:

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) To get an array of MIB_UDPROW_EX:

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 the buffers are different in few bytes only. We can lucidly
recapitulate these:
        
        Calls we are interested in have InputBuffer[1] set to 0x04 and mainly 
InputBuffer[17] on 0x01. Only after these input data we get filled OutputBuffer
with desiderative tables. If we want to get info about TCP ports we set 
InputBuffer[0] on 0x00, or on 0x01 for information about UDP. If we want 
extended output tables (MIB_TCPROW_EX or MIB_UDPROW_EX) we use Inputbuffer[16]
in second call set to 0x02.

        If we find out the call with these parameters we can change the output 
buffer. To get number of rows in output buffer simply divide Information from 
IoStatusBlock by size of the row. Hiding of one row is easy then. Just rewrite 
it with following rows and delete last row. Don't forget to change 
OutputBufferLength and IoStatusBlock.


=====[ 10.2 OpPorts on Win2k and NT4, FPort on Win2k ]==========================

        We use NtDeviceIoControlFile with IoControlCode 0x00210012 to determine 
if the handle of File type and name /Device/Tcp or /Device/Udp is the handle of 
open port.

        So at first we compare IoControlCode and then a type and the name of 
the handle. If it is still interesting then we compare the length of input 
buffer which should be equal to the length of struct TDI_CONNECTION_IN. This 
length is 0x18. OutputBuffer is TDI_CONNECTION_OUT.

        typedef struct _TDI_CONNECTION_IN
        {
                ULONG UserDataLength,
                PVOID UserData,
                ULONG OptionsLength,
                PVOID Options,
                ULONG RemoteAddressLength,
                PVOID RemoteAddress
        } TDI_CONNECTION_IN, *PTDI_CONNECTION_IN;

        typedef struct _TDI_CONNECTION_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_CONNECTION_OUT, *PTDI_CONNECTION_OUT;


        Concrete implementation of how to determine the handle is open port 
is available in source code of OpPorts on my site. We are interested in hiding 
specific port now. We already compared InputBufferLength and IoControlCode. 
Now we have to compare RemoteAddressLength. This is always 3 or 4 for open 
port. The last we have to do is to compare ReceivedTsdus from OutputBuffer 
which contains the port in network form and our list of ports we want to hide. 
Differentiate between TCP and UDP is done according to the name of the handle. 
By deleting OutputBuffer, changing IoStatusBlock and returning the value 
of STATUS_INVALID_ADDRESS we will hide this port.


       
=====[ 11. Ending ]=============================================================

        Concrete implementation of described techniques will be available with 
the source code of Hander defender rootkit in version 1.0.0 on my site.
        It is possible I will add some more information about invisibility on 
Windows NT in the future. New versions of this document could also contain  
improvement of described methods or new comments. 
        Special thanks to Ratter who give me a lot of knowhow which was 
necessary to write this document and to code project Hacker defender. 
        Send all remarks into my mailbox or put them on the board on my site.

===================================[ End ]======================================
科技中介服务机构在协助企业对接科研成果时,如何提升服务响应速度与专业化水平.docx 科技中介服务机构在协助企业对接科研成果时,如何提升服务响应速度与专业化水平 立即下载

相关推荐

国央企创新负责人在推动内部技术成果转化与外部协同创新时,如何实现资源的高效整合与协同联动?.docx

国央企创新负责人在推动内部技术成果转化与外部协同创新时,如何实现资源的高效整合与协同联动?

区域电网含风光火压缩空气储能抽水蓄能以及电化学储能的联合调度,加入IEEE39系统,进行潮流计算,分析电能质量研究(Matlab代码实现)

内容概要:本文研究了包含风能、太阳能、火电以及压缩空气储能、抽水蓄能和电化学储能等多种能源形式的区域电网联合调度问题,通过将系统接入IEEE 39节点标准测试系统,利用Matlab平台开展潮流计算与电能质量分析,旨在提升高比例可再生能源接入背景下电网运行的稳定性与供电品质。研究重点涵盖多类型电源与多种储能系统的协调优化调度策略设计,深入探讨储能系统在削峰填谷、平滑新能源出力波动方面的关键作用,并对复杂运行工况下电压偏差、频率波动、谐波污染等电能质量问题进行评估与改善。通过构建完整的仿真模型,系统性地分析了联合调度对电网电能质量的影响机制,为现代电力系统中多能互补与协同控制提供了理论依据和技术参考。; 适合人群:具备电力系统分析、优化调度及电能质量相关基础知识,熟悉Matlab/Simulink仿真环境的研究生、科研人员及电力系统相关领域的工程师。; 使用场景及目标:①为含多种储能的区域电网联合调度研究提供完整的Matlab仿真案例与开源代码参考;②分析大规模新能源接入对IEEE 39系统潮流分布及电能质量的综合影响,并定量评估不同类型储能系统的调控效果;③为电力系统优化调度、电能质量综合治理、多能协同控制等学术研究与工程项目提供可复现的技术支撑与解决方案。; 阅读建议:本资源以Matlab代码实现为核心,读者应在掌握电力系统基本理论的基础上,重点关注联合调度的数学建模过程、储能系统充放电策略的制定逻辑以及电能质量各项评价指标的计算方法。建议在学习过程中动手调试仿真代码,尝试调整系统参数、优化目标权重或改变新能源渗透率,以深入理解系统动态行为与控制策略的有效性。

机器人入门实战:用 ROS2 和 Gazebo 先把差速车 URDF 跑起来,再做一版 SLAM 建图(含教学手册与源码骨架)

原创教学资源包(VIP专属)。围绕机器人开发项目实战搭建可复现闭环:用差速车 URDF 把 base_link、左右轮和激光连杆的关节树写自洽,配一间教学库房的 Gazebo 世界与 launch 骨架;再提供一版合成二维占用栅格建图,对比纯里程计写入和扫描匹配修正,用来分辨 odom 系漂移与 map 系 SLAM 输出。内含中文实战手册与可 make 抽检的 ROS 2 源码骨架。实现均为教学桩,注释标明不是完整 Navigation2 栈,不能替代实机传感器标定,也不是 Cartographer / slam_toolbox 的生产方案。 使用方法:解压后进入 src/ 目录(需 Linux、Python 3;不必安装 ROS 2 或 Gazebo 也能抽检)。先执行 make clean && make test,或运行 python3 scripts/smoke_test.py,看到 ALL SMOKE TESTS PASSED 后再阅读手册.md、README.md 与源码注释。若本机已安装 ROS 2 Humble/Jazzy 与 Gazebo,再把 src/diffbot_slam_tutor 放入工作空间,按 README 中「读者本地环境再跑」的 launch 命令启动仿真。细节见手册.md 与 src/README_SRC.txt。 适合作为成长任务「机器人开发项目实战」的自制合规 VIP 资源上传。建议售价 9.90 元。模型与数据均为虚构示例,不含刷量、搬运或真实个人信息。

2026最新基于Aria2下载器解决百度网盘限速问题

Aria下载器

【云原生开发】基于Go语言高并发与容器化技术的微服务系统设计与实战

内容概要:本文系统讲解了Go语言在高并发与云原生领域的核心技术与实战应用,从Goroutine调度器、Channel底层实现、CSP并发模型等原理出发,深入剖析GMP调度机制、内存模型、同步原语与Context控制流,并结合Worker Pool、Pipeline、Fan-out/Fan-in等经典并发模式,逐步过渡到云原生实践。内容涵盖Docker容器化、Kubernetes编排、微服务架构设计、可观测性体系建设(日志、监控、链路追踪),并通过一个完整的高并发短链接服务项目,演示从代码实现、性能调优到云原生部署的全流程。; 适合人群:具备一定Go语言基础,有1-3年后端开发经验,希望深入理解并发原理并转型云原生方向的工程师;熟悉Java/Python等语言并计划转向Go生态的开发者;以及需要掌握Kubernetes内部机制的平台工程师。; 使用场景及目标:①理解Go并发核心机制如Goroutine、Channel、GMP调度、Context取消传播的底层原理与最佳实践;②掌握高并发场景下的Worker Pool、Pipeline等模式设计与性能调优方法;③实现服务的容器化打包、Kubernetes部署、自动扩缩容与可观测性集成,构建可投入生产的云原生系统。; 阅读建议:建议遵循“原理→模式→实战”的学习路径,结合书中代码示例动手实践,重点理解并发模型与云原生架构的设计思想。在学习过程中应使用pprof、trace、-race等工具进行调试与验证,强化对并发安全与性能瓶颈的认知。

两路半桥LLC谐振变换器软开关Simulink仿真(模拟谐振参数不同、分裂电容)

内容概要:本文介绍了“两路半桥LLC谐振变换器软开关Simulink仿真”资源包,重点在于基于Simulink平台对两路半桥LLC谐振变换器进行高精度建模与动态仿真,特别考虑了谐振参数不一致及分裂电容等非理想工况对系统性能的影响。该仿真模型不仅涵盖了主电路拓扑、软开关实现机制与谐振网络设计,还深入分析了不同参数配置下系统的启动特性、稳态效率、动态响应及软开关条件的满足情况。通过参数扫描与对比仿真,帮助用户掌握LLC变换器的关键设计要素与优化方法,具备较强的工程指导价值和科研教学意义。; 适合人群:电力电子、电气工程及其自动化等相关专业的高校师生,以及从事高频开关电源、新能源变换器、车载充电机等领域的研发工程师和技术人员。; 使用场景及目标:① 掌握两路并联半桥LLC谐振变换器的建模与仿真方法;② 理解软开关技术在提升变换器效率与降低EMI方面的关键作用;③ 分析谐振参数偏差与分裂电容结构对系统均流特性、增益曲线及软开关范围的影响;④ 支持科研项目中的拓扑验证、控制策略开发与故障工况分析; 阅读建议:建议结合Simulink仿真模型与配套说明文档进行学习,重点关注谐振腔参数设置、驱动时序设计及软开关波形观测;可通过调整谐振电感、电容值或引入参数失配,观察系统行为变化,深入理解LLC变换器的稳定边界与优化设计原则。

港股十档行情tick数据,包含逐笔成交与买卖委托快照 逐笔记录含成交时间、价格、成交量、成交方向及委托单类型 十档委托快照提供买卖各十个价位的挂单价格与挂单数量,可观察盘口深度变化 分钟数据以一分钟为

港股十档行情tick数据,包含逐笔成交与买卖委托快照。逐笔记录含成交时间、价格、成交量、成交方向及委托单类型。十档委托快照提供买卖各十个价位的挂单价格与挂单数量,可观察盘口深度变化。分钟数据以一分钟为单位,包含开盘价、最高价、最低价、收盘价、成交量及成交额。历史行情覆盖近十五年,提供完整日线csv表格,字段包含日期、开盘价、最高价、最低价、收盘价、成交量、成交额,部分还包含调整因子或前收盘价。所有数据均为非实时历史数据。 数据源:CMES金融数据库

双向全桥CLLC谐振变换器仿真模型(Simulink仿真实现)

内容概要:本文系统介绍了双向全桥CLLC谐振变换器的Simulink仿真模型,重点阐述了变频控制、闭环仿真及其与多种电力电子拓扑(如维也纳整流器、DAB变换器、图腾柱PFC等)的联合仿真设计。资源包涵盖2.5kW双向全桥LLC、V2G电动汽车充放电系统、三相PFC、多相交错LLC等多种变换器的仿真案例,并深入展示了三电平VIENNA整流器在双闭环PI控制与SVPWM调制策略下,结合上下电容电压差值补偿实现中点电位平衡的先进控制方法。通过仿真验证,该策略不仅有效维持了800V直流母线电压的稳定,还在动态工况下显著提升了电容电压的均衡度,同时保持了较低的输入电流THD,充分体现了SVPWM与中点平衡控制协同优化的技术优势。; 适合人群:具备电力电子与自动控制理论基础,从事新能源发电、电动汽车、工业电源、微电网等领域的研究生、工程师及科研人员。; 使用场景及目标:① 学习并构建高频谐振变换器(如LLC、CLLC)的Simulink仿真模型,掌握其变频与混合控制策略;② 深入理解并应用中点电位平衡、双闭环PI控制、SVPWM调制等核心技术于VIENNA等三电平变换器中;③ 复现高水平期刊论文中的控制算法,服务于科研项目申报、学术论文撰写或工程产品开发。; 阅读建议:该资源为综合性仿真资料库,建议使用者结合自身研究方向(如电动汽车充电、新能源并网)选择对应案例进行精学,重点关注控制策略的设计逻辑、仿真参数的整定方法以及SVPWM与中点平衡的协同机制,并充分利用附带的计算书和参考文献深化理解,以实现从仿真模型到实际工程应用的顺利转化。

高校技术转移办公室人员如何提升科技成果推介效率与质量?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

全桥LLC谐振(变频+移相混合控制)变换器闭环仿真模型(Simulink仿真实现)

全桥LLC谐振(变频+移相混合控制)变换器闭环仿真模型(Simulink仿真实现)

虚拟同步发电机(VSG)惯量阻尼自适应控制仿真模型(simulink仿真实现)

内容概要:本文提供了“虚拟同步发电机(VSG)惯量阻尼自适应控制仿真模型”的Simulink仿真实现方法,系统阐述了如何通过仿真手段研究VSG在电力系统中的动态响应特性,重点聚焦于其惯量与阻尼的自适应控制策略。文中详细说明了模型构建流程,涵盖控制算法设计、参数调节、根轨迹分析等内容,并通过对比不同调节系数下的系统响应,深入探讨了控制参数对系统稳定性与动态性能的影响。该仿真模型有效复现了VSG模拟传统同步发电机惯性与阻尼特性的能力,对于提升新能源并网系统的频率稳定性和抗扰动能力具有重要研究价值。; 适合人群:具备电力系统、自动化或相关领域基础知识,从事新能源并网、微电网控制、电力电子与电力系统仿真研究的研究生、科研人员及工程师。; 使用场景及目标:①用于教学与科研中深入理解虚拟同步发电机的工作原理及其在现代电力系统中的应用;②为新能源发电系统接入电网时的稳定性分析与控制策略设计提供仿真验证平台;③支持对VSG控制参数进行优化,提升系统应对负荷波动和扰动的能力。; 阅读建议:建议读者结合Matlab/Simulink软件动手实践,按照文档结构逐步搭建仿真模型,重点关注控制环路设计与参数整定部分,同时参考提供的代码与仿真结果进行对比分析,以加深对VSG自适应控制机制的理解。

基于双向Buck-Boost电路的锂电池储能充电+放电控制Simulink仿真

内容概要:本文系统介绍了基于双向Buck-Boost电路的锂电池储能系统充放电控制的Simulink仿真设计,重点构建了储能系统中能量双向流动的控制模型,涵盖充电与放电两种工作模式。通过Simulink平台搭建主电路拓扑与闭环控制系统,实现对锂电池的安全、高效能量管理,确保系统在不同工况下的稳定性与动态响应性能。研究不仅聚焦于Buck-Boost变换器的能量转换机制,还结合多种先进控制策略,如模型预测控制、电压下垂控制等,提升系统的控制精度与鲁棒性。同时,文中列举了包括LLC谐振变换器、Vienna整流器、PWM整流器等多种电力电子变换器的仿真案例,体现了该资源在新能源、微电网及电力电子系统建模与控制领域的广泛适用性与技术综合性; 适合人群:具备电力电子、自动控制或电气工程等相关专业背景,熟悉MATLAB/Simulink仿真环境,从事新能源系统、储能技术、电力电子变换器设计及相关领域研究的研发人员与高校研究生; 使用场景及目标:①深入理解双向Buck-Boost电路在锂电池储能系统中的能量管理原理与系统建模方法;②掌握基于Simulink的充放电控制策略设计、闭环系统搭建与仿真验证流程;③拓展至其他主流DC-DC与AC-DC变换器(如LLC、Vienna、DAB等)的建模与控制研究,服务于科研项目、课程设计、毕业课题或工程开发应用; 阅读建议:建议结合文中提供的仿真模型与参考资料,动手实践Simulink建模与参数调试过程,重点关注控制环路的设计逻辑、控制器参数整定方法及系统动态响应特性;同时可参考同系列其他变换器的仿真案例,横向比较不同拓扑的控制策略差异,以拓宽技术视野与工程应用能力。

两相交错并联Boost电路仿真模型(Simulink仿真实现)

内容概要:本文介绍了“两相交错并联Boost电路仿真模型(Simulink仿真实现)”的技术资源,属于电力电子变换器领域的仿真研究内容。该模型基于Simulink平台构建,旨在深入分析两相交错并联Boost电路的工作原理、动态响应特性及控制策略。交错并联结构通过错开各相开关管的导通时刻,有效降低输入电流纹波、提升系统效率与功率密度,适用于中高功率DC-DC变换应用场景。资源包含完整的主电路建模、PWM驱动信号生成、闭环控制器设计(如电压/电流双闭环控制)等关键模块,并可能涵盖软启动、均流控制等关键技术问题。整个仿真模型强调理论分析与工程实践的紧密结合,不仅有助于理解电路基本行为,也为优化控制算法提供验证平台,服务于科研与教学需求。; 适合人群:电气工程、自动化、电力电子及相关专业的高校本科生、研究生,以及从事电源系统研发的工程技术人员,具备一定的电路理论、自动控制原理和Simulink仿真基础者更佳。; 使用场景及目标:① 学习和掌握两相交错并联Boost电路的拓扑结构、工作机理及性能优势;② 利用Simulink进行电力电子电路的建模与仿真,深入理解PWM控制、闭环调节、均流控制等核心技术的应用;③ 为科研项目、课程设计或毕业设计提供可复用的仿真案例和技术支持,辅助开展中高功率电源系统的创新设计与优化研究。; 阅读建议:建议结合Simulink软件动手搭建并调试模型,通过调整占空比、开关频率、电感参数等变量,观察其对输入电流纹波、输出电压稳定性及动态响应的影响,以深化对电路特性的理解;同时可参考文中列出的其他相关资源(如LLC、PFC等仿真模型)进行横向对比学习,拓宽电力电子系统设计视野。

高校技术转移办公室人员需要哪些工具来提升成果转化服务能力?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

从零开始用飞牛fnas搭建集成DeepSeek-R1的远程AI工作台

从零开始用飞牛fnas搭建集成DeepSeek-R1的远程AI工作台

AI+全栈,AI+应用,实操落地,前沿技术 3809

永磁同步电机高效标定技术:从理论到实践的全面解析

本文全面解析永磁同步电机高效标定技术,从MTPA标定、弱磁区优化到初始角校准,详细介绍了理论原理和实战技巧。针对新能源汽车应用场景,提供标定系统集成要点和AI辅助优化方案,帮助工程师提升电机性能标定效率与精度。

weixin_28452161的博客 505
上一篇: MS06001 图形呈现引擎(WMF)漏洞分析学习手记
下一篇: FUTo
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值