Bitdefender Hypervisor Memory Introspection
|
#include "introcore.h"
#include "guests.h"
#include "intronet.h"
#include "winnet.h"
#include "winprocesshp.h"
#include "winpe.h"
#include "drivers.h"
#include "alerts.h"
#include "bitmask.h"
#include "structs.h"
Go to the source code of this file.
Data Structures | |
struct | _WINNET_STATE |
Structure that describe the kernel objects needed by introcore to extract connections. More... | |
struct | _WINNET_STATE::_PARTITION |
Describe information about the TCP partition containing endpoints. More... | |
struct | _WINNET_STATE::_BITMAP |
Describe information about the TCP port pool containing listeners. More... | |
Macros | |
#define | TCPIP_MAX_PARTITION_CNT 0x40 |
Maximum allowed count for the tcpip!PartitionCount value. More... | |
#define | NET_BYTE_ORDER(Word) (((Word) >> 8) | ((Word) << 8)) |
Switch a WORD from network endianness to little endina. More... | |
#define | VALID_PORT(Port) (0 != (Port) && 49151 != (Port)) |
Check if a port is valid. Not the best check, but a valid check. More... | |
#define | WINNET_LIST_ITERS_CAP 64 |
Upper limit for iterating through guest linked lists. More... | |
#define | ADDR_FAM_OFFSET (gGuest.Guest64 ? (gGuest.OSVersion >= 9200 ? 0x18 : 0x14) : 0xC) |
#define | TCP_DIRECTORY_ENTRY_CNT 0x80 |
#define | TCP_DIRECTORY_ENTRY_SIZE (2ull * (gGuest.WordSize)) |
#define | TCP_DIRECTORY_SIZE (TCP_DIRECTORY_ENTRY_CNT * TCP_DIRECTORY_ENTRY_SIZE) |
#define | WINNET_CLEAN_PTR_MASK ((QWORD)0xFFFFFFFFFFFFFFFCull) |
#define | TCP_PORT_ASSIGNMENT_ARRAY_INDEX(i) (((i) >> 8) & 0xFF) |
#define | TCP_PORT_ASSIGNMENT_INDEX(i) ((i) & 0xFF) |
Functions | |
static INTRO_NET_AF | IntWinNetConvertAf (WORD Af) |
Convert a windows address family value to an introcore one. More... | |
static INTSTATUS | IntWinNetGetAddrFam (const BYTE *Buffer, size_t Size, size_t *Offset, void *Context) |
Callback to get the address family from a guest buffer. More... | |
static INTSTATUS | IntWinNetGetLocalAddr (QWORD Gva, INTRONET_ENDPOINT *Endpoint) |
Get the local address of a connection from a given address. More... | |
static INTSTATUS | IntWinNetGetAddrInfo (const BYTE *Buffer, size_t Size, size_t *Offset, void *Context) |
Callback to get the address information from a guest buffer. More... | |
static INTSTATUS | IntWinNetGetPortsAndState (const BYTE *Buffer, size_t Size, size_t *Offset, void *Context) |
Callback to get the ports and state from a guest buffer. More... | |
static INTSTATUS | IntWinNetGetOwner (const BYTE *Buffer, size_t Size, size_t *Offset, void *Context) |
Callback to get the owner process from a guest buffer. More... | |
static INTSTATUS | IntWinNetGetListenerAddressInfo (const BYTE *Buffer, size_t Size, size_t *Offset, void *Context) |
Callback to get the address family and local address from a guest buffer. More... | |
static INTSTATUS | IntWinNetFillTcpStruct (const QWORD Gva, INT_STRUCT_INVARIANT *Invariants, size_t Count, DWORD PoolTag, BOOLEAN LogErrors, INTRONET_ENDPOINT *Endpoint) |
Wrapper over IntStructFill to map a guest page and perform the search there. More... | |
static INTSTATUS | IntWinNetGetTcpEndpoint (QWORD Gva, INTRONET_ENDPOINT *Endpoint) |
Search for a TCP endpoint structure from a given address. More... | |
static INTSTATUS | IntWinNetGetTcpListener (QWORD Gva, INTRONET_ENDPOINT *Endpoint) |
Search for a tcp endpoint structure from a given address. More... | |
static INTSTATUS | IntWinNetIterateLinkedList (QWORD Gva, PFUNC_IntWinNetCallback Callback, void *Context) |
Iterate through a doubly linked list of tcpip!_TCP_ENDPOINT structures and invoke the callback on each valid connection. More... | |
static INTSTATUS | IntWinNetParseTcpPartition (PFUNC_IntWinNetCallback Callback, void *Context) |
Iterate through the tcpip!PartitionTable and invoke the callback on each found connection. More... | |
static INTSTATUS | IntWinNetIterateSlinkedList (INTRONET_PORT Port, QWORD Gva, PFUNC_IntWinNetCallback Callback, void *Context) |
Iterate through a single linked list of tcpip endpoint structures and invoke the callback on each valid connection. More... | |
static INTSTATUS | IntWinNetParseTcpBitmap (PFUNC_IntWinNetCallback Callback, void *Context) |
Will iterate through the guest port bitmap and invoke the callback on each valid connection. More... | |
static INTSTATUS | IntWinNetCheckPartition (const BYTE *Buffer, size_t Size) |
Check wether a buffer contains a valid undocumented tcpip!_PARTITION object. More... | |
static INTSTATUS | IntWinNetFindTcpPartition (QWORD PartitionAddress, QWORD PartitionPointer) |
Get tcpip!PartitionTable information from the guest and initialize gWinNet. More... | |
static INTSTATUS | IntWinNetSearchForAlloc (QWORD Gva, DWORD Tag, QWORD *Alloc) |
Search for an allocation with given tag. More... | |
static INTSTATUS | IntWinNetGetTcpPortPoolFromCompartment (QWORD Gva, QWORD *PortPool) |
Get the address of a tcp port pool for windows RS1 and newer. More... | |
static INTSTATUS | IntWinNetGetTcpPortPool (QWORD Gva, QWORD *PortPool) |
Get the address of a tcp port pool for windows versions before RS1. More... | |
static INTSTATUS | IntWinNetFindTcpBitmap (QWORD Gva, QWORD Addr) |
Get tcpip!TcpPortPool information form the guest and initialize gWinNet. More... | |
static INTSTATUS | IntWinNetFindTcpObjects (void) |
Iterate through the .data section of tcpip.sys and attempt to find the objects that we need to initialize gWinNet. More... | |
static INTSTATUS | IntWinNetIterateConnections (PFUNC_IntWinNetCallback Callback, void *Context) |
Iterate through guest connections and invoke the callback on each one. More... | |
static INTSTATUS | IntWinNetSendConnectionEvent (const INTRONET_ENDPOINT *Endpoint, void *Context) |
Send a connection event. More... | |
INTSTATUS | IntWinNetSendProcessConnections (WIN_PROCESS_OBJECT *Process) |
Send connection events for all active connections whose owner is the given process. More... | |
static INTSTATUS | IntWinNetDumpConnection (const INTRONET_ENDPOINT *Endpoint, void *Context) |
Log a connection. More... | |
INTSTATUS | IntWinNetDumpConnections (void) |
Dump all active guest connections. More... | |
Variables | |
struct _WINNET_STATE | gWinNet |
#define ADDR_FAM_OFFSET (gGuest.Guest64 ? (gGuest.OSVersion >= 9200 ? 0x18 : 0x14) : 0xC) |
Referenced by IntWinNetGetAddrFam().
#define NET_BYTE_ORDER | ( | Word | ) | (((Word) >> 8) | ((Word) << 8)) |
Switch a WORD from network endianness to little endina.
Definition at line 29 of file winnet.c.
Referenced by IntWinNetGetListenerAddressInfo(), and IntWinNetGetPortsAndState().
#define TCP_DIRECTORY_ENTRY_CNT 0x80 |
Referenced by IntWinNetParseTcpPartition().
#define TCP_DIRECTORY_ENTRY_SIZE (2ull * (gGuest.WordSize)) |
Referenced by IntWinNetParseTcpPartition().
#define TCP_DIRECTORY_SIZE (TCP_DIRECTORY_ENTRY_CNT * TCP_DIRECTORY_ENTRY_SIZE) |
#define TCP_PORT_ASSIGNMENT_ARRAY_INDEX | ( | i | ) | (((i) >> 8) & 0xFF) |
Referenced by IntWinNetParseTcpBitmap().
#define TCP_PORT_ASSIGNMENT_INDEX | ( | i | ) | ((i) & 0xFF) |
Referenced by IntWinNetParseTcpBitmap().
#define TCPIP_MAX_PARTITION_CNT 0x40 |
Maximum allowed count for the tcpip!PartitionCount value.
For newer Windows versions, this value is the maximum that can be returned from tcpip!TcpNumPartitionsForProcessorCount.
For older Windows versions, this value is obtained using the maximum returned value from tcpip!TcpMaxPartitionShift. In this case, the count is calulated as (1 << shift).
However, for all of these, the maximum count remains the same.
Definition at line 26 of file winnet.c.
Referenced by IntWinNetFindTcpPartition().
#define VALID_PORT | ( | Port | ) | (0 != (Port) && 49151 != (Port)) |
Check if a port is valid. Not the best check, but a valid check.
Definition at line 32 of file winnet.c.
Referenced by IntWinNetGetPortsAndState().
#define WINNET_CLEAN_PTR_MASK ((QWORD)0xFFFFFFFFFFFFFFFCull) |
Referenced by IntWinNetIterateSlinkedList().
#define WINNET_LIST_ITERS_CAP 64 |
Upper limit for iterating through guest linked lists.
Definition at line 35 of file winnet.c.
Referenced by IntWinNetIterateLinkedList(), and IntWinNetIterateSlinkedList().
Check wether a buffer contains a valid undocumented tcpip!_PARTITION object.
Will check if the buffer contains 3 pointers, each to pointing in the same page to nt!_RTL_DYNAMIC_HASH_TABLE structures. Will check for the hash table structs simply by verifying that their allocation tag is THcT
.
[in] | Buffer | The buffer to be checked. |
[in] | Size | Size in bytes of the buffer. |
Definition at line 1062 of file winnet.c.
Referenced by IntWinNetFindTcpPartition().
|
inlinestatic |
Convert a windows address family value to an introcore one.
[in] | Af | The windows address family value. |
Definition at line 64 of file winnet.c.
Referenced by IntWinNetGetAddrFam().
|
static |
Log a connection.
[in] | Endpoint | Connection to log. |
[in,out] | Context | Not used. |
INT_STATUS_SUCCESS | On success. |
Definition at line 1790 of file winnet.c.
Referenced by IntWinNetDumpConnections().
INTSTATUS IntWinNetDumpConnections | ( | void | ) |
Dump all active guest connections.
|
static |
Wrapper over IntStructFill to map a guest page and perform the search there.
[in] | Gva | Gva from where to start searching. |
[in,out] | Invariants | Invariants to be applied in order to search/fill the structure. |
[in] | Count | Number of invariants to apply. |
[in] | PoolTag | Pool tag of the allocation in where we'll search for the structure. |
[in] | LogErrors | Set to TRUE if the function shoud log the errors it encounters. |
[in,out] | Endpoint | Pointer to a caller allocated (and initialized) structure to be filled. |
Definition at line 505 of file winnet.c.
Referenced by IntWinNetGetTcpEndpoint(), and IntWinNetGetTcpListener().
Get tcpip!TcpPortPool information form the guest and initialize gWinNet.
Will check if any given Gva points to a port pool ( before RS1), or an object that points to the port pool. Will use IntWinNetGetTcpPortPool or IntWinNetGetTcpPortPoolFromCompartment to get the propper address of the possible port pool. Furthermore, will search for 3 specific fields inside the port pool, namely the bitmap size, the bitmap, and a pointer to an array.
The size of the bitmap is always 0x10000, this is a size in bits, each one describing a used port. A pointer to the bitmap buffer is immediatley after, and the buffer is in the same page as the port pool. Next is an array of tcpip!_INET_PORT_ASSIGNMENT_ARRAY pointers. Each of those are small pool allocations with tag InPA.
[in] | Gva | Gva of the possible partition table. |
[in] | Addr | Gva of the place in the .data of tcpip.sys from where the first parameter was read. |
Definition at line 1496 of file winnet.c.
Referenced by IntWinNetFindTcpObjects().
|
static |
Iterate through the .data section of tcpip.sys and attempt to find the objects that we need to initialize gWinNet.
Will search for the bitmap in tcpip!TcpPortPool using IntWinNetFindTcpBitmap in order to extract listeners, and for tcpip!PartitionTable using IntWinNetFindTcpPartition for active connections.
Definition at line 1605 of file winnet.c.
Referenced by IntWinNetIterateConnections().
|
static |
Get tcpip!PartitionTable information from the guest and initialize gWinNet.
Will check if a given gva points to a valid undocumented tcpip!_PARTITION using IntWinNetCheckPartition.
From there, will iterate the page in search for a second one in order to determine the size of the structure. The second entry in the partition table will always be in the same page as the first one because there are 2 posiblities:
Next, find the valud inside tcpip!Partition count. This is a guest word just before tcpip!PartitionTable on windows 8+, or the second WORD after the tcpip!PartitionTable on older versions. It's size is also dependant on version, it may be a guest word or a WORD.
[in] | PartitionAddress | Gva of the possible partition table. |
[in] | PartitionPointer | Gva of the place in the .data of tcpip.sys from where the first parameter was read. |
Definition at line 1145 of file winnet.c.
Referenced by IntWinNetFindTcpObjects().
|
static |
Callback to get the address family from a guest buffer.
Will check if the Buffer contains a guest pointer to an address family. The address family is simply a WORD with values 2 (v4) or 17 (v6).
[in] | Buffer | Buffer in which the search is performed. |
[in] | Size | The size of the buffer. |
[in,out] | Offset | Offset in the buffer where the current search is being performed. Will increment this offset accordingly. |
[in,out] | Context | A caller allocated INTRONET_ENDPOINT structure to be filled. |
Definition at line 88 of file winnet.c.
Referenced by IntWinNetGetListenerAddressInfo(), and IntWinNetGetTcpEndpoint().
|
static |
Callback to get the address information from a guest buffer.
Will get the local and remote addresses of an active tcp endpoint.
Will check if the Buffer contains a guest pointer to an ADDR_INFO struct. From that struct, read a guest pointer to the remote address, and extract it from there. Next, from the same struct read a guest pointer to a LOCAL_ADDRESS from which we'll extract the local address using IntWinNetGetLocalAddr.
[in] | Buffer | Buffer in which the search is performed. |
[in] | Size | The size of the buffer. |
[in,out] | Offset | Offset in the buffer where the current search is being performed. Will increment this offset accordingly. |
[in,out] | Context | A caller allocated INTRONET_ENDPOINT structure to be filled. |
Definition at line 208 of file winnet.c.
Referenced by IntWinNetGetTcpEndpoint().
|
static |
Callback to get the address family and local address from a guest buffer.
The listener structure contains, in this order, the address family, local address and the local port. The local port is the same as the entry in the tcpip!TcpPortPool bitmap, so we'll use that as a very strong check. The local port field in the INTRONET_ENDPOINT must be set to the entry in the bitfield in order for this to be successful.
[in] | Buffer | Buffer in which the search is performed. |
[in] | Size | The size of the buffer. |
[in,out] | Offset | Offset in the buffer where the current search is being performed. Will increment this offset accordingly. |
[in,out] | Context | A caller allocated INTRONET_ENDPOINT structure to be filled. |
Definition at line 414 of file winnet.c.
Referenced by IntWinNetGetTcpListener().
|
static |
Get the local address of a connection from a given address.
The Gva should point to a memory location containing a LOCAL_ADDRESS structure. From that structure, the InAddr field points to a pointer to the local address.
[in] | Gva | Gva from where to extract the address. |
[out] | Endpoint | A caller allocated INTRONET_ENDPOINT structure to be filled. |
Definition at line 168 of file winnet.c.
Referenced by IntWinNetGetAddrInfo(), and IntWinNetGetListenerAddressInfo().
|
static |
Callback to get the owner process from a guest buffer.
Will simply read a guest pointer and try to find a matching process object.
[in] | Buffer | Buffer in which the search is performed. |
[in] | Size | The size of the buffer. |
[in,out] | Offset | Offset in the buffer where the current search is being performed. Will increment this offset accordingly. |
[in,out] | Context | A caller allocated INTRONET_ENDPOINT structure to be filled. |
Definition at line 367 of file winnet.c.
Referenced by IntWinNetGetTcpEndpoint(), and IntWinNetGetTcpListener().
|
static |
Callback to get the ports and state from a guest buffer.
Read the local & remote ports and the guest state from the buffer. Those are a DWORD ( state), and two WORDs (ports) in this order.
On their own, they have realy weak invariants: the list of valid ports is any port that's not 0 or 49151, and the list of valid states is any DWORD that's less than 14.
However, by searching for them together, ( since they're always going to be one after the other) their invariants become stronger.
[in] | Buffer | Buffer in which the search is performed. |
[in] | Size | The size of the buffer. |
[in,out] | Offset | Offset in the buffer where the current search is being performed. Will increment this offset accordingly. |
[in,out] | Context | A caller allocated INTRONET_ENDPOINT structure to be filled. |
Definition at line 288 of file winnet.c.
Referenced by IntWinNetGetTcpEndpoint().
|
static |
Search for a TCP endpoint structure from a given address.
[in] | Gva | Address from where to begin searching. |
[in,out] | Endpoint | Pointer to a caller allocated structure to be filled. |
Definition at line 617 of file winnet.c.
Referenced by IntWinNetIterateLinkedList().
|
static |
Search for a tcp endpoint structure from a given address.
[in] | Gva | Address from where to begin searching. |
[out] | Endpoint | Pointer to a caller allocate structure to be filled. |
Definition at line 675 of file winnet.c.
Referenced by IntWinNetIterateSlinkedList().
Get the address of a tcp port pool for windows versions before RS1.
The tcp port pool is a big pool allocation, meaning that it will always be page aligned.
For windows versions before RS1, tcpip!PortPool is a global variable so we check the Gva.
Now, the first port pool that we find might be the udp port pool, but we check for that as follows:
[in] | Gva | Address from where to start searching. |
[out] | PortPool | Will contain the address of the tcp port pool. |
Definition at line 1430 of file winnet.c.
Referenced by IntWinNetFindTcpBitmap().
Get the address of a tcp port pool for windows RS1 and newer.
The tcp port pool is a big pool allocation, meaning that it will always be page aligned.
Starting with RS1, we start from tcpip!TcpCompartmentSet, which is a small pool allocation with tag InCS (InetCompartmentSet).
Next, search for an InetCompartment, which should be a small pool allocaiton with tag InCo.
From there, search for a TcpCompartment, which is yet another small pool allocation with tag TcCo.
The first pointer inside the TcpCompartment is the port pool.
[in] | Gva | Address from where to start searching. |
[out] | PortPool | Will contain the address of the tcp port pool. |
Definition at line 1356 of file winnet.c.
Referenced by IntWinNetFindTcpBitmap().
|
static |
Iterate through guest connections and invoke the callback on each one.
[in] | Callback | Function to be invoked on each valid connection. |
[in,out] | Context | Optional context for the callback, can be anything. |
Definition at line 1691 of file winnet.c.
Referenced by IntWinNetDumpConnections(), and IntWinNetSendProcessConnections().
|
static |
Iterate through a doubly linked list of tcpip!_TCP_ENDPOINT structures and invoke the callback on each valid connection.
[in] | Gva | Address of the list head. |
[in] | Callback | Function to be invoked on each valid connection. |
[in,out] | Context | Optional context for the callback, can be anything. |
Definition at line 727 of file winnet.c.
Referenced by IntWinNetParseTcpPartition().
|
static |
Iterate through a single linked list of tcpip endpoint structures and invoke the callback on each valid connection.
[in] | Port | The port for which this function is called. |
[in] | Gva | Address of the list head. |
[in] | Callback | Function to be invoked on each valid connection. |
[in,out] | Context | Optional context for the callback, can be anything. |
Definition at line 885 of file winnet.c.
Referenced by IntWinNetParseTcpBitmap().
|
static |
Will iterate through the guest port bitmap and invoke the callback on each valid connection.
Will iterate through the bitmap and consider each set bit's index a connection in listening state whose local port is the index.
The port assignment array is an array of pointers to undocumented _INET_PORT_ASSIGNMENT_ARRAY structures. These are indexed by the higher byte of the bit index word.
Each element of the type above contains an array of undocumented _INET_PORT_ASSIGNMENT structures. This array is indexed via the lower byte of the bit index word.
The structure describe above containts a SLIST_HEAD whose entries are the listeners on this port.
[in] | Callback | Function to be invoked on each valid connection. |
[in,out] | Context | Optional context for the callback, can be anything. |
Definition at line 943 of file winnet.c.
Referenced by IntWinNetIterateConnections().
|
static |
Iterate through the tcpip!PartitionTable and invoke the callback on each found connection.
Will iterate through each tcpip!_PARTITION from the tcpip!PartitionTable.
Each entry has, as the first 3 elements, pointers to nt!_RTL_DYNAMIC_HASH_TABLE structures.
The first hash table contains tcpip!_TCP_ENDPOINT elements that we'll use to extract active connections.
The second hasn table contains tcpip!_TCP_TIME_WAIT_ENDPOINT elements that we ignore for now.
The Directory field in the hash table points to an array of 0x80 nt!_LIST_HEAD elements so we'll simply iterate each non-empty list from there.
[in] | Callback | Function to be invoked on each valid connection. |
[in,out] | Context | Optional context for the callback, can be anything. |
Definition at line 793 of file winnet.c.
Referenced by IntWinNetIterateConnections().
Search for an allocation with given tag.
Will map the whole page containing the address and iterate through it, treating it as an array of pointers, checking if any of those is pointing to a small pool allocation with given tag. Will only search starting from the given address untill the end of the page.
[in] | Gva | Address from where to begin searching. |
[in] | Tag | Pool tag of the allocation to be searched. |
[out] | Alloc | Will contain the address of the allocation. |
Definition at line 1297 of file winnet.c.
Referenced by IntWinNetGetTcpPortPoolFromCompartment().
|
static |
Send a connection event.
Will only send connections whose owner is the process described by the context.
[in] | Endpoint | Connection to send. |
[in,out] | Context | Will be a pointer to a WIN_PROCESS_OBJECT. |
Definition at line 1731 of file winnet.c.
Referenced by IntWinNetSendProcessConnections().
INTSTATUS IntWinNetSendProcessConnections | ( | WIN_PROCESS_OBJECT * | Process | ) |
Send connection events for all active connections whose owner is the given process.
[in] | Process | The process whose connections to send. |
Definition at line 1768 of file winnet.c.
Referenced by IntWinVadIsExecSuspicious().
struct _WINNET_STATE gWinNet |