Event short-circuiting
The event short-circuiting and ignoring mechanism in HyperDbg
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 '!monitor' 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 using event-short circuiting and the event calling stages.
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.
For the OUT instructions.
The same sc on
can also be applied to other events like !syscall, !msrread, !msrwrite, !monitor, etc. Certain events like !epthook and !epthook2 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 'events' 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.
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.
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 'events' command will ignore the execution (emulation) of the event only for ONE time.
Using Scripts To Change The Short-circuiting State
The most commonly utilized scenario is applying conditions and ignoring events in certain conditions by using scripts. This can be done by using the 'event_sc' function.
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).
Same as the 'events' command, this function only applies to the current execution (one-time) of the event.
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,
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,
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.
We run the above code, we'll see the following console results:
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.
You can see that the target process starts to produce results with the same number in the test
variable.
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).
The result will be:
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.
Example 3
The third example is event short-circuiting system-calls.
In this example, we decode the details of the system-call related to connecting network (socket) packets to the network and blocked the connections to HTTPS (port: 443). For more information, please read the detail provided here.
Example 4
The fourth example is event short-circuiting for transitions of the '!mode' command.
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.
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.
Last updated