И така първото нещо, с което смятам да се занимая е как точно да открием и обходим 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, за който е сложен следният коментар в дефиницията:
Което автоматично ни казва, че това е някакъв пойнтър към лист. Имайки в предвид името DebuggerDataList, частта от коментара "debugger data block" и като прочетем малко по надолу:
Вземане на адресът на 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
No comments:
Post a Comment