Showing posts with label EPROCESS. Show all posts
Showing posts with label EPROCESS. Show all posts

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, 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