PsSetCreateProcessNotifyRoutineEx ImageFileName issue

Hi everyone, I am trying to use PsSetCreateProcessNotifyRoutineEx because it is much easier to acquire the process path (CreateInfo->ImageFileName)

However, I have noticed that the variable type of ImageFileName is PCUNICODE_STRING.
I am trying to send the data up to application layer (C++ console application) and unable to pass the ImageFileName up to the application because there is no such thing as PCUNICODE_STRING for C++ console applications.

Is there anyway I can convert the ImageFileName to some other variable types before allowing me to send it up to application layer? Or is there other ways to do so?

I have tried googling for conversion methods of PCUNICODE_STRING but to no avail, I would really appreciate some help over here, Thanks in advance guys!

See the struct definition. You will find a pointer to the data and the
length of the data.

*ImageFileName*

A pointer to a *UNICODE_STRING*
http:
string
that holds the file name of the executable. If
theFileOpenNameAvailable member
is TRUE, the string specifies the exact file name that is used to open
the executable file. If FileOpenNameAvailable is FALSE, the operating
system might provide only a partial name.
Regards

El lunes, 4 de agosto de 2014, escribió:

> Hi everyone, I am trying to use PsSetCreateProcessNotifyRoutineEx because
> it is much easier to acquire the process path (CreateInfo->ImageFileName)
>
> However, I have noticed that the variable type of ImageFileName is
> PCUNICODE_STRING.
> I am trying to send the data up to application layer (C++ console
> application) and unable to pass the ImageFileName up to the application
> because there is no such thing as PCUNICODE_STRING for C++ console
> applications.
>
> Is there anyway I can convert the ImageFileName to some other variable
> types before allowing me to send it up to application layer? Or is there
> other ways to do so?
>
> I have tried googling for conversion methods of PCUNICODE_STRING but to no
> avail, I would really appreciate some help over here, Thanks in advance
> guys!
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
></http:>

use this api : RtlStringCbCopyUnicodeString

RtlStringCbCopyUnicodeString(WCHAR buffer, lenth of ImageFileName, CreateInfo->ImageFileName);

at ioctl :

RtlCopyMemory(pOutputBuffer, WCHAR buffer, lenth of ImageFileName);

Make sure to 0 terminate in addition when using RtlCopyMemory.
So assuming you have a max buffer size of 256 following code would do what you want:

WCHAR imageName[256];
RtlCopyMemory(imageName, Name->Buffer, min(Name->Length, 256));
imageName [min(Name->Length, 256) / sizeof(WCHAR)] = L’\0’;

While Name is the PCUNICODE_STRING

Thank you everyone for your help, I really appreciate it a lot.

However, I cant quite get the job done, when a process creates, I will pass the process information into a struct named extension, with a few variables for storing the process data, so for example:

extension->processid = processid;
extension->imagename = imagename;

I couldn’t use RtlStringCbCopyUnicodeString as it says the NTSTRSAFE_PWSTR differs in levels of inderection from WCHAR.

As for Ondracek’s solution, do I still need to use RtlStringCbCopyUnicodeString, or just the portion of code you provided? Also, what variable type should I set for my extension->imagename? I set it as WCHAR but I could not pass the imagename over as it says WCHAR differs in levels of inderection from WCHAR *

Pardon me for so many questions, I am relatively new to writing drivers, thank you once again for so much help!

You must mimic the ObQueryNameString function. To do so, the string buffer must immediately follow the UNICODE_STRING in memory. Use the POBJECT_NAME_INFORMATION buffer for this.

ULONG TotalLength = sizeof(UNICODE_STRING) + ImageFileName->MaximumLength;
POBJECT_NAME_INFORMATION ObjectName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(PagedPool,TotalLength,SOME_TAG);

if(ObjectName == NULL){
return STATUS_INSUFFICIENT_RESOURCES;
}
else{
ObjectName.Name.Lengh = ImageFileName->Length;
ObjectName.Name.MaximumLengh = ImageFileName.MaximumLengh;
// here we make the string buffer point just after the UNICODE_STRING
ObjectName.Buffer = (PWCHAR)(ObjectName+1);
// finally we copy the string
RtlCopyMemory(ObjectName->Buffer,ImageFileName->Buffer, ImageFileName->MaximumLength);
return STATUS_SUCCESD;
}

xxxxx@paxi.at wrote:

Make sure to 0 terminate in addition when using RtlCopyMemory.
So assuming you have a max buffer size of 256 following code would do what you want:

WCHAR imageName[256];
RtlCopyMemory(imageName, Name->Buffer, min(Name->Length, 256));
imageName [min(Name->Length, 256) / sizeof(WCHAR)] = L’\0’;

While Name is the PCUNICODE_STRING

Note that UNICODE_STRING.Length is a byte count, and 256 in the
example code is a character count. An additional issue is that the
256 number represents an index beyond the end of the allocated buffer,
and would be overwriting the stack.

WCHAR imageName[256];
RtlCopyMemory( imageName, Name->Buffer, min( Name->Length, sizeof(imageName) ) );
imageName[min( Name->Length, sizeof(imageName) - sizeof(WCHAR) ) / sizeof(WCHAR)] = L’\0’;

Correction:

Sorry for the errors.

ULONG TotalLength = sizeof(UNICODE_STRING) + ImageFileName->MaximumLength;

POBJECT_NAME_INFORMATION ObjectName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(PagedPool,TotalLength,SOME_TAG);

if(ObjectName == NULL){
return STATUS_INSUFFICIENT_RESOURCES; }
else{
ObjectName->Name.Lengh = ImageFileName->Length;
ObjectName->Name
MaximumLengh = ImageFileName.MaximumLengh;

// here we make the string buffer point just after the UNICODE_STRING

ObjectName->Buffer = (PWCHAR)(ObjectName+1);
/
/ finally we copy the string
RtlCopyMemory(ObjectName->Buffer,ImageFileName->Buffer, ImageFileName->MaximumLength);
return STATUS_SUCCESD;
}

Sorry again. This one should be ok.

ULONG TotalLength = sizeof(UNICODE_STRING) + ImageFileName->MaximumLength;

POBJECT_NAME_INFORMATION ObjectName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(PagedPool,TotalLength,SOME_TAG);

if(ObjectName == NULL){
return STATUS_INSUFFICIENT_RESOURCES; }
else{
ObjectName->Name.Lengh = ImageFileName->Length;
ObjectName->Name
MaximumLengh = ImageFileName.MaximumLengh;

// here we make the string buffer point just after the UNICODE_STRING

ObjectName->Name.Buffer = (PWCHAR)(ObjectName+1);
// finally we copy the string
RtlCopyMemory(ObjectName->Name.Buffer,ImageFileName->Buffer, ImageFileName->MaximumLength);
return STATUS_SUCCESS;
}

xxxxx@live.fr wrote:

Sorry again. This one should be ok.

It’s closer, but you still have 4 typos in here, all in one line:

ULONG TotalLength = sizeof(UNICODE_STRING) + ImageFileName->MaximumLength;

POBJECT_NAME_INFORMATION ObjectName = (POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(PagedPool,TotalLength,SOME_TAG);

if(ObjectName == NULL){
return STATUS_INSUFFICIENT_RESOURCES; }
else{
ObjectName->Name.Lengh = ImageFileName->Length;
* ObjectName->Name
MaximumLengh = ImageFileName.MaximumLengh; *

// here we make the string buffer point just after the UNICODE_STRING

ObjectName->Name.Buffer = (PWCHAR)(ObjectName+1);
// finally we copy the string
RtlCopyMemory(ObjectName->Name.Buffer,ImageFileName->Buffer, ImageFileName->MaximumLength);
return STATUS_SUCCESS;
}

ULONG TotalLength = sizeof(OBJECT_NAME_INFORMATION) +
ImageFileName->MaximumLength;
POBJECT_NAME_INFORMATION ObjectName =

(POBJECT_NAME_INFORMATION)ExAllocatePoolWithTag(PagedPool,TotalLength,SOME_TAG);
if( !ObjectName )
return STATUS_INSUFFICIENT_RESOURCES;
else {
ObjectName->Name.Length = 0;
ObjectName->Name.MaximumLength = ImageFileName->MaximumLength;
ObjectName->Name.Buffer = (PWCHAR)(ObjectName+1);
RtlUnicodeStringCopy(&ObjectName->Name, ImageFileName);
return STATUS_SUCCESS;
}


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Great, thanks for your help.

xxxxx@paxi.at wrote:

Make sure to 0 terminate in addition when using RtlCopyMemory.
So assuming you have a max buffer size of 256 following code would do what you
want:

WCHAR imageName[256];
RtlCopyMemory(imageName, Name->Buffer, min(Name->Length, 256));
imageName [min(Name->Length, 256) / sizeof(WCHAR)] = L’\0’;

While Name is the PCUNICODE_STRING

Note that UNICODE_STRING.Length is a byte count, and 256 in the
example code is a character count. An additional issue is that the
256 number represents an index beyond the end of the allocated buffer,
and would be overwriting the stack.

WCHAR imageName[256];
RtlCopyMemory( imageName, Name->Buffer, min( Name->Length, sizeof(imageName) )
);
imageName[ min( Name->Length, sizeof(imageName) - sizeof(WCHAR) ) /
sizeof(WCHAR) ] = L’\0’;

Thanks for pointing that out. I have wrapped that code in a function and using arraysize - 1 in my code, what I missed in here.
But i definitely missed the one about the byte count.
So corrected it would be:
RtlCopyMemory(imageName, Name->Buffer, min(Name->Length, 256*sizeof(WCHAR)));

imageName [min(Name->Length, 256 - 1) / sizeof(WCHAR)] = L’\0’;

You should use variable size structures rather then fixed size arrays. Of course the consumer and the service know how data is formatted in memory. The consumer must also be given a mean to get a hint of the required output buffer size. It could, for example, make a “probing call”. Many WIN32 APIs behave this way, there is nothing new here.

For example, a structure containing process informations could be defined like this:

typedef struct _PROCESS_INFO{
ULONG NextEntryOffset;
HANDLE ProcessId;
HANDLE ParentProcessId;
CLIENT_ID Cid;
UNICODE_STRING ImageName;
UNICODE_STRING CmdLine;
ULONG EntryFlags;
} PROCESS_INFO, *PPROCESS_INFO;

Here strings are not fixed size structures and the strings buffers must immediately follow the PROCESS_INFO structure in memory. Then the NextEntryOffset is the offset of the beginning of the next PROCESS_INFO structure if the buffer contains multiple such structures. In that case, the last one has a NextEntryOffset member set to zero.

Note that upon computation of NextEntryOffset, a padding may be needed so that every structures are aligned on a sizeof(PROCESS_INFO) boundary. The ROUND_TO_SIZE macro is helpful for that purpose.

Remember that you must never write data passed the end of the provided buffer because this can lead to system pool corruption (kernel mode buffer) or heap corruption (user mode buffer).

Thank you everyone for your help! I really, really appreciate it so much!
Sorry for such a late reply, but thanks to everyone’s input, I can do what i wanted to do already, so thank you so much, i couldn’t have done it without everyone’s help!