Bitdefender Hypervisor Memory Introspection
winagent.h File Reference
#include "aghcall.h"
#include "agent.h"

Go to the source code of this file.

Data Structures

struct  _WIN_AGENT
 

Macros

#define MAX_BOOTSTRAP_SIZE   512u
 Maximum size of the bootstrap code. More...
 
#define AG_OPT_INJECT_ON_RIP_POWSTATE_CHANGE   0x00000001
 

Typedefs

typedef INTSTATUS(* PFUNC_AgentInjection) (QWORD GuestVirtualAddress, DWORD AgentTag, void *Context)
 Injection callback. More...
 
typedef INTSTATUS(* PFUNC_AgentCompletion) (QWORD GuestVirtualAddress, DWORD ErrorCode, DWORD AgentTag, void *Context)
 Completion callback. More...
 
typedef QWORD(* PFUNC_AgentDeliver) (QWORD GuestVirtualAddress, DWORD MaxSize, void *Context)
 Called for VE and PT initialization. More...
 
typedef enum _AGENT_HCALL AGENT_HCALL
 
typedef struct _WIN_AGENT WIN_AGENT
 
typedef struct _WIN_AGENTPWIN_AGENT
 

Enumerations

enum  _AGENT_HCALL { AGENT_HCALL_VMCALL, AGENT_HCALL_INT3 }
 

Functions

BOOLEAN IntWinAgentIsRipInsideCurrentAgent (QWORD Rip)
 Return true if the given RIP points inside the currently active boot driver. More...
 
INTSTATUS IntWinAgentHandleVmcall (QWORD Rip)
 Handle a VMCALL that was executed inside the guest. More...
 
INTSTATUS IntWinAgentHandleInt3 (QWORD Rip, DWORD CpuNumber)
 Handle a breakpoint that was initiated inside the guest. More...
 
INTSTATUS IntWinAgentInject (PFUNC_AgentInjection InjectionCallback, PFUNC_AgentCompletion CompletionCallback, PFUNC_AgentDeliver DeliverCallback, void *Context, PBYTE AgentContent, DWORD AgentSize, BOOLEAN AgentInternal, DWORD AgentTag, AGENT_TYPE AgentType, const CHAR *Name, DWORD Options, const CHAR *Args, DWORD Pid, PWIN_AGENT *Agent)
 Schedule an agent injection inside the guest. More...
 
INTSTATUS IntWinAgentInjectBreakpoint (PFUNC_AgentInjection InjectionCallback, void *Context, PWIN_AGENT *Agent)
 Injects a breakpoint agent inside the guest. More...
 
INTSTATUS IntWinAgentInjectTrampoline (void)
 Inject the agent trampoline inside the guest. More...
 
INTSTATUS IntWinAgentEnableInjection (void)
 enables agent injections. More...
 
void IntWinAgentCheckIfProcessAgentAndIncrement (CHAR *ImageName, BOOLEAN *IsAgent, DWORD *Tag)
 Checks if a process is an agent or not, and increments the ref count of that name. More...
 
void IntWinAgentCheckIfProcessAgentAndDecrement (CHAR *ImageName, BOOLEAN *IsAgent, DWORD *Tag, BOOLEAN *Removed)
 Checks if a process is an agent or not, and decrements the ref count of that name. More...
 
void IntWinAgentRemoveEntryByAgid (DWORD Counter, DWORD *Tag)
 Removes an agent name from the list of names, using the ID. More...
 
void IntWinAgentDisablePendingAgents (void)
 Disables all pending agents. More...
 
BOOLEAN IntWinAgentIsPtrInTrampoline (QWORD Ptr, THS_PTR_TYPE Type)
 Check if the provided address points inside the agent trampoline. More...
 
AG_WAITSTATE IntWinAgentGetState (DWORD *Tag)
 Gets the global agents state. More...
 
INTSTATUS IntWinAgentActivatePendingAgent (void)
 Activates a pending agent that waits to be injected. More...
 
void IntWinAgentInit (void)
 Initialize the agents state. More...
 
INTSTATUS IntWinAgentUnInit (void)
 Uninit the agents state. More...
 

Macro Definition Documentation

◆ AG_OPT_INJECT_ON_RIP_POWSTATE_CHANGE

#define AG_OPT_INJECT_ON_RIP_POWSTATE_CHANGE   0x00000001

This flag is used for injecting the PT Filter/VE unloader directly from the NtSetSystemPowerState hook handler WARNING: do not use outside of the NtSetSystemPowerState callback (winpower.c) as it might have some unexpected results.

Definition at line 17 of file winagent.h.

Referenced by IntWinAgentActivatePendingAgent(), IntWinAgentHandleLoader1Hypercall(), IntWinAgentRemove(), and IntWinPowHandleEventCommon().

◆ MAX_BOOTSTRAP_SIZE

#define MAX_BOOTSTRAP_SIZE   512u

Maximum size of the bootstrap code.

Definition at line 12 of file winagent.h.

Referenced by IntWinAgentInject().

Typedef Documentation

◆ AGENT_HCALL

typedef enum _AGENT_HCALL AGENT_HCALL

Agent hyper call types.

◆ PFUNC_AgentCompletion

typedef INTSTATUS(* PFUNC_AgentCompletion) (QWORD GuestVirtualAddress, DWORD ErrorCode, DWORD AgentTag, void *Context)

Completion callback.

Completion callback. This callback is called after the in-guest agent boot driver has finished execution. Note that this callback is not called when the agent process, for example finishes execution; it is called when the trampoline, bootstrap code and the boot driver all finished their job (which may be the delivery of a file, or starting a process). In order to see when an injected processes finished execution, look after process termination events generated by that process.

Parameters
[in]GuestVirtualAddressGuest virtual address where the boot driver has been injected.
[in]ErrorCodeThe injection error code. If anything fails inside the guest, this ErrorCode will capture the failure information (for example, that a process could not be started).
[in]AgentTagThe agent tag, as provided to the IntWinAgentInject function.
[in]ContextOptional context, as passed to the IntWinAgentInject function.

Definition at line 56 of file winagent.h.

◆ PFUNC_AgentDeliver

typedef QWORD(* PFUNC_AgentDeliver) (QWORD GuestVirtualAddress, DWORD MaxSize, void *Context)

Called for VE and PT initialization.

This callback is called when the boot driver issues a specific hypercall; right now, this is reserved for the VE and PT drivers only, and it is used to do the their initialization or to free them, on unload. If someone needs special handling during agent injection, it can use this callback, as it can do any custom work when invoked by the boot driver.

Parameters
[in]GuestVirtualAddressGuest virtual address where the boot driver has been injected.
[in]MaxSizeA generic memory size, if anything was allocated by the boot driver.
[in]ContextOptional context, as passed to the IntWinAgentInject function.

Definition at line 77 of file winagent.h.

◆ PFUNC_AgentInjection

typedef INTSTATUS(* PFUNC_AgentInjection) (QWORD GuestVirtualAddress, DWORD AgentTag, void *Context)

Injection callback.

Injection callback. Once the bootstrap allocates the agent memory, this callback will be invoked. It should inject the actual code and data for the agent. The reason why a callback is used for this is because we might need the virtual address of the buffer to do some pre-processing (like applying the relocations, in case of a PE executable).

Parameters
[in]GuestVirtualAddressGuest virtual address where the boot driver has been injected.
[in]AgentTagThe agent tag, as provided to the IntWinAgentInject function.
[in]ContextOptional context, as passed to the IntWinAgentInject function.

Definition at line 33 of file winagent.h.

◆ PWIN_AGENT

typedef struct _WIN_AGENT * PWIN_AGENT

◆ WIN_AGENT

typedef struct _WIN_AGENT WIN_AGENT

Describes one agent running inside the guest.

Enumeration Type Documentation

◆ _AGENT_HCALL

Agent hyper call types.

Enumerator
AGENT_HCALL_VMCALL 

Hyper call using VMCALL.

AGENT_HCALL_INT3 

Hyper call using INT3.

Definition at line 87 of file winagent.h.

Function Documentation

◆ IntWinAgentActivatePendingAgent()

INTSTATUS IntWinAgentActivatePendingAgent ( void  )

Activates a pending agent that waits to be injected.

This function will inject a pending agent. The steps required are:

  1. Allocate slack space for the bootstrap code (NT slack)
  2. Inject & hide the bootstrap code inside the allocated slack space.
  3. Find a suitable instruction of length min 5 to detour
  4. Replace the instruction with a CALL to the trampoline code Once the trampoline hyper call is hit, we will move execution to the bootstrap code.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails.

Definition at line 920 of file winagent.c.

Referenced by IntAgentActivatePendingAgent(), IntWinAgentEnableInjection(), IntWinAgentHandleInt3(), IntWinAgentHandleVmcall(), IntWinAgentInject(), and IntWinAgentInjectBreakpoint().

◆ IntWinAgentCheckIfProcessAgentAndDecrement()

void IntWinAgentCheckIfProcessAgentAndDecrement ( CHAR ImageName,
BOOLEAN IsAgent,
DWORD Tag,
BOOLEAN Removed 
)

Checks if a process is an agent or not, and decrements the ref count of that name.

Each time a process terminates, we check if it was an agent, and we decrement the reference count if its name. Once the reference count of an agent name reaches 0, it will be removed.

Parameters
[in]ImageNameThe image name of the process which is checked.
[out]IsAgentTrue if the process is agent, false otherwise.
[out]TagThe agent tag, if the process is found to be an agent.
[out]RemovedTrue if the agent was removed.

Definition at line 3084 of file winagent.c.

Referenced by IntWinProcDeleteProcessObject().

◆ IntWinAgentCheckIfProcessAgentAndIncrement()

void IntWinAgentCheckIfProcessAgentAndIncrement ( CHAR ImageName,
BOOLEAN IsAgent,
DWORD Tag 
)

Checks if a process is an agent or not, and increments the ref count of that name.

Each time a process is created, we check if its name matches the name of a previously injected agent. If it does, we flag that process as an agent, and we increment the reference count of the name.

Parameters
[in]ImageNameThe image name of the process which is checked.
[out]IsAgentTrue if the process is agent, false otherwise.
[out]TagThe agent tag, if the process is found to be an agent.

Definition at line 3028 of file winagent.c.

Referenced by IntWinProcCreateProcessObject().

◆ IntWinAgentDisablePendingAgents()

void IntWinAgentDisablePendingAgents ( void  )

Disables all pending agents.

This function should be called during the uninit phase, as it will disable all the pending agents. These agents will never be injected inside the guest. The only exception is given by the VE or PT unloaders, which must be injected on uninit in order to remove the VE or PT drivers from the guest memory.

Definition at line 3291 of file winagent.c.

Referenced by IntAgentDisablePendingAgents().

◆ IntWinAgentEnableInjection()

INTSTATUS IntWinAgentEnableInjection ( void  )

enables agent injections.

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 3010 of file winagent.c.

Referenced by IntAgentEnableInjection().

◆ IntWinAgentGetState()

AG_WAITSTATE IntWinAgentGetState ( DWORD Tag)

Gets the global agents state.

Parameters
[out]TagOptional agent tag, if an agent is active or pending.
Return values
agActiveIf there's an active agent.
agWaitingIf there's a pending agent.
agNoneIf there are no active or pending agents.

Definition at line 3245 of file winagent.c.

Referenced by IntAgentGetState().

◆ IntWinAgentHandleInt3()

INTSTATUS IntWinAgentHandleInt3 ( QWORD  Rip,
DWORD  CpuNumber 
)

Handle a breakpoint that was initiated inside the guest.

This function will search for an appropriate handler for the breakpoint. There are several causes for such breakpoints:

  1. Issued by the trampoline code;
  2. Issued by the bootstrap code;
  3. Issued directly by the instruction that was replaced with a breakpoint (direct breakpoint agents);
  4. Spuriously issued by the remnant of an agent (it can happen in multi-CPU systems, where a breakpoint remains pending on a VCPU until another VCPU gets to handle it). NOTE: The notion of VMCALL or hyper call is used generically to any method of communication between the in-guest Introcore components and Introcore. Generally, due to space constraints, we use breakpoint "hyper calls" instead of VMCALL, since a breakpoint is a single byte, instead of three.
Parameters
[in]RipUnused.
[in]CpuNumberThe VCPU number on which the event took place.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_FOUNDIf a handler is not found.

Definition at line 2273 of file winagent.c.

Referenced by IntAgentHandleInt3().

◆ IntWinAgentHandleVmcall()

INTSTATUS IntWinAgentHandleVmcall ( QWORD  Rip)

Handle a VMCALL that was executed inside the guest.

This function handles VMCALLs that took place inside the guest. Since the small agent components (trampoline, bootstrap) use INT3, the VMCALL issued by the boot driver and the user-mode applications that get injected by Introcore.

Parameters
[in]RipThe RIP where the VMCALL was initiated.
Return values
INT_STATUS_SUCCESSOn success.

Definition at line 2397 of file winagent.c.

Referenced by IntAgentHandleVmcall().

◆ IntWinAgentInit()

void IntWinAgentInit ( void  )

Initialize the agents state.

Definition at line 3333 of file winagent.c.

Referenced by IntWinGuestNew().

◆ IntWinAgentInject()

INTSTATUS IntWinAgentInject ( PFUNC_AgentInjection  InjectionCallback,
PFUNC_AgentCompletion  CompletionCallback,
PFUNC_AgentDeliver  DeliverCallback,
void *  Context,
PBYTE  AgentContent,
DWORD  AgentSize,
BOOLEAN  AgentInternal,
DWORD  AgentTag,
AGENT_TYPE  AgentType,
const CHAR Name,
DWORD  Options,
const CHAR Args,
DWORD  Pid,
PWIN_AGENT Agent 
)

Schedule an agent injection inside the guest.

This function schedules the injection of an agent inside the guest space. If this function succeeds means that the injection has been successfully scheduled; it does not mean that the agent has been successfully injected. This function can be used to inject files or processes inside the guest. This function is also used to inject the VE and PT agents inside the guest. Due to the 3 callbacks architecture, it is very flexible and it allows the caller to extend this mechanism with his own defined callbacks.

Parameters
[in]InjectionCallbackThis callback is called after the boot driver has been successfully injected inside the guest.
[in]CompletionCallbackThis callback is called after the boot driver has finished execution, and the agent is being removed from memory.
[in]DeliverCallbackThis callback is called by VE and PT handlers inside the boot driver. This callback basically allows us to inject a next stage agent, and to initialize it, without having to rely on the guest for that.
[in]ContextOptional agent context.
[in]AgentContentPointer to a memory area containing the actual agent.
[in]AgentSizeThe size of the agent, in bytes.
[in]AgentInternalTrue if this is an internal agent (statically allocated inside Introcore).
[in]AgentTagAgent tag. Check out AGENT_TAG* for more info.
[in]AgentTypeAgent type. Check out AGENT_TYPE* for more info.
[in]NameAgent name.
[in]OptionsAgent options.
[in]ArgsAgent arguments. Passed as a command line for process agents.
[in]PidPID of the process that will be the parent of the agent process. if this is 0, winlogon will be chosen as a parent.
[in]AgentWill contain, in successful return, the handle to the newly scheduled agent.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_INVALID_PARAMETERIf an invalid parameter is supplied.
INT_STATUS_OPERATION_NOT_IMPLEMENTEDIf the current guest is not Windows.
INT_STATUS_ALREADY_INITIALIZEDIf an agent with the same name has already been injected.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails.

Definition at line 2608 of file winagent.c.

Referenced by IntPtiInjectPtFilter(), IntPtiRemovePtFilter(), IntVeDeployAgent(), IntVeRemoveAgent(), IntWinDepInjectFile(), and IntWinDepInjectProcess().

◆ IntWinAgentInjectBreakpoint()

INTSTATUS IntWinAgentInjectBreakpoint ( PFUNC_AgentInjection  InjectionCallback,
void *  Context,
PWIN_AGENT Agent 
)

Injects a breakpoint agent inside the guest.

This function injects a breakpoint agent inside the guest. These breakpoint agents are used simply to generate a breakpoint VM exit on the SYSCALL flow, since that flow is the safest to inject kernel faults or to call kernel APIs.

Parameters
[in]InjectionCallbackCallback to be called when the breakpoint is hit.
[in]ContextOptional context to be passed to the callback.
[out]AgentOptional agent handle.
Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_OPERATION_NOT_IMPLEMENTEDIf the guest is not Windows.
INT_STATUS_INSUFFICIENT_RESOURCESIf a memory alloc fails.

Definition at line 2921 of file winagent.c.

Referenced by IntSwapMemInjectMiniSwapper().

◆ IntWinAgentInjectTrampoline()

INTSTATUS IntWinAgentInjectTrampoline ( void  )

Inject the agent trampoline inside the guest.

The agent trampoline is a small chunk of code that gets injected inside a region of NT slack space. This trampoline is used to intermediate the code transfers to the bootstrap code, which is dynamically allocated and must be freed once the agent is done.

Return values
INT_STATUS_SUCCESSOn success.

Definition at line 364 of file winagent.c.

Referenced by IntWinGuestFinishInit().

◆ IntWinAgentIsPtrInTrampoline()

BOOLEAN IntWinAgentIsPtrInTrampoline ( QWORD  Ptr,
THS_PTR_TYPE  Type 
)

Check if the provided address points inside the agent trampoline.

Parameters
[in]PtrThe pointer to be checked.
[in]TypeThe pointer type: live RIP or stack value.
Returns
True if the address points inside the trampoline, false otherwise.

Definition at line 3219 of file winagent.c.

Referenced by IntAgentIsPtrInTrampoline().

◆ IntWinAgentIsRipInsideCurrentAgent()

BOOLEAN IntWinAgentIsRipInsideCurrentAgent ( QWORD  Rip)

Return true if the given RIP points inside the currently active boot driver.

Parameters
[in]RipThe RIP to be checked.
Returns
True if the Rip points inside an active boot driver, false otherwise.

Definition at line 197 of file winagent.c.

Referenced by IntWinDrvHandleRead().

◆ IntWinAgentRemoveEntryByAgid()

void IntWinAgentRemoveEntryByAgid ( DWORD  Counter,
DWORD Tag 
)

Removes an agent name from the list of names, using the ID.

Parameters
[in]CounterThe counter/ID to be removed.
[out]TagOptional tag of the removed name.

Definition at line 3171 of file winagent.c.

Referenced by IntWinAgentHandleAppVmcall(), and IntWinAgentHandleDriverVmcall().

◆ IntWinAgentUnInit()

INTSTATUS IntWinAgentUnInit ( void  )

Uninit the agents state.

Return values
INT_STATUS_SUCCESSOn success.
INT_STATUS_NOT_INITIALIZED_HINTIf the agents state has not been initialized yet.

Definition at line 3352 of file winagent.c.

Referenced by IntWinGuestUninit().