Friday, April 27, 2012

Структури и сканиране на памет.

Не съм писал от доста време - работа, занимания, чудесии. В една от предните статии стана въпрос за една структура, която съдържа адресите на някой доста често използвани структури - KdDebuggerBlog. Проблемът е,  че в 64 битовата 7-ца адресът на тази структура не е експортнат, съответно няма лесен (а дали?) начин да намерим адресът. Всъщност се оказва доста лесно да се намери адресът, използвайки малко common sense. 

Първото нещо, което може да се направи е да се disassemble-не някоя функция, за която знаем  че използва KdDebuggerBloc. Проблемите тук са основно 2:
  • Трябва да намерим функция, която използва въпросната променлива
  • Дори и да намерим такава, си е играчка да използваме някои от disassm библиотеките, за да обходим функция инструкция, по инструкция докато не стигнем до статично зададената инструкция, за която сме сигурни, че използва адресът на KdDebuggerBlock като аргумент. Например - 5-тата mov инструкция от функцията PsGetSystemProcess() (това е просто пример, таква функция в windows няма :) ).
Вторият вариант е подобен на първият, но доста по лесен за имплементиране (както ще стане ясно). За какво става на въпрос - този път пак ще сканираме паметта, но поне можем малко и ли много да съкратим search space-а и да използваме common knowledge, за да си осигурим адресът. Проблемът е да намерим needle in a haystack, като иглата е KdDebuggerBlock, а купата със сеното е kernel space-а. Разбира се абсурдно е да сканираме целият kernel space, затова ще сме умни и ще използваме следните фактори, за да намалим search space: 
  • KdDebuggerBlock  е променлива, която е част от кърнъла => ще се намира между kernel_base_address и kernel_base_address + size_of_kernel_image. 
  • Тъй като по дефиниция всички глобални променливи се записват в .data section-а на Windows автоматично ще ни интересува паметта между start_of_data_section и start_of_data_section + size_of_data_section. 
  • Тъй като знаем layout-а на структурата, виждаме че има променливи, които са глобално експортирани, тоест ако вземем някакъв блок памет, cast-нем го към типа на дадената структура и сравним дали на дадените позиции има стойностите, които имат тези глобални променливи (MmHighestUserAddres, MmSystemRangeStart и MmUserProbeAddress) то можем с голяма точно да определим дали даденият адрес представлява адресът на KdDebuggerBlock. 
     
    
    
И така ето го алгоритъмът:
  1. Намираме къде е зареден kernel image-а. 
  2. Parse-ваме PE image-a, за да намерим началото и краят на ".data" секцията. 
  3. Сканираме адресите в намереният в (2) диапазон и сравняваме дали от началото на всеки на точно определените offsets разполагаме с export-натите глобални променливи.
Ето и малко код:

void findKdDebuggerBlock() {
 
 DWORD bytesScanned;
 DWORD sectionSize = 0;
 PVOID kernelbase = GetNtosBaseAddr();
 PVOID sectionAddress = GetDataSectionAddress(kernelbase, &sectionSize);
 char *debugData = (char *)sectionAddress;
 
 DbgPrint("Starting search at address 0x%p\n", sectionAddress);
 for(bytesScanned = 0; bytesScanned < sectionSize; bytesScanned++) {
  if((PVOID)((PKDDEBUGGER_DATA64)debugData)->MmHighestUserAddress == &MmHighestUserAddress &&
   (PVOID)((PKDDEBUGGER_DATA64)debugData)->MmSystemRangeStart == &MmSystemRangeStart &&
   (PVOID)((PKDDEBUGGER_DATA64)debugData)->MmUserProbeAddress == &MmUserProbeAddress ) {
    DbgPrint("Found KDEVERSIOIN BLOCK AT 0x%p\n", debugData);
    break;
  }
 
  debugData++;
 }
 
 DbgPrint("Exhausted search space and found nothing\n");
}

Saturday, February 4, 2012

Enumerating Process list through HANDLE_TABLE

Въпросът на деня - "Как да вземем списък на всички вървящи процеси, без да използваме PsActiveProcessList". Отговорът е много прост, но нека малко встъпителни думи. "Вездесъщата" структура _EPROCESS съдържа следното поле (това се отнася за x64 Windows 7 под 32 бита офсетът е различен):

struct _EPROCESS {

//omitted for brevity

/*0x200*/     struct _HANDLE_TABLE* ObjectTable 

//omitted for brevity

}
 
Това всъщност е pointer към pointer към _HANDLE_TABLE: 
nt!_HANDLE_TABLE
   +0x000 TableCode        : Uint8B
   +0x008 QuotaProcess     : Ptr64 _EPROCESS
   +0x010 UniqueProcessId  : Ptr64 Void
   +0x018 HandleLock       : _EX_PUSH_LOCK
   +0x020 HandleTableList  : _LIST_ENTRY
   +0x030 HandleContentionEvent : _EX_PUSH_LOCK
   +0x038 DebugInfo        : Ptr64 _HANDLE_TRACE_DEBUG_INFO
   +0x040 ExtraInfoPages   : Int4B
   +0x044 Flags            : Uint4B
   +0x044 StrictFIFO       : Pos 0, 1 Bit
   +0x048 FirstFreeHandle  : Uint4B
   +0x050 LastFreeHandleEntry : Ptr64 _HANDLE_TABLE_ENTRY
   +0x058 HandleCount      : Uint4B
   +0x05c NextHandleNeedingPool : Uint4B
   +0x060 HandleCountHighWatermark : Uint4B

Идеята тук е проста - всеки процес в Windows отваря HANDLES към най-различни ресурси - файлове, други процеси, shared sections etc. Все някъде Windows трябва да пази тази информация и това се случва точно в тази структура, интересното обаче е, че всички handle таблици на процеси са вързани в един linked-list както се вижда от полето
HandleTableList
Тоест ние съвсем спокойно можем да обходим всички таблици на вървящи процеси на системата в даден момент. Други полета, които може да бъдат интересни са
QuotaProcess и UniqueProcessId

Първото съдържа pointer към _EPROCESS, на който принадлежи тази таблица, а второто съдържа PID на процесът. Следователно имаме абсолютно всичката необходима информация, която ни трябва да обходим процесите и в зависимост от даденият процес да ръчкаме по _EPROCESS обекта. Това би могло да послужи например, когато имаме процес, който е скрит от PsActiveProcessList и по-този начин да го открием. Всъщност това е един (от многото) похвати, които се използват от някои antirootkit програмки. Както винаги - ето и демо-код: 

VOID DskEnumProcessFromHandleTable() {
 
	PEPROCESS Process = NULL;
	PHANDLE_TABLE InitialHandleTable = NULL;
	PHANDLE_TABLE CurrentHandleTable = NULL;
	/*
	1. Get system process
	2. Get Handle table 
	2.1 Enumerate process of handle
	2.2 Get name of enumerated process 
	3. Travers handle table and repeat (2)
	*/
 
	/* we point to the system process */
	Process = PsInitialSystemProcess;
 
	InitialHandleTable = *(PHANDLE_TABLE *)((char *) Process + HANDLE_TABLE_OFFSET);
 
	Process = InitialHandleTable->QuotaProcess;
 
	/*QuotaProcess is alway null for system.exe, but just in case this changes in the future*/
	if(Process != NULL) {
		DbgPrint("Name of current process : %s\n", (char *) Process + PROCESS_NAME_OFFSET);
	} else {
		DbgPrint("system.exe\n");
 
	}
 
	CurrentHandleTable = CONTAINING_RECORD(InitialHandleTable->HandleTableList.Flink, HANDLE_TABLE, HandleTableList);
 
	while(InitialHandleTable != CurrentHandleTable) {
 
		Process = CurrentHandleTable->QuotaProcess;
		if(Process != NULL) {
			DbgPrint("Name of current process : %s\n", (char *) Process + PROCESS_NAME_OFFSET);
		} else {
			/*Idle's process name is always empty*/
			DbgPrint("We have the idle process\n");
 
		}
 
		CurrentHandleTable = CONTAINING_RECORD(CurrentHandleTable->HandleTableList.Flink, HANDLE_TABLE, HandleTableList);
	}
}

Sunday, January 22, 2012

Намиране на адресът на Ntoskrnl.exe в паметта.

Понякога за определени нужди е необходимо да се разбере адресът на ntoskrnl.exe. За целта могат да се направят няколко неща - като може би най-лесното е да се извика ZwQuerySystemInformation  с information class ModuleQueryInformation. Така ще имате копие на PsLoadedModuleLIst, който може да се обходи и да разберете адресът, на който е зареден кърнъла. Разбира се това не е единственият начин и определено е най-скучният. Днес ще покажа един друг метод, който е "стабилен" - тоест едва дали в бъдеще ще бъде премахнат и като цяло не разчита на volatile структури, които могат да бъдат обект на промяна при даден service pack или update. И така, за какво става на въпрос. 

PDRIVER_OBJECT
Всеки драйвър в entry point-а му бива подаден един pointer към структура от тип DRIVER_OBJECT. Тази структура е документирана в WDK-то и затова не смятам да я поствам тук, но щ обърна внимание на един интересен pointer : 
struct _DRIVER_OBJECT { 
//ommited for brevity
PVOID DriverSection;

 От декларацията му не става ясно към какво точно сочи, но всъщност ако човек си направи труда да се поразрови из сорсовете на WRK ще разбере, че всъщност това е pointer към структура от следният тип: 

typedef struct _KLDR_DATA_TABLE_ENTRY {
 LIST_ENTRY InLoadOrderLinks;
 PVOID ExceptionTable;
 ULONG ExceptionTableSize;
 // ULONG padding on IA64
 PVOID GpValue;
 PVOID NonPagedDebugInfo;
 PVOID DllBase;
 PVOID EntryPoint;
 ULONG SizeOfImage;
 UNICODE_STRING FullDllName;
 UNICODE_STRING BaseDllName;
 ULONG Flags;
 USHORT LoadCount;
 USHORT __Unused5;
 PVOID SectionPointer;
 ULONG CheckSum;
 // ULONG padding on IA64
 PVOID LoadedImports;
 PVOID PatchInformation;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;  
Това, което трябва да се отбележи е, че всички нови променливи, които ще бъдат добавени в декларация на тази структура, винаги се добавят в края, което означава, че съвсем спокойно можем да я ползваме. Полетата, които ни интересуват са LIST_ENTRY InLoadOrderLinks, както лесно може да се досетим - това е linked-list, които съдържа всички заредени драйвъри. BaseDllName  е името на даденият драйвър - за windows kernel-а, това винаги ще бъде ntoskrnl.exe, без значение коя версия на кърнъла сме заредили - ntoskrnl.exe или ntoskrnlpa. След като намерим entry-то, което ни трябва можем съвсем спокойно да вземем стойността на DllBase, която е адресът, на който е зареден кърнъла. От там нататък можем да парсваме този адрес като най-обикновен PE файл. Ето и малко код: 

PVOID GetNtosBaseAddr(PDRIVER_OBJECT DriverObject) {
 
 PKLDR_DATA_TABLE_ENTRY driverSection;
 PKLDR_DATA_TABLE_ENTRY ldrDataTableEntry;
 PVOID kernelBase = NULL;
 PLIST_ENTRY headEntry;
 PLIST_ENTRY currentEntry;
 UNICODE_STRING ntosString = {0};
 driverSection = (PKLDR_DATA_TABLE_ENTRY) DriverObject->DriverSection;
 RtlInitUnicodeString(&ntosString, L"ntoskrnl.exe");
 
 headEntry = driverSection->InLoadOrderLinks.Blink; //header points to prev entry
 
 currentEntry = headEntry->Flink;
 
 while(currentEntry != headEntry) {
 
  ldrDataTableEntry = CONTAINING_RECORD(currentEntry, KLDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
 
  if(RtlCompareUnicodeString(&ntosString, &ldrDataTableEntry->BaseDllName, TRUE) == 0) {
   DbgPrint("Found base address of NTOSKRNL: 0x%p\n", ldrDataTableEntry->DllBase );
 
   kernelBase = ldrDataTableEntry->DllBase;
 
   break;
  }
 
  currentEntry = currentEntry->Flink;
 }
 
 return kernelBase;
 
}

Sunday, January 15, 2012

Обектно ориентиране в Windows (3)

И така след дългата ваканция е време да довърша мисълта си за hooking на object procedures. Както бях казал в краят на миналия постинг - сега ще дискутира _OBJECT_TYPE_INITIALIZER структурата. Ето какво представлява тя:


kd> dt _OBJECT_TYPE_INITIALIZER
ntdll!_OBJECT_TYPE_INITIALIZER
   +0x000 Length           : Uint2B
   +0x002 ObjectTypeFlags  : UChar
   +0x002 CaseInsensitive  : Pos 0, 1 Bit
   +0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
   +0x002 UseDefaultObject : Pos 2, 1 Bit
   +0x002 SecurityRequired : Pos 3, 1 Bit
   +0x002 MaintainHandleCount : Pos 4, 1 Bit
   +0x002 MaintainTypeList : Pos 5, 1 Bit
   +0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
   +0x004 ObjectTypeCode   : Uint4B
   +0x008 InvalidAttributes : Uint4B
   +0x00c GenericMapping   : _GENERIC_MAPPING
   +0x01c ValidAccessMask  : Uint4B
   +0x020 RetainAccess     : Uint4B
   +0x024 PoolType         : _POOL_TYPE
   +0x028 DefaultPagedPoolCharge : Uint4B
   +0x02c DefaultNonPagedPoolCharge : Uint4B
   +0x030 DumpProcedure    : Ptr32     void 
   +0x034 OpenProcedure    : Ptr32     long 
   +0x038 CloseProcedure   : Ptr32     void 
   +0x03c DeleteProcedure  : Ptr32     void 
   +0x040 ParseProcedure   : Ptr32     long 
   +0x044 SecurityProcedure : Ptr32     long 
   +0x048 QueryNameProcedure : Ptr32     long 
   +0x04c OkayToCloseProcedure : Ptr32     unsigned char 
 
Всеки обект от тип TYPE има такава структура, която представлява допълнителна информация за даденият тип. Например - от кой pool да се алокира памет по подразбиране (PoolType), дали трябва да има security descriptor  за даденият тип обект, дали е case (in)sensitive имената като цяло се подразбират. Но това, което представлява интерес са *Procedure полетата, които всъщност представляват функции, които трябва да бъдат извикани винаги когато трябва да се изпълни точно определена операция - отваряне(създаване), затваряне, парсване, изтриване etc. Ето например как изглежда тази структура за обект от тип FILE_OBJECT тоест файловете в Windows: 

kd> dt _OBJECT_TYPE_INITIALIZER 841e87a8+0x28
ntdll!_OBJECT_TYPE_INITIALIZER
   +0x000 Length           : 0x50
   +0x002 ObjectTypeFlags  : 0x11 ''
   +0x002 CaseInsensitive  : 0y1
   +0x002 UnnamedObjectsOnly : 0y0
   +0x002 UseDefaultObject : 0y0
   +0x002 SecurityRequired : 0y0
   +0x002 MaintainHandleCount : 0y1
   +0x002 MaintainTypeList : 0y0
   +0x002 SupportsObjectCallbacks : 0y0
   +0x004 ObjectTypeCode   : 1
   +0x008 InvalidAttributes : 0x130
   +0x00c GenericMapping   : _GENERIC_MAPPING
   +0x01c ValidAccessMask  : 0x1f01ff
   +0x020 RetainAccess     : 0
   +0x024 PoolType         : 0 ( NonPagedPool )
   +0x028 DefaultPagedPoolCharge : 0x400
   +0x02c DefaultNonPagedPoolCharge : 0xf8
   +0x030 DumpProcedure    : (null) 
   +0x034 OpenProcedure    : (null) 
   +0x038 CloseProcedure   : 0x82a9bbaf     void  nt!IopCloseFile+0
   +0x03c DeleteProcedure  : 0x82a81cbb     void  nt!IopDeleteFile+0
   +0x040 ParseProcedure   : 0x82ac9fe0     long  nt!IopParseFile+0
   +0x044 SecurityProcedure : 0x82aa041d     long  nt!IopGetSetSecurityObject+0
   +0x048 QueryNameProcedure : 0x82aade11     long  nt!IopQueryName+0
   +0x04c OkayToCloseProcedure : (null) 
 
Тоест при всяко затваряне на файлов обект ще се изпълнява IopCloseFile, при всяко изтриване на файл (респективно изтриването на обектът от Windows Object Manager) ще се изпълни функцията IopDeleteFile и така нататък. Следоватено ако искаме да проследяваме или дори да блокираме създаването на определен файл то можем да "инсталираме" собствена функция, която въз основа на това какво име носи обектът да решава дали да разреши или забрани операцията. А как всъщност става това? Всяка една от 7те процедури си има индивидуална сигнатура, за целите на статията ще се концентрирам само върху OpenProcedure, но по абсолютно аналогичен начин е възможно да се вземе сигнатурата за всяка една от останалите 6 функции. Ето какво трябва да представлява OB_OPEN_PROCEDURE:

typedef NTSTATUS (*OB_OPEN_METHOD) (OB_OPEN_REASON OpenReas, CHAR Unknown1, PEPROCESS Process, PVOID Object, ACCESS_MASK GrantedAccess, ULONG32 HandleCount);

И така - това което представлява интерес за нас е PVOID Object пойнтъра, който сочи към тялото на обектът, който се създава/отваря. И тъй като в случая ще hook-нем файл, то тялото ще е от тип _FILE_OBJECT. Дефиницията може да бъде намерена на сайта на майкрософт тук. Както се вижда може да използваме FileName от структурата, за да разберем кой файл точно се отваря/създава. Единственото, което остава е само да имплементираме нашата версия на OpenProcedure и да set-нем адреса и като стойност на OpenProcedure member-а. И за да не съм празнословен ето малко код: 

1. Ето една много проста имплементация на OB_OPEN_METHOD: 

NTSTATUS myOpenProcedure(OB_OPEN_REASON OpenReason, CHAR Unknown1, PEPROCESS Process, PVOID Object, ACCESS_MASK GrantedAccess, ULONG32 HandleCount) {
 
 DbgPrint("Our openProcedure routine has been invoked\n");
 
 if(Process != NULL) {
  DbgPrint("Process with name: %s is requesting file opening\n", getName(Process));
  DbgPrint("A handle for %wZ has been opened \n", &((PFILE_OBJECT)Object)->FileName);
 }
 
 return STATUS_SUCCESS;
}
 
2. Ето и методът, който прави hook-ването: 
 
void hookFileObject() {

 DbgPrint("Address of our routine is: 0x%p\n", myOpenProcedure);
 DbgPrint("Address of original routine is: 0x%p", (*IoFileObjectType)->TypeInfo.OpenProcedure);

 InterlockedExchangePointer(&(*IoFileObjectType)->TypeInfo.OpenProcedure, myOpenProcedure); 
 
 DbgPrint("!!THIS IS DONE!! The current address of routine is 0x%p\n", (*IoFileObjectType)->TypeInfo.OpenProcedure);
} 

Възможно най-тъпият 1 liner, който ни осигурява thread-safety (тази тема, особено в контекста на windows kernel) си заслужава отделна серия постинги :).
Ако случайно се чудите (или искате да правите по-fine-grined) филтриране въз основа на типа събитие, ето и декларацията на OB_OPEN_REASON:

typedef enum _OB_OPEN_REASON {  
 ObCreateHandle,  
 ObOpenHandle,  
 ObDuplicateHandle,  
 ObInheritHandle,  
 ObMaxOpenReason  
} OB_OPEN_REASON; 

Ето как макар и да имаме 1 функция, тя ще се извиква при всички по-горе посочени действия - създаване, отваряне, дупликиране на handle etc. А тази структура, до колкото съм запознат в момента не се следи от Patchguard, съответно това би трябвало да работи и на x64 (макар че все пак ще се наложи да излъжите patchguard, ако искате да си заредите драйвърът )

Sunday, December 4, 2011

Обектно ориентиране в Windows (2)

И така, в тази част мисля да обърна внимание на структурите, които се на практика описват един обект. За целта на тази статия  ще взема за пример, произволен _EPROCESS обект. За момента е необходимо да знаете, че всеки процес в Windows има (освен всички останали) _EPROCESS структура, която съдържа един вид "accounting" информация. За да видим всички работещи процеси е необходимо да се изпълни командата !process 0 0  

Ето какво изкарва Windbg (ще пейстна само 1 entry, което ще изпозлвам за дискусията по-долу):

PROCESS 85b4c030  SessionId: 1  Cid: 0520    Peb: 7ffd6000  ParentCid: 0560
    DirBase: 3ee8f1a0  ObjectTable: 8ce0fa48  HandleCount: 759.
    Image: explorer.exe

Както се вижда _EPROCESS структурата се намира на адрес 0x85b4c030, съответно ако използваме командата dt nt!_EPROCESS 85b4c030 Windbg ще интерпрететира памета от този адрес до 85b4c030 + sizeof(_EPROCESS) като _EPROCESS и ще ни даде стойностите на различните полета (под-структури) за дадения процес: 


kd> dt nt!_EPROCESS 85b4c030
   +0x000 Pcb              : _KPROCESS
   +0x098 ProcessLock      : _EX_PUSH_LOCK
   +0x0a0 CreateTime       : _LARGE_INTEGER 0x1ccb28c`3e22d03a
   +0x0a8 ExitTime         : _LARGE_INTEGER 0x0
   +0x0b0 RundownProtect   : _EX_RUNDOWN_REF
   +0x0b4 UniqueProcessId  : 0x00000520 Void
   +0x0b8 ActiveProcessLinks : _LIST_ENTRY [ 0x84fd33f8 - 0x85b0a0e8 ]
   +0x0c0 ProcessQuotaUsage : [2] 0x6040
   +0x0c8 ProcessQuotaPeak : [2] 0x6d3c
   +0x0d0 CommitCharge     : 0x1706
   +0x0d4 QuotaBlock       : 0x85d57180 _EPROCESS_QUOTA_BLOCK
   +0x0d8 CpuQuotaBlock    : (null) 
   +0x0dc PeakVirtualSize  : 0xe9a0000
   +0x0e0 VirtualSize      : 0xcdec000
   +0x0e4 SessionProcessLinks : _LIST_ENTRY [ 0x84fd3424 - 0x85b0a114 ]
   +0x0ec DebugPort        : (null) 
   +0x0f0 ExceptionPortData : 0x841d5c90 Void
   +0x0f0 ExceptionPortValue : 0x841d5c90
   +0x0f0 ExceptionPortState : 0y000
   +0x0f4 ObjectTable      : 0x8ce0fa48 _HANDLE_TABLE
   +0x0f8 Token            : _EX_FAST_REF
   +0x0fc WorkingSetPage   : 0x104e8
   +0x100 AddressCreationLock : _EX_PUSH_LOCK
   +0x104 RotateInProgress : (null) 
   +0x108 ForkInProgress   : (null) 
   +0x10c HardwareTrigger  : 0
   +0x110 PhysicalVadRoot  : (null) 
   +0x114 CloneRoot        : (null) 
   +0x118 NumberOfPrivatePages : 0xf61
   +0x11c NumberOfLockedPages : 0
   +0x120 Win32Process     : 0xfe9bfe30 Void
   +0x124 Job              : (null) 
   +0x128 SectionObject    : 0x940657d8 Void
   +0x12c SectionBaseAddress : 0x00170000 Void
   +0x130 Cookie           : 0xe99c86ae
   +0x134 Spare8           : 0
   +0x138 WorkingSetWatch  : (null) 
   +0x13c Win32WindowStation : 0x00000030 Void
   +0x140 InheritedFromUniqueProcessId : 0x00000560 Void
   +0x144 LdtInformation   : (null) 
   +0x148 VdmObjects       : (null) 
   +0x14c ConsoleHostProcess : 0
   +0x150 DeviceMap        : 0x8fc39720 Void
   +0x154 EtwDataSource    : (null) 
   +0x158 FreeTebHint      : 0x7ff9f000 Void
   +0x160 PageDirectoryPte : _HARDWARE_PTE
   +0x160 Filler           : 0
   +0x168 Session          : 0x8a8b5000 Void
   +0x16c ImageFileName    : [15]  "explorer.exe"
   +0x17b PriorityClass    : 0x2 ''
   +0x17c JobLinks         : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x184 LockedPagesList  : (null) 
   +0x188 ThreadListHead   : _LIST_ENTRY [ 0x85b31fb0 - 0x850f3ef8 ]
   +0x190 SecurityPort     : (null) 
   +0x194 PaeTop           : 0x8508f1a0 Void
   +0x198 ActiveThreads    : 0x21
   +0x19c ImagePathHash    : 0xa80e4f97
   +0x1a0 DefaultHardErrorProcessing : 0
   +0x1a4 LastThreadExitStatus : 0n0
   +0x1a8 Peb              : 0x7ffd6000 _PEB
   +0x1ac PrefetchTrace    : _EX_FAST_REF
   +0x1b0 ReadOperationCount : _LARGE_INTEGER 0x364
   +0x1b8 WriteOperationCount : _LARGE_INTEGER 0x4
   +0x1c0 OtherOperationCount : _LARGE_INTEGER 0x79c6
   +0x1c8 ReadTransferCount : _LARGE_INTEGER 0x2f8dae
   +0x1d0 WriteTransferCount : _LARGE_INTEGER 0x368
   +0x1d8 OtherTransferCount : _LARGE_INTEGER 0x3be11
   +0x1e0 CommitChargeLimit : 0
   +0x1e4 CommitChargePeak : 0x2029
   +0x1e8 AweInfo          : (null) 
   +0x1ec SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
   +0x1f0 Vm               : _MMSUPPORT
   +0x25c MmProcessLinks   : _LIST_ENTRY [ 0x84fd359c - 0x85b0a28c ]
   +0x264 HighestUserAddress : 0x7fff0000 Void
   +0x268 ModifiedPageCount : 0x41
   +0x26c Flags2           : 0xd000
   +0x26c JobNotReallyActive : 0y0
   +0x26c AccountingFolded : 0y0
   +0x26c NewProcessReported : 0y0
   +0x26c ExitProcessReported : 0y0
   +0x26c ReportCommitChanges : 0y0
   +0x26c LastReportMemory : 0y0
   +0x26c ReportPhysicalPageChanges : 0y0
   +0x26c HandleTableRundown : 0y0
   +0x26c NeedsHandleRundown : 0y0
   +0x26c RefTraceEnabled  : 0y0
   +0x26c NumaAware        : 0y0
   +0x26c ProtectedProcess : 0y0
   +0x26c DefaultPagePriority : 0y101
   +0x26c PrimaryTokenFrozen : 0y1
   +0x26c ProcessVerifierTarget : 0y0
   +0x26c StackRandomizationDisabled : 0y0
   +0x26c AffinityPermanent : 0y0
   +0x26c AffinityUpdateEnable : 0y0
   +0x26c PropagateNode    : 0y0
   +0x26c ExplicitAffinity : 0y0
   +0x270 Flags            : 0x144d0801
   +0x270 CreateReported   : 0y1
   +0x270 NoDebugInherit   : 0y0
   +0x270 ProcessExiting   : 0y0
   +0x270 ProcessDelete    : 0y0
   +0x270 Wow64SplitPages  : 0y0
   +0x270 VmDeleted        : 0y0
   +0x270 OutswapEnabled   : 0y0
   +0x270 Outswapped       : 0y0
   +0x270 ForkFailed       : 0y0
   +0x270 Wow64VaSpace4Gb  : 0y0
   +0x270 AddressSpaceInitialized : 0y10
   +0x270 SetTimerResolution : 0y0
   +0x270 BreakOnTermination : 0y0
   +0x270 DeprioritizeViews : 0y0
   +0x270 WriteWatch       : 0y0
   +0x270 ProcessInSession : 0y1
   +0x270 OverrideAddressSpace : 0y0
   +0x270 HasAddressSpace  : 0y1
   +0x270 LaunchPrefetched : 0y1
   +0x270 InjectInpageErrors : 0y0
   +0x270 VmTopDown        : 0y0
   +0x270 ImageNotifyDone  : 0y1
   +0x270 PdeUpdateNeeded  : 0y0
   +0x270 VdmAllowed       : 0y0
   +0x270 CrossSessionCreate : 0y0
   +0x270 ProcessInserted  : 0y1
   +0x270 DefaultIoPriority : 0y010
   +0x270 ProcessSelfDelete : 0y0
   +0x270 SetTimerResolutionLink : 0y0
   +0x274 ExitStatus       : 0n259
   +0x278 VadRoot          : _MM_AVL_TABLE
   +0x298 AlpcContext      : _ALPC_PROCESS_CONTEXT
   +0x2a8 TimerResolutionLink : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x2b0 RequestedTimerResolution : 0
   +0x2b4 ActiveThreadsHighWatermark : 0x25
   +0x2b8 SmallestTimerResolution : 0
   +0x2bc TimerResolutionStackRecord : (null) 
 
Самата структура е доста обемна и сама по себе си заслужава отделен постинг, за да се опишат по-интересните полета, особено от гледна точка на rootkit development, но за момента искам да илюстрирам нещо друго - ако изпълним командата !object 85b4c030 ще видим следното: 

kd> !object 85b4c030
Object: 85b4c030  Type: (841338f0) Process
    ObjectHeader: 85b4c018 (new version)
    HandleCount: 5  PointerCount: 368 
 
Малко проста математика: 0x85b4c030 - 0x85b4c018 = 0x18 - тоест големината на _OBJECT_HEADER структурата е 0x18 байта (или 24 байта в десетична бройна система) и на практика тази структура е винаги _ПРЕДИ_  _EPROCESS структурата (или всяка друга, която дефинира executive обектите. Hint: ако искате да видите всички обекти, използвайте командата: !object \objecttypes ). Ето я и _OBJECT_HEADER структурата на Explorer.exe:

kd> dt _OBJECT_HEADER (0x85b4c030 - 0x18)
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n398
   +0x004 HandleCount      : 0n5
   +0x004 NextToFree       : 0x00000005 Void
   +0x008 Lock             : _EX_PUSH_LOCK
   +0x00c TypeIndex        : 0x7 ''
   +0x00d TraceFlags       : 0 ''
   +0x00e InfoMask         : 0x8 ''
   +0x00f Flags            : 0 ''
   +0x010 ObjectCreateInfo : 0x85d57180 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x85d57180 Void
   +0x014 SecurityDescriptor : 0x9024301a Void
   +0x018 Body             : _QUAD

Полетата на тази структура са горе-долу самодокументиращи се - брояч колко pointer-а има отворени към този обект (Explorer.exe в случая), колко handles има отворени, NextToFree не го знам какво е :Д, Lock - използващ се, когато object manager-а оперира върху този обект, за да се избегнат race conditions, Flags - флагове, които описват как точно трябва да се държи този обект - например тук са флагове като OBJ_INHERIT, OBJ_EXCLUSIVE, OBJ_KERNEL_HANDLE etc. 

TypeIndex

И така. TypeIndex полето е индекс в таблица, която указва кой обект от какъв тип е. Тази таблица е глобална и следният и може да бъде достъпена като nt!ObTypeIndexTable. За да се разбере какъв тип обект отговаря на даден header просто трябва да се използва следната формула: nt!ObTypeIndexTable + ( TypeIndex * sizeof(void *) ), в WinDBG това би изглеждало по следният начин: dt _OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * @$ptrsize)) или dt _OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * 4)) (големината на pointer на 32 битова машина е винаги 4 байта (32 бита), респективно за 64 битова архитектура това би било 8 байта/64 бита)).


kd> dt _OBJECT_TYPE poi(nt!ObTypeIndexTable + (7 * @$ptrsize))
ntdll!_OBJECT_TYPE
   +0x000 TypeList         : _LIST_ENTRY [ 0x841338f0 - 0x841338f0 ]
   +0x008 Name             : _UNICODE_STRING "Process"
   +0x010 DefaultObject    : (null) 
   +0x014 Index            : 0x7 ''
   +0x018 TotalNumberOfObjects : 0x25
   +0x01c TotalNumberOfHandles : 0xd6
   +0x020 HighWaterNumberOfObjects : 0x28
   +0x024 HighWaterNumberOfHandles : 0xde
   +0x028 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x078 TypeLock         : _EX_PUSH_LOCK
   +0x07c Key              : 0x636f7250
   +0x080 CallbackList     : _LIST_ENTRY [ 0x84133970 - 0x84133970 ]

Както виждаме правилно успяхме да получим _OBJECT_TYPE  за обект от тип Process. Полетата тук също бих казал, че са самодокументиращи се - първо виждаме, че всички _OBJECT_TYPE  структури са навързани в двоен linke-list, всяка има име, (незадължителен) обект по подразбиране за синхронизация, index  е индексът във ObTypeIndexTable. Броят обекти от даден тип - в случаят 0x25 или 37 процеса, броят handles, които са отворени към _EPROCESS обекти, HighWater не ги знам за какво са, TypeInfo ще го дискутирам в следващ постинг, но точно там нещата стават интересни ;-) TypeLock  се използва за синхронизация, когато се оперира върху тази структура (която има глобално значение, за всички обекти от тип _EPROCESS), CallbackList е двоен linked-list  с callbackovete, които трябва да бъдат извикани (Hint: ObRegisterCallbacks)

И така смятам да спра до тук, а в следващият постинг вече ще дам реален пример какво точно може да се направи с _OBJECT_TYPE_INITIALIZER структурата, за да може да се извиква нащ код винаги, когато се случва нещо с обект от даден тип.

Monday, November 21, 2011

Обектно ориентиране в Windows

И така, смятам да започна една поредица от постинги относно Object Manager-a в Windows и по-специално каква е неговата идея и какво интересно може да се случи с него в контекста на един rootkit. Само ще направя една вметка, че тук няма да става въпрос за обектно ориентирано програмиране :)

Обекти в Windows
Windows, като всяка модерна операционна система му се налага да оперира върху голям на брой обекти, като най-близката аналогия би била тази с data structures - обект е на практика съвкупност от променливи, които описват  даден ресурс в системата и съответно има прилежащи операции към тези ресурси - например файловете в Windows са ресурси (описани са тук), прозорците също са ресурс, процесите са ресурс, thread-овете също са ресурс, колкото и странно да звучи драйвърите също са ресурс за Windows, различните устройства като хард диск, усб флашове etc. Сега, както сами разбирате в Windows (а и в Линукс) има доста обекти и логиката би диктувала, че една голяма част от тях ще имат общи свойства и характеристики и не би имало смисъл те да бъдат дефинирани за абсолютно всеки тип. Именно този, но не само, проблем се опитва да реши Object Manager-а в Windows. 
Може би няма Win програмист на този свят, който да не е запознат с концепцията за HANDLE. И как това е един от начините Windows  да предостави абстрактен достъп до почти всички обекти - например handle към динамично заредена библиотека, handle към remote  процес, handle към пайп, handle към файл. В Windows е възможно към даден обект (например файл) да бъдат отворени няколко различни handle-и от няколко различни процеса, които не е задължително да знаят един за друг. Например би било доста лошо ако в един момент даден процес реши да изтрие този файл, без да се интересува дали някой друг го чете или ползва в момента, в тази ситуация се притича Object Manager-а на помощ - всеки път когатo handle бива даден  то Object Manager се грижи затова в една специална (_OBJECT_HEADER) структура да бъде увеличен handle count-а с едно и респективно, когато даден handle бъде освободен чрез някое от API-тата, то този handle count бива намален с едно. И тук има една малка уловка - докато в user-space ресурсите на системата са достъпни чрез handles,  то в kernel space  е възможно даден обект да бъде достъпен и чрез pointer - тоест да се получи директен достъп до "тялото" на обекта (в следваща публикация мисля да засегна по-подробно как точно изглеждат структурите), което означава, че дори handle count-а да е 0, то все пак е възможно да има драйвъри или части от системата, които да работят с този обект и изтриването му най-вероятно би предизвикало BSOD. 

Друг аспект, който всички обекти имат е security. Тоест кой потребител какви права има върху дадент обект. И вместо абсолютно всяка подсистема на windows сама да грижи за сигурността си, тази задача е делегирана на object manager-а. Когато се опитаме да достъпим даден обект (от user space), то OM  се грижи да направи необходимите проверки, за да види дали имаме достатъчни права да достъпим обекта.

Друга важна отговорност на OM е да се грижи за resource marshalling, тоест при всяко създаване на обект да следи, за това какви ресурси се използват и съответно отбелязва - един вид го играе счетоводител.

Ами като въведение общо взето е това. В следваща публикация ще обърна повече внимание на някои от структурите, които ОМ ползва, и които се грижат системата да е в изрядно състояние.

Sunday, November 20, 2011

Enumerating Process list

И така първото нещо, с което смятам да се занимая е как точно да открием и обходим PsActiveProcessHead - една не-експортната променлива, която е header pointer към doubly-linked lisт, съставен от _EPROCESS структури. В някой следващ постинг може да обърна повече внимание на тази структура. Но, да се върна на въпросът какво смятам да направя:
1. Първото и най-важно е да успеем да вземем адреса на PsActiveProcessHead, което пък ще ни даде възможност да обходим листа с всички _EPROCESS структури (освен онези, които са били премахнати от някой rootkit, нещо, което в последно време не се забелязва много, но и затова мога да пиша доста). 

2. Да обходя листа и да принтна някаква информация, колкото да покажа, че е възможно това да се направи. И така, да започнем.  

Вземане на адресът на PsActiveProcessHead 

За да се сдобия с адреса, ще използвам нещо, което се знае като "KPCR trick", какво всъщност представлява това - в Windows има една структура, която е дефинирана per processor и съдържа интересна информация като например - GDT таблицата, IDT таблицата, TSS, информация за L2 кеша, PRCB структурата, която за разлика от PCR е недокументиран както и един поинтър (сори, ама мразя да казвам на поинтърите - указатели) към структура, използвана от windows debugger-а (windbg). Структурата е от тип KPCR, а пойнтър към нея съответно PKPCR. За по-детайлна информация просто погледнете в даденият хедър.

И така, след като имаме бегла пердстава с какво си имаме работа ще вземем стойността на KdVersionBlock (този пойнтър е бил въведен за пръв път в Windows Xp, преди това мисля, че е бил Reserved). Само че тук има една малка уловка, този пойнтър е дефиниран като PVOID, което значи, че няма как (всъщност лъжа!) да знаем към какво сочи, е, точно тук е магията. Малко ще излъжа и ще се наложи да ми повярвате, но този пойнтър всъщност сочи към структура от тип DBGKD_GET_VERSION64, дефиницията, на която може да бъде намерена в 'wdbgexts.h', който идва с WDK-то. Не смятам, да пействам тук дефиницията, тъй като може да бъде видяна от всеки. Но все пак, member-а (е, как да кажа  член?), който представлява интерес за нас е DebuggerDataList, за който е сложен следният коментар в дефиницията:
 //
 // Components may register a debug data block for use by
 // debugger extensions.  This is the address of the list head.
 //
 // There will always be an entry for the debugger.
 //

Което автоматично ни казва, че това е някакъв пойнтър към лист. Имайки в предвид името DebuggerDataList, частта от коментара "debugger data block" и като прочетем малко по надолу:


typedef struct _KDDEBUGGER_DATA64 { 
//ommited for brevity
} KDDEBUGGER_DATA64, *PKDDEBUGGER_DATA64;
 
То лесно може да заключим, че DebuggerDataList всъщност пойнтър към doubly linked-list, съставен от структури от тип _KDDEBUGGER_DATA64. След като знаем това и като погледнем дефиницията на тази структура би трябвало да забележим нещо интересно:

 //
 // Addresses of various kernel data structures and lists
 // that are of interest to the kernel debugger.
 //
 
 ULONG64   PsLoadedModuleList;
 ULONG64   PsActiveProcessHead;
 ULONG64   PspCidTable;
Намерихме каквото търсехме - пойнтъри към променливи, които по подразбиране не са експортнати по подразбиране. Засега ще обърна внимание само на PsActiveProcessHead. Както името подсказва, това е първият node от един doubly linked-list, който съдържа всички _EPROCESS структури на вървящите процеси в системата. От тук нататък, може да правите каквото си искате с него - да го модифицирате, така че да "скриете" процес - макар, че при един cross-view на системата, лесно може да бъдете намерени. Или пък да вземете информация, която ви е нужна.  И накрая един бонус - функция, която илюстрира току-що написаното.

void PrintProcessInformation() {
 char name[16]; //holds the process name
 char *currentProc; //pointer to current _EPROCESS, char * to facilitate pointer arithmetics
 char *currentName; 
 int currentPid;
 int startPid;
 int count = 0;
 PKPCR kpcrBlock;
 PDBGKD_GET_VERSION64 versionBlock;
 PKDDEBUGGER_DATA64 debugData;
 
 //get access to the global struct with all the variables
 kpcrBlock = __readfsdword(FIELD_OFFSET(KPCR, SelfPcr));
 versionBlock = kpcrBlock->KdVersionBlock;
 debugData = ((PLIST_ENTRY64)(versionBlock->DebuggerDataList))->Flink;
 
 //this won't be touched, ever
 name[15] = '\0';
 
 //print the first process
 currentProc = (char *)((PLIST_ENTRY)debugData->PsActiveProcessHead)->Flink - EPROCESS_LIST_OFFSET;
 startPid = currentPid = *(int *)(currentProc + EPROCESS_PID_OFFSET);
 
 strncpy(name, getName(currentProc), 15);
 DbgPrint("[Proc: %d] PID: %d Name: %s Pointer Address: 0x%p\n", count, currentPid, name, currentProc);
 

 currentProc = nextEproc(currentProc);
 currentPid = *(int *)(currentProc + EPROCESS_PID_OFFSET);
 
 while(startPid != currentPid ) {
 
  strncpy(name, getName(currentProc), 15);
  DbgPrint("[Proc: %d] PID: %d Name: %s Pointer Address: 0x%p\n", count, currentPid, name, currentProc);
  
  currentProc = nextEproc(currentProc);
  currentPid = *(int *)(currentProc + EPROCESS_PID_OFFSET);
  count++;
 
 }
}
Ето и offset-ите, които съм ползвал - те важат Win 7 x32:
/* OFFSETS ARE TAKEN FROM WINDBG */
#define EPROCESS_PID_OFFSET  0x0b4
#define EPROCESS_LIST_OFFSET 0x0b8
#define EPROCESS_NAME_OFFSET 0x16c