📄 gdiobj.c
字号:
break;
}
else
{
/*
* The handle is currently locked, wait some time and try again.
*/
DelayExecution();
continue;
}
}
KeLeaveCriticalRegion();
return Object;
}
/*!
* Release GDI object. Every object locked by GDIOBJ_LockObj() must be unlocked. You should unlock the object
* as soon as you don't need to have access to it's data.
* \param Object Object pointer (as returned by GDIOBJ_LockObj).
*/
VOID INTERNAL_CALL
GDIOBJ_UnlockObjByPtr(PGDI_HANDLE_TABLE HandleTable, PGDIOBJ Object)
{
PGDIOBJHDR GdiHdr = GDIBdyToHdr(Object);
#ifdef GDI_DEBUG
if (InterlockedDecrement((PLONG)&GdiHdr->Locks) == 0)
{
GdiHdr->lockfile = NULL;
GdiHdr->lockline = 0;
}
#else
InterlockedDecrement((PLONG)&GdiHdr->Locks);
#endif
}
BOOL INTERNAL_CALL
GDIOBJ_OwnedByCurrentProcess(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle)
{
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId;
BOOL Ret;
DPRINT("GDIOBJ_OwnedByCurrentProcess: ObjectHandle: 0x%08x\n", ObjectHandle);
if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
{
ProcessId = PsGetCurrentProcessId();
Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle);
Ret = Entry->KernelData != NULL &&
(Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 &&
(HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) == ProcessId;
return Ret;
}
return FALSE;
}
BOOL INTERNAL_CALL
GDIOBJ_ConvertToStockObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ *hObj)
{
/*
* FIXME !!!!! THIS FUNCTION NEEDS TO BE FIXED - IT IS NOT SAFE WHEN OTHER THREADS
* MIGHT ATTEMPT TO LOCK THE OBJECT DURING THIS CALL!!!
*/
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId, LockedProcessId, PrevProcId;
PETHREAD Thread;
#ifdef GDI_DEBUG
ULONG Attempts = 0;
#endif
ASSERT(hObj);
DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", *hObj);
Thread = PsGetCurrentThread();
if(!GDI_HANDLE_IS_STOCKOBJ(*hObj))
{
ProcessId = PsGetCurrentProcessId();
LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
Entry = GDI_HANDLE_GET_ENTRY(HandleTable, *hObj);
LockHandle:
/* lock the object, we must not convert stock objects, so don't check!!! */
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId);
if(PrevProcId == ProcessId)
{
LONG NewType, PrevType, OldType;
/* we're locking an object that belongs to our process. First calculate
the new object type including the stock object flag and then try to
exchange it.*/
NewType = GDI_HANDLE_GET_TYPE(*hObj);
NewType |= NewType >> 16;
NewType |= (ULONG_PTR)(*hObj) & GDI_HANDLE_REUSE_MASK;
/* This is the type that the object should have right now, save it */
OldType = NewType;
/* As the object should be a stock object, set it's flag, but only in the upper 16 bits */
NewType |= GDI_HANDLE_STOCK_MASK;
/* Try to exchange the type field - but only if the old (previous type) matches! */
PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType);
if(PrevType == OldType && Entry->KernelData != NULL)
{
PETHREAD PrevThread;
PGDIOBJHDR GdiHdr;
/* We successfully set the stock object flag.
KernelData should never be NULL here!!! */
ASSERT(Entry->KernelData);
GdiHdr = GDIBdyToHdr(Entry->KernelData);
PrevThread = GdiHdr->LockingThread;
if(GdiHdr->Locks == 0 || PrevThread == Thread)
{
/* dereference the process' object counter */
if(PrevProcId != GDI_GLOBAL_PROCESS)
{
PEPROCESS OldProcess;
PW32PROCESS W32Process;
NTSTATUS Status;
/* FIXME */
Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
if(NT_SUCCESS(Status))
{
W32Process = (PW32PROCESS)OldProcess->Win32Process;
if(W32Process != NULL)
{
InterlockedDecrement(&W32Process->GDIObjects);
}
ObDereferenceObject(OldProcess);
}
}
/* remove the process id lock and make it global */
(void)InterlockedExchangePointer(&Entry->ProcessId, GDI_GLOBAL_PROCESS);
*hObj = (HGDIOBJ)((ULONG)(*hObj) | GDI_HANDLE_STOCK_MASK);
/* we're done, successfully converted the object */
return TRUE;
}
else
{
#ifdef GDI_DEBUG
if(++Attempts > 20)
{
if(GdiHdr->lockfile != NULL)
{
DPRINT1("[%d]Locked %s:%i by 0x%x (we're 0x%x)\n", Attempts, GdiHdr->lockfile, GdiHdr->lockline, PrevThread, Thread);
}
}
#endif
/* WTF?! The object is already locked by a different thread!
Release the lock, wait a bit and try again!
FIXME - we should give up after some time unless we want to wait forever! */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
DelayExecution();
goto LockHandle;
}
}
else
{
DPRINT1("Attempted to convert object 0x%x that is deleted! Should never get here!!!\n", hObj);
}
}
else if(PrevProcId == LockedProcessId)
{
#ifdef GDI_DEBUG
if(++Attempts > 20)
{
DPRINT1("[%d]Waiting on 0x%x\n", Attempts, hObj);
}
#endif
/* the object is currently locked, wait some time and try again.
FIXME - we shouldn't loop forever! Give up after some time! */
DelayExecution();
/* try again */
goto LockHandle;
}
else
{
DPRINT1("Attempted to convert invalid handle: 0x%x\n", hObj);
}
}
return FALSE;
}
void INTERNAL_CALL
GDIOBJ_SetOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle, PEPROCESS NewOwner)
{
PGDI_TABLE_ENTRY Entry;
HANDLE ProcessId, LockedProcessId, PrevProcId;
PETHREAD Thread;
#ifdef GDI_DEBUG
ULONG Attempts = 0;
#endif
DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
Thread = PsGetCurrentThread();
if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
{
ProcessId = PsGetCurrentProcessId();
LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
Entry = GDI_HANDLE_GET_ENTRY(HandleTable, ObjectHandle);
LockHandle:
/* lock the object, we must not convert stock objects, so don't check!!! */
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, ProcessId, LockedProcessId);
if(PrevProcId == ProcessId)
{
PETHREAD PrevThread;
if((Entry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 && Entry->KernelData != NULL)
{
PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
PrevThread = GdiHdr->LockingThread;
if(GdiHdr->Locks == 0 || PrevThread == Thread)
{
PEPROCESS OldProcess;
PW32PROCESS W32Process;
NTSTATUS Status;
/* dereference the process' object counter */
/* FIXME */
if((ULONG_PTR)PrevProcId & ~0x1)
{
Status = PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)PrevProcId & ~0x1), &OldProcess);
if(NT_SUCCESS(Status))
{
W32Process = (PW32PROCESS)OldProcess->Win32Process;
if(W32Process != NULL)
{
InterlockedDecrement(&W32Process->GDIObjects);
}
ObDereferenceObject(OldProcess);
}
}
if(NewOwner != NULL)
{
ProcessId = PsGetProcessId(NewOwner);
/* Increase the new process' object counter */
W32Process = (PW32PROCESS)NewOwner->Win32Process;
if(W32Process != NULL)
{
InterlockedIncrement(&W32Process->GDIObjects);
}
}
else
ProcessId = 0;
/* remove the process id lock and change it to the new process id */
(void)InterlockedExchangePointer(&Entry->ProcessId, ProcessId);
/* we're done! */
return;
}
else
{
#ifdef GDI_DEBUG
if(++Attempts > 20)
{
if(GdiHdr->lockfile != NULL)
{
DPRINT1("[%d]Locked from %s:%i by 0x%x (we're 0x%x)\n", Attempts, GdiHdr->lockfile, GdiHdr->lockline, PrevThread, Thread);
}
}
#endif
/* WTF?! The object is already locked by a different thread!
Release the lock, wait a bit and try again! DO reset the pid lock
so we make sure we don't access invalid memory in case the object is
being deleted in the meantime (because we don't have aquired a reference
at this point).
FIXME - we should give up after some time unless we want to wait forever! */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId);
DelayExecution();
goto LockHandle;
}
}
else
{
DPRINT1("Attempted to change ownership of an object 0x%x currently being destroyed!!!\n", ObjectHandle);
}
}
else if(PrevProcId == LockedProcessId)
{
#ifdef GDI_DEBUG
if(++Attempts > 20)
{
DPRINT1("[%d]Waiting on 0x%x\n", Attempts, ObjectHandle);
}
#endif
/* the object is currently locked, wait some time and try again.
FIXME - we shouldn't loop forever! Give up after some time! */
DelayExecution();
/* try again */
goto LockHandle;
}
else if(((ULONG_PTR)PrevProcId & ~0x1) == 0)
{
/* allow changing ownership of global objects */
ProcessId = NULL;
LockedProcessId = (HANDLE)((ULONG_PTR)ProcessId | 0x1);
goto LockHandle;
}
else if((HANDLE)((ULONG_PTR)PrevProcId & ~0x1) != PsGetCurrentProcessId())
{
DPRINT1("Attempted to change ownership of object 0x%x (pid: 0x%x) from pid 0x%x!!!\n", ObjectHandle, (ULONG_PTR)PrevProcId & ~0x1, PsGetCurrentProcessId());
}
else
{
DPRINT1("Attempted to change owner of invalid handle: 0x%x\n", ObjectHandle);
}
}
}
void INTERNAL_CALL
GDIOBJ_CopyOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ CopyFrom, HGDIOBJ CopyTo)
{
PGDI_TABLE_ENTRY FromEntry;
PETHREAD Thread;
HANDLE FromProcessId, FromLockedProcessId, FromPrevProcId;
#ifdef GDI_DEBUG
ULONG Attempts = 0;
#endif
DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
Thread = PsGetCurrentThread();
if(!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
{
FromEntry = GDI_HANDLE_GET_ENTRY(HandleTable, CopyFrom);
FromProcessId = (HANDLE)((ULONG_PTR)FromEntry->ProcessId & ~0x1);
FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
LockHandleFrom:
/* lock the object, we must not convert stock objects, so don't check!!! */
FromPrevProcId = InterlockedCompareExchangePointer(&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
if(FromPrevProcId == FromProcessId)
{
PETHREAD PrevThread;
PGDIOBJHDR GdiHdr;
if((FromEntry->Type & ~GDI_HANDLE_REUSE_MASK) != 0 && FromEntry->KernelData != NULL)
{
GdiHdr = GDIBdyToHdr(FromEntry->KernelData);
/* save the pointer to the calling thread so we know it was this thread
that locked the object */
PrevThread = GdiHdr->LockingThread;
if(GdiHdr->Locks == 0 || PrevThread == Thread)
{
/* now let's change the ownership of the target object */
if(((ULONG_PTR)FromPrevProcId & ~0x1) != 0)
{
PEPROCESS ProcessTo;
/* FIXME */
if(NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1), &ProcessTo)))
{
GDIOBJ_SetOwnership(HandleTable, CopyTo, ProcessTo);
ObDereferenceObject(ProcessTo);
}
}
else
{
/* mark the object as global */
GDIOBJ_SetOwnership(HandleTable, CopyTo, NULL);
}
(void)InterlockedExchangePointer(&FromEntry->ProcessId, FromPrevProcId);
}
else
{
#ifdef GDI_DEBUG
if(++Attempts > 20)
{
if(GdiHdr->lockfile != NULL)
{
DPRINT1("[%d]Locked from %s:%i by 0x%x (we're 0x%x)\n", Attempts, GdiHdr->lockfile, GdiHdr->lockline, PrevThread, Thread);
}
}
#endif
/* WTF?! The object is already locked by a different thread!
Release the lock, wait a bit and try again! DO reset the pid lock
so we make sure we don't access invalid memory in case the object is
being deleted in the meantime (because we don't have aquired a reference
at this point).
FIXME - we should give up after some time unless we want to wait forever! */
(void)InterlockedExchangePointer(&FromEntry->ProcessId, FromPrevProcId);
DelayExecution();
goto LockHandleFrom;
}
}
else
{
DPRINT1("Attempted to copy ownership from an object 0x%x currently being destroyed!!!\n", CopyFrom);
}
}
else if(FromPrevProcId == FromLockedProcessId)
{
#ifdef GDI_DEBUG
if(++Attempts > 20)
{
DPRINT1("[%d]Waiting on 0x%x\n", Attempts, CopyFrom);
}
#endif
/* the object is currently locked, wait some time and try again.
FIXME - we shouldn't loop forever! Give up after some time! */
DelayExecution();
/* try again */
goto LockHandleFrom;
}
else if((HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1) != PsGetCurrentProcessId())
{
/* FIXME - should we really allow copying ownership from objects that we don't even own? */
DPRINT1("WARNING! Changing copying ownership of object 0x%x (pid: 0x%x) to pid 0x%x!!!\n", CopyFrom, (ULONG_PTR)FromPrevProcId & ~0x1, PsGetCurrentProcessId());
FromProcessId = (HANDLE)((ULONG_PTR)FromPrevProcId & ~0x1);
FromLockedProcessId = (HANDLE)((ULONG_PTR)FromProcessId | 0x1);
goto LockHandleFrom;
}
else
{
DPRINT1("Attempted to copy ownership from invalid handle: 0x%x\n", CopyFrom);
}
}
}
PVOID INTERNAL_CALL
GDI_MapHandleTable(PSECTION_OBJECT SectionObject, PEPROCESS Process)
{
PVOID MappedView = NULL;
NTSTATUS Status;
LARGE_INTEGER Offset;
ULONG ViewSize = sizeof(GDI_HANDLE_TABLE);
Offset.QuadPart = 0;
ASSERT(SectionObject != NULL);
ASSERT(Process != NULL);
Status = MmMapViewOfSection(SectionObject,
Process,
&MappedView,
0,
0,
&Offset,
&ViewSize,
ViewUnmap,
SEC_NO_CHANGE,
PAGE_READONLY);
if (!NT_SUCCESS(Status))
return NULL;
return MappedView;
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -