I am curious why you are wasting your time and ours by showing code that
is not the code you are actually using. But the code as shown is buggy
beyond all reason.
RTFM. What are the specs of RtlAnsiStringToUnicodeString?
NTSTATUS RtlAnsiStringToUnicodeString(
Inout PUNICODE_STRING DestinationString,
In PCANSI_STRING SourceString,
In BOOLEAN AllocateDestinationString
);
So, did you give it a valid PUNICODE_STRING for the first parameter?
No, you gave it a NULL pointer!
Why would you create a PUNICODE_STRING variable, set it to NULL, and pass
that NULL in as a valid pointer?
You would declare a variable of type UNICODE_STRING and pass the pointer
to *that*. It is a common beginner error to mistake the specification of
a parameter for a requirement for a variable of that type, but most people
get over this in the first week after pointers are taught. So you should
have declared
UNICODE_STRING DestinationString;
Now, as several people have pointed out, the 8-bit character is dead,
dead, dead (except for debug printouts, and the reasons for that are
probably historical accident). No part of the kernel uses 8-bit strings
for anything. Even lowly NotePad will write Unicode files. In fact, you
should check to see if the files starts with a BOM mark; there are three
of interest: little-endian Unicode (what Windows uses), big-endian Unicode
(which a SparcStation might write, but you could consider it fair to
simply reject as improperly-formatted a big-endian Unicode file, and
UTF-8, which has no endianess and consequently is completely
platform-neutral.
Next, you declare your file name to be a CHAR buffer of size 100. Since
we assume that this filter driver will only be installed on machines with
English-speaking users, we can accept that it is CHAR. But how in the
world did you come up with the totally random number “100”? I don’t know
if the kernel defined a symbol for this, but in user space it is MAX_PATH,
and its value, which you would never use as a string of digits, is 263.
So do you have some reason for working only with files whose names do not
exceed 99, which is considerably less than half of the permissible length?
Also, you do not show how that buffer is initialized; given the other
bugs, it would not surprise me to find that you are doing a strcpy of the
string characters just so you can have them in this buffer. And you do
NOT use strcpy in the kernel, ever. Unless you want to make headlines.
The kind that say “File system product results in successful exploit that
compromised over 300,000 computers in eight hours”. So we need to see
where those bits are coming from and how they get there.
Now, let’s look at the second parameter: PCANSI_STRING. What are you
passing in? tempBuffer. It wants a PCANSI_STRING and you give it a
CHAR*? How did this even compile?
So either this is not the code you used, or you turned off or ignored the
warning messages from the compiler.
Hint: kernel code should compile warning-free. And you should never
compile at less than Warning Level 4, a.k.a. /W4. We can ignore the
(nonexistent) warning level 0, which, if I understand it correctly, can
accept Java, C#, and FORTRAN source files and not give any warnings. The
first real level /W1, is almost as lenient, but will issue warnings for
FORTRAN (but will not issue warnings about COBOL source). /W3, which is
the default, is felt by many to be far too close to /W0 to be trusted.
Surprisingly, there is an actual link to the ANSI_STRING documentation.
Or, not surprising; what is surprising is that you did not follow it and
discover:
typedef struct _STRING {
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} ANSI_STRING, *PANSI_STRING;
I think it should be obvious why passing a CHAR* to a function that
expects to find this structure will give you access faults. What you
should have declared was
ANSI_STRING tempBuffer.
So, *after* you have initialized the ANSI_STRING tempBuffer (even the name
scares me, because if you have a table of filenames, there is no need for
a temporary buffer for any purpose whatsoever), your call would be
ntstatus = RtlAnsiStringToUnicodeString(&DestinationString, &tempBuffer,
TRUE);
Now, since you have created this Unicode string, you have to make sure
that you properly free the allocated buffer when you are finished with it.
I do not see that happening in the code that is shown.
Oh, yes, why do you call RtlInitUnicodeString at all? If you wanted the
string in myFileName2, why didn’t you pass &myFileName2 in as the
parameter to RtlAnsiStringToUnicodeString.
So, while we’re at it, let’s look at the parameters to RtlInitUnicodeString:
VOID RtlInitUnicodeString(
Out PUNICODE_STRING DestinationString,
In_opt PCWSTR SourceString
);
So the first parameter is the expected PUNICODE_STRING. But the second
parameter is a pointer to a PCWSTR. You gave it a PUNICODE_STRING so it
could not have possibly compiled without errors. Didn’t this failure to
compile give you a clue? But even if you had specified the correct
address, that is, DestinationString.Buffer, this is a UNICODE_STRING. A
UNICODE_STRING is not guaranteed to end with a NUL character (NULL is a
pointer; NUL is the name of the character whose value is 0). Since
RtlInitUnicodeString requires a terminating NUL, and
RtlAnsiStringToUnicodeString most explicitly does NOT say that the .Buffer
member of the result UNICODE_STRING is NUL-terminated, this code is not
guaranteed to work.
So what is the real code you used, and does it compile warning-free at /W4?
p.s. check RtlFreeUnicodeString, as mentioned in the documentation for
RtlAnsiStringToUnicodeString. Show us where you call it.
None of this is Deep Kernel Magic. All of it is elementary C programming
and knowing how to read documentation. Everything you needed to know was
right in the documentation. As a C programmer, it should have been easy
to understand. And if you are not an experienced C programmer, playing in
the kernel is like juggling live hand grenades. The outcome is
inevitable.
joe
I had tried RtlAnsiStringToUnicodeString earlier but was facing some
problem and it still persists.
This is the code :
PUNICODE_STRING DestinationString=NULL;
char tempBuffer[100];
DbgPrint(“Temp Buffer is::%s\n”, tempBuffer);
ntstatus=RtlAnsiStringToUnicodeString(DestinationString,tempBuffer,TRUE);
if(NT_SUCCESS(ntstatus))
{
RtlInitUnicodeString(&myFileName2, DestinationString);
DbgPrint(“File Read is::%wZ\n”,&myFileName2);
}
I have in tempBuffer my file name fro my common file.
But how did it get there? Why do you not show this code?
Initially I had not initialized the DestinsationString and it resulted in
compiling error.
well, yes. But why was it not obvious to you that passing a NULL pointer
as an argument to where an actual pointer to a real data object is
expected will cause the kernel to crash? The compiler said “If you walk
down this path, you will fall into an open manhole”, and you responded by
cutting a manhole cover out of paper and painting it to look like metal,
so that annoying compiler would stop nagging you. Now you can walk down
the street, texting your friends, and not notice any open manholes. Until
you step on the fake paper cover you taped to the hole. But, hey, at
least the compiler shut up. I’m more concerned with the reasons your
horrific type mismatches on the parameters passed all the tests. The code
you show could not possibly compile without warnings or errors.
The failure to run !analyze -v and include the output makes it difficult
to point out to you how to analyze what went wrong, so you could correct
it.
But now it is compiling yet it gives KERNEL_MODE_EXCEPTION_NOT_HANDLED
error in dump file.
Every time I try to install driver it results in crash.
Before I added the RtlInitUnicodeString(&myFileName2, DestinationString);
Driver was installing with a success.
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