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 

Hello world

Добре дошли в "Из дебрите на Windows", мястото където смятам да водя записки относно нещата, с които експериментирам, за да счупя Windows. Главната тематика ще се върти около windows internals и по-специално методи, чрез които може да се subvert-не ядрото. Доста е вероятно да "открия" топлата вода, но все пак Learning by doing е най-добрият учител, така че ако се занимавате с нещо подобно от доста време е твърде вероятно да не намерите ground breaking stuff тук, но все пак ;-)