Open skvl opened 2 years ago
One possible solution that I could imagine is to use MTF
(monitor trap flag
) to move one instruction forward from entry point before injection.
Though it looks complicated. And without checks.
I would be glad if anybody could give me some advise for this issue.
IMHO the solution is pretty clearly that on a given vCPU a single injection ought to happen at a time. The first plugin that injects ought to prevent subsequent plugins from overriding the in-flight injection.
IMHO the solution is pretty clearly that on a given vCPU a single injection ought to happen at a time. The first plugin that injects ought to prevent subsequent plugins from overriding the in-flight injection.
This is already done by the patch mentioned above. This fixes issues 1 and 2. But the question is how to fix the issue 3.
I think I would extend libinjector
to know about all injections in progress. And prevent vmi.c
to call other plug-ins until injection complete.
The idea always was that injection happens only during the setup phase of the VM and during runtime no injection should take place as the state of the OS in no longer guaranteed to meet sane parameters. Disabling callbacks to other plugins while an injection is taking place may not be the best solution as injection may take a long time and cause other events to be missed by other plugins. For now with case 3 I think its better to just have some duplicate events logged due to injection.
[...] during runtime no injection should take place [...]
but that's what we do in multiple plugins. We've been aware of this issue with @chivay and @kscieslinski for a long while, but only solution we've been able to come up would require a major refactor to both drakvuf engine and drakvuf plugins.
[...] during runtime no injection should take place [...]
but that's what we do in multiple plugins. We've been aware of this issue with @chivay and @kscieslinski for a long while, but only solution we've been able to come up would require a major refactor to both drakvuf engine and drakvuf plugins.
I would try to fix this. Already in progress.
For now with case 3 I think its better to just have some duplicate events logged due to injection.
I believe that duplicate events are very bad. Such events mask real behavior of a sample.
So I could suggest other method: drop events in context of PID : TID
from injection beginning until it finish. All other events would be logged as is. Thus we get much cleaner trace.
That's a possible solution but IMHO it would be better to keep it configurable instead of hard-coding something. My concern is that if there is a way for malware to trigger a behavior in drakvuf that skips logging events than it would be tempting to try to trigger it to hide certain malware behavior. For example, if injection is needed to page memory back in and it won't issue any plugin callbacks until that is finished, well, now you have a pid:tid that goes dark as far as drakvuf is concerned. What if you have another tid that anticipates drakvuf's injection and hijacks it right after, making the thread totally dark as the drakvuf injection never returns? Would be a perfect anti-drakvuf setup. So I think any time injection is taking place on the vm more caution needs to be performed and blindly dropping events by itself is going to cause issues down the road. At least if its left configurable malware can't target a potentially vulnerable default configuration.
I'm agree.
In #1450 it have been noticed several messages
Failed to read address
fromsyscalls
plug-in. This start to occur after makinglibusermode
to injectMmCopyVirtualMemory
instead of page faults.I have researched the error and found several architectural issues.
Issue 1. If two or more plug-ins injects function calls then undefined behavior occur.
The scenario:
S1
.int3
event thelibdrakvuf/vmi.c :: int3_cb
calls the callback of plug-inP1
thenP2
P1
injects call for some functionF1
. This means thatinfo->regs
is changed (RIP
equals the address ofF1
and other registers contains arguments) and some values are pushed onto the stack.P2
injects call forF2
. The registers and stack are changed again.F2
completion theP2
would complete its job. And restores state.F1
injection.P1
would wait until the expected state (PID
,TID
,RSP
).Issue 2. If one plug-in injects function call then other plug-ins could read the invalid state.
The scenario:
S1
.int3
event thelibdrakvuf/vmi.c :: int3_cb
calls the callback of plug-inP1
thenP2
P1
injects function call forF1
. This changes theinfo->regs
.P2
reads VM's state. Thus it reads modified registers.The example trace:
One could see that failed address
0x77c87930
is the same asRDX
after the injection ofMmCopyVirtualMemory
.I have patch for this in tesing.
Issue 3. If one plug-in injects other plug-ins coult get parasit events on return from injected function.
The scenario:
S1
.int3
event thelibdrakvuf/vmi.c :: int3_cb
calls the callback of plug-inP1
thenP2
P1
injects function call forF1
. This sets return address to entry point ofS1
.F1
is hooked byP2
or other plug-in then it would be logged.P2
logs the hook event onS1
.F1
return the hook event onS1
occur.P2
logs the hook event onS1
again.Thus one or more parasit events could be logged.
The short example from my patched version:
This could be drawn like this (https://excalidraw.com/):
So with the patch the "Issue 2" is fixed but "Issue 3" remains.
I'm looking for better patch.