fullpath name of current process in win2k?

Im trying to get the full file path name of the current process. I have been using some code I found by Tony Mason. It works fine in XP & Vista and was stated to work in 2000, however I am running into issues with 2000. Everytime I try and run ZwQueryInformationProcess I get an ACCESS_VIOLATION.

Here is the code:

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;

}

Why would I be getting an access violation? Does anyone know any alternative methods for getting the full file path?

Hi!

ALTERNATIVE WAYS:

Below are the two methods that I know of:

  1. Undocumented method (not a recommended one): Find out the offset of file name in the EPROCESS structure. And then you can simply use it to find the process name. Basically you can call PsGetCurrentProcess() and then jump to the offset in this structure.

  2. Documented method: Register for the load image notification using PsSetLoadImageNotifyRoutine. The first callback that comes in the context of a particular process is that for the file from which that process was created. But note that the name of the process might actually be different from the name of the on disk file.

There may be other ways also. :slight_smile:

Regards,
Ayush Gupta

If I said it worked on Windows 2000, I misspoke. The information isn’t maintained on Windows 2000.

Sadly, the very reason I wrote the article was to convince people NOT to use the name in the EPROCESS - using it has created a broad range of security attacks (it is why many trojan horse programs are now called svchost.exe - everyone expects to see that name.) I recall spending a lot of time trying to figure out how to do that and while I had some interesting prospects, there was never anything definitive (the challenge is getting the file object. MM has it, since it backs the section, but does not provide any simple way to retireve it.)

Tony
OSR

Hrrrm…

I have played with using with PsGetCurrentProcess method before and if I remember correctly it only gives you the relative file name (test.exe rather than \Device\HarddiskVolume1\test.exe).

PsSetLoadImageNotifyRoutine looks it may do what I need. I’m assuming the common use of this, it so have the callback add the process id and path to a lookup, query the lookup whenever you require the name, and remove it from the lookup through a PsRemoveLoadImageNotifyRoutine?

Thanks for the suggestions!

Hey Guys thanks for all the suggestions. I also received an email from Bo Brantén with the following code which worked perfect!

typedef struct _RTL_USER_PROCESS_PARAMETERS {
UCHAR dummy[0x38]; //??? ? ??? 0x38 - ???, ??? ???
UNICODE_STRING ImagePathName;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

#define SYSNAME “System”

ULONG FileSpyGetProcessNameOffset( VOID)
{
PEPROCESS curproc;
int i;

//NTSTATUS Status = STATUS_SUCCESS;

curproc = PsGetCurrentProcess();

// Scan for 12KB, hoping the KPEB never grows that big!
//
for( i = 0; i < 3*PAGE_SIZE; i++ )
{
if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) ))
{
return i;
}
}

//
// Name not found - oh, well
//
return 0;
}

ProcessNameOffset = FileSpyGetProcessNameOffset();

PCHAR GetPathImageProcess( PCHAR PathImage )
{
PEPROCESS curproc;
char *nameptr;
DWORD dw = 0;
LPDWORD tdw;
ANSI_STRING ansi;
NTSTATUS ntStatus;
PRTL_USER_PROCESS_PARAMETERS pupp = NULL;

if( ProcessNameOffset )
{
curproc = PsGetCurrentProcess();
//nameptr = (PCHAR) curproc + ProcessNameOffset; //+0x1DC
//??? NT 4
if( 476==ProcessNameOffset )
{
tdw = (LPDWORD)(((PCHAR)curproc)+0x18C); //??? 18C
dw = *tdw; //_PEB
tdw = (LPDWORD)((PCHAR)dw+0x10);
dw = *tdw; //ProcessParameters
tdw = (LPDWORD)((PCHAR)dw + 0x0);
dw = *tdw;
}
else
{
//??? WIN 2000
tdw = (LPDWORD)(((PCHAR)curproc)+0x1B0); //???
dw = *tdw; //_PEB 0x7ffdf000
tdw = (LPDWORD)((PCHAR)dw+0x10);
dw = *tdw;
tdw = (LPDWORD)((PCHAR)dw + 0x0);
dw = *tdw;
}
//??? ??? ??? ? ??? ???
pupp = (PRTL_USER_PROCESS_PARAMETERS)(tdw);
ntStatus = RtlUnicodeStringToAnsiString( &ansi, &pupp->ImagePathName, TRUE);
if( ntStatus==STATUS_SUCCESS )
{
dw = ansi.Length;
if( dw > 2045 )
dw = 2045;
memcpy( PathImage, ansi.Buffer, dw );
PathImage[dw] = 0;
RtlFreeAnsiString( &ansi );
}//??? ??? ??? ???
}
else
{
strcpy( PathImage, “???” );
}
return PathImage;
}

Note, that depending on the OS this will crash. The only safe mechanism
for all OS’es you want is the PsSetLoadImageNotifyRoutine approach.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr
Remove StopSpam to reply

wrote in message news:xxxxx@ntfsd…
Hey Guys thanks for all the suggestions. I also received an email from Bo
Brantén with the following code which worked perfect!

typedef struct _RTL_USER_PROCESS_PARAMETERS {
UCHAR dummy[0x38]; //??? ? ??? 0x38 - ???,
??? ???
UNICODE_STRING ImagePathName;
} RTL_USER_PROCESS_PARAMETERS, PRTL_USER_PROCESS_PARAMETERS;

#define SYSNAME “System”

ULONG FileSpyGetProcessNameOffset( VOID)
{
PEPROCESS curproc;
int i;

//NTSTATUS Status = STATUS_SUCCESS;

curproc = PsGetCurrentProcess();

// Scan for 12KB, hoping the KPEB never grows that big!
//
for( i = 0; i < 3
PAGE_SIZE; i++ )
{
if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) ))
{
return i;
}
}

//
// Name not found - oh, well
//
return 0;
}

ProcessNameOffset = FileSpyGetProcessNameOffset();

PCHAR GetPathImageProcess( PCHAR PathImage )
{
PEPROCESS curproc;
char *nameptr;
DWORD dw = 0;
LPDWORD tdw;
ANSI_STRING ansi;
NTSTATUS ntStatus;
PRTL_USER_PROCESS_PARAMETERS pupp = NULL;

if( ProcessNameOffset )
{
curproc = PsGetCurrentProcess();
//nameptr = (PCHAR) curproc + ProcessNameOffset; //+0x1DC
//??? NT 4
if( 476==ProcessNameOffset )
{
tdw = (LPDWORD)(((PCHAR)curproc)+0x18C); //???
18C
dw = *tdw; //_PEB
tdw = (LPDWORD)((PCHAR)dw+0x10);
dw = *tdw; //ProcessParameters
tdw = (LPDWORD)((PCHAR)dw + 0x0);
dw = *tdw;
}
else
{
//??? WIN 2000
tdw = (LPDWORD)(((PCHAR)curproc)+0x1B0); //???
dw = *tdw; //_PEB 0x7ffdf000
tdw = (LPDWORD)((PCHAR)dw+0x10);
dw = *tdw;
tdw = (LPDWORD)((PCHAR)dw + 0x0);
dw = *tdw;
}
//??? ??? ??? ? ??? ???
pupp = (PRTL_USER_PROCESS_PARAMETERS)(tdw);
ntStatus = RtlUnicodeStringToAnsiString( &ansi,
&pupp->ImagePathName, TRUE);
if( ntStatus==STATUS_SUCCESS )
{
dw = ansi.Length;
if( dw > 2045 )
dw = 2045;
memcpy( PathImage, ansi.Buffer, dw );
PathImage[dw] = 0;
RtlFreeAnsiString( &ansi );
}//??? ??? ??? ???
}
else
{
strcpy( PathImage, “???” );
}
return PathImage;
}

Thanks for the note.
I was looking in the ntddk.h and I see that PsRemoveLoadImageNotifyRoutine is only exported on XP+. How would I cleanly shutdown my driver in 2K without PsRemoveLoadImageNotifyRoutine?

Nevermind. Just came across http://www.themssforum.com/Drivers/PsRemoveLoadImageNotifyRoutine/ which states that in 2K, you cannot unload your image notify routine.

why not getting the ProcessID and sending it to user mode and get back again the full path with the help of user mode API’s…