Pass .NET Structure per IOCTL to KMDF

Have you tried sending some simple test data across the managed/unmanaged boundary?

C#:
ACTIVATE_MONITOR_INFO example = new ACTIVATE_MONITOR_INFO
{
hEventHandle = 2,
HashValue = new string[2]
{
“Test1”,
“AnotherTest”
}
};

Is this populated in _REGISTER_EVENT correctly? Are you passing the correct sizes to the system apis?

xxxxx@freenet.de wrote:

i have a windows service written in c#.
I try to pass a struct with string arrays with an ioctl to the windows driver, but it doesn’t work. The Array-size is known at runtime.

Your ioctl structure is poorly designed. It’s a very bad idea to pass
user-mode addresses in an ioctl buffer, much less the address of a list
of other addresses. The size of a pointer is different for 32-bit and
64-bit applications, and your driver is required to handle that. And
the address space for a user-mode process can evaporate suddenly.

If you need to pass multiple strings, it would have been much smarter to
do it like a REG_MULTI_SZ registry value, where the buffer contain a
list of strings separated by null bytes and terminated by a double null.

The following is the c#-structure:

public struct ACTIVATE_MONITOR_INFO
{

public int hEventHandle;
public string HashValue;
}

Don’t you have to mark this as [StructLayout(LayoutKind.Sequential)]?
Otherwise, you get .NET memory layout, not unmanaged layout.


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

I don’t have the details at hand, but the user should annotate the structure appropriately and use marshalling to convert to unmanaged form. The standard marshalling can handle mapping from a managed string to or from a zero-terminated string of fixed size. (it can also marshal to a pointer, but as previously noted passing user-space pointers to an IOCTL is a very bad idea). Marshalling an array of strings is, I believe, an exercise for the user. I don’t think the standard marshalling can handle that.

? Bob Ammerman
? xxxxx@ramsystems.biz
716.864.8337

138 Liston St
Buffalo, NY 14223
www.ramsystems.biz

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-614435-
xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Monday, August 15, 2016 12:25 PM
To: Windows System Software Devs Interest List
> Subject: Re: [ntdev] Pass .NET Structure per IOCTL to KMDF
>
> xxxxx@freenet.de wrote:
> > i have a windows service written in c#.
> > I try to pass a struct with string arrays with an ioctl to the windows driver,
> but it doesn’t work. The Array-size is known at runtime.
>
> Your ioctl structure is poorly designed. It’s a very bad idea to pass user-mode
> addresses in an ioctl buffer, much less the address of a list of other
> addresses. The size of a pointer is different for 32-bit and 64-bit applications,
> and your driver is required to handle that. And the address space for a user-
> mode process can evaporate suddenly.
>
> If you need to pass multiple strings, it would have been much smarter to do it
> like a REG_MULTI_SZ registry value, where the buffer contain a list of strings
> separated by null bytes and terminated by a double null.
>
>
> > The following is the c#-structure:
> >
> > public struct ACTIVATE_MONITOR_INFO
> > {
> >
> > public int hEventHandle;
> > public string HashValue; }
>
> Don’t you have to mark this as [StructLayout(LayoutKind.Sequential)]?
> Otherwise, you get .NET memory layout, not unmanaged layout.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list online at:
> http:
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at
> http:</http:></http:></http:>

The "StructLayoutAttribute class " MSDN page is interesting. It shows how to build a C# struct that matches the C struct SYSTEMTIME to perform the Win32 API call GetSystemTime(). This is a good starting point.

https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute(v=vs.110).aspx

Hi,

as Tim said, unfortunately your struct design is poor and wont work that way. The most fearsome here is the pointer that could point to anything in your kernel space. The marshaller of the .NET CLR crossing from managed to unmanaged needs to know how exactly it has to pass the data and in what way. The magic behind this is CLR attributes. Important things are packing, layout and data width. All can be arranged by attributes attached to the struct and members. You should try these definitions. The 100 is just an example and you should replace it by your appropriate string size. Char type is always unicode in internal net representation:

[StructLayout(
LayoutKind.Sequential,
CharSet = CharSet.Unicode)]
public struct Argument
{
public int hEventHandle;

[MarshalAs(UnmanagedType.LPWStr, SizeConst = 100)]
public string HashValue;
}

or possibly this one:

[StructLayout(
LayoutKind.Sequential,
CharSet = CharSet.Unicode)]
unsafe public struct Argument
{
public int hEventHandle;
fixed char HashValue[100];
}

From experience you can pass nearly anything from userland to kernel space in C# as long as you keep the contract on booth sides. NEVER EVER pass pointers, since these can change very quickly! Also keep in your mind, that a CLR string is totally different from an UNICODE_STRING. Go for some web research for more info.

you should have a closer look here and related information: https://msdn.microsoft.com/en-us/library/s9ts558h.aspx

hope this helps

K.

Hi,

thanks a lot for your replies.
I’ve read the postings (MSDN) but i think i’m too stupid.
Sorry i think my first post was a little bit confusing.
In C# i have a string array with multiple hash values which will be filled during runtime with hash values from a database. So when i declared the string array in the structure i can’t use a fixed size.
Can i use the following declaration and fill the information before i pass it to the driver:

public struct ACTIVATE_MONITOR_INFO
{
public int hEventHandle;
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 1)]
String ar;
int size;
}

And later then:

var actInfo = new ACTIVATE_MONITOR_INFO();
actInfo.hEventHandle = _kernelEventHandle.ToInt32(); //THIS WORKS

IntPtr actInfoPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(ACTIVATE_MONITOR_INFO)));

var ret = NativeFile.DeviceIoControl(handle, ServiceInstaller.IOCTL_REGISTER_EVENT, actInfoPtr, Marshal.SizeOf(typeof(ACTIVATE_MONITOR_INFO)),IntPtr.Zero, 0, out retSize, IntPtr.Zero);

Sorry for my questions i really try to understand whats the problem and how to solve it.

Daniel

I can only reinforce what has been said before. You cannot safely pass any pointers to kernel mode. You will need to convert your entire input to a single contiguous data structure that can be passed down to the driver. Perhaps the easiest way is to do something like this (untested code):

int totallen = 0;
foreach (string s in strings)
totallen += s.Length;

// Allocate a buffer big enough to hold everything
ushort buffer = new ushort[1 + strings.Length + totallen];

int p = 0; // pointer into buffer
buffer[p++] = (ushort)strings.Count;
foreach (string s in strings)
{
buffer[p++]=(ushort)s.Length;
foreach (char ch in s)
Buffer[p++] = (ushort)ch;
}

Now ‘buffer’ will start with the number of strings, followed by each string stored in Unicode with it length first.

You can now marshal ‘buffer’ to an unmanaged buffer and pass it down to your IOCTL (waves hands…)

* Bob

? Bob Ammerman
? xxxxx@ramsystems.biz
716.864.8337

138 Liston St
Buffalo, NY 14223
www.ramsystems.biz

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-614461-
xxxxx@lists.osr.com] On Behalf Of xxxxx@arcor.de
Sent: Tuesday, August 16, 2016 12:57 AM
To: Windows System Software Devs Interest List
> Subject: RE:[ntdev] Pass .NET Structure per IOCTL to KMDF
>
> Hi,
>
> as Tim said, unfortunately your struct design is poor and wont work that way.
> The most fearsome here is the pointer that could point to anything in your
> kernel space. The marshaller of the .NET CLR crossing from managed to
> unmanaged needs to know how exactly it has to pass the data and in what
> way. The magic behind this is CLR attributes. Important things are packing,
> layout and data width. All can be arranged by attributes attached to the
> struct and members. You should try these definitions. The 100 is just an
> example and you should replace it by your appropriate string size. Char type
> is always unicode in internal net representation:
>
> [StructLayout(
> LayoutKind.Sequential,
> CharSet = CharSet.Unicode)]
> public struct Argument
> {
> public int hEventHandle;
>
> [MarshalAs(UnmanagedType.LPWStr, SizeConst = 100)]
> public string HashValue;
> }
>
> or possibly this one:
>
> [StructLayout(
> LayoutKind.Sequential,
> CharSet = CharSet.Unicode)]
> unsafe public struct Argument
> {
> public int hEventHandle;
> fixed char HashValue[100];
> }
>
> From experience you can pass nearly anything from userland to kernel space
> in C# as long as you keep the contract on booth sides. NEVER EVER pass
> pointers, since these can change very quickly! Also keep in your mind, that a
> CLR string is totally different from an UNICODE_STRING. Go for some web
> research for more info.
>
> you should have a closer look here and related information:
> https://msdn.microsoft.com/en-us/library/s9ts558h.aspx
>
> hope this helps
>
> K.
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list online at:
> http:
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at
> http:</http:></http:></http:>

Ah… just noticed you are also trying to pass down a handle. What it is a handle to and how did you create it?

If it is safe to pass that handle down you can add it to your buffer of ushort values by using the BitConverter class first to convert the int to bytes, and then again to reconvert the bytes to two ushort’s:

byte bytes = BitConverter.GetBytes(handle);
buffer[p++] = BitConverter.ToUInt16(bytes,0);
buffer[p++] = BItConverter.ToUInt16(bytes,2);

You’d put the value back together in the kernel code.

* Bob

? Bob Ammerman
? xxxxx@ramsystems.biz
716.864.8337

138 Liston St
Buffalo, NY 14223
www.ramsystems.biz

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-614489-
xxxxx@lists.osr.com] On Behalf Of Robert Ammerman
Sent: Tuesday, August 16, 2016 7:21 AM
To: Windows System Software Devs Interest List
> Subject: RE: RE:[ntdev] Pass .NET Structure per IOCTL to KMDF
>
> I can only reinforce what has been said before. You cannot safely pass any
> pointers to kernel mode. You will need to convert your entire input to a
> single contiguous data structure that can be passed down to the driver.
> Perhaps the easiest way is to do something like this (untested code):
>
> int totallen = 0;
> foreach (string s in strings)
> totallen += s.Length;
>
> // Allocate a buffer big enough to hold everything ushort buffer = new
> ushort[1 + strings.Length + totallen];
>
> int p = 0; // pointer into buffer
> buffer[p++] = (ushort)strings.Count;
> foreach (string s in strings)
> {
> buffer[p++]=(ushort)s.Length;
> foreach (char ch in s)
> Buffer[p++] = (ushort)ch;
> }
>
> Now ‘buffer’ will start with the number of strings, followed by each string
> stored in Unicode with it length first.
>
> You can now marshal ‘buffer’ to an unmanaged buffer and pass it down to
> your IOCTL (waves hands…)
>
> * Bob
>
>
> ? Bob Ammerman
> ? xxxxx@ramsystems.biz
> 716.864.8337
>
> 138 Liston St
> Buffalo, NY 14223
> www.ramsystems.biz
>
>
> > -----Original Message-----
> > From: xxxxx@lists.osr.com [mailto:bounce-614461-
> > xxxxx@lists.osr.com] On Behalf Of xxxxx@arcor.de
> > Sent: Tuesday, August 16, 2016 12:57 AM
> > To: Windows System Software Devs Interest List
> > Subject: RE:[ntdev] Pass .NET Structure per IOCTL to KMDF
> >
> > Hi,
> >
> > as Tim said, unfortunately your struct design is poor and wont work that
> way.
> > The most fearsome here is the pointer that could point to anything in your
> > kernel space. The marshaller of the .NET CLR crossing from managed to
> > unmanaged needs to know how exactly it has to pass the data and in what
> > way. The magic behind this is CLR attributes. Important things are packing,
> > layout and data width. All can be arranged by attributes attached to the
> > struct and members. You should try these definitions. The 100 is just an
> > example and you should replace it by your appropriate string size. Char
> type
> > is always unicode in internal net representation:
> >
> > [StructLayout(
> > LayoutKind.Sequential,
> > CharSet = CharSet.Unicode)]
> > public struct Argument
> > {
> > public int hEventHandle;
> >
> > [MarshalAs(UnmanagedType.LPWStr, SizeConst = 100)]
> > public string HashValue;
> > }
> >
> > or possibly this one:
> >
> > [StructLayout(
> > LayoutKind.Sequential,
> > CharSet = CharSet.Unicode)]
> > unsafe public struct Argument
> > {
> > public int hEventHandle;
> > fixed char HashValue[100];
> > }
> >
> > From experience you can pass nearly anything from userland to kernel
> space
> > in C# as long as you keep the contract on booth sides. NEVER EVER pass
> > pointers, since these can change very quickly! Also keep in your mind, that
> a
> > CLR string is totally different from an UNICODE_STRING. Go for some web
> > research for more info.
> >
> > you should have a closer look here and related information:
> > https://msdn.microsoft.com/en-us/library/s9ts558h.aspx
> >
> > hope this helps
> >
> > K.
> >
> > —
> > NTDEV is sponsored by OSR
> >
> > Visit the list online at:
> > http:
> >
> > MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> > software drivers!
> > Details at http:
> >
> > To unsubscribe, visit the List Server section of OSR Online at
> > http:
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list online at:
> http:
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at
> http:</http:></http:></http:></http:></http:></http:>

xxxxx@freenet.de wrote:

thanks a lot for your replies.
I’ve read the postings (MSDN) but i think i’m too stupid.
Sorry i think my first post was a little bit confusing.

No, I don’t think it was.

In C# i have a string array with multiple hash values which will be filled during runtime with hash values from a database. So when i declared the string array in the structure i can’t use a fixed size.

You have focused on the solution you’ve chosen, not the problem you have
to solve. The user/kernel boundary is not as infinitely flexibly as a
function call boundary. You have to think about your problem in a
different way. You could, for example, concatenate the strings into one
large string, embedding the event handle in the first few bytes.
Consider this:

using System;
using System.Collections.Generic;

public struct ActivateMonitorInfo
{
public int hEventHandle;
public int count;
public List array;

public byte ToBytes()
{
int length = 4 + 4;
count = array.Count;
for( int i = 0; i < count; i++ )
{
length += array[i].Length * 2 + 2;
}

byte temp = new byte[length];

int iCur = 0;
System.Buffer.BlockCopy(
BitConverter.GetBytes(hEventHandle), 0,
temp, iCur, 4
);
iCur += 4;

System.Buffer.BlockCopy(
BitConverter.GetBytes(count), 0,
temp, iCur, 4
);
iCur += 4;

for( int i = 0; i < count; i++ )
{
Console.WriteLine( “Doing string {0}.”, i );
System.Buffer.BlockCopy(
array[i].ToCharArray(), 0,
temp, iCur, array[i].Length * 2
);
iCur += array[i].Length * 2 + 2;
}

return temp;
}
}

public static class Program {
static public void Main()
{
ActivateMonitorInfo ami = new ActivateMonitorInfo();
ami.hEventHandle = 0x1234;
ami.array = new List();
ami.array.Add( “Hello” );
ami.array.Add( “world” );
ami.array.Add( “from” );
ami.array.Add( “me” );

byte buffer = ami.ToBytes();
Console.WriteLine( “Buffer is {0} bytes”, buffer.Length );
Console.WriteLine( BitConverter.ToString(buffer) );
}
}

The “ToBytes” function returns a byte array that you can pass to kernel
mode safely. The “count” member tells the kernel how many strings to
expect, and each one is terminated by a null.


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

And shouldn’t it be IntPtr hEventHandle? If this is a kmdf driver you will need to convert the handle to the event object in the io preprocessing routine where you have the correct app context.

Get Outlook for Androidhttps:

From: Tim Roberts
Sent: Tuesday, August 16, 10:58 AM
Subject: Re: [ntdev] Pass .NET Structure per IOCTL to KMDF
To: Windows System Software Devs Interest List

xxxxx@freenet.de wrote: > thanks a lot for your replies. > I’ve read the postings (MSDN) but i think i’m too stupid. > Sorry i think my first post was a little bit confusing. No, I don’t think it was. > In C# i have a string array with multiple hash values which will be filled during runtime with hash values from a database. So when i declared the string array in the structure i can’t use a fixed size. You have focused on the solution you’ve chosen, not the problem you have to solve. The user/kernel boundary is not as infinitely flexibly as a function call boundary. You have to think about your problem in a different way. You could, for example, concatenate the strings into one large string, embedding the event handle in the first few bytes. Consider this: using System; using System.Collections.Generic; public struct ActivateMonitorInfo { public int hEventHandle; public int count; public List array; public byte ToBytes() { int length = 4 + 4; count = array.Count; for( int i = 0; i < count; i++ ) { length += array[i].Length * 2 + 2; } byte temp = new byte[length]; int iCur = 0; System.Buffer.BlockCopy( BitConverter.GetBytes(hEventHandle), 0, temp, iCur, 4 ); iCur += 4; System.Buffer.BlockCopy( BitConverter.GetBytes(count), 0, temp, iCur, 4 ); iCur += 4; for( int i = 0; i < count; i++ ) { Console.WriteLine( “Doing string {0}.”, i ); System.Buffer.BlockCopy( array[i].ToCharArray(), 0, temp, iCur, array[i].Length * 2 ); iCur += array[i].Length * 2 + 2; } return temp; } } public static class Program { static public void Main() { ActivateMonitorInfo ami = new ActivateMonitorInfo(); ami.hEventHandle = 0x1234; ami.array = new List(); ami.array.Add( “Hello” ); ami.array.Add( “world” ); ami.array.Add( “from” ); ami.array.Add( “me” ); byte buffer = ami.ToBytes(); Console.WriteLine( “Buffer is {0} bytes”, buffer.Length ); Console.WriteLine( BitConverter.ToString(buffer) ); } } The “ToBytes” function returns a byte array that you can pass to kernel mode safely. The “count” member tells the kernel how many strings to expect, and each one is terminated by a null. – Tim Roberts, xxxxx@probo.com Providenza & Boekelheide, Inc. — NTDEV is sponsored by OSR Visit the list online at: MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers! Details at To unsubscribe, visit the List Server section of OSR Online at</https:>

If you can develop a driver, you can develop a library (DLL) written in the C language that would perform communications tasks between user-mode and kernel-mode.

So, you would have a layered model with the C# app on top, the DLL in the middle, and the driver at the bottom.

The DLL’s exported APIs would handle “standard” C types like HANDLE and WCHAR arrays so that the interface betwwen the C# app and the DLL is simple. The DLL and the driver would share the same struct definitions so they communications are made easy and consistent as well.

This is interesting because you can, this way, ensure that data is properly layed out in the user-mode/kernel-mode channel and you can continue to use C# for the user-mode app without too much “unsafe” code.

>This is interesting because you can, this way, ensure that data is properly layed out in the

user-mode/kernel-mode channel and you can continue to use C# for the user-mode app without too
much “unsafe” code.

Looking back at the inital question, i dont think that there is any need for a n-tier solution in this case. Passing such a “simple” piece of memory doesnt need anything in between. There are really very rare cases you cant fully translate C style definitions to C# CLR and if you hit such a case, then you could even operate on raw memory (data arrays, memory streams, etc.) in C# and pass it simply as a single package of memory block to the DeviceIoControl. We even had some neat examples here. Another approach is shared memory which is very well documented here and as well on ms pages:

http://www.osronline.com/article.cfm?article=39
https://support.microsoft.com/en-us/kb/191840

K.

>Looking back at the inital question, i dont think that there is any need for a n-tier solution in this case.

I do think there is.

Passing such a “simple” piece of memory doesnt need anything in between…

So why does the OP request help ?

There are really very rare cases you cant fully translate C style definitions to C# CLR and if you hit such a case, then you could even operate on raw memory (data arrays, memory streams, etc.) in C# and pass it simply as a single package of memory block to the DeviceIoControl. We even had some neat examples here.

Another just plain stupid statement. Using C# to do C! Really stupid.

Another approach is shared memory which is very well documented here and as well on ms pages…

Off topic…

>Another just plain stupid statement. Using C# to do C! Really stupid.

this is your opinion

>this is your opinion

“Criticism is easy, and art is difficult.”

The second alternative is to use managed C++ to create a small assembly that does the marshalling. Since you can more simply describe the native struct AND provide a managed call interface, you get the best of both from the language. Not much else, but for this it suites its purposes

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Tuesday, August 16, 2016 10:48 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Pass .NET Structure per IOCTL to KMDF

>this is your opinion

“Criticism is easy, and art is difficult.”


NTDEV is sponsored by OSR

Visit the list online at: http:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

>The second alternative is to use managed C++ to create a small assembly that does the marshalling. Since you can more simply describe the native struct AND provide a managed call interface, you get the best of both from the language. Not much else, but for this it suites its purposes

Yes, even better.

Well, my opinion is that adding a C (or C++) DLL Is just an unneeded complication. Unless performance is of the utmost importance the BitConverter class and marshalling are your friends. If desired, this low-level mangling of things could be easily hidden from the end application.

* Bob

? Bob Ammerman
? xxxxx@ramsystems.biz
716.864.8337

138 Liston St
Buffalo, NY 14223
www.ramsystems.biz

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-614561-
xxxxx@lists.osr.com] On Behalf Of xxxxx@arcor.de
Sent: Tuesday, August 16, 2016 10:35 PM
To: Windows System Software Devs Interest List
> Subject: RE:[ntdev] Pass .NET Structure per IOCTL to KMDF
>
> >Another just plain stupid statement. Using C# to do C! Really stupid.
>
> this is your opinion
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list online at: http:
>
> MONTHLY seminars on crash dump analysis, WDF, Windows internals and
> software drivers!
> Details at http:
>
> To unsubscribe, visit the List Server section of OSR Online at
> http:</http:></http:></http:>

Thank you very much for your patience,

i’ve tried it by concating the string hash-values, convert them to a byte array and pass it down to driver by the following code:

string _HashValues =
*14cf73d771fa977a9f1cbaa5c301f912*7f0e061f5b6f311013968503d4c1d052*

static byte GetBytes(string str)
{
byte bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}

byte inBuffer = GetBytes(_HashValues);
DeviceIoControl(handle, ServiceInstaller.IOCTL_UPDATE_PROG_TABLE, inBuffer, inBuffer.Length, outBuffer, 0, out bytesReturned, IntPtr.Zero);

My last problem (and question, i promise) is that sometimes not the correct string-value appears in the driver:

wchar_t* test = (wchar_t*)Irp->AssociatedIrp.SystemBuffer;
DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, “test-wchar_t: %ls\n”,test);

The output looks like this (at the end of the string additional character are appended):

*14cf73d771fa977a9f1cbaa5c301f912*7f0e061f5b6f311013968503d4c1d052*e2-806e6f6e6963
or
*14cf73d771fa977a9f1cbaa5c301f912*7f0e061f5b6f311013968503d4c1d052*???}}}
(but not always)

I think i make a great mistake somewhere

xxxxx@freenet.de wrote:

i’ve tried it by concating the string hash-values, convert them to a byte array and pass it down to driver by the following code:

string _HashValues =
*14cf73d771fa977a9f1cbaa5c301f912*7f0e061f5b6f311013968503d4c1d052*

static byte GetBytes(string str)
{
byte bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}

byte inBuffer = GetBytes(_HashValues);
DeviceIoControl(handle, ServiceInstaller.IOCTL_UPDATE_PROG_TABLE, inBuffer, inBuffer.Length, outBuffer, 0, out bytesReturned, IntPtr.Zero);

My last problem (and question, i promise) is that sometimes not the correct string-value appears in the driver:

wchar_t* test = (wchar_t*)Irp->AssociatedIrp.SystemBuffer;
DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, “test-wchar_t: %ls\n”,test);

The output looks like this (at the end of the string additional character are appended):

*14cf73d771fa977a9f1cbaa5c301f912*7f0e061f5b6f311013968503d4c1d052*e2-806e6f6e6963
or
*14cf73d771fa977a9f1cbaa5c301f912*7f0e061f5b6f311013968503d4c1d052*???}}}
(but not always)

I think i make a great mistake somewhere

Your mistake is not stepping back to think about what you are doing.

Say your string is 5 characters long, “ABCDE”. You are allocating 10
bytes. You then copy 10 bytes, so the buffer looks like this:
41 00 42 00 43 00 44 00 45 00

You then pass that to kernel mode, where you try to DbgPrint it with
%ls. What exactly does “%ls” mean? You are telling printf “I am
passing you a zero-terminated Unicode string.” But you are lying to
printf, because your string does not have a zero terminator. Printf
doesn’t know where the end of the string is.

So, the data is being passed correctly. It is your debug print that is
wrong. If you really want to print the string, there are several
options. You could wrap the buffer in a UNICODE_STRING structure and
print it using %Z:

UNICODE_STRING us = {
irpStack->Parameters.DeviceIoControl.InputBufferLength,
irpStack->Parameters.DeviceIoControl.InputBufferLength,
Irp->AssociatedIrp.SystemBuffer
};
DebugPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_ERROR_LEVEL, “test-wchar_t:
%Z\n”, &us );

Or, you can pass the length in:
DebugPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_ERROR_LEVEL, “test-wchar_t:
%.*ls\n”,
irpStack->Parameters.DeviceIoControl.InputBufferLength,
Irp->AssociatedIrp.SystemBuffer
);

Why are you not writing a KMDF driver?


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