Prev: fltmgr.sys PDB and - fltkd WinDBG extension not working (windows XP) ...
Next: RPC memory leak under Vista
From: Arno Garrels on 11 Jan 2007 16:34 Hello, I know that there's a working, documented solution for XP, however that returns a device name instead of a DOS name, and I really need something that works at least in W2K as well. Here is a Q&D snippet that works in current process but raises an exception while accessing the ImagePathName->Buffer member. ----- #define BASE_PROCESS_PEB_OFFSET 0x01B0 #define BASE_PEB_PROCESS_PARAMETER_OFFSET 0x0010 #define BASE_PROCESS_PARAMETER_FULL_IMAGE_NAME 0x003C PCWSTR GetProcessImageName( HANDLE hProcessId ) { PEPROCESS ProcessPointer; ULONG uLong = 0; if (KeGetCurrentIrql() != PASSIVE_LEVEL){ DebugPrint(("*NO PASSIVE_LEVEL*\n")); return NULL; } // If ProcessPointer points to current process, no problem! // But we are called from the ProcessNotifyCallback, so when // a new process is going to be created we need to get the // new Process object. uLong = PsLookupProcessByProcessId((ULONG)hProcessId, &ProcessPointer); if (!NT_SUCCESS(uLong)) { DebugPrint(("*PsLookupProcessByProcessId Failed 0x%x\n*", uLong)); return NULL; } try { uLong = (ULONG)(PVOID *) ProcessPointer; if(uLong == 0 || uLong == 0xFFFFFFFF) { DebugPrint(("*Invalid EPROCESS\n*")); return 0; } //PEB // It's XP in this case uLong += BASE_PROCESS_PEB_OFFSET; if((uLong = *(ULONG*)uLong) == 0){ DebugPrint(("*PebBaseAddr is NULL\n*")); return 0; } // Peb->PRTL_USER_PROCESS_PARAMETERS uLong += BASE_PEB_PROCESS_PARAMETER_OFFSET; if ((uLong = *(ULONG*)uLong) == 0){ DebugPrint(("*PRTL_USER_PROCESS_PARAMETERS is NULL\n*")); return 0; } try { // On dereferencing the ImagePathName member the exception is raised // However the Length member is accessable and counts the correct // number of bytes, so the buffer should cointain data. // PRTL_USER_PROCESS_PARAMETERS->ImagePathName uLong += BASE_PROCESS_PARAMETER_FULL_IMAGE_NAME; if ((uLong = *(ULONG*)uLong) == 0){ DebugPrint(("*ImagePathName is NULL\n*")); return NULL; } DebugPrint(("ImageName %ws\n", (PCWSTR)uLong)); return (PCWSTR)uLong; } except(EXCEPTION_EXECUTE_HANDLER) { uLong = GetExceptionCode(); DebugPrint(( "Exception while accessing ImagePathName.Buffer 0X%08X \n", uLong)); } } finally { ObDereferenceObject(ProcessPointer); } return 0; } ----- I tried KeAttachProcess()/KeDetachProcess() but no change, ZwReadVirtualMemory() also returns an exception status. Hopefully someone can help. Arno Garrels
From: anton bassov on 11 Jan 2007 17:16 On W2K you can do something that user-mode GetModuleFileName() and GetModuleFileNameEx() do, i.e. obtain the image path right from PEB.... First of all, call ZwQueryInformationProcess() with infoclass 0 - it will return the following structure : typedef struct _PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PPEB PebBaseAddress; ULONG_PTR AffinityMask; LONG BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION ; Its second parameter is a pointer to PEB. Cast this pointer to the following structure: typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[9]; PPEB_LDR_DATA LoaderData; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; BYTE Reserved3[448]; ULONG SessionId; } PEB, *PPEB; Then cast 'ProcessParameters' of PEB structure to RTL_USER_PROCESS_PARAMETERS, which is declared like: typedef struct _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[56]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; BYTE Reserved2[92]; } RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS; At this point you will be able to get UNICODE_STRING that hold s the full path to the image file on the disk.... I make an assumption that you are obtaining the path of the caller process. If you want to obtain the path of some other process, you have to attach your thread to its address space with KeStackAttachProcess() before you access PEB. All above mentioned structures are documented on MSDN, so that you are not going to have any trouble with them Anton Bassov Arno Garrels wrote: > Hello, > > I know that there's a working, documented solution for XP, however > that returns a device name instead of a DOS name, and I really need > something that works at least in W2K as well. Here is a Q&D snippet > that works in current process but raises an exception while accessing > the ImagePathName->Buffer member. > > ----- > > #define BASE_PROCESS_PEB_OFFSET 0x01B0 > #define BASE_PEB_PROCESS_PARAMETER_OFFSET 0x0010 > #define BASE_PROCESS_PARAMETER_FULL_IMAGE_NAME 0x003C > > PCWSTR > GetProcessImageName( > HANDLE hProcessId > ) > { > PEPROCESS ProcessPointer; > ULONG uLong = 0; > > if (KeGetCurrentIrql() != PASSIVE_LEVEL){ > DebugPrint(("*NO PASSIVE_LEVEL*\n")); > return NULL; > } > > // If ProcessPointer points to current process, no problem! > // But we are called from the ProcessNotifyCallback, so when > // a new process is going to be created we need to get the > // new Process object. > uLong = PsLookupProcessByProcessId((ULONG)hProcessId, &ProcessPointer); > if (!NT_SUCCESS(uLong)) > { > DebugPrint(("*PsLookupProcessByProcessId Failed 0x%x\n*", uLong)); > return NULL; > } > > try > { > uLong = (ULONG)(PVOID *) ProcessPointer; > > if(uLong == 0 || uLong == 0xFFFFFFFF) { > DebugPrint(("*Invalid EPROCESS\n*")); > return 0; > } > > //PEB > // It's XP in this case > uLong += BASE_PROCESS_PEB_OFFSET; > > if((uLong = *(ULONG*)uLong) == 0){ > DebugPrint(("*PebBaseAddr is NULL\n*")); > return 0; > } > > // Peb->PRTL_USER_PROCESS_PARAMETERS > uLong += BASE_PEB_PROCESS_PARAMETER_OFFSET; > if ((uLong = *(ULONG*)uLong) == 0){ > DebugPrint(("*PRTL_USER_PROCESS_PARAMETERS is NULL\n*")); > return 0; > } > > try > { > // On dereferencing the ImagePathName member the exception is raised > // However the Length member is accessable and counts the correct > // number of bytes, so the buffer should cointain data. > // PRTL_USER_PROCESS_PARAMETERS->ImagePathName > uLong += BASE_PROCESS_PARAMETER_FULL_IMAGE_NAME; > if ((uLong = *(ULONG*)uLong) == 0){ > DebugPrint(("*ImagePathName is NULL\n*")); > return NULL; > } > DebugPrint(("ImageName %ws\n", (PCWSTR)uLong)); > return (PCWSTR)uLong; > } > except(EXCEPTION_EXECUTE_HANDLER) > { > uLong = GetExceptionCode(); > DebugPrint(( > "Exception while accessing ImagePathName.Buffer 0X%08X \n", uLong)); > } > } finally { > ObDereferenceObject(ProcessPointer); > } > return 0; > } > > ----- > > I tried KeAttachProcess()/KeDetachProcess() but no change, ZwReadVirtualMemory() > also returns an exception status. > > Hopefully someone can help. > > Arno Garrels
From: Arno Garrels on 11 Jan 2007 17:47 anton bassov wrote: > > At this point you will be able to get UNICODE_STRING that hold s the > full path to the image file on the disk.... Thanks for the speedy reply. However I don't see any difference, the snippet I posted works fine in the current/caller process. AFAIR I tried to get the PebBaseAddress by ZwQueryInformationProcess() as well but that didn't make a difference. > > I make an assumption that you are obtaining the path of the caller > process. Yup > If you want to obtain the path of some other process, you > have to attach your thread to its address space with > KeStackAttachProcess() before you access PEB. Well, I tried KeAttachProcess() before accessing the PEB, it should switch to the context of the other process, I've not yet tried KeStackAttachProcess(), is this the winning point? Arno Garrels
From: anton bassov on 11 Jan 2007 18:21 > However I don't see any difference, Try to do it the way I say - you will see the difference right on the spot..... > the snippet I posted works fine in the current/caller process. If this is the case, how would you explain the excerpt below then???? [begin quote] Here is a Q&D snippet that works in current process but raises an exception while accessing the ImagePathName->Buffer member. [end quote] The only reason why I provided structure declarations is to make you understand that there is a bug in your code - image path is UNICODE_STRING and not PUNICODE_STRING, so that it should be accessed as 'ImagePathName.Buffer' , rather than 'ImagePathName->Buffer'...... The line 'ImagePathName->Buffer' is the only reason for the exception. In general, it is better to overlay structures on memory blocks, rather than just using offsets. Such approach may save you an awful lot of time - it may take quite a while to find a bug like that, because people normally suspect a problem to lie somewhere else.... Anton Bassov Arno Garrels wrote: > anton bassov wrote: > > > > At this point you will be able to get UNICODE_STRING that hold s the > > full path to the image file on the disk.... > > Thanks for the speedy reply. However I don't see any difference, the > snippet I posted works fine in the current/caller process. AFAIR I tried > to get the PebBaseAddress by ZwQueryInformationProcess() as well but > that didn't make a difference. > > > > > I make an assumption that you are obtaining the path of the caller > > process. > > Yup > > > If you want to obtain the path of some other process, you > > have to attach your thread to its address space with > > KeStackAttachProcess() before you access PEB. > > Well, I tried KeAttachProcess() before accessing the PEB, it should > switch to the context of the other process, I've not yet tried > KeStackAttachProcess(), is this the winning point? > > Arno Garrels
From: Arno Garrels on 12 Jan 2007 03:37 anton bassov wrote: > The only reason why I provided structure declarations is to make you > understand that there is a bug in your code - image path is > UNICODE_STRING and not > PUNICODE_STRING, so that it should be accessed as > 'ImagePathName.Buffer' , rather than > 'ImagePathName->Buffer'...... I do not see a bug, it's just a typo in the comment! #define BASE_PROCESS_PARAMETER_FULL_IMAGE_NAME 0x003C 0:000> !kdex2x86.strct _RTL_USER_PROCESS_PARAMETERS struct _RTL_USER_PROCESS_PARAMETERS (sizeof=656) +000 uint32 MaximumLength +004 uint32 Length +008 uint32 Flags +00c uint32 DebugFlags +010 void *ConsoleHandle +014 uint32 ConsoleFlags +018 void *StandardInput +01c void *StandardOutput +020 void *StandardError +024 struct _CURDIR CurrentDirectory +024 struct _UNICODE_STRING DosPath +024 uint16 Length +026 uint16 MaximumLength +028 uint16 *Buffer +02c void *Handle +030 struct _UNICODE_STRING DllPath +030 uint16 Length +032 uint16 MaximumLength +034 uint16 *Buffer +038 struct _UNICODE_STRING ImagePathName +038 uint16 Length +03a uint16 MaximumLength +03c uint16 *Buffer > In general, it is better to overlay structures on memory > blocks, rather than just using offsets. Agreed, but using structures gives the same exception. Again, it works when called in current process! The exception is raised when current context is parent context, upon accessing the Buffer member of the UNICODE_STRING structure. In other words the same always works with PsGetCurrentProcess() as well as when the process is terminated. Accessing the Length member is no problem also it always contains the correct number of bytes. KeStackAttachProcess() as well as KeAttachProcess() do not change anything. Arno Garrels
|
Next
|
Last
Pages: 1 2 Prev: fltmgr.sys PDB and - fltkd WinDBG extension not working (windows XP) ... Next: RPC memory leak under Vista |