RSS Amplifier

secrary [dot] com – All Content · Aug 25, 2018

Hooking via InstrumentationCallback

0
Sign in to vote or save

khasaia · secrary [dot] com

I want to write about a very interesting epilogue hooking method presented by Alex Ionescu at REcon 2015.

An epilogue detour allows for post-processing. It is useful for filtering output parameters once an original routine has performed its duties.

I know it’s not a new technique, but I found it very interesting. Additionally, all the POC codes I found were crashing.

I tried to create a POC that does not crash (at least for me) and ends normally (by the way, it’s an EXE, not a DLL).

The KPROCESS structure contains a field called InstrumentationCallback at 0x2c8:

0:000> dt _KPROCESS

ntdll!_KPROCESS

+0x000 Header : _DISPATCHER_HEADER

+0x018 ProfileListHead : _LIST_ENTRY

+0x028 DirectoryTableBase : Uint8B

+0x030 ThreadListHead : _LIST_ENTRY

+0x040 ProcessLock : Uint4B

+0x044 ProcessTimerDelay : Uint4B

+0x048 DeepFreezeStartTime : Uint8B

+0x050 Affinity : _KAFFINITY_EX

+0x0f8 ReadyListHead : _LIST_ENTRY

+0x108 SwapListEntry : _SINGLE_LIST_ENTRY

+0x110 ActiveProcessors : _KAFFINITY_EX

+0x1b8 AutoAlignment : Pos 0, 1 Bit

+0x1b8 DisableBoost : Pos 1, 1 Bit

+0x1b8 DisableQuantum : Pos 2, 1 Bit

+0x1b8 DeepFreeze : Pos 3, 1 Bit

+0x1b8 TimerVirtualization : Pos 4, 1 Bit

+0x1b8 CheckStackExtents : Pos 5, 1 Bit

+0x1b8 PpmPolicy : Pos 6, 3 Bits

+0x1b8 ActiveGroupsMask : Pos 9, 20 Bits

+0x1b8 ReservedFlags : Pos 29, 3 Bits

+0x1b8 ProcessFlags : Int4B

+0x1bc BasePriority : Char

+0x1bd QuantumReset : Char

+0x1be Visited : UChar

+0x1bf Flags : _KEXECUTE_OPTIONS

+0x1c0 ThreadSeed : [20] Uint4B

+0x210 IdealNode : [20] Uint2B

+0x238 IdealGlobalNode : Uint2B

+0x23a Spare1 : Uint2B

+0x23c StackCount : _KSTACK_COUNT

+0x240 ProcessListEntry : _LIST_ENTRY

+0x250 CycleTime : Uint8B

+0x258 ContextSwitches : Uint8B

+0x260 SchedulingGroup : Ptr64 _KSCHEDULING_GROUP

+0x268 FreezeCount : Uint4B

+0x26c KernelTime : Uint4B

+0x270 UserTime : Uint4B

+0x274 ReadyTime : Uint4B

+0x278 Spare2 : [80] UChar

+0x2c8 InstrumentationCallback : Ptr64 Void <<< That's it :)

+0x2d0 SecureState : <unnamed-tag>

Windows Vista and later you can specify callback address using InstrumentationCallback field and the callback will be called after each time any function returns from kernel to user mode.

One way to specify callback address is by using a driver, but as turns out there is a much easier way via NtSetInformationProcess API from user mode without any special privileges, we just need to specify correct structures and that’s all.

PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION nirvana;

nirvana.Callback = (PVOID)(ULONG_PTR)medium; // callback function

nirvana.Reserved = 0; // always 0

nirvana.Version = 0; // 0 for x64, 1 for x86

// just one call

NtSetInformationProcess(

GetCurrentProcess(),

(PROCESS_INFORMATION_CLASS)ProcessInstrumentationCallback,

&nirvana,

sizeof(nirvana) /*0x8*/ );

There are pitfalls, we have to use assembly inside our code for the callback function, due to we need to deal with registers directly.

include ksamd64.inc

EXTERN hook:NEAR

.code

medium PROC

; why pushing this registers? >> https://docs.microsoft.com/en-us/cpp/build/caller-callee-saved-registers

push rax ; return value

push rcx

push RBX

push RBP

push RDI

push RSI

push RSP

push R12

push R13

push R14

push R15

; without this it crashes :)

; Much smaller value is enough: https://www.reddit.com/r/ReverseEngineering/comments/7gpkw4/hooking_via_instrumentationcallback/

; P.S. thank you for feedback

sub rsp, 1000h

mov rdx, rax

mov rcx, r10

call hook

add rsp, 1000h

pop R15

pop R14

pop R13

pop R12

pop RSP

pop RSI

pop RDI

pop RBP

pop RBX

pop rcx

pop rax

jmp R10

medium ENDP

END

That’s all :) Works on Windows 10 v1709 x64

You can get POC code from GitHub

instr

Resourses:

Read the original on secrary.com

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.