Discussion:
retrieving current process Full Image Path Name in kernel mode
(too old to reply)
Alexander
2006-01-05 14:33:40 UTC
Permalink
Hi all,

I want to retrieve, in a kernel driver , the full image path name for
the current process, without using PSAPI.lib (only works in user mode).

I use the following strategy:
I use ZwQueryInformationProcess to retrieve a pointer to
PROCESS_BASIC_INFORMATION structure. Now, from here we obtain the
PebBAseAddress field; from this we retrieve a pointer to a
RTL_USER_PROCESS_PARAMETERS structure called ProcessParametes. from
this structure is possible to extract the ImagePathName.Buffer field
(the type is WCHAR).

Here is my code:

---------------------------------------
PROCESS_BASIC_INFORMATION ProcInfo;
PPEB myPEB;
PRTL_USER_PROCESS_PARAMETERS pupp = NULL;
RTL_USER_PROCESS_PARAMETERS procParams;
ULONG cbRet, ret;
CHAR s3[256];
WCHAR wstr[MAX_PATH];

hProcess = NtCurrentProcess();

if( ProcessNameOffset )
{
pid = (ULONG)PsGetCurrentProcessId();
if(pid==4) //System process
{
strcpy( PathImage, "System - no path" );
return;
}

if(!NT_SUCCESS(ntStatus = ZwQueryInformationProcess(
hProcess,
ProcessBasicInformation,
&ProcInfo,
sizeof(ProcInfo),
&cbRet))) {
DbgPrint("Error1");
return; }

if ((myPEB = (PEB*)ProcInfo.PebBaseAddress)!=NULL) {
pupp = myPEB->ProcessParameters;
if (pupp) {
DbgPrint("%ws", pupp->ImagePathName.Buffer);
}

/* in this way the complete path is correctly printed on DbgView,
when I try to access it I get BSOD: e.g. if I try to do
sprintf(s3,"%ws",pupp->ImagePathName.Buffer)
I get BSOD.
*/

/* Adding this code... */

if(!NT_SUCCESS(ntStatus = ZwReadVirtualMemory(
hProcess,
pupp->ImagePathName.Buffer,
&wstr,
pupp->ImagePathName.Length,
&cbRet)))
{
sprintf(PathImage, "Error2 - code: %d\n", ntStatus);
return; }

wstr[procParams.ImagePathName.Length / sizeof(WCHAR)] = 0;

//DbgPrint( "%ws",wstr);

sprintf(s3,"%ws",wstr);
/*--------------------------------------------------------*/

...with ZwReadVirtualMemory I retrieve in wstr a copy of the path , and
I can use it in any way. The problem is that this method doesn't work
for every calling process; this function often returns the NTSTATUS
code -1073741819 (corrisponding to STATUS_ACCESS_VIOLATION).

I just want to discover how to avoid this error, and why this is
generated...

If someone knows any other working solution to my problem , or an
alternative way to get the complete image path forma kernel driver
please tell me...

Alexander
Don Burn
2006-01-05 14:53:24 UTC
Permalink
The PEB is not docuemtented using it is a risk. There are three ways to
tackle this:

1. Have a service to support the driver, and use the PSAPI.lib to get the
info, this works on all versions of Windows.

2. Build your own conversion table, based on the PsSetXXXNotifyRoutine
calls, this works on 2000 and up.

3. On XP and later use the undocumented PsGetProcessImageFileName. This is
also not documented, but if you search the web you can probably find the
info.
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Post by Alexander
Hi all,
I want to retrieve, in a kernel driver , the full image path name for
the current process, without using PSAPI.lib (only works in user mode).
I use ZwQueryInformationProcess to retrieve a pointer to
PROCESS_BASIC_INFORMATION structure. Now, from here we obtain the
PebBAseAddress field; from this we retrieve a pointer to a
RTL_USER_PROCESS_PARAMETERS structure called ProcessParametes. from
this structure is possible to extract the ImagePathName.Buffer field
(the type is WCHAR).
---------------------------------------
PROCESS_BASIC_INFORMATION ProcInfo;
PPEB myPEB;
PRTL_USER_PROCESS_PARAMETERS pupp = NULL;
RTL_USER_PROCESS_PARAMETERS procParams;
ULONG cbRet, ret;
CHAR s3[256];
WCHAR wstr[MAX_PATH];
hProcess = NtCurrentProcess();
if( ProcessNameOffset )
{
pid = (ULONG)PsGetCurrentProcessId();
if(pid==4) //System process
{
strcpy( PathImage, "System - no path" );
return;
}
if(!NT_SUCCESS(ntStatus = ZwQueryInformationProcess(
hProcess,
ProcessBasicInformation,
&ProcInfo,
sizeof(ProcInfo),
&cbRet))) {
DbgPrint("Error1");
return; }
if ((myPEB = (PEB*)ProcInfo.PebBaseAddress)!=NULL) {
pupp = myPEB->ProcessParameters;
if (pupp) {
DbgPrint("%ws", pupp->ImagePathName.Buffer);
}
/* in this way the complete path is correctly printed on DbgView,
when I try to access it I get BSOD: e.g. if I try to do
sprintf(s3,"%ws",pupp->ImagePathName.Buffer)
I get BSOD.
*/
/* Adding this code... */
if(!NT_SUCCESS(ntStatus = ZwReadVirtualMemory(
hProcess,
pupp->ImagePathName.Buffer,
&wstr,
pupp->ImagePathName.Length,
&cbRet)))
{
sprintf(PathImage, "Error2 - code: %d\n", ntStatus);
return; }
wstr[procParams.ImagePathName.Length / sizeof(WCHAR)] = 0;
//DbgPrint( "%ws",wstr);
sprintf(s3,"%ws",wstr);
/*--------------------------------------------------------*/
...with ZwReadVirtualMemory I retrieve in wstr a copy of the path , and
I can use it in any way. The problem is that this method doesn't work
for every calling process; this function often returns the NTSTATUS
code -1073741819 (corrisponding to STATUS_ACCESS_VIOLATION).
I just want to discover how to avoid this error, and why this is
generated...
If someone knows any other working solution to my problem , or an
alternative way to get the complete image path forma kernel driver
please tell me...
Alexander
Alexander
2006-01-05 15:33:06 UTC
Permalink
1. We can't use a service to support the driver , we need only kernel
mode methods to do it

2. Can you give me more information about this method, or a short
example code?

3. That routine gets only the ImagePathName from the EPROCESS...we need
the full path of the process image instead (e.g.
"c:\Windows\system\afile.exe") .
Don Burn
2006-01-05 15:40:04 UTC
Permalink
Post by Alexander
1. We can't use a service to support the driver , we need only kernel
mode methods to do it
Why?
Post by Alexander
2. Can you give me more information about this method, or a short
example code?
Build a table with callbacks from PsSetCreateProcessNotify to create or
destroy an entry. Use the first callback from PsSetLoadImageNotify for a
given process to retrieve the pathname of the file and put it in the table.
Post by Alexander
3. That routine gets only the ImagePathName from the EPROCESS...we need
the full path of the process image instead (e.g.
"c:\Windows\system\afile.exe") .
The undocumented routine returned the full path, Microsoft uses this in
several drivers, this is one that should be documented.
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Alexander
2006-01-05 15:57:55 UTC
Permalink
Have you an idea about the error that occurs in my code? I get
correctly the full path, but only for about 40% of processes
Post by Don Burn
The undocumented routine returned the full path, Microsoft uses this in
several drivers, this is one that should be documented.

Please can you tell me where can I find any infos about this function?
Can you show me a short code to show this, or a link where I can find
some code or suggestions? How can I use it without getting the
'undefined' error? What do I have to include?
Don Burn
2006-01-05 16:02:38 UTC
Permalink
Try:

char *PsGetProcessImageFileName( PEPROCESS proc );
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Post by Don Burn
Post by Alexander
1. We can't use a service to support the driver , we need only kernel
mode methods to do it
Why?
Post by Alexander
2. Can you give me more information about this method, or a short
example code?
Build a table with callbacks from PsSetCreateProcessNotify to create or
destroy an entry. Use the first callback from PsSetLoadImageNotify for a
given process to retrieve the pathname of the file and put it in the table.
Post by Alexander
3. That routine gets only the ImagePathName from the EPROCESS...we need
the full path of the process image instead (e.g.
"c:\Windows\system\afile.exe") .
The undocumented routine returned the full path, Microsoft uses this in
several drivers, this is one that should be documented.
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Alexander
2006-01-05 16:10:21 UTC
Permalink
I tried it with:

DbgPrint("Image: %s", PsGetProcessImageFileName(curproc));

and it returns only the name of the executable file (e.g." firefox.exe
" )...

How can I make it return the full path?
Don Burn
2006-01-05 16:14:00 UTC
Permalink
I haven't used it much or seen this behavior. I would go with the service
or building your own table at this point.
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Post by Alexander
DbgPrint("Image: %s", PsGetProcessImageFileName(curproc));
and it returns only the name of the executable file (e.g." firefox.exe
" )...
How can I make it return the full path?
Maxim S. Shatskih
2006-01-06 13:05:16 UTC
Permalink
This does not return the full path.
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
***@storagecraft.com
http://www.storagecraft.com
Post by Don Burn
char *PsGetProcessImageFileName( PEPROCESS proc );
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Post by Don Burn
Post by Alexander
1. We can't use a service to support the driver , we need only kernel
mode methods to do it
Why?
Post by Alexander
2. Can you give me more information about this method, or a short
example code?
Build a table with callbacks from PsSetCreateProcessNotify to create or
destroy an entry. Use the first callback from PsSetLoadImageNotify for a
given process to retrieve the pathname of the file and put it in the table.
Post by Alexander
3. That routine gets only the ImagePathName from the EPROCESS...we need
the full path of the process image instead (e.g.
"c:\Windows\system\afile.exe") .
The undocumented routine returned the full path, Microsoft uses this in
several drivers, this is one that should be documented.
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Maxim S. Shatskih
2006-01-05 15:43:48 UTC
Permalink
Post by Don Burn
1. Have a service to support the driver, and use the PSAPI.lib to get the
info, this works on all versions of Windows.
PSAPI does exactly the same. Nevertheless, the Windows Firewall service uses
exactly the way you have described.
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
***@storagecraft.com
http://www.storagecraft.com
Alexander
2006-01-05 15:59:47 UTC
Permalink
I believe you at all! But I am in a kernel driver, and I can't use
PSAPI in kernel mode...
Don Burn
2006-01-05 16:05:34 UTC
Permalink
So use a service and an inverted call to it to use the PSAPI code. This is
done by a ton of products.

For all of this remember the path is not a valid security check. It is way
too easy to create a program with a known path that is not the "blessed
program". Search the web and the groups and you will see multiple
discussions of this.
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Post by Alexander
I believe you at all! But I am in a kernel driver, and I can't use
PSAPI in kernel mode...
Frederick
2006-01-05 16:36:11 UTC
Permalink
Post by Don Burn
The PEB is not docuemtented using it is a risk. There are three ways to
1. Have a service to support the driver, and use the PSAPI.lib to get the
info, this works on all versions of Windows.
Slow. I'm not sure what planet you (and the others here who also
recommend going to service for every single "semi undocumented" event)
are on, but say there is something which occurs many times, going to the
old service "every now and then" to get an updated list, even if you
cache it (coherency is then an issue) at some point, is slower than
doing it all in kernel mode.

Sure in this particular case you could setup a callback from
PsSetXXXNotifyRoutine and only get the list from the service when a
create occurs then store it, but how much bulk do you want to add to
your driver+service when it can all be done in kernel mode on every
single NT version, with less than 50 lines of code?
Post by Don Burn
2. Build your own conversion table, based on the PsSetXXXNotifyRoutine
calls, this works on 2000 and up.
So I guess create a boot driver which puts its callback in there, and
hope every process ID on the current system is put to your callback?
Nice reliability. "Should work" will go well with your future employers.
Unless you use this #2 as I said above, it is useless due to coherency.
Post by Don Burn
3. On XP and later use the undocumented PsGetProcessImageFileName. This is
also not documented, but if you search the web you can probably find the
info.
...
Don Burn
2006-01-05 16:55:15 UTC
Permalink
Fredrick,

I realize you are not happy with me since I won't give you my
techniques and I rapped your friends at Ghost Security. But lets no spill
this over to any posting on this newgroup.

As far as your analysis below, please give some quantitative data of the
service versus the the hacks needed to safely access the PEB. I never
claimed it was lightening fast, but in this case the cost versus the create
process is low.

Approach 2 is reliable, you do want to start the driver fairly early,
and yes there is a small cost for the storage of the path. I don't know why
you believe it sometimes works.
--
Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
Remove StopSpam from the email to reply
Post by Don Burn
The PEB is not docuemtented using it is a risk. There are three ways to
1. Have a service to support the driver, and use the PSAPI.lib to get
the info, this works on all versions of Windows.
Slow. I'm not sure what planet you (and the others here who also recommend
going to service for every single "semi undocumented" event) are on, but
say there is something which occurs many times, going to the old service
"every now and then" to get an updated list, even if you cache it
(coherency is then an issue) at some point, is slower than doing it all in
kernel mode.
Sure in this particular case you could setup a callback from
PsSetXXXNotifyRoutine and only get the list from the service when a create
occurs then store it, but how much bulk do you want to add to your
driver+service when it can all be done in kernel mode on every single NT
version, with less than 50 lines of code?
Post by Don Burn
2. Build your own conversion table, based on the PsSetXXXNotifyRoutine
calls, this works on 2000 and up.
So I guess create a boot driver which puts its callback in there, and hope
every process ID on the current system is put to your callback? Nice
reliability. "Should work" will go well with your future employers. Unless
you use this #2 as I said above, it is useless due to coherency.
Post by Don Burn
3. On XP and later use the undocumented PsGetProcessImageFileName. This
is also not documented, but if you search the web you can probably find
the info.
...
Frederick
2006-01-05 18:02:52 UTC
Permalink
Post by Don Burn
Fredrick,
I realize you are not happy with me since I won't give you my
techniques and I rapped your friends at Ghost Security. But lets no spill
this over to any posting on this newgroup.
Don, you are entitled to your own opinions on whatever you want, and the
only reason I posted about Ghost Security is because a lot of you
cluebats (my opinion) said it was "near impossible" or "very hard" to
hook on XP64.

Of course since you are up to date on all kernel events you already knew
someone had gone and made it work, making my post quite pointless for
you, right? I'm sorry that it upsets you that someone has hooked XP64
and it goes against your ethos, can you build a bridge and get over it?

The problem isn't what you said any one time Don, its your general
attitude towards anything which maybe you don't quite possibly
understand to the fullest extent. "oh I don't know what he means, they
must be hacks"
Post by Don Burn
As far as your analysis below, please give some quantitative data of the
service versus the the hacks needed to safely access the PEB. I never
claimed it was lightening fast, but in this case the cost versus the create
process is low.
"hacks" eh. I'm sure your future employers reading this forum will love
to know you will only take the documented approach, even if it means
increasing the time taken to make driver, increasing the complexity and
decreasing performance. Now I know why I need a 3GHz machine just to
connect to the internet, people like you. ;)

Even though your "documented" method might only add 10-100ms of time to
a CreateProcess and 4-8KB of more memory usage, it could be a big
percentage of total time in relation to the whole event. Now lets say
there are 5 drivers like yours on the system, or 10, or 20. Doesn't
scale well does it. Now everytime I try and run a program I have this
extra unneeded delay because percy jones here was being careful about
documented approaches to things.

But damn, lack of performance and increased complexity are things which
documented peeps like yourself embrace as ways to increase your stock
portfolio in intel or amd. If only I was hiring semi-incompetent,
know-it-all, dont-understand-performance-issues kernel developers, you'd
be my first pick.
Post by Don Burn
Approach 2 is reliable, you do want to start the driver fairly early,
and yes there is a small cost for the storage of the path. I don't know why
you believe it sometimes works.
"Why it sometimes works" ? Well unless it is a boot driver, it will
randomly miss some early process creations, even as a SYSTEM driver. In
this case it won't be a coherent view of all processes, and you'll need
to do another check for safety, which makes the whole thing of relying
on ONLY this very useless. As I pointed out. Plus you made no mention of
being a BOOT driver which is why I thought the OP should know its a
completely useless method unless it is a boot driver. You might want to
go check the differences between a BOOT and SYSTEM drivers before replying.
Maxim S. Shatskih
2006-01-06 12:55:41 UTC
Permalink
Post by Frederick
"hacks" eh. I'm sure your future employers reading this forum will love
to know you will only take the documented approach, even if it means
increasing the time taken to make driver, increasing the complexity and
decreasing performance.
In these cases - yes, normal employers will take the documented way. Timeframes
(of 1-2 day) and very minor (unmeasurable) perf issues are surely nothing
compared to product stability.

The employer will drown in interop issues with other software otherwise.

For me, using hooks to get the EXE pathname is a no-no. Use PSAPI. If you have
user-mode parts of the package anyway - then use PSAPI from them.

If you have no - then, well, correct direct access to PEB from kmode - guarded
by try-except, and never crashing if PEB is junk - is also an idea.

But hooking for such a purpose?
Post by Frederick
Now I know why I need a 3GHz machine just to
connect to the internet, people like you. ;)
No, this is due to resident security software only. PII-600 is OK to browse the
Internet otherwise. :)
Post by Frederick
Even though your "documented" method might only add 10-100ms of time to
a CreateProcess and 4-8KB of more memory usage
No. 100 CPU instructions each CreateProcess, not more.
Post by Frederick
portfolio in intel or amd. If only I was hiring semi-incompetent,
know-it-all, dont-understand-performance-issues kernel developers,
The only other way is to create dirty products, notorios for interops and for
decreases of the OS stability.
Post by Frederick
being a BOOT driver which is why I thought the OP should know its a
completely useless method unless it is a boot driver.
Why boot drivers are bad?
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
***@storagecraft.com
http://www.storagecraft.com
PCAUSA
2006-01-05 17:04:11 UTC
Permalink
Frederick,

Do understand that there are coherency issues even with a kerenl-mode
implementation. Certainly, the risk is smaller if you don't go through
user-mode but the risk is still there.

I hope that you really understand how easily this can be spoofed and
the effort (MDL hash, etc) that you would have to expend to attempt to
verify that you aren't being spoofed.

There is also the issue of application/driver combinations where the
the application's supporting driver starts a kernel thread in the
system process to do all the work. (This is common in AV and networking
products). In this case the "process" that you fetch (any method you
come up with...) will always the the "System". Not very helpful.

I would agree with the ongoing advice being given here that use of a
companion service and documented APIs is the preferred route. I would
also agree that many of us are facing legitimate issues that simply
cannot be dealt with using the information provided by Microsoft. In my
most recent encounter, I had to set TCP/IP route entries from within a
driver and there wasn't an obvious solution.

Good luck,

Thomas F. Divine, Windows DDK MVP
http://www.pcausa.com
Frederick
2006-01-05 17:40:27 UTC
Permalink
Post by PCAUSA
Frederick,
Do understand that there are coherency issues even with a kerenl-mode
implementation. Certainly, the risk is smaller if you don't go through
user-mode but the risk is still there.
I hope that you really understand how easily this can be spoofed and
the effort (MDL hash, etc) that you would have to expend to attempt to
verify that you aren't being spoofed.
There is also the issue of application/driver combinations where the
the application's supporting driver starts a kernel thread in the
system process to do all the work. (This is common in AV and networking
products). In this case the "process" that you fetch (any method you
come up with...) will always the the "System". Not very helpful.
I would agree with the ongoing advice being given here that use of a
companion service and documented APIs is the preferred route. I would
also agree that many of us are facing legitimate issues that simply
cannot be dealt with using the information provided by Microsoft. In my
most recent encounter, I had to set TCP/IP route entries from within a
driver and there wasn't an obvious solution.
Good luck,
Thomas F. Divine, Windows DDK MVP
http://www.pcausa.com
Hi Thomas, of course without a way to secure the process name (hashing
on creation is one method) it won't be secure. As far as I am aware the
original poster was asking how to get the process name, I guess I could
try and wonder why, or maybe I could help him achieve his goal. I don't
see what a supporting kernel worker thread has to do with process
creation however.

You can ask me what is better, working out some communication scheme
using events and IO to get a process list and then reading and storing
the list, co-ordinating an EXE and a driver OR calling a simple function
from kernel mode which gives you your desired information. Seriously I
don't care if its undocumented or not, if it works it works, if it
breaks, a work-around will be needed, big deal, Microsoft CANNOT remove
the basic way something works, all they might do is possibly move a
pointer location or something else similar, which is 5 minutes work to
fix (so far I have never had to fix anything like this).

So far from using this method in some of my drivers it has not broken
since even Windows 2000 was released, nearly 5 years old code, done
once, working fine all the time and now. Oh but I guess because the
possibility that it *might* break sometime is enough to not use it...
just remember even Microsoft's documented API's sometimes BREAK.

It makes me laugh that some people will seek the documented way to do
everything, even if it means their code complexity and resource use
increases whilst performance decreases. Good logic. Glad the world is
using these drivers and other software *rolls eyes* .
Carl Woodward
2006-01-05 21:36:44 UTC
Permalink
Microsoft CANNOT remove the basic way something works, all they might do
is possibly move a pointer location or something else similar, which is 5
minutes work to fix (so far I have never had to fix anything like this).
So you are assuming that an undocumented structure has a pointer that you
are going to dereference in kernel mode (as in the original postees
example)... and everything goes blue... Whilst I whole heartedly agree it
would only be a 5 minute fix, its the consequences of your assumption that
cause problems. I'm sure your customers would be very thankful for the
attractive shade of blue denial of service attack you just gave them because
they unwisely installed a hotfix. I've seen it happen...

Yes I agree the changes are rare, but the problems associated with this kind
of approach are widely acknowledged, even by undocumented internals guys
like Butler and Hoglund in their Rootkits book.

We do periodically have to go all round the houses to achieve something in a
documented way, but I'm pretty sure customers prefer that to some or all
parts of their systems not working correctly because Microsoft changes
something we were relying on.

Carly
Frederick
2006-01-06 00:31:57 UTC
Permalink
Post by Carl Woodward
Microsoft CANNOT remove the basic way something works, all they might do
is possibly move a pointer location or something else similar, which is 5
minutes work to fix (so far I have never had to fix anything like this).
So you are assuming that an undocumented structure has a pointer that you
are going to dereference in kernel mode (as in the original postees
example)... and everything goes blue... Whilst I whole heartedly agree it
would only be a 5 minute fix, its the consequences of your assumption that
cause problems. I'm sure your customers would be very thankful for the
attractive shade of blue denial of service attack you just gave them because
they unwisely installed a hotfix. I've seen it happen...
Yes I agree the changes are rare, but the problems associated with this kind
of approach are widely acknowledged, even by undocumented internals guys
like Butler and Hoglund in their Rootkits book.
We do periodically have to go all round the houses to achieve something in a
documented way, but I'm pretty sure customers prefer that to some or all
parts of their systems not working correctly because Microsoft changes
something we were relying on.
Carly
Hi Carl,

Incase it isn't obvious, the method uses ReadProcessMemory to fill
buffers. No pointer dereferencing should occur, unlike the original
posters example. Why? For the exact same reason you mentioned.

Please don't assume because something is undocumented that it will BSOD
your machine, there are ways to handle these things so that in a worst
case situation all that will happen is your code won't work as it should
(ie. it will error and return). But thanks anyhow for trying to
understand the concepts here.
Carl Woodward
2006-01-06 01:22:33 UTC
Permalink
Post by Frederick
Post by Carl Woodward
Microsoft CANNOT remove the basic way something works, all they might do
is possibly move a pointer location or something else similar, which is
5 minutes work to fix (so far I have never had to fix anything like
this).
So you are assuming that an undocumented structure has a pointer that you
are going to dereference in kernel mode (as in the original postees
example)... and everything goes blue... Whilst I whole heartedly agree it
would only be a 5 minute fix, its the consequences of your assumption
that cause problems. I'm sure your customers would be very thankful for
the attractive shade of blue denial of service attack you just gave them
because they unwisely installed a hotfix. I've seen it happen...
Yes I agree the changes are rare, but the problems associated with this
kind of approach are widely acknowledged, even by undocumented internals
guys like Butler and Hoglund in their Rootkits book.
We do periodically have to go all round the houses to achieve something
in a documented way, but I'm pretty sure customers prefer that to some or
all parts of their systems not working correctly because Microsoft
changes something we were relying on.
Carly
Hi Carl,
Incase it isn't obvious, the method uses ReadProcessMemory to fill
buffers. No pointer dereferencing should occur, unlike the original
posters example. Why? For the exact same reason you mentioned.
ReadProcessMemory is not available in kernel mode.

It was a general point.
Post by Frederick
Please don't assume because something is undocumented that it will BSOD
your machine, there are ways to handle these things so that in a worst
case situation all that will happen is your code won't work as it should
(ie. it will error and return). But thanks anyhow for trying to understand
the concepts here.
I didn't say undocumented always causes blue screens of death. I gave a
concrete example of how it can happen and the fact that I have seen it
happen. I was warning against taking unnecessary risks and using
undocumented routines and data types, but thanks anyhow for trying to
understand my post.
Frederick
2006-01-06 05:02:57 UTC
Permalink
Post by Carl Woodward
Post by Frederick
Incase it isn't obvious, the method uses ReadProcessMemory to fill
buffers. No pointer dereferencing should occur, unlike the original
posters example. Why? For the exact same reason you mentioned.
ReadProcessMemory is not available in kernel mode.
It was a general point.
ReadProcessMemory *IS* available, you just need to load it dynamically.
Post by Carl Woodward
Post by Frederick
Please don't assume because something is undocumented that it will BSOD
your machine, there are ways to handle these things so that in a worst
case situation all that will happen is your code won't work as it should
(ie. it will error and return). But thanks anyhow for trying to understand
the concepts here.
I didn't say undocumented always causes blue screens of death. I gave a
concrete example of how it can happen and the fact that I have seen it
happen. I was warning against taking unnecessary risks and using
undocumented routines and data types, but thanks anyhow for trying to
understand my post.
No you implied *MY* method is dereferencing a pointer simply because the
original poster did. These sorts of issues aren't related to
undocumented/documented functions/structures, but rather to how
experienced a coder you are. I don't see how these items are related.
Did you know you can cause a BSOD using all documented functions and
structures? Yeah it's true.
Carl Woodward
2006-01-06 12:10:26 UTC
Permalink
Post by Frederick
Post by Carl Woodward
Post by Frederick
Incase it isn't obvious, the method uses ReadProcessMemory to fill
buffers. No pointer dereferencing should occur, unlike the original
posters example. Why? For the exact same reason you mentioned.
ReadProcessMemory is not available in kernel mode.
It was a general point.
ReadProcessMemory *IS* available, you just need to load it dynamically.
nt!NtReadVirtualMemory is available in kernel mode.
kernel32!ReadProcessMemory isn't unless you are in the context of a user
mode process and call it using parameters (and preferably code) from a user
mode virtual region allocated with ZwAllocateVirtualMemory. I used to create
processes from kernel mode in Windows 2000 in this way. Needless to say,
this approach is just asking for trouble.
Post by Frederick
Post by Carl Woodward
Post by Frederick
Please don't assume because something is undocumented that it will BSOD
your machine, there are ways to handle these things so that in a worst
case situation all that will happen is your code won't work as it
should (ie. it will error and return). But thanks anyhow for trying to
understand the concepts here.
I didn't say undocumented always causes blue screens of death. I gave a
concrete example of how it can happen and the fact that I have seen it
happen. I was warning against taking unnecessary risks and using
undocumented routines and data types, but thanks anyhow for trying to
understand my post.
No you implied *MY* method is dereferencing a pointer simply because the
original poster did. These sorts of issues aren't related to
undocumented/documented functions/structures, but rather to how
experienced a coder you are. I don't see how these items are related. Did
you know you can cause a BSOD using all documented functions and
structures? Yeah it's true.
I have been writing NT drivers for a very long time, I have a pretty good
idea of what can cause a blue screen of death!

Carly
Carl Woodward
2006-01-06 01:57:53 UTC
Permalink
Post by Frederick
Please don't assume because something is undocumented that it will BSOD
your machine, there are ways to handle these things so that in a worst
case situation all that will happen is your code won't work as it should
(ie. it will error and return).
Even if your code fails safe, it still doesn't do what it says on the tin;
if is is critical code and it stops working, that is a denial of service
attack that was (in effect) intentionally written by the developer. I
personally dont like drivers or software that end up showing error messages
asking me to contact the vendor or wait for developers to produce and update
when Microsoft issues a hotfix or service pack. But then that is just me I
guess... Microsoft goes to quite some lengths that provide APIs services
that are (as far as possible) not going to change. Take PoCallDriver and
PoStartNextPowerIrp on Vista for example.

I realise that the kinds of changes that affect the approaches you advocate
are rare and probably run inline with major step changes in the OS (in which
case code alteration may be necessary anyway) but it is just one extra risk
to take. It doesn't take much to annoy a customer and they have long
memorys. I have had significant problems with Symantec drivers for example,
blue screens through poor coding or improper testing Bug Check 0x20:
KERNEL_APC_PENDING_DURING_EXIT was the most recent one. I now refuse to use
Symantec products, one of those blue screens of death nailed my MFT.

I've spent the last 5 years writing security device drivers for 2000 and XP,
and over the past 3 years each and every undocumented part was replaced with
a documented variant - no discernable difference performance wise. The
reason I made the changes then? Because twice, assumptions about
undocumented aspects of the operating system were no longer valid. Granted I
was doing very different things to what we have been dicussing, but the
point holds. If security is about Confidentiality, Integrity and
Availability then *clearly* doing anything that increases the risk of
damaging any of these three key tenants is unwise. That is my two penneth.

Anyway, this is miles of topic and it has been done to death! I guess we'll
just have to agree to disagree!

Carly
Frederick
2006-01-06 05:13:04 UTC
Permalink
Post by Carl Woodward
Post by Frederick
Please don't assume because something is undocumented that it will BSOD
your machine, there are ways to handle these things so that in a worst
case situation all that will happen is your code won't work as it should
(ie. it will error and return).
Even if your code fails safe, it still doesn't do what it says on the tin;
if is is critical code and it stops working, that is a denial of service
attack that was (in effect) intentionally written by the developer. I
personally dont like drivers or software that end up showing error messages
asking me to contact the vendor or wait for developers to produce and update
when Microsoft issues a hotfix or service pack. But then that is just me I
guess... Microsoft goes to quite some lengths that provide APIs services
that are (as far as possible) not going to change. Take PoCallDriver and
PoStartNextPowerIrp on Vista for example.
I realise that the kinds of changes that affect the approaches you advocate
are rare and probably run inline with major step changes in the OS (in which
case code alteration may be necessary anyway) but it is just one extra risk
to take. It doesn't take much to annoy a customer and they have long
memorys. I have had significant problems with Symantec drivers for example,
KERNEL_APC_PENDING_DURING_EXIT was the most recent one. I now refuse to use
Symantec products, one of those blue screens of death nailed my MFT.
I've spent the last 5 years writing security device drivers for 2000 and XP,
and over the past 3 years each and every undocumented part was replaced with
a documented variant - no discernable difference performance wise. The
reason I made the changes then? Because twice, assumptions about
undocumented aspects of the operating system were no longer valid. Granted I
was doing very different things to what we have been dicussing, but the
point holds. If security is about Confidentiality, Integrity and
Availability then *clearly* doing anything that increases the risk of
damaging any of these three key tenants is unwise. That is my two penneth.
Anyway, this is miles of topic and it has been done to death! I guess we'll
just have to agree to disagree!
Carly
Don't get me wrong Carl, it's not like I support writing code which ends
up causing BSOD's or which denies service. The fact is my undocumented
code has never done this. So sit on one side of the fence throwing
sticks at me about :- "my methods" :- whilst I write code which works
well on all the OS's and is simple and bug free. I'll take the middle
ground. You can continue to restrict yourself to the documented side of
the OS, it's your choice, this makes it a fact I can write more
versatile and useful code than you simply because I don't restrict
myself, employers like that.

I agree wholeheartedly with what you are saying, do I increase risk by
using undocumented functions and structures in some places? sure I do
but it's only small (and I have yet to encounter it), but there is
already a risk just by writing code. it's not like if I stick to
documented functions and structures I'd never receive any issues eventually.
PCAUSA
2006-01-06 06:16:38 UTC
Permalink
You know, there was a point in my career when I thought along the same
lines. Hey! This technique has worked reliably since Windows NT 3.51!

As an independent developer, I don't have any end-user customers.
Instead, I license pieces to others. Unfortunately, some of my code
(using undocumented or poorly documented structures...) was licensed to
a fairly large nameless security outfit. They, in turn, had a brand-new
contract to distribute their software on CD to a big telecommunications
outfit.

Then along can XP SP2 and wouldn't you know it! There was one of those
"gotcha's" that caused the code they had been using for years to die a
horrible death on XP SP2.

It changed my attitude when this happened.

If there are thousands of copies out there that are based on
undocumented interfaces, then eventually you're going to get burned
very badly. It's going to happen with your biggest customer at the most
inconvenient time.
Frederick
2006-01-06 06:40:17 UTC
Permalink
Post by PCAUSA
You know, there was a point in my career when I thought along the same
lines. Hey! This technique has worked reliably since Windows NT 3.51!
As an independent developer, I don't have any end-user customers.
Instead, I license pieces to others. Unfortunately, some of my code
(using undocumented or poorly documented structures...) was licensed to
a fairly large nameless security outfit. They, in turn, had a brand-new
contract to distribute their software on CD to a big telecommunications
outfit.
Then along can XP SP2 and wouldn't you know it! There was one of those
"gotcha's" that caused the code they had been using for years to die a
horrible death on XP SP2.
It changed my attitude when this happened.
If there are thousands of copies out there that are based on
undocumented interfaces, then eventually you're going to get burned
very badly. It's going to happen with your biggest customer at the most
inconvenient time.
Hi, thats a good story. Luckily (I guess) my code didn't break on SP2?
Sounds like maybe you were involved in networknig.

From my experience dealing with undocumented features of the OS I
realized there are many different ways you can make it as safe as
possible (still a risk) maybe that's why my code didn't break, or maybe
you are really right on the fringe.

BTW, you could have tested SP2 before the majority of the populace went
out and installed it, allowing you to fix any issues with your code. I
recommend any decent kernel developer does this with any major update
with a SP or a new OS, whether you are going dark with undocumented or not.
Sergei Zhirikov
2006-01-05 18:57:34 UTC
Permalink
Post by Don Burn
3. On XP and later use the undocumented PsGetProcessImageFileName.
By the way, that function appears to be also exported from NTOSKRNL.EXE on
Windows 2000. (SP4, file version 5.0.2195.7071).
And I'm curious, why does it return char*? I thought kernel was all unicode.
What if the file name contains some "strange" characters?
--
Sergei.
Maxim S. Shatskih
2006-01-06 13:02:16 UTC
Permalink
Post by Sergei Zhirikov
Post by Don Burn
3. On XP and later use the undocumented PsGetProcessImageFileName.
By the way, that function appears to be also exported from NTOSKRNL.EXE on
Windows 2000. (SP4, file version 5.0.2195.7071).
And I'm curious, why does it return char*? I thought kernel was all unicode.
Correct. It only returns the _short_ image file name (not a full pathname), and
in ANSI encoding. It just returns the pointer to the undocumented EPROCESS
field, which is widely known to be 8.3 and to be ANSI.

The full unicode EXE pathname is kept in user mode PEB (the accompaniying "user
process parameters" structure) only, and PSAPI uses ReadProcessMemory against
this structure to access it.

Debugging tools like TLIST and the Windows Firewall service depend on this.

What Microsoft lacks is:
- the kmode call to get the section object pointer from the VA within the
process
- the kmode call to get PFILE_OBJECT from the section object pointer.

Adding these 2 calls to the kernel can be a good idea, and I envision they
would be absolutely trivial in implementation.
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
***@storagecraft.com
http://www.storagecraft.com
Frederick
2006-01-05 16:50:15 UTC
Permalink
Post by Alexander
Hi all,
I want to retrieve, in a kernel driver , the full image path name for
the current process, without using PSAPI.lib (only works in user mode).
I use ZwQueryInformationProcess to retrieve a pointer to
PROCESS_BASIC_INFORMATION structure. Now, from here we obtain the
PebBAseAddress field; from this we retrieve a pointer to a
RTL_USER_PROCESS_PARAMETERS structure called ProcessParametes. from
this structure is possible to extract the ImagePathName.Buffer field
(the type is WCHAR).
---------------------------------------
PROCESS_BASIC_INFORMATION ProcInfo;
PPEB myPEB;
PRTL_USER_PROCESS_PARAMETERS pupp = NULL;
RTL_USER_PROCESS_PARAMETERS procParams;
ULONG cbRet, ret;
CHAR s3[256];
WCHAR wstr[MAX_PATH];
hProcess = NtCurrentProcess();
if( ProcessNameOffset )
{
pid = (ULONG)PsGetCurrentProcessId();
if(pid==4) //System process
{
strcpy( PathImage, "System - no path" );
return;
}
if(!NT_SUCCESS(ntStatus = ZwQueryInformationProcess(
hProcess,
ProcessBasicInformation,
&ProcInfo,
sizeof(ProcInfo),
&cbRet))) {
DbgPrint("Error1");
return; }
if ((myPEB = (PEB*)ProcInfo.PebBaseAddress)!=NULL) {
pupp = myPEB->ProcessParameters;
if (pupp) {
DbgPrint("%ws", pupp->ImagePathName.Buffer);
}
/* in this way the complete path is correctly printed on DbgView,
when I try to access it I get BSOD: e.g. if I try to do
sprintf(s3,"%ws",pupp->ImagePathName.Buffer)
I get BSOD.
*/
/* Adding this code... */
if(!NT_SUCCESS(ntStatus = ZwReadVirtualMemory(
hProcess,
pupp->ImagePathName.Buffer,
&wstr,
pupp->ImagePathName.Length,
&cbRet)))
{
sprintf(PathImage, "Error2 - code: %d\n", ntStatus);
return; }
wstr[procParams.ImagePathName.Length / sizeof(WCHAR)] = 0;
//DbgPrint( "%ws",wstr);
sprintf(s3,"%ws",wstr);
/*--------------------------------------------------------*/
...with ZwReadVirtualMemory I retrieve in wstr a copy of the path , and
I can use it in any way. The problem is that this method doesn't work
for every calling process; this function often returns the NTSTATUS
code -1073741819 (corrisponding to STATUS_ACCESS_VIOLATION).
I just want to discover how to avoid this error, and why this is
generated...
If someone knows any other working solution to my problem , or an
alternative way to get the complete image path forma kernel driver
please tell me...
Alexander
hi alexander, You are nearly on the right path, except you are missing a
few extra readprocessmemory's (to handle not in same context name grabbing).

Readmemory BasicInfo.PebBaseAddress this into a buffer of about 128
bytes (the peb).

Then readmemory peb.ProcessParameters to get your user parameters

Then do your last Readmemory call as it is

just make sure you do this test before the last readmemory call. this is
just hand written so make sure you do proper pointer arithmetic.


if( (UserParam.Flags & 1) == 0)
{
UserParam.ImagePathName.Buffer+=peb.ProcessParameters;
}
Alexander
2006-01-06 16:47:45 UTC
Permalink
thank you all for your support!

I found a solution to my problem by using ZwQueryInformationProcess
with an undcumented Process Information Class (ProcessImageFileName):

---------------------------------------
if(!NT_SUCCESS(ntStatus = ZwQueryInformationProcess(
hProcess,
ProcessImageFileName,
&wstr,
sizeof(wstr),
&cbRet)))
{
strcpy( PathImage, "Error in getting path!\n" );
//DbgPrint(Error in getting path -- code: %d", ntStatus);
return;
}

sprintf(path, "%wZ", wstr);
//DbgPrint("from ZWQIP: --- path: %s PID = %d", path, pid);
strcpy( PathImage, path );
----------------------------

In this way I get the full path in this form:
\Device\HardDiskVolume0\Windows\System\crsss.exe

and this is exactly what I want! The solution is very simple, the
difficult thing is only to retrieve informations about the undocumented
functions/parameters...
Maxim S. Shatskih
2006-01-06 17:45:07 UTC
Permalink
What are the supported OSes?
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
***@storagecraft.com
http://www.storagecraft.com
Post by Alexander
thank you all for your support!
I found a solution to my problem by using ZwQueryInformationProcess
---------------------------------------
if(!NT_SUCCESS(ntStatus = ZwQueryInformationProcess(
hProcess,
ProcessImageFileName,
&wstr,
sizeof(wstr),
&cbRet)))
{
strcpy( PathImage, "Error in getting path!\n" );
//DbgPrint(Error in getting path -- code: %d", ntStatus);
return;
}
sprintf(path, "%wZ", wstr);
//DbgPrint("from ZWQIP: --- path: %s PID = %d", path, pid);
strcpy( PathImage, path );
----------------------------
\Device\HardDiskVolume0\Windows\System\crsss.exe
and this is exactly what I want! The solution is very simple, the
difficult thing is only to retrieve informations about the undocumented
functions/parameters...
Alexander
2006-01-06 20:22:25 UTC
Permalink
I believe only WinXP... I've found on some forums that the undocumented
Process Information Class I used is defined only in WinXP
Post by Maxim S. Shatskih
What are the supported OSes?
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
http://www.storagecraft.com
Post by Alexander
thank you all for your support!
I found a solution to my problem by using ZwQueryInformationProcess
---------------------------------------
if(!NT_SUCCESS(ntStatus = ZwQueryInformationProcess(
hProcess,
ProcessImageFileName,
&wstr,
sizeof(wstr),
&cbRet)))
{
strcpy( PathImage, "Error in getting path!\n" );
//DbgPrint(Error in getting path -- code: %d", ntStatus);
return;
}
sprintf(path, "%wZ", wstr);
//DbgPrint("from ZWQIP: --- path: %s PID = %d", path, pid);
strcpy( PathImage, path );
----------------------------
\Device\HardDiskVolume0\Windows\System\crsss.exe
and this is exactly what I want! The solution is very simple, the
difficult thing is only to retrieve informations about the undocumented
functions/parameters...
Loading...