понедельник, 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
# FsRtlpHeatRegisterVolume - located in PAGE section
section .data
fsection PAGE
call_exp ExAcquireResourceExclusiveLite
# MS_StorageTiering_Provider_Context - store in index 2
stg2 load
# MS_StorageTiering_Provider
guid FC 55 0C 99 62 26 F6 47 B7 D7 EB 3C 02 7C B1 3F
stg1 call

# IoInitSystemPreDrivers - located in INIT section
section .data
fsection INIT
call_imp ExpInitializeStateSeparationPhase0
# IoTraceHandle - store in index 3
stg3 load
# IoTraceProvider
guid BD CA 03 A1 42 82 93 4A 8D F5 1C DF 3B 3F 26 A6
call_exp EtwRegister
# IoMgrProvider_Context - store in index 4
stg4 load
# IoMgrProvider
guid 86 F5 F1 AB 50 2E A8 4B 92 8D 49 04 4E 6F 0D B7
# call to MS_StorageTiering_Provider - stored in first rule with index 1
gcall 1

# PnpDiagInitialize - located in INIT section
section .data
fsection INIT
# MS_KernelPnP_Provider_Context - store in index 5
stg5 load
# MS_KernelPnP_Provider
guid 39 5A 20 9C 50 12 7D 48 AB D7 E8 31 C6 29 05 39
# call to MS_StorageTiering_Provider - stored in first rule with index 1
gcall 1

As you can see I just store address of McGenEventRegister_EtwRegister in first rule with index 1 and then use gcall 1 as last state - just to be sure if this function really was called. Remaining indexes described in comments. Apply this rules to kernel 20251:
afsm.exe -a D:\src\armpatched\Release\mc.fsm D:\work\kernel\w10\20251\arm\ntoskrnl.exe
[0] D:\work\kernel\w10\20251\arm\ntoskrnl.exe: found at 0
 1 - 399238
 2 - C0DBE0
[0] D:\work\kernel\w10\20251\arm\ntoskrnl.exe: found at 0
 1 - 399238
 2 - C0DBE0
 3 - C4A5D8
 4 - C0A280
[0] D:\work\kernel\w10\20251\arm\ntoskrnl.exe: found at 0
 1 - 399238
 2 - C0DBE0
 3 - C4A5D8
 4 - C0A280
 5 - C04780

Result are in storage - for example C0DBE0 - RVA of MS_StorageTiering_Provider_Context bcs it was stored with index 2 etc. 
Now run this rules on kernel 18362:
afsm.exe -a D:\src\armpatched\Release\mc.fsm D:\work\kernel\w10\18362\arm\ntoskrnl.exe
[0] D:\work\kernel\w10\18362\arm\ntoskrnl.exe: found at 0
 1 - 1942A8
 2 - 3561A0
[0] D:\work\kernel\w10\18362\arm\ntoskrnl.exe: found at 0
 1 - 1942A8
 2 - 3561A0
 5 - 352E20

Second rules has no match - it`s bcs IoMgrTraceHandle registered with EtwRegister on old versions of kernel, so lets add new rule:
# IoInitSystemPreDrivers on old kernel
section .data
fsection INIT
call_imp ExpInitializeStateSeparationPhase0
stg3 load
guid BD CA 03 A1 42 82 93 4A 8D F5 1C DF 3B 3F 26 A6
call_exp EtwRegister
# IoMgrTraceHandle - store in index 6
stg6 load
guid 86 F5 F1 AB 50 2E A8 4B 92 8D 49 04 4E 6F 0D B7
call_exp EtwRegister

You can ask me - wait, function IoInitSystemPreDrivers is so long, why first state which you want is call imported ExpInitializeStateSeparationPhase0? Bcs I don`t care about other used variables - I want only build FSM to extract addresses of IoTraceHandle & IoMgrProvider_Context

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

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