Regarding fullpath name of current process.

Hi ,

I got fullpath of process name from Kernel Mode
through the position of _PEB in _EPROCESS Structure.
but some times for some Process which name length is grater than 16
it works but some times its gives message like

“Only part of a ReadProcessMemory or WriteProcessMemory request was completed .”

i m working on WinXP.

This error becz that time offset2 value is 0.
and this error for this line

memcpy(&offset3, ptr, 2);

I tried following, but can’t get address that points fullpath.
when offset2 is 0 i set the value for
offset2 = 0x2000
offset3 = 0x7c4

but it gives same error for the line
memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR));

I tried following, but can’t get address that points fullpath

I would appreciate any comment , wht i have to do it will work for all cases.
Thanks.

//----------------------------------------------------------------------
// GetProcessName
//----------------------------------------------------------------------
void GetProcessName(PWCHAR Name)
{
PEPROCESS curproc;
char* ptr;
int offset1, offset2;
short offset3;
WCHAR wBuff[255];

curproc = PsGetCurrentProcess();

ptr = (PCHAR)curproc + 0x1b0; // 0x1b0 :
position of _PEB in _EPROCESS
structure
memcpy(&offset1, ptr, 4);

ptr = (PCHAR)(offset1 + 0x10); // 0x10 : position of
ProcessParameters
in _PEB structure
memcpy(&offset2, ptr, 4);

ptr = (PCHAR)(offset2 + 0x3c); // 0x3c : position of
fullpath(ImagePath) in ProcessParameters
memcpy(&offset3, ptr, 2);

memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR));
// DbgPrint((“offset1:[%X], offset2:[%X], offset3:[%X],
ImagePath:[%ws]\n”,
offset1, offset2, offset3, wBuff));

wcscpy(Name, wBuff);
return Name;
}


Find out what India is talking about on Yahoo! Answers India.

The only documented mechanism is by setting a create process notify routine (PsSetCreateProcessNotifyRoutine) and building your own lookup table. There are a couple of undocumented ways, but they are subject to change without notice.


Ken Johnson (Skywing)
Windows SDK MVP

“vijay patil” wrote in message news:xxxxx@ntfsd…
Hi ,

I got fullpath of process name from Kernel Mode
through the position of _PEB in _EPROCESS Structure.
but some times for some Process which name length is grater than 16
it works but some times its gives message like

“Only part of a ReadProcessMemory or WriteProcessMemory request was completed .”

i m working on WinXP.

This error becz that time offset2 value is 0.
and this error for this line

memcpy(&offset3, ptr, 2);

I tried following, but can’t get address that points fullpath.
when offset2 is 0 i set the value for
offset2 = 0x2000
offset3 = 0x7c4

but it gives same error for the line
memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR));

I tried following, but can’t get address that points fullpath

I would appreciate any comment , wht i have to do it will work for all cases.
Thanks.

//----------------------------------------------------------------------
// GetProcessName
//----------------------------------------------------------------------
void GetProcessName(PWCHAR Name)
{
PEPROCESS curproc;
char* ptr;
int offset1, offset2;
short offset3;
WCHAR wBuff[255];

curproc = PsGetCurrentProcess();

ptr = (PCHAR)curproc + 0x1b0; // 0x1b0 :
position of _PEB in _EPROCESS
structure
memcpy(&offset1, ptr, 4);

ptr = (PCHAR)(offset1 + 0x10); // 0x10 : position of
ProcessParameters
in _PEB structure
memcpy(&offset2, ptr, 4);

ptr = (PCHAR)(offset2 + 0x3c); // 0x3c : position of
fullpath(ImagePath) in ProcessParameters
memcpy(&offset3, ptr, 2);

memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR));
// DbgPrint((“offset1:[%X], offset2:[%X], offset3:[%X],
ImagePath:[%ws]\n”,
offset1, offset2, offset3, wBuff));

wcscpy(Name, wBuff);
return Name;
}

------------------------------------------------------------------------------
Find out what India is talking about on Yahoo! Answers India.

VIJAY:

This is what I think might be going on:

  • The code below will fail if the current process is either the system
    process or the idle process, as neither has a PEB.
  • The PEB and it’s nested structures/pointers are user mode accessible
    and thus always potentially paged out. In addition to ensuring the
    EPROCESS::PEB is != NULL (from above), you need to probe it fully, and
    guard it with SEH. It is quite possible that the OS takes care of this
    automatically, but unless you know that it does, I would do this.
  • Are you looking for process name/filename or full image path? If
    you seek process name, you need to look at EPROCESS::ImageFileName.
    This is where “System” and “Idle” are stored for the PEB less
    processes.
  • The length of ImagePath is not necessarily 255 wide characters
    (memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR))). Nor,
    strictly speaking, is it necessarily null terminated. You are almost
    certainy copying garbage, which, given that this is occuring on an IA32
    in the very small FS segment, might cause an access violation by
    overunning the segment. The length to copy is a member of
    UNICODE_STRING.

FOR WHAT IT IS WORTH:

I would strongly advise you throw out this routine and start over. My
guess is that you copied this routine from somewhere. As noted in other
postings, this whole operation is inherently version specific, under the
best of circumstances, unless you go the reflection to a user mode
service or image load notify routine routes. What you have below,
however, in addition to being filled with constraints under which it
will work, is almost incomprehensible, basically for two reasons. The
first is, of course, the lack of structure definitions - hard coded
offsets. Your basic question is a very reasonable one (image
filenames), and is easily one of the most common one on these lists; yet
very few seem to have responded to you. This is why. The second
follows from the first - with structure definitions (even incomplete
ones with only the salient fields and dummy fields for the rest), all of
the offset variables (and the memcpy()) go away. In particular the last
really sketchy 16 bit copy to offset3.

ALL OF THIS:

ptr = (PCHAR)curproc + 0x1b0; // 0x1b0 :

position of _PEB in _EPROCESS
structure
memcpy(&offset1, ptr, 4);

ptr = (PCHAR)(offset1 + 0x10); // 0x10 :
position of
ProcessParameters
in _PEB structure
memcpy(&offset2, ptr, 4);

ptr = (PCHAR)(offset2 + 0x3c); // 0x3c :
position of
fullpath(ImagePath) in ProcessParameters
memcpy(&offset3, ptr, 2);

memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR));
// DbgPrint((“offset1:[%X], offset2:[%X], offset3:[%X],
ImagePath:[%ws]\n”,
offset1, offset2, offset3, wBuff));

wcscpy(Name, wBuff);

BECOMES THIS:

memcpy(Name, NtCurrentPeb()->ProcessParameters->ImagePath.Buffer,
(NtCurrentPeb()->ProcessParameters->ImagePath.Length + 1) *
sizeof(wchar_t));

I mention this not to criticize, but to give you some ideas for ways to
improve the likelhood of getting answers to your questions.

I hope this helps,

MM

>> xxxxx@yahoo.co.in 2006-07-21 11:20 >>>
Hi ,

I got fullpath of process name from Kernel Mode
through the position of _PEB in _EPROCESS Structure.
but some times for some Process which name length is grater than 16
it works but some times its gives message like

“Only part of a ReadProcessMemory or WriteProcessMemory request was
completed .”

i m working on WinXP.

This error becz that time offset2 value is 0.
and this error for this line

memcpy(&offset3, ptr, 2);

I tried following, but can’t get address that points fullpath.
when offset2 is 0 i set the value for
offset2 = 0x2000
offset3 = 0x7c4

but it gives same error for the line
memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR));

I tried following, but can’t get address that points fullpath

I would appreciate any comment , wht i have to do it will work for
all cases.
Thanks.

//----------------------------------------------------------------------
// GetProcessName
//----------------------------------------------------------------------
void GetProcessName(PWCHAR Name)
{
PEPROCESS curproc;
char* ptr;
int offset1, offset2;
short offset3;
WCHAR wBuff[255];

curproc = PsGetCurrentProcess();

ptr = (PCHAR)curproc + 0x1b0; // 0x1b0 :

position of _PEB in _EPROCESS
structure
memcpy(&offset1, ptr, 4);

ptr = (PCHAR)(offset1 + 0x10); // 0x10 :
position of
ProcessParameters
in _PEB structure
memcpy(&offset2, ptr, 4);

ptr = (PCHAR)(offset2 + 0x3c); // 0x3c :
position of
fullpath(ImagePath) in ProcessParameters
memcpy(&offset3, ptr, 2);

memcpy(wBuff, (char*)(offset2+offset3), 255 * sizeof(WCHAR));
// DbgPrint((“offset1:[%X], offset2:[%X], offset3:[%X],
ImagePath:[%ws]\n”,
offset1, offset2, offset3, wBuff));

wcscpy(Name, wBuff);
return Name;
}


Find out what India is talking about on Yahoo! Answers India.

Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@evitechnology.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Hi mate

Look how it can be done under XP, given a process ID:

1.PsLookupProcessByProcessId(pid,&eprocess);

2.ObOpenObjectByPointer(eprocess,0, NULL, 0,0,KernelMode,&handle);

3.NtQueryInformationProcess(handle,0x1B,namebuff,1024,&a);

First of all, you get the pointer to EPROCESS of your target process
with PsLookupProcessByProcessId. Then you pass EPROCESS pointer to
ObOpenObjectByPointer() in order to get the handle. Finally, you pass
the handle to
NtQueryInformationProcess (infoclass 0x1B, which is not covered by
“Windows
NT/2000 Native API Reference”). Output buffer must be large enough to
hold
UNICODE_STRING, immediately followed by name

If you need only the file name, rather than the full path, you can also
do it with PsGetProcessImageFileName() - this function obtains the
sought info from EPROCESS

I would say that the former method is better - in fact,
NtQueryInformationProcess() with 0x1B index gets called internally by
GetModuleFileName()

Anton Bassov

My observation has been that NtQueryInformationProcess requires the use
of a user-mode buffer if the previous mode was “UserMode” (otherwise
your buffer won’t validate properly.) While NtQueryInformationProcess
is in ntifs.h, ZwQueryInformationProcess is not (although it has the
same signature.)

For what its worth, 0x1B is ProcessImageInformation (see
PROCESSINFOCLASS in ntifs.h).

The demonstrated technique also potentially creates a security hole if
called in anything other than the system process, because it creates a
handle in the process object handle table; this could potentially be
exploited by a malicious program or it could lead to accidental use of
the process handle created.

Here is the code I’m using for an article I’m writing on this topic for
The NT Insider:

typedef NTSTATUS (*QUERY_INFO_PROCESS) (
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);

QUERY_INFO_PROCESS ZwQueryInformationProcess;

NTSTATUS GetProcessImageName(PUNICODE_STRING ProcessImageName)
{
NTSTATUS status;
ULONG returnedLength;
ULONG bufferLength;
PVOID buffer;
PUNICODE_STRING imageName;

PAGED_CODE(); // this eliminates the possibility of the IDLE
Thread/Process

if (NULL == ZwQueryInformationProcess) {
UNICODE_STRING routineName;

RtlInitUnicodeString(&routineName,
L"ZwQueryInformationProcess");

ZwQueryInformationProcess = (QUERY_INFO_PROCESS)
MmGetSystemRoutineAddress(&routineName);

if (NULL == ZwQueryInformationProcess) {
DbgPrint(“Cannot resolve ZwQueryInformationProcess\n”);
}
}

//
// Step one - get the size we need
//
status = ZwQueryInformationProcess( NtCurrentProcess(),
ProcessImageFileName,
NULL, // buffer
0, // buffer size
&returnedLength);

if (STATUS_INFO_LENGTH_MISMATCH != status) {
return status;
}

//
// Is the passed-in buffer going to be big enough for us? This
function returns a single contguous buffer model…
//
bufferLength = returnedLength - sizeof(UNICODE_STRING);

if (ProcessImageName->MaximumLength < bufferLength) {
ProcessImageName->Length = (USHORT) bufferLength;
return STATUS_BUFFER_OVERFLOW;
}

//
// If we get here, the buffer IS going to be big enough for us, so
let’s allocate some storage.
//
buffer = ExAllocatePoolWithTag(PagedPool, returnedLength, ‘boof’);

if (NULL == buffer) {
return STATUS_INSUFFICIENT_RESOURCES;
}

//
// Now lets go get the data
//
status = ZwQueryInformationProcess( NtCurrentProcess(),
ProcessImageFileName,
buffer,
returnedLength,
&returnedLength);

if (NT_SUCCESS(status)) {
//
// Ah, we got what we needed
//
imageName = (PUNICODE_STRING) buffer;
RtlCopyUnicodeString(ProcessImageName, imageName);
}

//
// free our buffer
//
ExFreePool(buffer);

//
// And tell the caller what happened.
//
return status;

}

This retrieves the name of the *current* process. Some notes about
this:

  • If you have the EPROCESS, you can attach (KeStackAttachProcess) and
    retrieve the process name without using the handle.
  • If the executable image is renamed, it will NOT be reflected in this
    name. In other words, this is the name of the executable at the time
    the file name is first retrieved and it may have changed since then.
  • You cannot retrieve the image name for the IDLE process (there isn’t
    one).

This code works on W2K, XP, W2K3 and Vista B2. I’ll have a more
detailed article on this in the NT Insider, but since this has come up
several times in the past few days I figured that I’d provide this
material now. Of course, if anyone has comments please let me know
since I’d rather correct any issues now rather than after it has been
published.

Tony

Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com

>- If the executable image is renamed, it will NOT be reflected in this

name. In other words, this is the name of the executable at the time
the file name is first retrieved and it may have changed since then.

Loaded EXE/DLL files are usually locked, so, any attempt to rename them cause
sharing violation.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

Actually, that doesn’t agree with my experience with in-use executable
images because normally they are no longer open and hence there is no
share access check. As long as the file is not opened for WRITE_DATA or
DELETE (which isn’t needed for rename) it can be renamed. Here, for
example is the relevant code from FAT:

//
// If the user wants write access access to the file make sure
there
// is not a process mapping this file as an image. Any attempt
to
// delete the file will be stopped in fileinfo.c
//
// If the user wants to delete on close, we must check at this
// point though.
//

if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {

Fcb->OpenCount += 1;
DecrementFcbOpenCount = TRUE;

if (!MmFlushImageSection(
&Fcb->NonPaged->SectionObjectPointers,
MmFlushForWrite )) {

Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
STATUS_SHARING_VIOLATION;
try_return( Iosb );
}
}

I’ve renamed in-use DLLs and executables numerous times in the past as a
result (I do it from the command line - your mileage may vary if you use
other tools that try to open the file differently.)

Tony

Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Saturday, July 22, 2006 8:19 AM
To: ntfsd redirect
Subject: Re: [ntfsd] Regarding fullpath name of current process.

  • If the executable image is renamed, it will NOT be reflected in this
    name. In other words, this is the name of the executable at the time
    the file name is first retrieved and it may have changed since then.

Loaded EXE/DLL files are usually locked, so, any attempt to rename them
cause
sharing violation.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Tony Mason wrote:

I’ve renamed in-use DLLs and executables numerous times in the past as a
result (I do it from the command line - your mileage may vary if you use
other tools that try to open the file differently.)

It’s really useful behaviour for updating things that start up at boot…
doesn’t work for everything though - if a file is locked by LSASS it can’t be
renamed.

Tony

I think it is KnownDLLs which cannot be renamed.

c:\winnt\system32> move ole32.dll ole32_.dll
(worked fine, but copied the file instead of moving)

Then, the resulting ole32_.dll file can be renamed later, but not deleted!
ACLs are permitting this delete, but neither CMD nor the shell can delete it,
amazing…

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

----- Original Message -----
From: “Tony Mason”
To: “Windows File Systems Devs Interest List”
Sent: Saturday, July 22, 2006 7:33 PM
Subject: RE: [ntfsd] Regarding fullpath name of current process.

Actually, that doesn’t agree with my experience with in-use executable
images because normally they are no longer open and hence there is no
share access check. As long as the file is not opened for WRITE_DATA or
DELETE (which isn’t needed for rename) it can be renamed. Here, for
example is the relevant code from FAT:

//
// If the user wants write access access to the file make sure
there
// is not a process mapping this file as an image. Any attempt
to
// delete the file will be stopped in fileinfo.c
//
// If the user wants to delete on close, we must check at this
// point though.
//

if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {

Fcb->OpenCount += 1;
DecrementFcbOpenCount = TRUE;

if (!MmFlushImageSection(
&Fcb->NonPaged->SectionObjectPointers,
MmFlushForWrite )) {

Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
STATUS_SHARING_VIOLATION;
try_return( Iosb );
}
}

I’ve renamed in-use DLLs and executables numerous times in the past as a
result (I do it from the command line - your mileage may vary if you use
other tools that try to open the file differently.)

Tony

Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Saturday, July 22, 2006 8:19 AM
To: ntfsd redirect
Subject: Re: [ntfsd] Regarding fullpath name of current process.

>- If the executable image is renamed, it will NOT be reflected in this
>name. In other words, this is the name of the executable at the time
>the file name is first retrieved and it may have changed since then.

Loaded EXE/DLL files are usually locked, so, any attempt to rename them
cause
sharing violation.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: unknown lmsubst tag argument: ‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com

> Loaded EXE/DLL files are usually locked, so, any attempt to rename them

cause
sharing violation.

They aren’t. rename is actually the only change operation
which works on those files.

L.

The key to keep in mind is that a file may be opened or it may be mapped
or both. If the file is opened then normal share access comes into
play, if the file is mapped then that magic code in FAT (and NTFS) comes
into play. If it is both, then you’ll find that both come into play.

There’s nothing that requires an executable be closed after the mapping
is done, but that’s rather common; I suspect that DLLs loaded explicitly
exhibit different behavior (e.g., the LSASS example previously given.)

Of course drives have no such problem like this because they are backed
by the paging file, not by the original. Thus the original file can be
deleted, overwritten or renamed…

Tony

Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Saturday, July 22, 2006 3:11 PM
To: ntfsd redirect
Subject: Re: [ntfsd] Regarding fullpath name of current process.

I think it is KnownDLLs which cannot be renamed.

c:\winnt\system32> move ole32.dll ole32_.dll
(worked fine, but copied the file instead of moving)

Then, the resulting ole32_.dll file can be renamed later, but not
deleted!
ACLs are permitting this delete, but neither CMD nor the shell can
delete it,
amazing…

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

----- Original Message -----
From: “Tony Mason”
To: “Windows File Systems Devs Interest List”
Sent: Saturday, July 22, 2006 7:33 PM
Subject: RE: [ntfsd] Regarding fullpath name of current process.

Actually, that doesn’t agree with my experience with in-use executable
images because normally they are no longer open and hence there is no
share access check. As long as the file is not opened for WRITE_DATA or
DELETE (which isn’t needed for rename) it can be renamed. Here, for
example is the relevant code from FAT:

//
// If the user wants write access access to the file make sure
there
// is not a process mapping this file as an image. Any attempt
to
// delete the file will be stopped in fileinfo.c
//
// If the user wants to delete on close, we must check at this
// point though.
//

if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) {

Fcb->OpenCount += 1;
DecrementFcbOpenCount = TRUE;

if (!MmFlushImageSection(
&Fcb->NonPaged->SectionObjectPointers,
MmFlushForWrite )) {

Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
STATUS_SHARING_VIOLATION;
try_return( Iosb );
}
}

I’ve renamed in-use DLLs and executables numerous times in the past as a
result (I do it from the command line - your mileage may vary if you use
other tools that try to open the file differently.)

Tony

Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Saturday, July 22, 2006 8:19 AM
To: ntfsd redirect
Subject: Re: [ntfsd] Regarding fullpath name of current process.

>- If the executable image is renamed, it will NOT be reflected in this
>name. In other words, this is the name of the executable at the time
>the file name is first retrieved and it may have changed since then.

Loaded EXE/DLL files are usually locked, so, any attempt to rename them
cause
sharing violation.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: unknown lmsubst tag argument:
‘’
To unsubscribe send a blank email to xxxxx@lists.osr.com


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Hi Tony

My observation has been that NtQueryInformationProcess requires the use
of a user-mode buffer if the previous mode was “UserMode” (otherwise
your buffer won’t validate properly.) While NtQueryInformationProcess
is in ntifs.h, ZwQueryInformationProcess is not (although it has the
same signature.)

I am afraid you confused NtQueryInformationProcess() and ZwQueryInformationProcess() - although in user mode these are just 2 different names for the same entry point in ntdll.dll, they have quite different implications in kernel mode. When you call ZwQueryInformationProcess() from the kernel mode, execution gets transfered to the service dispatcher, which makes all necessary checks, gets the address of NtQueryInformationProcess() from SSDT, and calls it. However, when you call NtQueryInformationProcess(), you call the service implementation in itself - service dispatcher is not involved. Therefore, your observation applies to ZwQueryInformationProcess(), rather than
NtQueryInformationProcess() - there is no need for NtQueryInformationProcess() to make any checks, because it gets called only by trusted code( i.e driver or service dispatcher)

The demonstrated technique also potentially creates a security hole if
called in anything other than the system process, because it creates a
handle in the process object handle table; this could potentially be
exploited by a malicious program or it could lead to accidental use of
the process handle created.

My example assumes that the target process is not necessarily the calling one - otherwise, I would just pass (HANDLE)-1 the wway you did. In user-mode terms, my example acts as GetProcessImageFileName(), and yours acts as GetModuleFileName(). It is understandable that you have to close handle after you are done with it.

Concerning exloits and accidents, don’t forget that this handle may be used only by kernel-mode code - once we have opened it in the kernel mode, its is numerically above 0x80000000. Therefore, even if we don’t close it, user-mode code has no chance to make any use of this handle - if it passes this handle to any API function, it is not going to pass MmUserProbeAddress test, so that error will be returned

Anton Bassov

Actually, it is you who is confused about Nt versus Zw. Zw will, as you
note, recapture the “previous mode” but this time since “previous mode”
is kernel mode the behavior will be to trust the parameters. Using
NtQueryInformationProcess does not recapture the “previous mode” and
thus it will remain “UserMode” and will validate the buffers.

As for the example, I agree that one could make it correct if one were
to specify OBJ_KERNEL_HANDLE in the second parameter (the
HandleAttributes) but your example did not do this. I did not state that
one could not do so, I merely observed the side-effect of the code that
you provided. Specifying that the open is kernel mode does not,
however, create it in the system process object handle table (which is
the effect of OBJ_KERNEL_HANDLE).

One reason I was providing a sample is that it is important in this
forum to provide known correct examples and point out issues with
incorrect examples - otherwise we risk having people “pick up” the
incorrect implementation and incorporating it into their drivers
(something we’ve seen with sfilter and filemon for example - there is a
multiplicative effect involved.)

I realize your example was not code, per se, but rather a basic outline.
Still it is important to ensure everyone realizes the potential issues
involved in the details of implementation.

Tony

Tony Mason
Consulting Partner
OSR Open Systems Resources, Inc.
http://www.osr.com

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@hotmail.com
Sent: Saturday, July 22, 2006 10:16 PM
To: ntfsd redirect
Subject: RE:[ntfsd] Regarding fullpath name of current process.

Hi Tony

My observation has been that NtQueryInformationProcess requires the
use
of a user-mode buffer if the previous mode was “UserMode” (otherwise
your buffer won’t validate properly.) While NtQueryInformationProcess
is in ntifs.h, ZwQueryInformationProcess is not (although it has the
same signature.)

I am afraid you confused NtQueryInformationProcess() and
ZwQueryInformationProcess() - although in user mode these are just 2
different names for the same entry point in ntdll.dll, they have quite
different implications in kernel mode. When you call
ZwQueryInformationProcess() from the kernel mode, execution gets
transfered to the service dispatcher, which makes all necessary checks,
gets the address of NtQueryInformationProcess() from SSDT, and calls it.
However, when you call NtQueryInformationProcess(), you call the service
implementation in itself - service dispatcher is not involved.
Therefore, your observation applies to ZwQueryInformationProcess(),
rather than
NtQueryInformationProcess() - there is no need for
NtQueryInformationProcess() to make any checks, because it gets called
only by trusted code( i.e driver or service dispatcher)

The demonstrated technique also potentially creates a security hole if
called in anything other than the system process, because it creates a
handle in the process object handle table; this could potentially be
exploited by a malicious program or it could lead to accidental use of
the process handle created.

My example assumes that the target process is not necessarily the
calling one - otherwise, I would just pass (HANDLE)-1 the wway you did.
In user-mode terms, my example acts as GetProcessImageFileName(), and
yours acts as GetModuleFileName(). It is understandable that you have to
close handle after you are done with it.

Concerning exloits and accidents, don’t forget that this handle may be
used only by kernel-mode code - once we have opened it in the kernel
mode, its is numerically above 0x80000000. Therefore, even if we don’t
close it, user-mode code has no chance to make any use of this handle -
if it passes this handle to any API function, it is not going to pass
MmUserProbeAddress test, so that error will be returned

Anton Bassov


Questions? First check the IFS FAQ at
https://www.osronline.com/article.cfm?id=17

You are currently subscribed to ntfsd as: xxxxx@osr.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

Hi all.
thank you for your help and concern.
I tried to solve this & it works well.

Yes, Tony I did. Thanks for the support. It’s okay

typedef NTSTATUS (*QUERY_INFO_PROCESS) (
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);

QUERY_INFO_PROCESS ZwQueryInformationProcess;

NTSTATUS GetProcessImageName(PUNICODE_STRING ProcessImageName)
Thanks for your support.

Regards,

Vijay Patil

Almost the same as the example before, but no retry on zw. This example uses try/finally and hits 99% or more in a standadrd buffer.

NTSTATUS ResLibGetImageFileNameFromProcess(
IN PEPROCESS ProcessCBlock,
OUT PPROCESS_IMAGEFILENAME_INFORMATION
*ImageFileNameIBlock
)
/*---------------------------------------------------------------------------
ResLibGetImageFileNameFromProcess routine.

Routine Description:

The routine returns the full image file name of the process.

Arguments:

ProcessCBlock - Pointer to Extended Process block.

ImageFileNameIBlock - Pointer to PROCESS_IMAGEFILENAME_INFORMATION.

Return Value:

Mode: Kernel, irql 0.

Can’t be run under the protection of a spinlock!

–*/
{
HANDLE processHandle;
ULONG nameInfoLength = 0;
NTSTATUS status = STATUS_SUCCESS;
PPROCESS_IMAGEFILENAME_INFORMATION pImageFileNameInfo = NULL;

*ImageFileNameIBlock = NULL;

//-----------------------------------------------------------------------
// Check if we have a process. Return on failure.
//
if (NULL == ProcessCBlock)
{
return STATUS_UNSUCCESSFUL;
}

//-----------------------------------------------------------------------
// Open the Process object. Return on failure.
//
status = ObOpenObjectByPointer(
ProcessCBlock,
0,
NULL,
SYNCHRONIZE,
NULL,
KernelMode,
&processHandle
);

if(!NT_SUCCESS(status))
{
return status;
}

//-----------------------------------------------------------------------
// Allocate the storage area. From here on we need to free resources!!!
// Because we don’t know the required size, we start off with the most
// common fit and retry the allocation until it fits. We ‘leave’ the loop
// when the operation failed after retrying with larger sizes, or succee-
// ded.
//
try
{
nameInfoLength = 256;
pImageFileNameInfo = ExAllocatePoolWithTag(
NonPagedPool,
nameInfoLength,
RL_POOL_TAG
);

if (NULL == pImageFileNameInfo)
{
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}

while (TRUE)
{
pImageFileNameInfo->ImageFileNameLength = 0;

//---------------------------------------------------------------
// Query the ImageFileName.
//
status = ZwQueryInformationProcess(
processHandle,
#if WINVER == 0x0500
MaxProcessInfoClass,
#else
ProcessImageFileName,
#endif
pImageFileNameInfo,
nameInfoLength,
NULL
);

if (NT_SUCCESS(status))
{
leave;
}
else
{
if (STATUS_BUFFER_OVERFLOW == status)
{
//-------------------------------------------------------
// Did we hit our retry limit? If not, retry with assumed
// success.
//
if (nameInfoLength >= 4096)
{
leave;
}

status = STATUS_SUCCESS;

//-------------------------------------------------------
// The buffer was too small, so grow it and try again.
//
nameInfoLength = nameInfoLength * 2;

ExFreePoolWithTag(
pImageFileNameInfo,
RL_POOL_TAG
);

pImageFileNameInfo = NULL;

pImageFileNameInfo = ExAllocatePoolWithTag(
NonPagedPool,
nameInfoLength,
RL_POOL_TAG
);

if (NULL == pImageFileNameInfo)
{
status = STATUS_INSUFFICIENT_RESOURCES;
leave;
}
}
else
{
leave;
}
}
}
}
finally
{
//-------------------------------------------------------------------
// Cleanup.
//
if (!NT_SUCCESS(status))
{
if (pImageFileNameInfo)
{
ExFreePoolWithTag(
pImageFileNameInfo,
RL_POOL_TAG
);

pImageFileNameInfo = NULL;
}
}

ZwClose(
processHandle
);

//-------------------------------------------------------------------
// Correct the one process that doesn’t have a PEB (System).
//
#define SystemProcessName L"System"

if (pImageFileNameInfo && pImageFileNameInfo->ImageFileNameLength == 0)
{
pImageFileNameInfo->ImageFileNameLength = sizeof(SystemProcessName);

RtlCopyMemory(
pImageFileNameInfo->ImageFileNameBuffer,
SystemProcessName,
pImageFileNameInfo->ImageFileNameLength
);
}
}

//-----------------------------------------------------------------------
// Return the information to the caller.
//
*ImageFileNameIBlock = pImageFileNameInfo;

return status;
}