m. taujanskas

-

> Instrumentation callbacks, et al.

The instrumentation callback is fairly standard:

push    r10 {ic_return_address}
push    rax {__saved_rax}
pushfq   {flags}
push    rbx {__saved_rbx}
mov     rbx, rsp {__saved_rbx}
lea     rax, [rel instrumentation_callback]
cmp     rcx, rax
cmove   rcx, r10
lea     r10, [rsp-0xc0 {var_e0}]
and     r10 {var_e0}, 0xfffffffffffffff0
mov     rsp, r10
cld     
mov     qword [rsp+0xb0 {target_address_1}], rcx
mov     qword [rsp+0xa8 {__saved_rdx}], rdx
mov     qword [rsp+0xa0 {__saved_r8}], r8
mov     qword [rsp+0x98 {__saved_r9}], r9
mov     qword [rsp+0x90 {__saved_r11}], r11
movaps  xmmword [rsp+0x80 {__saved_zmm0}], xmm0
movaps  xmmword [rsp+0x70 {__saved_zmm1}], xmm1
movaps  xmmword [rsp+0x60 {__saved_zmm2}], xmm2
movaps  xmmword [rsp+0x50 {__saved_zmm3}], xmm3
movaps  xmmword [rsp+0x40 {__saved_zmm4}], xmm4
movaps  xmmword [rsp+0x30 {__saved_zmm5}], xmm5
mov     rcx, qword [rbx+0x18 {ic_return_address}]
call    ic_to_LdrInitThunk_or_UserApcDispatch
mov     qword [rbx+0x18 {var_8}], rax
mov     rcx, qword [rsp+0xb0 {target_address_1}]
mov     rdx, qword [rsp+0xa8 {__saved_rdx}]
mov     r8, qword [rsp+0xa0 {__saved_r8}]
mov     r9, qword [rsp+0x98 {__saved_r9}]
mov     r11, qword [rsp+0x90 {__saved_r11}]
movaps  xmm0, xmmword [rsp+0x80 {__saved_zmm0}]
movaps  xmm1, xmmword [rsp+0x70 {__saved_zmm1}]
movaps  xmm2, xmmword [rsp+0x60 {__saved_zmm2}]
movaps  xmm3, xmmword [rsp+0x50 {__saved_zmm3}]
movaps  xmm4, xmmword [rsp+0x40 {__saved_zmm4}]
movaps  xmm5, xmmword [rsp+0x30 {__saved_zmm5}]
mov     rsp, rbx
pop     rbx {__saved_rbx}
popfq   
pop     rax {__saved_rax}
pop     r10 {var_8}
jmp     r10

Which simply boils down to:

void
instrumentation_callback (
    uint64_t* target /* rcx */, uint64_t* return_rip /* r10 */)
{
    if (target == instrumentation_callback)
        target = return_rip;
    __jump (ic_to_LdrInitThunk_or_UserApcDispatch (return_rip));
}

Then, the proceeding function essentially switches against return_rip to determine which function was called, and act based on that:

void
ic_to_LdrInitThunk_or_UserApcDispatch (uint64_t* return_rip /* rcx */)
{
    switch (return_rip)
    {
        case &LdrInitializeThunk:
            __clearTrap ();
            return &ic_LdrInitializeThunk;
        case &KiUserApcDispatcher:
            return &ic_KiUserApcDispatcher;
    }
    /* these functions not matched, read below */
}

Essentially injecting its own intermediate functionality for either Windows function, if neither function is matched, then it continues as such:

if (!__teb->ExceptionList)
{
    if (return_rip == &KiUserExceptionDispatcher)
        return &ic_KiUserApcDispatcher;
    __clearTrap ();
    return /* `return_rip`, unmodified */;
}