четверг, 18 февраля 2021 г.

poorgcc: IDA Pro plugin to fix poor gcc code on arm64

Lets see what generates gcc for arm64 - for example gcc7.5 and linux kernel
Function do_sysinstr:

ADRP            X0, #__func__.48604@PAGE ; "arm64_show_signal"
ADD             X0, X0, #__func__.48604@PAGEOFF
ADRP            X3, #ctr_read_handler@PAGE
ADD             X0, X0, #0x218
ADD             X3, X3, #ctr_read_handler@PAGEOFF

Wtf happened here? Instead of loading x0 with address of sys64_hooks we have two consecutive loads and no value x0 used between. You can peek some random functions - this is very common pattern, I personally think this is bug in gcc arm64 codegen. Anyway, it does not allow to see right xrefs so I wrote simple plugin for IDA Pro to fix this

Plugin just try to find instructions "add add reg, reg, imm" without data xref and backtrack if this register was loaded somewhere above - sure code is not sample of elegance. You can add to plugins.cfg string like this

process_all_poor_gcc_functions    poorgcc64     0      1

to process all functions

Some results - after applying plugin to function do_sysinstr code looks like:

ADRP            X0, #__func__.48604@PAGE ; "arm64_show_signal"
ADD             X0, X0, #__func__.48604@PAGEOFF
ADRP            X3, #ctr_read_handler@PAGE
ADD             X0, X0, #0x218 ; FFFFFFC010C116C8
ADD             X3, X3, #ctr_read_handler@PAGEOFF


FFFFFFC010C116C8 is address of sys64_hooks and now it has right xref

понедельник, 15 февраля 2021 г.

fsm rules for rpcrt4!GlobalRpcServer

I already described how you can extract address of GlobalRpcServer and offset to some RPC_SERVER_T fields. Lets do it for arm64 in declarative manner using FSM

Start again with I_RpcServerRegisterForwardFunction function - we can get address of RpcHasBeenInitialized (will be stored with index 1), GlobalRpcServer (with index 2) and RPC_SERVER_T.pRpcForwardFunction offset (with index 3):

section .data
func I_RpcServerRegisterForwardFunction
# 1 - RpcHasBeenInitialized
stg1 load
# 2 - GlobalRpcServer
stg2 load
# 3 - ForwardFunction offset
stg3 strx

Next we can get size of RPC_SERVER_T - from function InitializeRpcServer as argument to AllocWrapper. But InitializeRpcServer is surprisingly hard to find - it is not exported and called one time from InitializeServerDLL (which also non-exported). It using lots of unicode strings but unfortunately they all have common prefix "NT AUTHORITY" what makes them indistinguishable for signature 16 bytes. But you can notice that inside this function registering some RPC_SERVER_INTERFACE - so we can use its content as GUID: 

среда, 10 февраля 2021 г.

using FSM to recover struct fields offsets

In previous post I described declarative way to find non-exported data and functions using FSM. But often you also need to know offsets to some fields in structures - they can be changed in different versions of Windows. So let see if this can be done in the same declarative manner

Perhaps most safe way is to track registers contained arguments to some function (btw not necessary exported). So I added yet two states to FSM

  • ldrx register_index. Can have prefix stg N to remember this address
  • addx register_index. Can have prefix stg N to remember this address
Amazing but it`s all that we need to start recover offsets!

Lets see example - I wrote simple rules to extract some ETW related structures fields offsets. It starts with exported function EtwRegister contained couple of non-exported functions PsGetCurrentServerSiloGlobals (which you can use for example to extract address of PspHostSiloGlobals - I'll leave this as simple exercise for the reader) and EtwpRegisterProvider - it expects ETW_SILODRIVERSTATE as first parameter, so we can ldrx0 here and get ESERVERSILO_GLOBALS.EtwSiloState offset

Then process EtwpRegisterProvider - it contains calls to EtwpFindGuidEntryByGuid & EtwpAddGuidEntry and ExAcquirePushLockExclusiveEx - in x0 we also can get ETW_GUID_ENTRY.Lock offset

Finally process EtwpFindGuidEntryByGuid to extract ETW_GUID_ENTRY.Guid offset
Run on kernel 20251:

понедельник, 8 февраля 2021 г.

fsm rules syntax

I added saving and loading of FSM rules in file - so now you can edit them (or perhaps even write new manually) and then apply with new tool afsm. So lets see how it works

  1. We must make functions distinguishable. Functions must be either exported or contain loading of some constant - from constant pool or from .rdata section
  2. Then this functions disassembling and FSM rules applied to code-flow graph. There may be several results, so I added global storage - it can be accessed by index from any rules (but sure this storage belongs to each processed file). Storage logic cannot be auto-derived so you should write such rules manually - storing states must have "stg" prefix with index
Each rule starts with "section" keyword - it is section where located address which you want to find (you can use comments starting with '#'). Then you must pick function. If functions is exported it`s easy - "func" export_name, if not - just pick section where this function located with "fsection" section_name
Then follow one or more states of FSM:
  • load - loading from "section". Can have prefix stg N to remember this address
  • store - storing to "section". Can have prefix stg N to remember this address
  • ldrb - like "load" but for 1 byte
  • ldrh - like "load" but for 2 bytes
  • strb - like "store" but for 1 byte
  • strh - like "store" but for 2 byte
  • gload index - load address from storage with index
  • gstore index - store to address from storage with index
  • const - load some constant from constant pool
  • rdata - load some 8 byte constant from .rdata section
  • guid - load 16 byte guid from .rdata section. Actually rdata and guid could be one state with variable size but I am too lazy
  • call_imp - call some imported function from IAT
  • call_dimp - call some function from delayed IAT
  • call_exp - call exported function
  • call - just some call, perhaps located in specific section. Can have prefix stg N to remember this address
  • gcall index - call function with address in storage

Lets see example - say we want to find MCGEN_TRACE_CONTEXTs in kernel - registered with non-exported function McGenEventRegister_EtwRegister, There are 3 functions where this call occurs:
  • FsRtlpHeatRegisterVolume
  • IoInitSystemPreDrivers
  • PnpDiagInitialize
none of them are exported. Try write rules for them

вторник, 26 января 2021 г.

auto-derived FSM for usermode dlls

As expected results of auto-derived FSM for usermode dlls are much worse - for example on rpcrt4.dll can be found only 76 symbols from 228. It's because code in usermode contains much fewer unique constants (like NTSTATUS or allocation tags in kernel). So we need to use some additional data to make edges more distinguishable. Lets consider several candidates

load_config

Contains addresses of SecurityCookie and ptrs to GuardCFCheckFunctionPointer & GuardCFDispatchFunctionPointer. At least knowing SecurityCookie we can distinguish loading of some address in .data section from loading of cookies in prolog/epilogue of functions. But results are almost the same - 78 from 228

delayed import

New source of data missing in kernel mode. So I added new state to FSM - call_dimp, almost the same as call_imp but for delayed IAT. As expected results have grown - 109 from 228

constants in .rdata section

arm64 code can use not only ldr from constant pool but regular const data in .rdata section - for example strings for GetProcAddress etc. Lets see how looks such code:

понедельник, 25 января 2021 г.

W32pServiceTable from windows 10 build 20292 64bit

 It seems that MS cut off whole apfnSimpleCall dispatching - no more functions

  • NtUserCallHwndParamLock
  • NtUserCallHwndParam
  • NtUserCallHwndLockSafe
  • NtUserCallHwndParamLockSafe
  • NtUserCallHwndLock
  • NtUserCallHwnd
  • NtUserCallNoParam
  • NtUserCallTwoParam
  • NtUserCallOneParam
  • NtUserCallHwndSafe
  • NtUserCallHwndOpt
Instead all functions from apfnSimpleCall now exported and contained in W32pServiceTable. Like (just to name few):
  • CreateMenu -> NtUserCreateMenu
  • CreatePopupMenu -> NtUserCreatePopupMenu
  • AllowForegroundActivation -> NtUserAllowForegroundActivation
etc etc
content of W32pServiceTable (W32pServiceLimit .eq. 0x5AA):

четверг, 14 января 2021 г.

using of auto-derived state machines

Let`s see what we can do with our auto-derived state-machines. All source code in my github repo

Simple case: KdLocalDebugEnabled

Assume that we want to find address of KdLocalDebugEnabled. On kernel 18345 RVA is 37CC18 and it located in section .data. Run
ldr.exe -se -t 8 -der D:\work\kernel\w10\18346\arm\ntoskrnl.exe 37CC18
to build rules. Option -t sets number of threads. Results:

found at 0076D850 - KdSystemDebugControl
 ldrb exorted KdDebuggerEnabled
 ldrb
apply return 37CC18, must_be 37CC18

This rule say that we must find exported function KdSystemDebugControl, wait for loading of exported symbol KdDebuggerEnabled and next loading operation will give us address of KdLocalDebugEnabled
Now apply this rule for kernel RTM 2004 (with option -T you can specify files on which to test rules):
ldr.exe -se -t 8 -der D:\work\kernel\w10\18346\arm\ntoskrnl.exe 37CC18 -T d:\work\kernel\w10\rtm\2004\arm\ntoskrnl.exe
 ldrb exorted KdDebuggerEnabled
 ldrb
Test[0]: C3F639

Lets check this address
// pubsym <rva 0xc3f639> KdLocalDebugEnabled

Second case: CmpTraceRoutine

IDA Pro shows 106 xrefs on kernel 18345, RVA is 8A8008. Lets see if rule for finding this address can be derived automatically: