четверг, 21 мая 2020 г.

kernel pte in windows 10 64bit

Quarantine is a good time to re-read some old but useful papers and check if you can catch trick with making KUSER_SHARED_DATA writable again So lets see what we need:
  • some logic to extract PTE base from MiGetPteAddress
  • primitive to check if some address is valid - I used MmIsAddressValid
  • primitive to read page from kernel memory
Start with some system info:
pSystemRangeStart: FFFF800000000000
PTE base address: FFFF880000000000
PTE mask: 7FFFFFFFF8
PTE shift: 9

Do some calculation
function to get offset to PTE looks like:
return (address >> 9) & 0x7FFFFFFFF8;

for pSystemRangeStart PTE will be
4000000000 + pte_base = FFFF884000000000
You may notice that this address located above pte_base

for last available address in system FFFFFFFFFFFFFFFF PTE will be
7FFFFFFFF8 + pte_base = FFFF887FFFFFFFF8

Also we need some inverse function to convert from PTE to page address. First we need sub pte_base, then divide on sizeof(MMPTE_HARDWARE) and then multiply to size of page. And add some base address. Try to calculate this base for example for PTE of pSystemRangeStart FFFF884000000000:
(FFFF884000000000 - FFFF880000000000) / sizeof(MMPTE_HARDWARE) * 0x1000 = 800000000000

Our base is FFFF800000000000 (value of pSystemRangeStart) - 800000000000 = FFFF000000000000

Notice that this base does not match with pSystemRangeStart
So our inverse function may looks like:
return 0xFFFF000000000000 + (ptr_addr - pte_base) / sizeof(MMPTE_HARDWARE) * 0x1000;

Ok, it seems that we have all puzzle pieces and can scan all PTE from FFFF884000000000 to FFFF887FFFFFFFF8. Yes, all 0x4000000000 bytes - 256Gb. Sure, we can wait for results before retirement

вторник, 5 мая 2020 г.

afd endpoints owner

Alex and Yarden as usually made perfect work to bypass even paranoid EDRs
The main problem is detection of duplicated sockets. There is a hint however:
all ownership of the socket still belongs to the original creator – even when the creator exists (and actually, because Netio.sys is still referencing the original EPROCESS, the creator and the PID become “zombies” and leak resources).
o`k, reason is true, but reference holds by afd.sys. Lets see why
We need disasm 2 functions to write simple script. First - we need back offset from afd!AfdEndpointListHead to read endpoint. It can be extracted from AfdIsAddressInUse:
  mov     [rsp+arg_0], rbx
  mov     [rsp+arg_8], rbp
  mov     [rsp+arg_10], rsi
  push    rdi
  sub     rsp, 30h
  mov     rsi, rcx
  xor     ebx, ebx
  mov     rcx, cs:AfdGlobalData
  call    cs:__imp_ExEnterCriticalRegionAndAcquireResourceShared
  nop     dword ptr [rax+rax+00h]
  mov     rdi, cs:AfdEndpointListHead
  lea     rbp, AfdEndpointListHead
  jmp     short loc_1C003C0D3
; ---------------------------------------------------------------------------

loc_1C003C054:                          ; CODE XREF: AfdIsAddressInUse+BE
  lea     rdx, [rdi-120h]
...
loc_1C003C0D3
  cmp     rdi, rbp
  jnz     loc_1C003C054


Then we need offset to EPROCESS - it can be extracted for example from AfdFreeEndpointResources:

  mov     rcx, [rbx+28h]
  mov     edx, 200h
  call    cs:__imp_PsReturnPoolQuota
  nop     dword ptr [rax+rax+00h]
  mov     rcx, [rbx+28h]  ; Object
  call    cs:__imp_ObfDereferenceObject


Now we have all parts of this puzzle. Let`s see what we can do in windbg

суббота, 18 апреля 2020 г.

PsKernelRangeList on arm64 kernel

can be found using the same old trick
Sure constants are now different, so now KUSER_SHARED_DATA.SystemCall is 0xFFFFF78000000308 and KUSER_SHARED_DATA.ProcessorFeatures is 0xFFFFF78000000274

Commited today simple logic to find and parse it in my armpatched

пятница, 17 апреля 2020 г.

IDA Pro plugin for arm64 switch tables processing

IDA Pro supports arm64 very poorly - it also cannot parse switch tables. Let`s see how they looks on arm64 - for example in function NtQueryInformationThread:
 CMP             W1, #0x2D           ; check index
 B.HI            loc_140673294
 ADR             X9, dword_14066E9EC ; switch tab address
 LDRSW           X8, [X9,W1,UXTW#2]  ; index in W1 << 2
 ADR             X9, loc_14066E358   ; base address
 ADD             X8, X9, X8,LSL#2    ; base address + offset << 2
 BR              X8

What happens here? first "ADR x9, addr" loads address of switch table
Next LDRSW is like "mov x8, [x9 + 4 * w1]" on Intel - load DWORD at x9 + index w1 left shifted by 2
Then second ADR loads address of base for this switch table
ADD x8, x9, x8 << 2 sets in x8 address of actual jumps
and finally BR go to this address

So I just wrote quick and dirty plugin arm64sw.p64 based on armpatched for switch tables processing

четверг, 16 апреля 2020 г.

KiTpExcludedRoutines

As you can guess from name this is array of functions for which you can`t set kernel tracepoint. Curious that this lists differs in x64 and arm64
x64

воскресенье, 12 апреля 2020 г.

bug in ida pro arm64 module

Lets see in ida pro some arm64 windows kernel, for example good old function PspSetCreateThreadNotifyRoutine:
 ADRP            X8, #PspNotifyEnableMask@PAGE
 ADD             X11, X8, #PspNotifyEnableMask@PAGEOFF
 TBNZ            W20, #0, loc_140690960
 ADD             X10, X11, #0x33C


register x11 contains address of PspNotifyEnableMask - in my case this is 0x1408AE6B0 and then x10 loading address of PspNotifyEnableMask + 0x33c = 0x1408AE9EC - this is actually PspCreateThreadNotifyRoutineCount. And no - you cannot fix last instruction with pressing O or Ctrl + O
Given that cross-refs in arm64 is highly dependent from correct code analysis - this is very annoing
Tested in ida pro 6.9 and 7.2

четверг, 9 апреля 2020 г.

armpatched

Several days ago I started my new pet project on GitHub, bcs
  • quarantine is boring
  • reading a book "ARM 64-Bit Assembly Language" without practice is useless
So I just forked arm64 disasm called armadillo, ported it on windows, added naïve pe loader (btw attempt to use MapViewOfFile function was unsuccessful with GetLastError 1132) and today add some practical usage of static code analysis to extract lists and lock of lookaside lists from arm64 windows kernel

Main magic happens in ntoskrnl_hack::find_lock_list function