Home > Blockchain >  using RtlCompareString to compare user data crashes OS
using RtlCompareString to compare user data crashes OS

Time:07-04

I have the following code which is responsible to receive and send data between my mini-filter driver and user-mode:

NTSTATUS MiniSendRecv(PVOID portcookie, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG RetLength) {
    PCHAR msg = "Hi User";
    PCHAR userData = (PCHAR)InputBuffer;
    DbgPrintEx(0, 0, "User said: %d:%s\n", strlen(userData), userData);
    DbgPrintEx(0, 0, "Before comparing strings\n");
    if (RtlCompareString(userData, (PCHAR)"status=stop", TRUE) == 0) {
        DbgPrintEx(0, 0, "stop requested\n");
    }
    //if((PCHAR)InputBuffer.contains("status=stopservice"))

    if (strlen(msg) > OutputBufferLength) {

        DbgPrintEx(0, 0, "message length too big\n");
        return STATUS_SUCCESS;
    }
    strncpy((PCHAR)OutputBuffer, msg, 500);
    return STATUS_SUCCESS;
}

WinDBG output:

User said: 11:status=stop
Before comparing strings
KDTARGET: Refreshing KD connection

*** Fatal System Error: 0x0000003b
                       (0x00000000C0000005,0xFFFFF8046D001E82,0xFFFF8580E9924C20,0x0000000000000000)

Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

nt!DbgBreakPointWithStatus:
fffff804`6cdffc70 cc              int     3

As you can see the data is received just fine, but as soon as it hit RtlCompareString, the driver crashes causing the OS to crash as well.

Also prior to using PCHAR userData, I was doing if (RtlCompareString((PCHAR)InputBuffer, (PCHAR)"status=stop", TRUE) == 0) but that didn't do any good as well.

Can anyone tell me what is wrong here? when I call RtlCompareString against OutputBuffer, it works just fine.

CodePudding user response:

RtlCompareString compares counted strings. What you have are null terminated strings. Just use the regular strcmp function, or since you seem to be trying to do a case insensitive string comparison you could try the non-standard _stricmp function.

CodePudding user response:

Try something like this (I always try to implement in terms of standard C i.o. winapi calls). string_view is a nice lightweight class to make views on buffers which has hardly any overhead but gives you things like a compare function.

#include <Windows.h>
#include <array>
#include <string>
#include <iostream>

NTSTATUS MiniSendRecv(PVOID portcookie, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG RetLength)
{
    // you can make msg static it will not vary from call to call
    static const std::string_view msg{ "Hi User" };

    // create a string_view on the input, using the passed input length
    const std::string_view input{ static_cast<const char*>(InputBuffer), static_cast<std::size_t>(InputBufferLength) };

    // and now you can just use string_view compare instead of awkward win api call
    if (msg == input)
    {
        std::cout << "messages are equal\n";
    }

    return ERROR_SUCCESS;
}

int main()
{
    std::array hi_buffer{ 'H','i',' ','U','s','e','r' }; // Note : NO trailing '\0` in hi_buffer
    std::array<char, 16> output_buffer;
    ULONG ret_buffer_size{ 0ul };

    MiniSendRecv
    (
        nullptr,
        static_cast<PVOID>(hi_buffer.data()), hi_buffer.size(),
        static_cast<PVOID>(output_buffer.data()), output_buffer.size(),
        &ret_buffer_size
    );

    return 0;
}
  • Related