Hi Joseph M. Newcomer
Thanks a lot for your help, very helpful.
Note the key point here: those names are DIFFERENT NAMES! The first is in
the GLOBAL?? namespace, and is the internal name of the device driver, and
is visible only to other device drivers. The second is in the Device space,
and is the user-visible name. You cannot open a kernel internal name from
user space, and this is deliberately done to prevent potential security
violations that could occur if an application could open some low-level
driver.
Thanks for clarification, now I understand, but my tests (probable wrong) show different results as I wrote a few minutes ago.
Enumerating all my drivers with this tool (http://esagelab.com/resources.php?s=bootkit_remover) I found that I only have two device drivers that has this \DosDevices\ - they are COM1 and LPT1.
All the others has \Devices\, and I noted that a few of them I’m able to open calling \.\DriverName - Do you know why I’m able to open a few of this devices as Administrator (user-space) if they do not start with \DosDevices\?
Also, I noted that a few entries that has very different names in SymbolicLink and Destination entry, I’m only able to open the one listed in SymbolicLink (“\GLOBAL??\FPSfilter”).
That sounds very strange to me, I only see two \DosDevices\, I can open a few of this drivers starting with \.\SomeDriverName and also I may open sometimes a few of this SymbolicLink (“\GLOBAL??\FPSfilter”).
Also, if I log with a restricted account (not administrator) I’m able to open at least one of this SymbolicLink (“\GLOBAL??\FPSfilter”), but it failed with permission denied (ERROR 5) at CreateFileW() for all others. I liked this tool (http://esagelab.com/resources.php?s=bootkit_remover) because it allows me to list all drivers and their SymbolicLink and Destination, but it does not show the permissions of those device drivers. There is a tool that allows me to list all Device Drivers SymbolicLink and Destination like this tool but also show what user is able to open each of them for read and write?
With restricted user (not administrator) I only was able to open SymbolicLink (“\GLOBAL??\FPSfilter”), all other fails with access denied. I tried to replace the GENERIC_READ and GENERIC_WRITE with FILE_SHARE_READ | FILE_SHARE_WRITE and the same happens.
I mean, it’s OK drivers has different permissions, but for example I have a Antivirus installed and it has a driver and I can’t open it. But, if I open the Antivirus icon with restricted user I’m able to manage it, like ask to it scan the system, etc and I believe this commands are sent to kernel-land via this driver, right? So, why I can’t open it if the GUI application that I call with restricted access is able to do it?
It sounds like you are sending an invalid request. Can you show the
CTL_CODE macro that defines the operation you are using, and make sure you
show the definitions of the driver-specific names used in CTL_CODE? (That
is, show the definition of the first and second parameters to CTL_CODE)
I don’t have this information because I don’t have the source code of the driver. I’m using a driver developed by a third-party (not supported anymore) and the source code is not available.
That’s why I used a IOCTL monitor to try get this informations to communicate with this device driver.
With the IrpTracker.exe tool I’m not able to get all this information from a sent request instead of get from the source code definition?
Also, before your post, these hex-values (IOCTL control codes) passed as parameter to DeviceIoControl Function was “randomly” chosen by the driver developer in my mind. For example, they could control and choose any IOCTL code number of any task without follow any rule, like for example I can create any name to a function (except the reserved ones) my idea was that a developer could use whatever number he wanted.
Looking more carefully at documentation I see:
"dwIoControlCode [in]
The control code for the operation. This value identifies the specific operation to be performed and the type of device on which to perform it.
For a list of the control codes, see Remarks. The documentation for each control code provides usage details for the lpInBuffer, nInBufferSize, lpOutBuffer, and nOutBufferSize parameters."
http://msdn.microsoft.com/en-us/library/aa363216(VS.85).aspx
However I can’t find a documentation to dissect a IoControlCode, for example to identify if it’s METHOD_NEITHER or METHOD_BUFFERED like you did, what is the permission, or whatever other information I can get from it. Can you point me some document that will help me in this task? Preferably a documentation for dummies.
All I saw was a completely black window
Strange, I can access it and I see a piece of the IrpTracker.exe tool screenshot http://img254.imageshack.us/img254/5439/picggi.png
Just as a footnote: you should never call ExitProcess. Or Exit. Or do
anything other than return from the main function. These bad habits lead to
code that is unmaintainable.
Thanks for the suggestion, very appreciated. But I can’t use return() since the function that I call ExitProcess() is a void function. Anyway, I will change the type of the function to return a valid or bad code and do a clean return() on the main function. Thanks again.
Try not to put more than one statement on a line. The code becomes unreadable.
Where? I don’t see it in my code. Maybe a problem when I copied? I mean, I call one function per line, that’s a bad development practice? You mean that I should break long lines with \ ?
I find the recurring occurrence of random constants more than a little
disturbing. What does 0x330 mean? Or in decimal, 816? Why would you call
VirtualAlloc to allocate a 816-byte buffer? This doesn’t make any sense.
Why not call malloc()? Or even HeapAlloc? But VirtualAlloc? Wrong API!
If the buffer size is a constant, why not write
char Buff[0x330];
which makes more sense?
You are right again, I will fix it.
Yes, I random chose this size, just as a test, it could be any size, I was just testing.
What is that nonsense 0xA028442f? I have NEVER seen such an insane piece of
code!
I’m ashamed!
This 0xA028442f is the IOCTL code that I got from the IOCTL monitoring tool, at least, I did believe it was…
The ONLY valid argument that can appear there is either a CTL_CODE
macro or a symbol defined in terms of the CTL_CODE macro!
#define SOME_OPERATION CTL_CODE(…parmeters…)
Humm…
You do not need to cast NULL to an (LPOVERLAPPED)
And I need to cast the nInBufferSize and nOutBufferSize to DWORD?
And what is the meaning of 0x04? In a sane world, this would be specified
in a way that was completely dependent on the contents of tcode. For
example, “strlen(tcode)” or something else reasonable.
You are right, I modified the code so may times trying to make it work that it has a lot of very bad code, sorry about that. once I get it working I will re-write the whole code to make it better / clean it.
Where did the random device type 0xA028 come from?
From the IOCTL monitor. Also, I was not aware that this code was broken and not a whole number.
It is 41000.
How do you know if you don’t know the device driver? Or all has to start with 4100? Where I can find a list of this valid device type?
This sort of looks like a reasonable device type, but it would be defined as
#define MY_DEVICE 41000
and we would see
CTL_CODE(MY_DEVICE, …other parameters…)
Now, the bits 0xa028442f & 0xC000 would give me the access type, that is
4000, or 0100 0000 0000 0000. Code 01 is FILE_READ_ACCESS, and the
low-order 2 bits, 11, indicate METHOD_NEITHER. So the very LEAST that
should be there is
Where you got the 0xC000 from?
At CreateFile() I see that FILE_READ_ACCESS is 01, but where you got the reference to METHOD_NEITHER?
CTL_CODE(MY_DEVICE, …, METHOD_NEITHER, FILE_READ_ACCESS)
so you need to know what the symbol is for defining the device (41000) and
the symbolic name of the actual operation value, 4363. So you should see
something in a header file of the form
#define MY_DEVICE 41000
#define SOME_OPERATION 4363
#define IOCTL_SOME_OPERATION CTL_CODE(MY_DEVICE, SOME_OPERATION, METHOD_NEITHER, FILE_READ_ACCESS)
Did you get this values from MY_DEVICE and SOME_OPERATION from your experience just as a example, right? I’m afraid that you “guessed” this numbers from my example, and if is the case I’m not following you.
If you got any one of these wrong, you will get the “not supported” error,
so the generation of this magical random number is very suspect. The
canonical code in a driver is
switch(stk->Parameters.DeviceIoControl.IoControlCode)
{
case …:
…do something;
break;
case …:
…do something else;
break;
default:
Irp->IoStatus.status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp);
return STATUS_NOT_SUPPORTED;
}
Now it make much more sense why I’m getting that error.
so my first suspicion is that the random number 0xA028442f is not one of the
known cases, so the default is taken. So why do you believe this is a valid
IoControlCode?
Because I got it from a IOCTL monitor tool that grab all IOCTL requests and show it in a user-friendly interface.
Thanks a lot for all your help.