PspCidTable 을 이용한 프로세스 목록 구하기 예제
ReactOS의 Handle Indexing 방법이 있는 코드다.

미친감자님의 블로그에 핸들 테이블 관련 정보가 있길래 포스팅합니다. :-)
심심이는 프로세스 목록을 얻기 위해 아래의 두가지를 이용합니다.
 - 스케쥴러 관련 정보
 - 핸들 테이블 (PspCidTable)

아래 함수는 xp 에서 핸들 테이블을 이용해서 프로세스 목록을 구하는 함수입니다.
오래전에 PoC 형태로 작성했던 코드라.. 지저분 하고, 걸레스럽지만 뭐 잘 돌아가기때문에.. 심심이에서 그대로 쓰고 있죠. -_-;;
자세한 내용은 http://somma.egloos.com/2947301 를 참고하시면 되고요.



/** -----------------------------------------------------------------------
\brief

\param
\return
\code

\endcode
-------------------------------------------------------------------------*/
NTSTATUS __stdcall ScanXpHandleTable(IN PHANDLE_TABLE pPspCidTable,
/*IN DWORD NumberOfCpu, */
IN PPROC_MANAGER pPm)
{
ASSERT(NULL != pPspCidTable);
ASSERT(NULL != pPm);
if ( (NULL == pPspCidTable) || (NULL == pPm) )
{
SPDEBUG(DBG_GENERAL, DBG_ERR, "%s >> invalid parameter", __FUNCTION__);
return STATUS_INVALID_PARAMETER;
}

PXP_HANDLE_TABLE pXpHandleTable = (PXP_HANDLE_TABLE)pPspCidTable;
ULONG i = 0, j = 0, k = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;

// 31 2 1 0
// |--------------------------------|-|-|
// 상위 30 비트 : _HANDLE_TABLE_ENTRY 포인터
// 하위 2 비트 : 핸들 테이블 레벨 인덱스
//
// LevelIndex : 현재 시스템에 구성된 HANDLE_TABLE 레벨
// pEntryPtr : 현재 LevelIndex 에 맞는 첫번째 PHANDLE_TABLE_ENTRY
//
ULONG LevelIndex = pXpHandleTable->TableCode & TABLE_LEVEL_MASK;
ULONG pEntryPtr = pXpHandleTable->TableCode & ~TABLE_LEVEL_MASK;

// xp, 2003 의 경우 페이지가 수용하는 만큼의 HANDLE_TABLE_ENTRY -1 개를 생성하며
// x86 mmu 는 프로세스당 16M 의 핸들을 사용할 수 있게 한다.
// top level pointers = 32 개
// mid level pointers = 1024 개
// sub handle table = 512 개
//
ULONG top_level_count = 32;
ULONG mid_level_count = 1024;
ULONG sub_level_count = PAGE_SIZE / sizeof(HANDLE_TABLE_ENTRY);

DWORD Cid = 0;
PHANDLE_TABLE_ENTRY pEntry = NULL;

// xp 의 경우 _HANDLE_TABLE.TableCode 의 하위 2비트를 통해서
// 3 단계 _HANDLE_TABLE 을 구성한다.
//
switch (LevelIndex)
{
case 0 :
SPDEBUG(DBG_GENERAL, DBG_INFO, "handle table level index = 0", "");
for (i = 0; i < sub_level_count; i++)
{
pEntry = &((PHANDLE_TABLE_ENTRY)pEntryPtr)[i];

if ( ( NULL != pEntry ) && (NULL != pEntry->Object) )
{
// xp, 2003 은 _HANDLE_TABLE_ENTRY.Object 필드의 최하위 비트가 Lock 비트 이므로
// Lock 비트를 클리어시키면 _HANDLE_TABLE_ENTRY.Object 는 커널 오브젝트 포인터가 된다.
// 즉 이것은 _OBJECT_HEADER.Body 를 가리키는 포인터이다.
// 이때 _OBJECT_HEADER.Type 필드를 참조해서 Body 가 어떤 오브젝트인지 판단하며
// 만일 Process object 인 경우 Body 필드는 _EPROCESS 구조체의 시작 주소가 된다.
// 주의할 것은 _OBJECT_HEADER.Body 필드는 포인터가 아닌 실제 구조체란 것이다.
//
// ( (ULONG) Entry->Object & ~XP_TABLE_ENTRY_LOCK_BIT )
//
// 위 식은 실제 Object 를 가리키는 포인터 이므로 _OBJECT_HEADER 를 찾기 위해서는
//
// PVOID pObj = ( (ULONG) Entry->Object & ~XP_TABLE_ENTRY_LOCK_BIT ); // process (_EPROCESS) / thread (_ETHREAD)
//
// POBJECT_HEADER pObjHeader = (ULONG) pObj - (Body offset);
//
// BodyOffset 은 xp sp2 의 경우 0x18 이다.
//
// kd> dt _OBJECT_HEADER
// +0x000 PointerCount : Int4B
// +0x004 HandleCount : Int4B
// +0x004 NextToFree : Ptr32 Void
// +0x008 Type : Ptr32 _OBJECT_TYPE
// +0x00c NameInfoOffset : UChar
// +0x00d HandleInfoOffset : UChar
// +0x00e QuotaInfoOffset : UChar
// +0x00f Flags : UChar
// +0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
// +0x010 QuotaBlockCharged : Ptr32 Void
// +0x014 SecurityDescriptor : Ptr32 Void
// +0x018 Body : _QUAD <<<<=======
//
//
PVOID pObjBody = (PVOID)( (ULONG) pEntry->Object & ~XP_TABLE_ENTRY_LOCK_BIT );
POBJECT_HEADER pObjHdr = OBJECT_TO_OBJECT_HEADER(pObjBody);
if (pObjHdr->Type == *PsProcessType)
{
PEPROCESS pEproc = (PEPROCESS) pObjBody;
Cid = *(ULONG*)((ULONG)pEproc + pPm->UniqueProcessId_offset);
//
// process list 에 추가
//
status = AddProcessAtDpcLevel(pPm, Cid, pEproc);
if (! NT_SUCCESS(status) )
{
SPDEBUG(DBG_GENERAL, DBG_ERR,
"AddProcessAtDpcLevel()");
continue;
}
}//if (pObjHdr->Type == *PsProcessType)
}
} // for
break;

case 1 :
SPDEBUG(DBG_GENERAL, DBG_INFO, "handle table level index = 1", "");
for (i = 0; i < mid_level_count; i++)
{
if (NULL != ( (PVOID *)pEntryPtr)[i] )
{
for (j = 0; j < sub_level_count; j++)
{
pEntry = &((PHANDLE_TABLE_ENTRY *)pEntryPtr)[i][j];
if ( (NULL != pEntry) && (NULL != pEntry->Object) )
{
PVOID pObjBody = (PVOID)( (ULONG) pEntry->Object & ~XP_TABLE_ENTRY_LOCK_BIT );
POBJECT_HEADER pObjHdr = OBJECT_TO_OBJECT_HEADER(pObjBody);
if (pObjHdr->Type == *PsProcessType)
{
PEPROCESS pEproc = (PEPROCESS) pObjBody;
Cid = *(ULONG*)((ULONG)pEproc + pPm->UniqueProcessId_offset);
//
// process list 에 추가
//
status = AddProcessAtDpcLevel(pPm, Cid, pEproc);
if (! NT_SUCCESS(status) )
{
SPDEBUG(DBG_GENERAL, DBG_ERR,
"AddProcessAtDpcLevel()");
continue;
}
}
} // if
}//for
}//if
}//for
break;

case 2 :
SPDEBUG(DBG_GENERAL, DBG_INFO, "handle table level index = 2", "");
for (i = 0; i < top_level_count; i++)
{
if (NULL != ( (PVOID *)pEntryPtr)[i] )
{
for (j = 0; j < mid_level_count; j++)
{
if (NULL != ((PVOID **)pEntryPtr)[i][j])
{
for (k = 0; k < sub_level_count; k++)
{
pEntry = &((PHANDLE_TABLE_ENTRY **)pEntryPtr)[i][j][k];
if ( (NULL != pEntry) && (NULL != pEntry->Object) )
{
PVOID pObjBody = (PVOID)( (ULONG) pEntry->Object & ~XP_TABLE_ENTRY_LOCK_BIT );
POBJECT_HEADER pObjHdr = OBJECT_TO_OBJECT_HEADER(pObjBody);
if (pObjHdr->Type == *PsProcessType)
{
PEPROCESS pEproc = (PEPROCESS) pObjBody;
Cid = *(ULONG*)((ULONG)pEproc + pPm->UniqueProcessId_offset);
//
// process list 에 추가
//
status = AddProcessAtDpcLevel(pPm, Cid, pEproc);
if (! NT_SUCCESS(status) )
{
SPDEBUG(DBG_GENERAL, DBG_ERR,
"AddProcessAtDpcLevel");
continue;
}
}
}
}
}
}//for
}//if
}//for
break;
default:
SPDEBUG(DBG_GENERAL, DBG_INFO,
"oops! handle table level index is over 3?");
break;
}

return STATUS_SUCCESS;
}

이 글과 관련있는 글을 자동검색한 결과입니다 [?]

by somma | 2008/03/27 14:02 | 심심이 | 트랙백 | 핑백(1) | 덧글(17)
트랙백 주소 : http://somma.egloos.com/tb/3678104
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at 빌게이츠가 부를때까지 -_- .. at 2008/05/13 20:37

... klight made by F-Securehttp://fullc0de.egloos.com/3708461PspCidTable 을 이용한 프로세스 목록 구하기 예제http://somma.egloos.com/3678104[UnExported Symbol]PspCidTable의 주소 구하기[출처] [UnExported Symbol]PspCidTable의 주소 구하기.|작성 ... more

Commented by xeraph at 2008/03/27 14:07
for if for if for if if if --;;;
Commented by somma at 2008/03/27 14:58
ㅋㅋㅋㅋㅋ . 상당히 걸래스럽죠? :-)
Commented by 몰라몰라 at 2008/03/27 16:40
감사합니다~. 필요한 코드였는데 공개해주시다니.. ^^
그런데 소스를 copy & paste 했더니 한 줄로 복사된다는..
깔끔하게 복사하는 방법있나요? ^^
Commented by somma at 2008/03/27 17:13
몰라몰라 / 읔... 그렇군요. -_-;;
어떻게 해야 하는지 모르겠네요..
Commented by 미친감자 at 2008/03/27 22:16
허거덕...감사합니다.^^ 잘쓰겠습니다.
Commented by Dual at 2008/03/28 00:21
이런 유용한 정보를 ' 0 '!ㅎㅎㅎ
Commented by noname at 2008/03/28 00:24
... <-- 왔다간 흔적
Commented by qwer at 2008/03/28 08:11
감사합니다.
조만간 공개할 예정이라던 코드가 드디어 공개되는군요 ㅋㅋㅋ
Commented by 홍가이버 at 2008/03/28 08:59
잘보고 갑니다. ^^
Commented by somma at 2008/03/28 10:10
미친감자 / 별말씀을요..
noname / 하하... 흔적 확인했습니다. ^^
qwer/ 엊그제 사무실 놀러오셨던 분인가보군여.. ^^
홍가이버 / 감사합니다.
Commented by Woof at 2008/03/28 10:57
PspCidTable 구하는게 더.. :|
핸들을 뒤지는건 W2K용하고 그 이후용으로 나누고 거기서 layer가 없거나 마지막 layer 뒤지는 부분을 함수로 분리했더니 그나마 깨끗해지던데.
Commented by kkamagui at 2008/03/29 13:54
와우~ 좋은 글 잘 보고 갑니다. ^^)/~
소마님의 포스팅은 실용적인(?) 글이 많은 것 같습니다. ^^
Commented by somma at 2008/04/01 10:17
kkamagui / 감사합니다. 요즘 멀티 코어 관련 글들 잘 보고 있습니다. (어렵더군요. -_-) 잘 정리해서 계속 알려주세요. ^^
Commented by 미친감자 at 2008/04/05 21:14
음...세미나때..사용좀 해도 될까요???
Commented by somma at 2008/04/07 10:44
미친감자 / 네 쓰셔도 돼요. ^^
Commented by 미친감자 at 2008/06/10 17:55
[질문]
PVOID pObjBody = (PVOID)( (ULONG) pEntry->Object & ~XP_TABLE_ENTRY_LOCK_BIT ); POBJECT_HEADER pObjHdr = OBJECT_TO_OBJECT_HEADER(pObjBody);

음 그러니까.. pEntry->Object 이 값이 body가 아니라 object header값이 아닌가요?
아님... PspCidTable은 틀린건가요???

Commented by somma at 2008/06/12 09:58
body 값이 맞습니다. OBJECT_TO_OBJECT_HEADER() 매크로는 header 에서 body 까지의 offset 으로 header 의 위치를 찾는것이니까요. ^^

:         :

:

비공개 덧글



< 이전페이지 다음페이지 >