HyperDbg Documentation
CommunityDownloadResearchTutorialhwdbg
  • HyperDbg
  • Getting Started
    • Quick Start
    • FAQ
    • Build & Install
    • Attach to HyperDbg
      • Attach to a remote machine
      • Attach to local machine
      • Start a new process
      • Attach to a running process
  • Using HyperDbg
    • Prerequisites
      • Operation Modes
      • How to create a condition?
      • How to create an action?
      • Signatures
    • User-mode Debugging
      • Principles
      • Examples
        • basics
        • events
          • Getting Results of a System-call
    • Kernel-mode Debugging
      • Principles
      • Examples
        • beginning
          • Connecting To HyperDbg
          • Configuring Symbol Server/Path
        • basics
          • Setting Breakpoints & Stepping Instructions
          • Displaying & Editing & Searching Memory
          • Showing & Modifying Registers and Flags
          • Switching to a Specific Process or Thread
          • Mapping Data & Create Structures, and Enums From Symbols
        • events
          • Managing Events
          • Hooking Any Function
          • Intercepting All SYSCALLs
          • Monitoring Accesses To Structures
          • Triggering Special Instructions
          • Identifying System Behavior
        • Scripting Language Examples
    • Software Development Kit (SDK)
      • Events
        • Conditions
        • Actions
      • IOCTL
        • Event Registration
  • Commands
    • Debugging Commands
      • ? (evaluate and execute expressions and scripts in debuggee)
      • ~ (display and change the current operating core)
      • a (assemble virtual address)
      • load (load the kernel modules)
      • unload (unload the kernel modules)
      • status (show the debuggee status)
      • events (show and modify active/disabled events)
      • p (step-over)
      • t (step-in)
      • i (instrumentation step-in)
      • gu (step-out or go up)
      • r (read or modify registers)
      • bp (set breakpoint)
      • bl (list breakpoints)
      • be (enable breakpoints)
      • bd (disable breakpoints)
      • bc (clear and remove breakpoints)
      • g (continue debuggee or processing kernel packets)
      • x (examine symbols and find functions and variables address)
      • db, dc, dd, dq (read virtual memory)
      • eb, ed, eq (edit virtual memory)
      • sb, sd, sq (search virtual memory)
      • u, u64, u2, u32 (disassemble virtual address)
      • k, kd, kq (display stack backtrace)
      • dt (display and map virtual memory to structures)
      • struct (make structures, enums, data types from symbols)
      • sleep (wait for specific time in the .script command)
      • pause (break to the debugger and pause processing kernel packets)
      • print (evaluate and print expression in debuggee)
      • lm (view loaded modules)
      • cpu (check cpu supported technologies)
      • rdmsr (read model-specific register)
      • wrmsr (write model-specific register)
      • flush (remove pending kernel buffers and messages)
      • prealloc (reserve pre-allocated pools)
      • preactivate (pre-activate special functionalities)
      • output (create output source for event forwarding)
      • test (test functionalities)
      • settings (configures different options and preferences)
      • exit (exit from the debugger)
    • Meta Commands
      • .help (show the help of commands)
      • .debug (prepare and connect to debugger)
      • .connect (connect to a session)
      • .disconnect (disconnect from a session)
      • .listen (listen on a port and wait for the debugger to connect)
      • .status (show the debugger status)
      • .start (start a new process)
      • .restart (restart the process)
      • .attach (attach to a process)
      • .detach (detach from the process)
      • .switch (show the list and switch between active debugging processes)
      • .kill (terminate the process)
      • .process, .process2 (show the current process and switch to another process)
      • .thread, .thread2 (show the current thread and switch to another thread)
      • .pagein (bring the page into the RAM)
      • .dump (save the virtual memory into a file)
      • .formats (show number formats)
      • .script (run batch script commands)
      • .sympath (set the symbol server)
      • .sym (load pdb symbols)
      • .pe (parse PE file)
      • .logopen (open log file)
      • .logclose (close log file)
      • .cls (clear the screen)
    • Extension Commands
      • !a (assemble physical address)
      • !pte (display page-level address and entries)
      • !db, !dc, !dd, !dq (read physical memory)
      • !eb, !ed, !eq (edit physical memory)
      • !sb, !sd, !sq (search physical memory)
      • !u, !u64, !u2, !u32 (disassemble physical address)
      • !dt (display and map physical memory to structures)
      • !track (track and map function calls and returns to the symbols)
      • !epthook (hidden hook with EPT - stealth breakpoints)
      • !epthook2 (hidden hook with EPT - detours)
      • !monitor (monitor read/write/execute to a range of memory)
      • !syscall, !syscall2 (hook system-calls)
      • !sysret, !sysret2 (hook SYSRET instruction execution)
      • !mode (detect kernel-to-user and user-to-kernel transitions)
      • !cpuid (hook CPUID instruction execution)
      • !msrread (hook RDMSR instruction execution)
      • !msrwrite (hook WRMSR instruction execution)
      • !tsc (hook RDTSC/RDTSCP instruction execution)
      • !pmc (hook RDPMC instruction execution)
      • !vmcall (hook hypercalls)
      • !exception (hook first 32 entries of IDT)
      • !interrupt (hook external device interrupts)
      • !dr (hook access to debug registers)
      • !ioin (hook IN instruction execution)
      • !ioout (hook OUT instruction execution)
      • !hide (enable transparent-mode)
      • !unhide (disable transparent-mode)
      • !measure (measuring and providing details for transparent-mode)
      • !va2pa (convert a virtual address to physical address)
      • !pa2va (convert physical address to virtual address)
      • !dump (save the physical memory into a file)
      • !pcitree (show PCI/PCIe device tree)
      • !pcicam (dump the PCI/PCIe configuration space)
      • !idt (show Interrupt Descriptor Table entries)
      • !apic (dump local APIC entries in XAPIC and X2APIC modes)
      • !ioapic (dump I/O APIC)
    • Scripting Language
      • Assumptions & Evaluations
      • Variables & Assignments
      • Casting & Type-awareness
      • Conditionals & Loops
      • Constants & Functions
      • Debugger Script (DS)
      • Examples
        • view system state (registers, memory, variables)
        • change system state (registers, memory, variables)
        • trace function calls
        • pause the debugger conditionally
        • conditional breakpoints and events
        • patch the normal sequence of execution
        • access to a shared variable from different cores
        • count occurrences of events
      • Functions
        • debugger
          • pause
        • events
          • event_enable
          • event_disable
          • event_clear
          • event_sc
          • event_inject
          • event_inject_error_code
          • flush
        • exports
          • print
          • printf
        • interlocked
          • interlocked_compare_exchange
          • interlocked_decrement
          • interlocked_exchange
          • interlocked_exchange_add
          • interlocked_increment
        • memory
          • check_address
          • eb, ed, eq
          • eb_pa, ed_pa, eq_pa
          • memcpy
          • memcpy_pa
          • memcmp
          • virtual_to_physical
          • physical_to_virtual
        • diassembler
          • disassemble_len
          • disassemble_len32
        • spinlocks
          • spinlock_lock
          • spinlock_lock_custom_wait
          • spinlock_unlock
        • timings
          • rdtsc
          • rdtscp
          • microsleep
        • strings
          • strlen
          • wcslen
          • strcmp
          • strncmp
          • wcscmp
          • wcsncmp
    • Commands Map
  • Tips & Tricks
    • Considerations
      • Basic concepts in Intel VT-x
      • VMX root-mode vs VMX non-root mode
      • The "unsafe" behavior
      • Script engine in VMX non-root mode
      • Difference between process and thread switching commands
      • Accessing Invalid Address
      • Transparent Mode
    • Nested-Virtualization Environments
      • Supported Virtual Machines
      • Run HyperDbg on VMware
      • Run HyperDbg on Hyper-V
      • Supporting VMware/Hyper-V
      • VMware backdoor I/O ports
    • Misc
      • Event forwarding
      • Event short-circuiting
      • Event calling stage
      • Instant events
      • Message overflow
      • Customize build
        • Increase Communication Buffer Size
        • Number of EPT Hooks in One Page
        • Change Script Engine Limitations
      • Enable and disable events in Debugger Mode
      • Switch to New Process Layout
  • Contribution
    • Style Guide
      • Coding style
      • Command style
      • Doxygen style
    • Logo & Artworks
  • Design
    • Features
      • VMM (Module)
        • Control over NMIs
        • VMX root-mode compatible message tracing
        • Design of !epthook
        • Design of !epthook2
        • Design of !monitor
        • Design of !syscall & !sysret
        • Design of !exception & !interrupt
    • Debugger Internals
      • Events
      • Conditions
      • Actions
      • Kernel Debugger
        • Design Perspective
        • Connection
  • Links
    • Twitter
    • Telegram
    • Discord
    • Matrix
    • Mastodon
    • YouTube
    • hwdbg (Chip Debugger)
    • Doxygen
    • Contribution
Powered by GitBook
On this page
  • Default Short-circuiting State
  • Manually Changing The Short-circuiting State
  • Using Scripts To Change The Short-circuiting State
  • Examples
Edit on GitHub
  1. Tips & Tricks
  2. Misc

Event short-circuiting

The event short-circuiting and ignoring mechanism in HyperDbg

PreviousEvent forwardingNextEvent calling stage

Last updated 1 year ago

Starting from version 0.3, HyperDbg introduces event short-circuiting as a mechanism, allowing the ignoring of certain events. For example, imagine that a SYSCALL event is triggered in the debuggee, now based on the user-defined conditions, you want to ignore the execution of this event as if no SYSCALL instruction is executed. This is where the event short-circuiting becomes handy.

The same scenario happens to most of the events. For example, certain IN/OUT instructions need to be ignored. Again this mechanism can be used or for instance, if you want to ignore the execution of an RDMSR or a WRMSR, again the event short-circuiting can be used.

Event short-circuiting is also handy in the '' command. Imagine, you want to ignore memory writes to the certain field of a structure. You can simply ignore the memory write and write something else in the target location.

Once you short-circuit an event, the 'post' calling stage will no longer be called. Please refer to the documentation for more information about .

This mechanism is mainly handled by utilizing commands and functions.

Default Short-circuiting State

The default short-circuiting state is used whenever you want to short-circuit all of the executions of the target event. For example, one might want to block the execution of IN/OUT instructions on port 0x3F8. In this case, we can add sc on to the target event.

!ioin 0x3f8 sc on script { printf("IO port (in) has been access.\n"); }

For the OUT instructions.

!ioout 0x3f8 sc on script { printf("IO port (out) has been access.\n"); }

The same sc on can also be applied to other events like , , , , etc. Certain events like and don't support event short-circuiting as this concept doesn't make sense in the case of these events. Please check the documentation of each event to see whether the target event supports this mechanism or not.

By default, the 'sc' state of the event is set to off, which means the event will be triggered while the target instruction also will be executed (emulated).

Manually Changing The Short-circuiting State

Using the '' command, you can change the short-circuiting state of the event for the corresponding execution.

For example, the following event is triggered and paused the debugger.

!syscall 0x55 pid 1c0

Now, you conclude that the execution of SYSCALL for the current event (only for the current execution) should be ignored. Thus, you can use the following command to short-circuit the event.

0: kHyperDbg> events sc on

Using Scripts To Change The Short-circuiting State

This function gets 1 or 0 as the input while 1 means the short-circuiting is ON and the event should be ignored and 0 means the event is not short-circuited and should be executed (emulated).

Using this function you can have two approaches: Blocklisting and whitelisting.

Blocklisting Approach

In the blocklisting approach, you only short-circuit certain events that met a special condition while the default short-circuiting state is off.

For example,

!syscall script {

	if (@rcx == 0xf000 && @rdx == 0x55) {
		event_sc(1);
	}
}

Whitelisting Approach

In the whitelisting approach, you allow certain events that met a special condition while the default short-circuiting state is on and all other events will be short-circuited.

For example,

!syscall 0x55 sc on script {
	
	if (@rcx == 0xf0) {
		event_sc(0);
	}
}

Examples

Event short-circuiting can be applied in numerous scenarios. Let's see some examples.

Example 1

The first scenario is for preventing memory modifications. For this example, assume that we compiled the following code.

#include <iostream>
#include <Windows.h>

volatile int test = 0;

int main()
{
	printf("Address of test variable: %llx | pid: %x\n", &test, GetCurrentProcessId());

	for (;;)
	{
		test++;
		printf("test value is : %d\n", test);
		Sleep(2000);
	}
}

We run the above code, we'll see the following console results:

Address of test variable: 7ff71f118210 | pid: 3fa8
test value is : 1
test value is : 2
test value is : 3
test value is : 4
...

Now, let's return to HyperDbg. Based on the above output, we use the following script to prevent memory writings (test++;) on the test variable memory.

!monitor w 7ff71f118210 7ff71f118210+4 pid 3fa8 script {

  printf("writng into memory address: %llx is ignored\n", $context);
  event_sc(1);
}

You can see that the target process starts to produce results with the same number in the test variable.

Address of test variable: 7ff71f118210 | pid: 3fa8
test value is : 1
test value is : 2
test value is : 3
test value is : 4
test value is : 4
test value is : 4
test value is : 4
test value is : 4
...

If we remove the events using the following command, the process will get the chance to execute the target instructions to modify the memory (increase the value).

0: kHyperDbg> events c all

The result will be:

Address of test variable: 7ff71f118210 | pid: 3fa8
test value is : 1
test value is : 2
test value is : 3
test value is : 4
test value is : 4
test value is : 4
test value is : 4
test value is : 4
test value is : 5
test value is : 6
test value is : 7
...

That's how you can prevent the modification of memory and it's clear that it's possible to use conditional statements to only prevent the execution in certain circumstances.

Example 2

The second example is preventing a special MSR (MSR_LSTAR) from reading its original value. For example, assume the original value is changed and the SYSCALL handler points to another location, then we can use the following script to change the address when a kernel-level module tries to read this MSR, it will see the modified version.

!msrread c0000082 script {
	
	//
	// Fill the EDX:EAX
	//
	@rdx = f0f0f0f0;
	@rax = 10203040;
	
	printf("msr %llx read!\n", $context);
	event_sc(1);
}

Example 3

The third example is event short-circuiting system-calls.

!syscall script {

  if (@rax == 0x7) {
  
    if (dw(@rsp + 30) == 0x12007) {

      //
      // Get the port address
      //
      port_num_high_bit = db(poi(@rsp + 38) + 1a);
      port_num_low_bit = db(poi(@rsp + 38) + 1b);

      port_num = 0;
      port_num = port_num_high_bit << 8 | port_num_low_bit;

      //
      // Get the IP address
      //
      part0 = db(poi(@rsp + 38) + 1c);
      part1 = db(poi(@rsp + 38) + 1d);
      part2 = db(poi(@rsp + 38) + 1e);
      part3 = db(poi(@rsp + 38) + 1f);

      part0 = part0 << 0n24;
      part1 = part1 << 0n16;
      part2 = part2 << 0n8;
      part3 = part3 << 0n0;

      ip_addr = part0 | part1 | part2 | part3;

      printf("Process Id: %x, name: %s connects to ====> Address: %d.%d.%d.%d:%d\n",
		$pid,
		$pname,
        (ip_addr & 0xFF000000) >> 0n24,
        (ip_addr & 0x00FF0000) >> 0n16,
        (ip_addr & 0x0000FF00) >> 0n8,
        ip_addr & 0x000000FF,
		port_num);
		
	if (port_num == 0n443) {
			
		//
		// Block the connection to port 443
		//
		printf("Connection to port 443 is blocked!\n");
		event_sc(1);
	}
    }
  }
}

Example 4

In this example, we blocked (paused) the execution of a process with the process ID equal to 0x1c0. After running the below command, only the target process is halted and cannot execute any user-mode instruction while the entire system is running properly. Once you clear this event, the process will continue its normal execution.

!mode u pid 0x1c0 script {

	//
	// The user-mode execution of the process is paused and
	// instruction fetches in the user-mode is prevented
	//
	event_sc(1);
}

Here are some cases, where event short-circuiting can be useful. Event short-circuiting can prove highly advantageous in various cases due to its ability to selectively bypass events based on certain conditions. This technique finds utility in numerous scenarios, offering flexibility and control over program execution.

Please note that the default short-circuiting state of the above event is 'off' which means that the next execution of the event will execute the SYSCALL. In other words, short-circuiting by using the '' command will ignore the execution (emulation) of the event only for ONE time.

The most commonly utilized scenario is applying conditions and ignoring events in certain conditions by using scripts. This can be done by using the '' function.

Same as the '' command, this function only applies to the current execution (one-time) of the event.

In this example, we decode the details of the system-call related to network (socket) packets to the network and blocked the connections to HTTPS (port: 443). For more information, please read the detail provided .

The fourth example is event short-circuiting for transitions of the '' command.

!monitor
using event-short circuiting and the event calling stages
!syscall
!msrread
!msrwrite
!monitor
!epthook
!epthook2
events
events
event_sc
events
connecting
here
!mode