пятница, 8 января 2021 г.

(semi)auto building of state machine

Several days ago I made PoC to extract addresses of WSK data from windows 10 arm64 afd.sys - specifically AfdWskClientListHead and lock AfdWskClientSpinLock. Nothing special except fact that afd.sys has no exported functions. So you must find some rare constant, then find functions which use it and only then do some disasm applying state machine to each code block (see lambda passed to traverse_simple_state_graph)

While I was writing this code, I was not left with a question whether it is possible to employ computer to build such state machines. And now I know that this is possible (at least for code on plain C for RISC-like asm with predictable addresses of instructions etc etc)

Lets see how such algo can be arranged:

1) you must find all cross-refs to desired variable and collect list of functions which use it (exactly what deriv_hack::find_xrefs method does)

2) then you must disasm each such function and try to get some primitives - like loading of constants, calling imported/exported functions etc - see deriv_hack::make_path method. Sure set of this primitives will be different for each processor and perhaps will depends from your tasks

Results for afd.sys!AfdWskClientListHead:

found at 00002698
 load
 call_imp KeAcquireInStackQueuedSpinLock
 load
found at 00004B30
 const 43444661 count 1
 call_imp ExAllocatePoolWithTag
 call_imp KeInitializeSpinLock
 load
 call_imp KeAcquireInStackQueuedSpinLock
 load
found at 000078C4
 load
 call_imp KeAcquireInStackQueuedSpinLock
 load
found at 0000D8B0
 load
 call_imp ExEnterCriticalRegionAndAcquireResourceExclusive
 load
 call_imp KeAcquireInStackQueuedSpinLock
 load
found at 0000D9F0
 load
 call_imp KeAcquireInStackQueuedSpinLock
 load
found at 00015BD8
 load
 load
 call_imp KeAcquireInStackQueuedSpinLock
 load
found at 000988D0
 load

Function at RVA 4B30 is AfdWskNotifyAttachClient and my manually written state machine does the same:
  1. wait for loading of constant 0x43444661
  2. then wait for ExAllocatePoolWithTag call
  3. then wait for KeAcquireInStackQueuedSpinLock
  4. and first loading in this state is AfdWskClientListHead
Very good results IMHO. You can play with this algo using -der option, first argument is filename to disasm and second RVA for symbol to find. For example to find KiInitialProcess in kernel (RVA 4A7080) run

ldr.exe -der D:\work\kernel\w10\18362\arm\ntoskrnl.exe 4A7080

Btw best candidate is exported KeQueryPriorityThread

Комментариев нет:

Отправить комментарий