views:

32

answers:

1

Hi

I'm very new to communication with Windows Device Drivers. :)

I'm new to the forum too, I will be helpful if someone help me.

A) I need to communicate with a third-party driver. I see that CreateFile() accept both the device name (such as \\.\DeviceName) and also I can call the full file name (such as \\.\C:\MyPath\DriverName.sys). What is the best option? Why? Both works on the same way?

B) I see that many device drivers has two names, for example:

SymbolicLink "\GLOBAL??\VirtualSerial" Destination "\Device\VrSerialrs232"

If I try open for example open VrSerialrs232 with CreateFile() it fails. So, why is used the VrSerialrs232 if I always have to call the SymbolicLink (VirtualSerial)?

C) I installed a DeviceIOControl monitor to check why my code is failing with Error 50 (The request is not supported) and I can't figure why.

The output of the DeviceIOControl monitor is here: http://img254.imageshack.us/img254/5439/picggi.png

The ones from test.exe are my code, the other (protected) is the original application calling the same device.

My code is like this:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <strsafe.h>

void ErrorExit(LPTSTR lpszFunction){ 
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError(); 

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); 
    StringCchPrintf((LPTSTR)lpDisplayBuf, 
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"), 
        lpszFunction, dw, lpMsgBuf); 
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(dw); 
}

BOOL OpenDevice(PWSTR DriverName, HANDLE *lphDevice){

    WCHAR DeviceName[MAX_PATH]; HANDLE hDevice;

    if ((GetVersion() & 0xFF) >= 5) { 
        wcscpy(DeviceName, L"\\\\.\\Global\\");
    } else {

        wcscpy(DeviceName, L"\\\\.\\"); }
        wcscat(DeviceName, DriverName); printf("Opening.. %S\n", DeviceName);
        hDevice = CreateFileW(DeviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hDevice == INVALID_HANDLE_VALUE) {
    printf("CreateFile() ERROR %d\n", GetLastError());  return FALSE;

    }

    *lphDevice = hDevice;   return TRUE;
}

int _tmain(int argc, _TCHAR* argv[]){

 HANDLE    hDevice = NULL;
 DWORD    cb = 0;
 int ret = 0;
 char tcode[] = "\x8a\xb3\x39\x9d"; /* Copied from original request seen on Monitor) */

 if(!OpenDevice(L"MyDeviceName",&hDevice)) {

     printf("Error: Error opening device\n");   
     return(0);
 } else {

     printf("Device succesfully opened!\n");

 }

char *Buff = (char *)VirtualAlloc(NULL, 0x330, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

if (Buff){

 ret = DeviceIoControl(hDevice, 0xa028442f, tcode, 0x04, 0, NULL, &cb, (LPOVERLAPPED)NULL);

 if (ret == 0) {
   printf("Error: Bytes returned %#x\n",cb);
   ErrorExit(TEXT("DeviceIoControl: "));
    }

}

 CloseHandle(hDevice);
 return(0);
}

I always get this error:

C:>Test.exe Opening.. \.\Global\MyDeviceName Device succesfully opened! Error: Bytes returned 0 DeviceIOControl: Error 50 - The request is not supported

Why?

I don't know the name of the IOCTL commands, but I know the numbers. There is a way to translate a IOCTL number to a name?

This is a valid and real request that I captured with a IOCTL monitor.

Log started...
'C:\PathToApplication\OriginalAppName.exe' (PID: 2896)
'\Device\VSFilterbpd' (0x86b83c40) [\??\C:\LocalPath\DeviceDriverName.sys]
SymbolicLink "\GLOBAL??\VSFFilter"
IOCTL Code: 0xa028442f,  Method: METHOD_NEITHER

    InBuff: 0x004883a4,  InSize: 0x00000004
--------------------------------------------------------------------
9c 84 e2 86                                       | ....

   OutBuff: 0x004b4f68, OutSize: 0x00001b20
--------------------------------------------------------------------
03 00 00 00 1c 03 00 00  00 00 00 00 00 00 00 00  | ................
00 00 00 00 e4 0c 00 00  00 00 00 00 00 00 00 00  | ................
A lot of data.

What I'm missing to reproduce / clone / replicate the exact same message to the same driver by from my own application?

Thanks

+2  A: 

Typically, Windows device drivers present themselves to user mode applications by creating a symbolic link to themselves in the global namespace via IoCreateSymbolicLink().

So, it woud appear that the author of the driver in question has decided to expose this device to user mode applications, using the name "GLOBAL??\VirtualSerial". So, "\\.\VirtualSerial" (escaped) is the name your application should be using to obtain handles to the device.

User mode services do not have access to the "\Device" namespace for security reasons. This is why your user mode applications cannot open "\Device\VrSerialrs232".

Now, the return code from DeviceIOControl() indicates that the command that you're sending the device is not supported. IOCTL commands are DWORD values whose bits describe the format of the command (buffered/unbuffered, access rights required, etc.). Your best bet would be to obtain a list of the IOCTL commands for the device in question before you start working with this device. If this is a serial port type device, this would be a good place to start.

Good luck!

Bukes
@Hans, I fixed the IOCTL code number, now it's correct.@Hans, I f ret = DeviceIoControl(hDevice, 0x86DB3F68, tcode, 0x04, 0, NULL, And the problem persist. Any other idea?Where you see on the screenshot that the method is 3? I can't see it. And why it's odd?Thanks
Fred
@Bukes, thanks for explanation, very helpful.The command that I'm sending? In this case the contents of variable tcode? The buffered/unbuffered, access rights required, etc should not be defined when I call CreateFileW()?Thanks
Fred
And not, it's not a serial device or related. It's a kind of file system filter. Thanks
Fred
Fred, the command you are sending is the IOCTL code, '0xa028442f'. The INPUT PAYLOAD for the command is a a 4 byte array '9c 84 e2 86'. That said, the reason you may be failing could be that you are not specifying an OUTPUT buffer (you're passing NULL, and 0). The IOCTL in question may REQUIRE this.
Bukes