Get PEB from PsSetImageLoadNotify callback routine

Hi,

I’m trying to list loaded module of a just-loaded process, looking for IAT hooks.

My objective is to get the current process PEB, then, using PLDR_DATA_TABLE_ENTRY, checking all LDR_MODULE of the linked list.

My code is running in ring 0, so, to be in process address space I register a callback routine to PsSetImageLoadNotifyRoutine :


PsSetLoadImageNotifyRoutine(MyImageLoadNotify);

VOID MyImageLoadNotify(IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId,
IN PIMAGE_INFO ImageInfo)
{

//…

DumpCurentProcessDLL();
}

My problem is when I try to get the process PEB, I got an Access Violation error doing

mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET)

Here is the code :

DWORD GetFirstCurrentProcessPLDR(void)
{
DWORD* module = NULL;

__asm
{
push eax
mov eax, fs:[30h] //PEB
mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET) = _PEB_LDR_DATA and ACCES VIOLATION ERRRRRRROR
mov module, eax
pop eax
}

return (DWORD)module;
}

VOID DumpCurentProcessDLL(void)
{
PLDR_MODULE pCurModule, pFirstModule;
PLDR_DATA_TABLE_ENTRY pldr;
int count = 0;

pldr = (PLDR_DATA_TABLE_ENTRY)GetFirstCurrentProcessPLDR();

pFirstModule = (PLDR_MODULE) pldr->InMemoryOrderLinks.Flink;
pFirstModule = ((DWORD)pFirstModule - XP_FLINKOFFSET);

pCurModule = pFirstModule;

for(;:wink:
{
if ((count >= 1) && (pCurModule == pFirstModule))
break;

DbgPrint(“dll : %ws\n”, pCurModule->BaseDllName.Buffer);
DbgPrint(“path : %ws\n”, pCurModule->FullDllName.Buffer);
DbgPrint(“===============\n”);

pCurModule = (PLDR_MODULE) pCurModule->InMemoryOrderModuleList.Flink;
pCurModule = ((DWORD)pCurModule - XP_FLINKOFFSET);

++count;
}
}

Does MyImageLoadNotify really executes in process address space?
Why can’t I get PEB?

Thanks for your help.

You can get the PEB base address using ZwQueryInformationProcess with the
PROCESS_BASIC_INFO flag, the PebBaseAddress element will hold the base
address. Just so you know, you don’t need to write a driver to achieve this
goal, it can be done from user mode fairly easily.

I suppose an advantage of doing it from kernel mode is that you avoid any
API hooks placed in user mode that might subvert your code…

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@gmail.com
Sent: Sunday, September 14, 2008 11:08
To: Windows System Software Devs Interest List
Subject: [ntdev] Get PEB from PsSetImageLoadNotify callback routine

Hi,

I’m trying to list loaded module of a just-loaded process, looking for IAT
hooks.

My objective is to get the current process PEB, then, using
PLDR_DATA_TABLE_ENTRY, checking all LDR_MODULE of the linked list.

My code is running in ring 0, so, to be in process address space I register
a callback routine to PsSetImageLoadNotifyRoutine :


PsSetLoadImageNotifyRoutine(MyImageLoadNotify);

VOID MyImageLoadNotify(IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId,
IN PIMAGE_INFO ImageInfo)
{

//…

DumpCurentProcessDLL();
}

My problem is when I try to get the process PEB, I got an Access Violation
error doing

mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET)

Here is the code :

DWORD GetFirstCurrentProcessPLDR(void)
{
DWORD* module = NULL;

__asm
{
push eax
mov eax, fs:[30h] //PEB
mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET) = _PEB_LDR_DATA and ACCES
VIOLATION ERRRRRRROR
mov module, eax
pop eax
}

return (DWORD)module;
}

VOID DumpCurentProcessDLL(void)
{
PLDR_MODULE pCurModule, pFirstModule;
PLDR_DATA_TABLE_ENTRY pldr;
int count = 0;

pldr = (PLDR_DATA_TABLE_ENTRY)GetFirstCurrentProcessPLDR();

pFirstModule = (PLDR_MODULE) pldr->InMemoryOrderLinks.Flink;
pFirstModule = ((DWORD)pFirstModule - XP_FLINKOFFSET);

pCurModule = pFirstModule;

for(;:wink:
{
if ((count >= 1) && (pCurModule == pFirstModule))
break;

DbgPrint(“dll : %ws\n”, pCurModule->BaseDllName.Buffer);
DbgPrint(“path : %ws\n”, pCurModule->FullDllName.Buffer);
DbgPrint(“===============\n”);

pCurModule = (PLDR_MODULE) pCurModule->InMemoryOrderModuleList.Flink;
pCurModule = ((DWORD)pCurModule - XP_FLINKOFFSET);

++count;
}
}

Does MyImageLoadNotify really executes in process address space?
Why can’t I get PEB?

Thanks for your help.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

__________ Information from ESET NOD32 Antivirus, version of virus signature
database 3440 (20080913) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com

__________ Information from ESET NOD32 Antivirus, version of virus signature
database 3440 (20080913) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com

You really don’t want to be traversing user mode linked lists from kernel mode. A malicious user mode caller can set things up to have you looping for an almost arbitrary amount of time, even if you have visited node detection (which may suddenly provide an easy with to consume an arbitrary amount of kernel mode memory too). You need to either hard cap the number of nodes, in which case someone just needs to load X+1 modules to avoid your checks, or you need to really not do this in kernel mode in the first place.

And that does not even go into all of the other problems with validating complex user mode data structures.

Please don’t try and do this from kernel mode, you’re almost certain to introduce security holes of some sort.

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Sunday, September 14, 2008 6:08 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Get PEB from PsSetImageLoadNotify callback routine

Hi,

I’m trying to list loaded module of a just-loaded process, looking for IAT hooks.

My objective is to get the current process PEB, then, using PLDR_DATA_TABLE_ENTRY, checking all LDR_MODULE of the linked list.

My code is running in ring 0, so, to be in process address space I register a callback routine to PsSetImageLoadNotifyRoutine :


PsSetLoadImageNotifyRoutine(MyImageLoadNotify);

VOID MyImageLoadNotify(IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId,
IN PIMAGE_INFO ImageInfo)
{

//…

DumpCurentProcessDLL();
}

My problem is when I try to get the process PEB, I got an Access Violation error doing

mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET)

Here is the code :

DWORD GetFirstCurrentProcessPLDR(void)
{
DWORD* module = NULL;

__asm
{
push eax
mov eax, fs:[30h] //PEB
mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET) = _PEB_LDR_DATA and ACCES VIOLATION ERRRRRRROR
mov module, eax
pop eax
}

return (DWORD)module;
}

VOID DumpCurentProcessDLL(void)
{
PLDR_MODULE pCurModule, pFirstModule;
PLDR_DATA_TABLE_ENTRY pldr;
int count = 0;

pldr = (PLDR_DATA_TABLE_ENTRY)GetFirstCurrentProcessPLDR();

pFirstModule = (PLDR_MODULE) pldr->InMemoryOrderLinks.Flink;
pFirstModule = ((DWORD)pFirstModule - XP_FLINKOFFSET);

pCurModule = pFirstModule;

for(;:wink:
{
if ((count >= 1) && (pCurModule == pFirstModule))
break;

DbgPrint(“dll : %ws\n”, pCurModule->BaseDllName.Buffer);
DbgPrint(“path : %ws\n”, pCurModule->FullDllName.Buffer);
DbgPrint(“===============\n”);

pCurModule = (PLDR_MODULE) pCurModule->InMemoryOrderModuleList.Flink;
pCurModule = ((DWORD)pCurModule - XP_FLINKOFFSET);

++count;
}
}

Does MyImageLoadNotify really executes in process address space?
Why can’t I get PEB?

Thanks for your help.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

On Sun, Sep 14, 2008 at 4:37 PM, Skywing wrote:

> You really don’t want to be traversing user mode linked lists from kernel
> mode. A malicious user mode caller can set things up to have you looping
> for an almost arbitrary amount of time, even if you have visited node
> detection (which may suddenly provide an easy with to consume an arbitrary
> amount of kernel mode memory too). You need to either hard cap the number
> of nodes, in which case someone just needs to load X+1 modules to avoid your
> checks, or you need to really not do this in kernel mode in the first place.
>
> And that does not even go into all of the other problems with validating
> complex user mode data structures.
>
> Please don’t try and do this from kernel mode, you’re almost certain to
> introduce security holes of some sort.

Thanks for your advice, maybe you’re all right.

But I keep my question : Can I get the PEB of the loading process using a
PsSetImageLoadRoutine routine?
Why my code generates an Acces Violation?

Just for knowledge, How could you create a double linked list that would
make me loop an “almost arbitrary time”?
Even kernel process is scheduled, I will just make a longer time to detect a
strange behavior (I am making a IDS base on behavor).


Matthieu Loriol
EPITA 2009 - SRS - ACU

Ok, to begin with, you can replace this asm block with __readfsdword()
intrinsic. It will be easier to debug.

–PA

xxxxx@gmail.com wrote:

Hi,

I’m trying to list loaded module of a just-loaded process, looking for IAT hooks.

My objective is to get the current process PEB, then, using PLDR_DATA_TABLE_ENTRY, checking all LDR_MODULE of the linked list.

My code is running in ring 0, so, to be in process address space I register a callback routine to PsSetImageLoadNotifyRoutine :


PsSetLoadImageNotifyRoutine(MyImageLoadNotify);

VOID MyImageLoadNotify(IN PUNICODE_STRING FullImageName,
IN HANDLE ProcessId,
IN PIMAGE_INFO ImageInfo)
{

//…

DumpCurentProcessDLL();
}

My problem is when I try to get the process PEB, I got an Access Violation error doing

mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET)

Here is the code :

DWORD GetFirstCurrentProcessPLDR(void)
{
DWORD* module = NULL;

__asm
{
push eax
mov eax, fs:[30h] //PEB
mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET) = _PEB_LDR_DATA and ACCES VIOLATION ERRRRRRROR
mov module, eax
pop eax
}

return (DWORD)module;
}

VOID DumpCurentProcessDLL(void)
{
PLDR_MODULE pCurModule, pFirstModule;
PLDR_DATA_TABLE_ENTRY pldr;
int count = 0;

pldr = (PLDR_DATA_TABLE_ENTRY)GetFirstCurrentProcessPLDR();

pFirstModule = (PLDR_MODULE) pldr->InMemoryOrderLinks.Flink;
pFirstModule = ((DWORD)pFirstModule - XP_FLINKOFFSET);

pCurModule = pFirstModule;

for(;:wink:
{
if ((count >= 1) && (pCurModule == pFirstModule))
break;

DbgPrint(“dll : %ws\n”, pCurModule->BaseDllName.Buffer);
DbgPrint(“path : %ws\n”, pCurModule->FullDllName.Buffer);
DbgPrint(“===============\n”);

pCurModule = (PLDR_MODULE) pCurModule->InMemoryOrderModuleList.Flink;
pCurModule = ((DWORD)pCurModule - XP_FLINKOFFSET);

++count;
}
}

Does MyImageLoadNotify really executes in process address space?
Why can’t I get PEB?

Thanks for your help.

> But I keep my question : Can I get the PEB of the loading process using a

PsSetImageLoadRoutine routine?

Well, your question has been answered already - this can be done by ZwQuerySystemInformation() that may get called by both KM and UM code. Therefore, you can call it from your callback, once is runs at low IRQL. Please note that this address refers to the UM portion of the address space of the target process and not the one in context of which your callback is invoked. Therefore, you will have to do attach to the address space of the target process before you can make any use of it… However, the code that you have shown us tries to do it in context of the current process (i.e. mov eax, fs:[30h] ). In case if this process does not have UM representation (i.e. is a system process), eax points to the middle of nowhere. This is why you crash.

In any case, as Ken already pointed out,it is better not to mess around with it, especially in your position - it looks like that you don’t really know what you are doing. Therefore, using these tricks in a commercial product would be unwise in your position - although it can be done from time to time, it requires the level of knowledge well beyond the one your questions suggest…

Anton Bassov

On Sun, Sep 14, 2008 at 8:08 PM, wrote:

> > But I keep my question : Can I get the PEB of the loading process using a
> > PsSetImageLoadRoutine routine?
>
> Well, your question has been answered already - this can be done by
> ZwQuerySystemInformation() that may get called by both KM and UM code.

Yes, but my objective is to detecte hooks. I try to avoid / reproduce API
calls.

> Therefore, you can call it from your callback, once is runs at low IRQL.
> Please note that this address refers to the UM portion of the address space
> of the target process and not the one in context of which your callback
> is invoked.

Ok

> Therefore, you will have to do attach to the address space of the target
> process before you can make any use of it… However, the code that you have
> shown us tries to do it in context of the current process (i.e. mov eax,
> fs:[30h] ). In case if this process does not have UM representation (i.e. is
> a system process), eax points to the middle of nowhere. This is why you
> crash.
>

I am sorry, I don’t understand :

I have another code that (using the same design : a PsSetLoadImageRoutine
routine) parses the PE file image using base address given by the callback,
and this code works well.

You said I have to attach the process address space, but how can I parse the
PE file image if I am not already in process address space…?

In any case, as Ken already pointed out,it is better not to mess around with
> it, especially in your position - it looks like that you don’t really know
> what you are doing.

This is my first Windows Driver code (I use to dev on Linux/Unix env), and
it is really interesting.

> Therefore, using these tricks in a commercial product would be unwise in
> your position - although it can be done from time to time, it requires the
> level of knowledge well beyond the one your questions suggest…
>

My code is not comercial at all, I just try to improve my knowledge of
Windows design, and testing some algorithm.

Thanks for your help.


Matthieu Loriol

> My code is not comercial at all, I just try to improve my knowledge of Windows design,

and testing some algorithm.

This is what you should have started with - at this point you will be able to ask questions in this NG without expecting scornful replies whenever you asks about something “not-so-conventional”. More on it below…

Yes, but my objective is to detecte hooks. I try to avoid / reproduce API calls.

Well, you need to get to some starting point (in this case, a pointer to the target process’s PEB) in order to start you analysis, right? This is why we mentioned ZwQeryInformationProcess() here - it will return a pointed to PEB of the process you are interested in…

I am sorry, I don’t understand : I have another code that
(using the same design : a PsSetLoadImageRoutine routine) parses the PE file image
using base address given by the callback, and this code works well. You said I have
to attach the process address space, but how can I parse the PE file image if I
am not already in process address space…?

What may be possibly complex here??? Every process has its own address space, with KM portion of it being shared by all processes. You may get the image base address, successfully access it… but it going to be a PE header of the image that is mapped to the given address in the virtual address space of the CALLED process, rather than the target one.

As long as we speak about the kernel image (i.e. driver) there is no difference whatsoever, because kernel portion of the virtual address space is the same for everyone. However, if this is a usermode image, things work a bit differently. If you are lucky and nothing is mapped to the given address, you are just going to crash, so that your mistake becomes obvious to you straight away. However, if some image is mapped to the same base address in the address space of the called process… well, you may do the parsing successfully, but you will parse the wrong header. Furthermore, it may happen that the same image is mapped to the same UM virtual address (as it happens with ntdll,.dll kernel.dll and friends), which makes your mistake even less obvious to you - in this case you read the right image header, but modifications that you make take place in the address space of the called process. Therefore, in order to avoid errors, you should always attach to a your target process 's address space whenever you access some UM address from your driver (unless you are interested in the called process itself, of course)…

In your particular case, whenever you access PEB like mov eax, fs:[30h], you access the one of the CALLED process , and there is no guarantee that the called process has its PEB, in the first place - once PEB is UM structure, a process that does not have its UM representation (i.e. a system process) is not going to have any…

This is my first Windows Driver code (I use to dev on Linux/Unix env), and it is really interesting.

Actually, I don’t really know what may be possibly “interesting” here - I have migrated to the opposite direction exactly for this reason. What you are trying to do is, certainly, interesting… but this is not what Windows drivers are supposed to do. Instead, you are supposed to do exactly what you are told, and all your attempts to do something “unconventional” will be met with resentment, at least in this NG…

Anton Bassov

Please note that you cannot use ZwQueryInformationProcess, or any function that need the process handle, from within your callback.
You can only do that for the EXE module itself and for NTDLL. You cannot do that for DLLs modules. So better avoid doing this from within the callback function.

-----Mensaje original-----
De: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] En nombre de Crispin Wright
Enviado el: domingo, 14 de septiembre de 2008 13:07
Para: Windows System Software Devs Interest List
Asunto: RE: [ntdev] Get PEB from PsSetImageLoadNotify callback routine

You can get the PEB base address using ZwQueryInformationProcess with the PROCESS_BASIC_INFO flag, the PebBaseAddress element will hold the base address. Just so you know, you don’t need to write a driver to achieve this goal, it can be done from user mode fairly easily.

I suppose an advantage of doing it from kernel mode is that you avoid any API hooks placed in user mode that might subvert your code…

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Sunday, September 14, 2008 11:08
To: Windows System Software Devs Interest List
Subject: [ntdev] Get PEB from PsSetImageLoadNotify callback routine

Hi,

I’m trying to list loaded module of a just-loaded process, looking for IAT hooks.

My objective is to get the current process PEB, then, using PLDR_DATA_TABLE_ENTRY, checking all LDR_MODULE of the linked list.

My code is running in ring 0, so, to be in process address space I register a callback routine to PsSetImageLoadNotifyRoutine :


PsSetLoadImageNotifyRoutine(MyImageLoadNotify);

VOID MyImageLoadNotify(IN PUNICODE_STRING FullImageName, IN HANDLE ProcessId, IN PIMAGE_INFO ImageInfo) {

//…

DumpCurentProcessDLL();
}

My problem is when I try to get the process PEB, I got an Access Violation error doing

mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET)

Here is the code :

DWORD GetFirstCurrentProcessPLDR(void)
{
DWORD* module = NULL;

__asm
{
push eax
mov eax, fs:[30h] //PEB
mov eax, [eax + 0ch] //*(PEB + LDR_OFFSET) = _PEB_LDR_DATA and ACCES VIOLATION ERRRRRRROR mov module, eax pop eax }

return (DWORD)module;
}

VOID DumpCurentProcessDLL(void)
{
PLDR_MODULE pCurModule, pFirstModule;
PLDR_DATA_TABLE_ENTRY pldr;
int count = 0;

pldr = (PLDR_DATA_TABLE_ENTRY)GetFirstCurrentProcessPLDR();

pFirstModule = (PLDR_MODULE) pldr->InMemoryOrderLinks.Flink; pFirstModule = ((DWORD)pFirstModule - XP_FLINKOFFSET);

pCurModule = pFirstModule;

for(;:wink:
{
if ((count >= 1) && (pCurModule == pFirstModule)) break;

DbgPrint(“dll : %ws\n”, pCurModule->BaseDllName.Buffer); DbgPrint(“path : %ws\n”, pCurModule->FullDllName.Buffer); DbgPrint(“===============\n”);

pCurModule = (PLDR_MODULE) pCurModule->InMemoryOrderModuleList.Flink;
pCurModule = ((DWORD)pCurModule - XP_FLINKOFFSET);

++count;
}
}

Does MyImageLoadNotify really executes in process address space?
Why can’t I get PEB?

Thanks for your help.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

__________ Information from ESET NOD32 Antivirus, version of virus signature database 3440 (20080913) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com

__________ Information from ESET NOD32 Antivirus, version of virus signature database 3440 (20080913) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> Please note that you cannot use ZwQueryInformationProcess, or any function

that need the process handle, from within your callback.

Why is that??? IIRC, this callback runs at PASSIVE_LEVEL, and you can call any kernel exports at PASSIVE_LEVEL, apart from the ones that explicitly require elevated IRQL (for example, KeAcquireSpinlockAtDpcLevel())…

Anton Bassov

It is because you cannot ‘open’ the process to get a handle because the process space lock is already acquired before your callback is called.
If you try to open the process with this lock acquired you will deadlock because the open function tried to acquire the lock again. Note that the synchronizer used is a fast mutex (or guarded mutex for certain OS versions) so you cannot acquire it recursively.

This happens for all modules loaded by a process except the EXE module itself and the NTDLL.
The reason you can open the process in these two cases is that the callback is called from 3 different points.
Unfortunately the point when the process loads a DLL, the thread is holding the address space process lock acquired while calling the ps module notification functions.

The net result is that you cannot call any function that tries to open a handle to the target process while you are within your callback function.

By the way, you can infer from the above that this functions is no always called at PASSIVE level. In Windows 2000 and XP it is called at APC level for DLLs (because fast mutex raise the IRQL to APC). This is not a problem for calling most functions but has some interesting consequences when performing certain actions from within the callback function. Under W2003 and higher it was replaced by a guarded mutex, that does not raise the IRQL. Under Vista a Push Lock is used.

This behavior was fixed in Vista SP1.

-----Mensaje original-----
De: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] En nombre de xxxxx@hotmail.com
Enviado el: lunes, 15 de septiembre de 2008 13:00
Para: Windows System Software Devs Interest List
Asunto: RE:[ntdev] Get PEB from PsSetImageLoadNotify callback routine

Please note that you cannot use ZwQueryInformationProcess, or any
function that need the process handle, from within your callback.

Why is that??? IIRC, this callback runs at PASSIVE_LEVEL, and you can call any kernel exports at PASSIVE_LEVEL, apart from the ones that explicitly require elevated IRQL (for example, KeAcquireSpinlockAtDpcLevel())…

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Ooops, I correct myself: what may fail is “the use of the handle” and not the “opening of the handle” itself. (as it should be obvious because “Process” object type does not have an OpenProcedure!).

Certain process functions that do not require to acquire the lock do work, but most dont.

So I should have stated: don’t use these functions without being aware of this potential deadlock!

inaki.

-----Mensaje original-----
De: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] En nombre de I?aki Castillo
Enviado el: lunes, 15 de septiembre de 2008 13:49
Para: Windows System Software Devs Interest List
Asunto: RE: [ntdev] Get PEB from PsSetImageLoadNotify callback routine

It is because you cannot ‘open’ the process to get a handle because the process space lock is already acquired before your callback is called.
If you try to open the process with this lock acquired you will deadlock because the open function tried to acquire the lock again. Note that the synchronizer used is a fast mutex (or guarded mutex for certain OS versions) so you cannot acquire it recursively.

This happens for all modules loaded by a process except the EXE module itself and the NTDLL.
The reason you can open the process in these two cases is that the callback is called from 3 different points.
Unfortunately the point when the process loads a DLL, the thread is holding the address space process lock acquired while calling the ps module notification functions.

The net result is that you cannot call any function that tries to open a handle to the target process while you are within your callback function.

By the way, you can infer from the above that this functions is no always called at PASSIVE level. In Windows 2000 and XP it is called at APC level for DLLs (because fast mutex raise the IRQL to APC). This is not a problem for calling most functions but has some interesting consequences when performing certain actions from within the callback function. Under W2003 and higher it was replaced by a guarded mutex, that does not raise the IRQL. Under Vista a Push Lock is used.

This behavior was fixed in Vista SP1.

-----Mensaje original-----
De: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] En nombre de xxxxx@hotmail.com Enviado el: lunes, 15 de septiembre de 2008 13:00
Para: Windows System Software Devs Interest List
Asunto: RE:[ntdev] Get PEB from PsSetImageLoadNotify callback routine

Please note that you cannot use ZwQueryInformationProcess, or any
function that need the process handle, from within your callback.

Why is that??? IIRC, this callback runs at PASSIVE_LEVEL, and you can call any kernel exports at PASSIVE_LEVEL, apart from the ones that explicitly require elevated IRQL (for example, KeAcquireSpinlockAtDpcLevel())…

Anton Bassov


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

> Note that the synchronizer used is a fast mutex (or guarded mutex for certain OS versions)

so you cannot acquire it recursively.

Actually, this is the reason why I mentioned IRQL. Documentation mentions PASSIVE_LEVEL as a requirement, which means that it just cannot be invoked at the time when fast mutex is being held, because fast mutex raises the IRQL to APC_LEVEL(unless I got it wrong and this requirement applies only to registration but not to invocation)…

Anton Bassov