среда, 8 августа 2018 г.

bug in wtsapi32!WTSFreeMemoryExA

prototype
BOOL WTSFreeMemoryExA(
  WTS_TYPE_CLASS WTSTypeClass,
  PVOID          pMemory,
  ULONG          NumberOfEntries
);

WTS_TYPE_CLASS declared in WtsApi32.h as
enum _WTS_TYPE_CLASS {
  WTSTypeProcessInfoLevel0 = 0x0,
  WTSTypeProcessInfoLevel1 = 0x1,
  WTSTypeSessionInfoLevel1 = 0x2,
};

ok, check in disasm what happens:
WTSFreeMemoryExA proc near 
  push    rbx
  sub     rsp, 20h
  xor     ebx, ebx
  cmp     ecx, ebx
  jl      short loc_7FF70582EC2
  cmp     ecx, 1 ; whut ?
  jg      short loc_7FF70582EC2
  call    WTSFreeMemoryExW
  mov     ebx, eax
  jmp     short loc_7FF70582ECD

loc_7FF70582EC2: 
  mov     ecx, 87         ; dwErrCode - ERROR_INVALID_PARAMETER
  call    cs:__imp_SetLastError 

as you can see you cannot pass WTSTypeSessionInfoLevel1 to function WTSFreeMemoryExA - it gives error ERROR_INVALID_PARAMETER. As dirty workaround you can use WTSFreeMemoryExW - it has correct checking of WTSTypeClass. btw this lead to memory leaks and known at least since 2013

пятница, 29 июня 2018 г.

interesting case of memory leak

after three weeks of work service osqueryd.exe consumed about 150 mb of memory. so I made full memory dump with process explorer and run !heap -l in windbg
298991 string in log ! lets write quick and ditry perl script to calculate sizes of leaked blocks:
my $state = 0;
my($str, %dict, $size);
while( $str = <> )
{
  chomp $str;
  last if ( $str eq '' );
  if ( ! $state )
  {
    $state = 1 if ( $str =~ /^-----/ );
    next;
  }
  $str = substr($str, 72, 10);
  $str =~ s/^\s+//g;
  $str =~ s/\s+$//g;
  $size = hex($str);
  next if ( !$size );
  $dict{$size} += 1;
}

# dump results
my $iter;
foreach $iter ( sort { $dict{$b} <=> $dict{$a} } keys %dict )
{
  printf("%X %d\n", $iter, $dict{$iter});
}
results are encouraging:

среда, 17 января 2018 г.

wincheck rc8.60

download
mirror
Changelog:
  • add some support of meltdown patched kernels. It seems that Microsoft backported from w10 InterruptObject to KPRCB on windows 8.1. so all offsets below this field were shifted downward and previous version of wincheck produced BSODs
  • add dumping of SYSTEM_KERNEL_VA_SHADOW_INFORMATION
  • add support of windows 10 build 17063
  • add lots of new WNF IDs names from ADK version 10.1.16299

пятница, 24 ноября 2017 г.

wincheck rc8.59

download
mirror
Changelog:
  • add support of numerous versions of windows 10 insider preview - up to ~17025
  • add -dsip option to dump SIPs from crypt32.dll
  • add -dac & -dsac options to dump activation contexts and system activation contexts. based on this code from @deroko
  • add dumping of rpcrt4 security providers
  • add dumping of ETW private loggers (-wmi option)
  • add lots of WNF IDs names
  • add dumping of registered with winnsi!NsiRpcRegisterChangeNotification notifications

четверг, 16 ноября 2017 г.

crypt32.dll SIPs

in cool paper "subverting windows trust" was described mechanism of subject interface package (SIP)
Lets see how we can extract and dump them
Unfortunately list of SIPs inside crypt32.dll don't have name in .pdb. One way is to find it with help of IDA Pro from function FindDll:

  push    [ebp+nSize]                   ; nSize
  push    ebx                           ; lpDst
  push    [ebp+lpSrc]                   ; lpSrc
  call    ds:__imp__ExpandEnvironmentStringsW@12
  test    eax, eax
  jz      short loc_5CF28F50
  push    offset dll_cs

  call    ds:__imp__EnterCriticalSection@4
  mov     edi, dll_list ; linked list of SIPs
  test    edi, edi
  jz      short loc_5CF28F89

next_item:
  push    0FFFFFFFFh                    ; cchCount2
  push    dword ptr [edi+8]             ; lpString2
  push    0FFFFFFFFh                    ; cchCount1
  push    ebx                           ; lpString1
  push    1                             ; dwCmpFlags
  push    409h                          ; Locale
  call    ds:__imp__CompareStringW@24
  dec     eax
  sub     eax, 1
  jz      short loc_5CF28F41
  mov     edi, [edi+4]
  test    edi, edi
  jnz     short next_item


this address (I named it dll_list) contains head of linked list to SIPs structures like this:
struct sip_item
{
  sip_item *next;
  PVOID unk4;        // ptr to crypto32_dll_list_item
  const char *fname; // actually ends to end of sip_item
  PVOID pfn; // if function was resolved, else NULL
};

struct crypto32_dll_list_item
{
  PVOID unk;
  crypto32_dll_list_item *next;
  const wchar_t *dll_name;

  HANDLE base; // if dll was loaded - load base else NULL
  DWORD unk10;
  DWORD unk14;
  sip_item *func_items_list;
  PVOID unk20;
  PVOID unk24;
  PVOID unk28;
};

вторник, 7 ноября 2017 г.

rpcrt4 security providers

Count of loaded providers stored in rpcrt4!LoadedProviders and list in rpcrt4!ProviderList
Structure of each provider can be partially recovered from function FindSecurityPackage:
struct _rpc_loaded_provider
{
  DWORD unk1;
  PVOID unk2;
  PSecurityFunctionTable table; 
  PVOID unk3;
  PVOID unk4;
}; // size of struct 0x14 for x86 and 0x28 for x64


It's interesting that the function of InitSecurityFunctionTable patches the contents of SECURITY_FUNCTION_TABLE. Sample of output from w8.1: