A forum for reverse engineering, OS internals and malware analysis 

Forum for announcements and questions about tools and software.
 #30524  by pwl
 Sat Jul 01, 2017 8:07 pm
I'm reading https://github.com/erynian/virtdbg sources and have trouble understanding this code:
Code: Select all
    for (i = 0; i < KeNumberProcessors; i++) 
    {
        OldAffinity = KeSetSystemAffinityThreadEx((KAFFINITY) (1 << i));
        OldIrql = KeRaiseIrqlToDpcLevel();
        _StartVirtualization();
        KeLowerIrql(OldIrql);
        KeRevertToUserAffinityThreadEx(OldAffinity);
    }
Code: Select all
_StartVirtualization PROC
    ;int 3
	push	rax
	push	rcx
	push	rdx
	push	rbx
	push	rbp
	push	rsi
	push	rdi
	push	r8
	push	r9
	push	r10
	push	r11
	push	r12
	push	r13
	push	r14
	push	r15

	sub	rsp, 28h

	mov	rcx, rsp
	call	StartVirtualization
_StartVirtualization ENDP
Inside StartVirtualization, there is some VMX setup code and then a call to Virtualize:
Code: Select all
NTSTATUS Virtualize(PVIRT_CPU pCpu)
{
/*    ULONG64 rsp;*/
    ULONG32 i;
    
    i = KeGetCurrentProcessorNumber();
    DbgLog(("CPU: 0x%p \n", pCpu));
    DbgLog(("rsp: 0x%llx \n", _Rsp()));

    _VmLaunch();
    /* never returns if successful */
So we have a call tree that ends in vmlaunch that starts exexuting guest code if successful and doesn't return! How is the topmost loop going to terminate then, or proceed to virtualize more than 1 processors?
 #30530  by dmr
 Mon Jul 03, 2017 6:43 am
You need to read Intel manuals, iirc, especially 3C. The answer you're looking for is there.
 #30543  by feryno
 Thu Jul 06, 2017 10:48 am
@dmr:
pwl will read hundreds pages of manual for very long time until finding the answer

@pwl:
on successful vmlaunch, the RIP (x64) / EIP (x86) is obtained from VMCS (from guest RIP), also RSP (x64) / ESP (x86) (from guest RSP), also a lot of other things like selectors (CS, SS, DS, ES, FS, GS) and their bases/limits/access rights, control registers (CR0, CR3, CR4), LDTR, TR, GDT, IDT, ...

to make things clear and understandable, the best would be to point the guest RIP to the address immediately following the vmlaunch instruction

but because C / NASM does not allow you to access a label inside a proc from different proc, the author of virtdbg used some tricks to make things running:
he set guest RIP to the _GuestEntryPoint
he set guest RSP to the RSP at the time of call StartVirtualization (the only one param passed in RCX to the proc StartVirtualization is the actual RSP)

this way the epilogues either RET instructions of triple procedures StartVirtualization / _Virtualize / _VmLaunch are not reached in case of vmlaunch success (but would be executed in case of vmlaunch failure)
this is quite dangerous, imagine that the prologue of any of the _Virtualize / StartVirtualization proc pushed some nonvolatile registers and proc overwrote with own values (RBX, RBP, RSI, RDI, R11-R15) - usage of such registers completely depends on decision of C compiler - to survive this the guest RIP points to a proc GuestEntryPoint which pops all registers in reverse order as they were pushed on _StartVirtualization
 #30552  by pwl
 Fri Jul 07, 2017 6:30 pm
Indeed, intel manuals are huge, I just started to learn about VT-x.
Thanks for the answer feryno.