Archive for August, 2007

Using FileObject and FsContext

Wednesday, August 29th, 2007

Well, with some posts and a little patience to endure my jokes, we can construct a simple driver that responds to calls from applications. A call to CreateFile function creates a connection between the application and device, returning a handle which will later be used to route reading/writting requests to the device. If there are more calls to CreateFile function, new handles will be returned. Like it happens with files, each handle has its own context. Suppose you open the same file twice so, you will get two handles with different contexts. A reading of 100 bytes from the first handle would cause the file’s current location be different from the initial position. A new reading using the same handle would result on getting the next 100 bytes ahead of the ones already read. Now if you used the second handle, you would get the first 100 bytes of the file. That’s because each handle would keep different file locations. In this post, I will talk about how to keep this context between the different opened handles for your device.

The issue in practice

Not long ago, in one of my posts, I gave a basic driver example that implements a linked list of buffers that were written to the device. The same buffers are obtained from further reads to the same device. This post will be based on this sample driver to make the tests and suggested modifications. The driver’s string list was implemented as a single global variable. If there is a single list, the various handles gotten from the applications will manipulate this same list.

Remember that the test program writes the strings, that were typed in a console at the device until an empty one is supplied. When this occurs, the application starts reading and displaying the results at the screen. Thus, the same provided string sequence should be displayed. To reproduce the problem, follow the steps below with the test driver already installed:

  1. Open up a Prompt window and execute a test program instance.
  2. Enter the string sequence that goes from “111”, “222” until “555”, but don’t enter the empty one yet.
  3. Open up a new Prompt window and execute another test program instance.
  4. On this new window, enter the string sequence that goes from “666” until “999” and then, an empty one.
  5. Go back to the previous instance and then, enter an empty string into the test program.

You should get an output as it is shown below. Note that the first test program instance has not read any string, despite having written several ones. These missing strings were got to the second test program instance.

Separating lists

Creating an algorithm able to separate these lists using the process identification could even work, but try to imagine that a single application could use two different libraries, which in turn, would use these lists. In this way, one library list would merge into the other library list, since both libraries are at the same process. To separate the context using various device openings, we use the FileObject member of the current stack location.

When an application calls the CreateFile function, this request goes to the ObjectManager which verifies the existence of the desired object, then checks whether the application has rights to obtain a handle to this object, and, if everything is agreed, the request reaches your driver in the form of an IRP with its Major Function as IRP_MJ_CREATE. To get the FileObject referring to this new connection being created, you need to do as shown at the code below.

    //-f--> Gets the FileObject referring to this list
    pStack = IoGetCurrentIrpStackLocation(pIrp);
    pFileObject = pStack->FileObject;

This or that list?

All subsequent operations that come from the same object instance will come with the same FileObject. This helps tracking the context of a certain device opening from the several ones that your driver receives.

So, all that I need to do is to create a list of FileObjects and then link each one of them to a string list? The idea of linking the FileObject to a structure that holds this context is so obvious that the system has already reserved a space into the FILE_OBJECT structure exclusively for this use.

typedef struct _FILE_OBJECT
{
    CSHORT  Type;
    CSHORT  Size;
    PDEVICE_OBJECT  DeviceObject;
    PVPB  Vpb;
    PVOID  FsContext;
    PVOID  FsContext2;
    PSECTION_OBJECT_POINTERS  SectionObjectPointer;
    PVOID  PrivateCacheMap;
    NTSTATUS  FinalStatus;
    struct _FILE_OBJECT  *RelatedFileObject;
    BOOLEAN  LockOperation;
    BOOLEAN  DeletePending;
    BOOLEAN  ReadAccess;
    BOOLEAN  WriteAccess;
    BOOLEAN  DeleteAccess;
    BOOLEAN  SharedRead;
    BOOLEAN  SharedWrite;
    BOOLEAN  SharedDelete;
    ULONG  Flags;
    UNICODE_STRING  FileName;
    LARGE_INTEGER  CurrentByteOffset;
    ULONG  Waiters;
    ULONG  Busy;
    PVOID  LastLock;
    KEVENT  Lock;
    KEVENT  Event;
    PIO_COMPLETION_CONTEXT  CompletionContext;
    KSPIN_LOCK  IrpListLock;
    LIST_ENTRY  IrpList;
    PVOID  FileObjectExtension;
 
} FILE_OBJECT, *PFILE_OBJECT;

The FsContext and FsContext2 fields are used for this purpose and unless you implement a filter, you can at ease use them. To make each device opening has its own list, it is necessary to store the head list address in one of these fields, as it is shown below at the new implementation of OnCreate. The whole source code changes are available for downloading at the end of this post.

/****
***     OnCreate
**
**      This routine is called whenever an application or driver
**      tries to get a handle to the device we have created.
*/
 
NTSTATUS
OnCreate(IN PDEVICE_OBJECT  pDeviceObj,
         IN PIRP            pIrp)
{
    NTSTATUS            nts = STATUS_SUCCESS;
    PBUFFER_LIST_HEAD   pListHead;
    PIO_STACK_LOCATION  pStack;
 
    //-f--> A hello to the debugger...
    KdPrint(("Opening EchoDevice...\n"));
 
    //-f--> Allocates the list head for this IRP_MJ_CREATE
    pListHead = (PBUFFER_LIST_HEAD) ExAllocatePoolWithTag(
        PagedPool,
        sizeof(BUFFER_LIST_HEAD),
        ECHO_TAG);
 
    if (pListHead)
    {
        //-f--> Initializing the buffer list and its Mutex
        InitializeListHead(&pListHead->BufferList);
        KeInitializeMutex(&pListHead->Mutex, 0);
 
        //-f--> We store the context to the FileObject.
        pStack = IoGetCurrentIrpStackLocation(pIrp);
        pStack->FileObject->FsContext = pListHead;
    }
    else
        nts = STATUS_INSUFFICIENT_RESOURCES;
 
    //-f--> Here we complete the IRP with success.
    pIrp->IoStatus.Status = nts;
    pIrp->IoStatus.Information = 0;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return nts;
}

Is a FileObject equivalent to a Handle?

No. Initially we have a handle for each FileObject, but the number of handles to a FileObject increases as their handles are duplicated. When the CreateFile function is called, your driver receives an IRP_MJ_CREATE; however your driver is not alerted when someone calls the DuplicateHandle function. Thus, each handle points to an object but an object can be pointed out by several handles.

Who will clean this mess?

When all references to a given FileObject are released, your device will receive an IRP_MJ_CLOSE. Let’s use this event to clean up any remaining strings on the list.

/****
***     OnClose
**
**      I'll make it simple just saying that this routine is called, whenever
**      an application or driver closes the handle which was previously opened.
**      Actually, this does not happen exactly in this way. (postponed to a future post)
*/
 
NTSTATUS
OnClose(IN PDEVICE_OBJECT  pDeviceObj,
        IN PIRP            pIrp)
{
    PBUFFER_LIST_HEAD   pListHead;
    PIO_STACK_LOCATION  pStack;
    PLIST_ENTRY         pEntry;
    PBUFFER_ENTRY       pBufferEntry;
 
    //-f--> A hello to the debugger...
    KdPrint(("Closing EchoDevice...\n"));
 
    //-f--> Retrieves the list referring to this FileObject.
    pStack = IoGetCurrentIrpStackLocation(pIrp);
    pListHead = (PBUFFER_LIST_HEAD)pStack->FileObject->FsContext;
 
    //-f--> Here, we remove all the remaining nodes that were not read
    //      by the application. That would happen if the application had called
    //      WriteFile but not ReadFile.
    while(!IsListEmpty(&pListHead->BufferList))
    {
        //-f--> It takes the first node from the list.
 
        pEntry = RemoveHeadList(&pListHead->BufferList);
 
        //-f--> Retrieves the base address from the node
        pBufferEntry = CONTAINING_RECORD(pEntry, BUFFER_ENTRY, Entry);
 
        //-f--> Finally releases the memory used by
        //      that node.
        ExFreePool(pBufferEntry);
    }
 
    //-f--> Releases the memory used by the head list.
 
    ExFreePool(pListHead);
 
    //-f--> Here, we complete the IRP with success.
    pIrp->IoStatus.Status = STATUS_SUCCESS;
    pIrp->IoStatus.Information = 0;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}

When an application is terminated or even when it falls unwillingly, all those application handles are closed by the system. Thus, it is guaranteed that your driver will always receive the IRP_MJ_CLOSE related to the object that was released. Actually, there is a little story about IRP_MJ_CLEANUP and IRP_MJ_CLOSE that we will let to the next time.

Once implemented the change, each opened handle will own list, unless the handle is duplicated. If we repeat the same sequence of the listed steps above to force the error, we will get the following output.

In a future post, I’ll show you how to give names to the lists in order to allow different processes begin able to open the same list from a known name.

CYA! 🙂

FileObjEcho.zip

Debug Option or Security Fault?

Tuesday, August 21st, 2007

Some time ago I have written a post that talks about replacing faulty drivers using WinDbg. This is nn excellent technique to substitute drivers which, because of some kind of problem, prevents the machine from starting. However, to be able to enjoy all of this facility, there must be a connection between the system and the Kernel Debugger. This brings us to my last post that ostensibly talks about how to enable this feature just being in front of the machine, and at worst, having a serial port. All of this is too easy, after all; you never know where an unknown problem can happen and much less, in which machine ir is going to happen. But all of this convenience has a price. The side effect is that anyone can debug the kernel of a machine without ever having any valid account on it. In fact, a laptop, a cable and a serial port are beyond than enough weapons to dismantle the system security, without a password, wireless network and even without brute-force, only doing Kernel Debugging.

Installing a Driver Through the Serial Port

Drivers are a kind of software that needs to be reliable and very well written. After all, they run at the lowest level of the system. With the drivers, it is actually very easy to cheat the system, since most of the system runs on the service offered by the kernel. The posts above mentioned have motivated me to write a small proof of concept that aims to inject a driver which installs itself on the system. This driver, in turn, extracts and installs a program into the Windows which will run every time one logs on the system. To do that, we only need a machine that can be debugged. My last post shows that this condition is not so difficult to be found. Want to try? What’s the percentage of computers around you that have serial ports?

Step by Step

This is one of those posts that come with a code available for downloading. The whole procedure shown here can be reproduced and modified by the readers of this blog. This is not a blog devoted to attack Windows; and my goal here is purely didactic. I won’t explain every line of the sample code; otherwise, this post would be very extensive. However, I am willing to answer any questions about this. The figure below outlines the steps to be taken to achieve our goal.

  1. The first step occurs when compiling the sample driver. The solution has three available projects. The first project is the application to be injected. In this case, a Win32 application that just displays a message and is ended up. We will refer to this application as MyFile.exe. The C/C++ Run Time was removed, in order the smallest possible application to be obtained. This will be worthy a lot when you have to transfer everything via a serial cable at 19200. The second project is just one tool. Using the archive MyFile.exe, which must already be compiled, this tool generates a header file that creates a variable of the type array of characters contained into its body, where the file passed as a command line. This is not the most advanced method of making a Self-Extractor, but it is enough for our purpose here. Let’s call this tool HeaderFile.exe. When the driver is compiled, this header file is included making the variable containing the application be injected. We will call our driver MapInject.sys. The driver in this example is compiled using ddkbuild.cmd with Visual Studio 2005. More details with this regard in this post.

    /****
    ***     WinMain
    **
    **      This application does almost nothing and doesn't use C/C++ Run Time
    **      so that we can avoid a bunch of codes.
    */
     
    int WINAPI WinMain(HINSTANCE   hInstance,
                       HINSTANCE   hPrevInstance,
                       LPSTR       lpCmdLine,
                       int         nShowCmd)
    {
        //-f--> That is it...
        MessageBox(NULL,
                   L"A serial port was found",
                   L"DriverEntry.com.br",
                   MB_OK | MB_ICONEXCLAMATION);
     
        return 0;
    }
  2. Using driver mapping techniques demonstrated in this post, we can make our driver be loaded in replacement of any driver in the pre-existing system. Obviously, our driver will not perform all the steps that the original driver should perform, thus, we must not choose a driver which does essential tasks for the system loading, such as disk drives, video or something like that. Particularly I have chosen using the Partport.sys parallel port driver, which is a driver that exists in any basic Windows installation and don’t not make us so missed while playing here. This driver is not also a Boot driver, because boot drivers need a special Loader on Windows XP to be mapped by the Debugger.

    map 
    \Windows\System32\drivers\parport.sys 
    Z:\MapInject\Driver\objfre_wnet_x86\i386\MapInject.sys
  3. After the driver has been loaded and mapped by the system, all that we need to do on the system is just some willingness. When our driver is first loaded, it is loaded in replacement of Parport.sys. In this condition, the driver must install itself on the system. Some things have never changed. To install a driver on Windows NT platform just create a few key values in the system registry, as described in this post. This will still work on Windows Vista. Our driver does this at this time.

  4. After making the registry modifications, now we have to rename our driver because it was mapped and, for that reason, it gets the replaced driver name. Thus, a function changes the name of the driver from Parport.sys to MapInject.sys. This driver could remain installed using the original name but, our driver would be replaced by the system restore when the driver mapping didn’t take place.

  5. As you know, our driver has a variable that contains the whole body of our application. Thus, it is very simple to extract the application and save it into the disk. The System32 directory comes in handy as a destination for our application. Since we’re running on system account at this time, we have no problem on doing it.

  6. Now that our application has been extracted, we have to make it run automagically. Some of you may know that there is no documented or reliable enough way to create a process from the system kernel however, there are several places on registry where we could write and ask an existing process in Windows to start our application. One of the most classic registry keys that allow this it is the Run of Windows Explorer; but, as shown in this application, there are many other keys to be chosen. When a user logs on the system, the Shell enumerates this key and executes each line in the user’s account that is logged on. This will make our program be executed.

Making it Work

Again, a virtual machine fits like a glove for this type of thing. If you do not know how to do Kernel Debugging using a virtual machine, this post can help you. Everything is very simple after the driver being already encoded. The only thing needed to complete the test set is a mapping that replaces the Parport.sys driver for a MapInject.sys file, as it is shown in the map file above. After that, just wait until the system loads up and everything is done. Any user who logs on to the system will see the message of our program. A point to note is that, even if the user is smart enough to find the MyFile.exe file, our change at the registry and delete them, they will be recreated when the MapInject driver starts on each system reboot. To stop this process, just remove the MapInject driver from the system.


Password? What For?

Windows protects its most important resource for most users, allowing only administrators to have access to the machine settings that can compromise the system stability. This phrase is kind of “cute” and makes several system administrators to feel comfortable. But life is a box of surprises, and in a nice sunny morning, a post is published on a RootKits website, providing tips on how to log into a system in Debug Mode without any password. Recently, another post has come out about it and I will not repeat everything here but, I can say that this same technique also works with Windows Vista. In fact, if you can log into the system without using any password, you will not need to map a driver to make it run on this machine. Just log in as an administrator, install it and go ahead but, I admit that it was at least funny to write this proof of concept, and moreover, the sources may still be an example for some tasks you want to do in Kernel Mode.

A possible solution? Maybe letting your serial port disabled in BIOS, which should be password protected, is something to be done. But there is not much you can do when someone has physical access to the machine.

Enough, I already wrote too much.
Hugs!

MapInject.zip

Emergency Debug

Wednesday, August 15th, 2007

Suddenly, a blue screen. That’s right, that driver which you had not seen its source files for so long, which was your model for stable driver, the one that was installed in the machine of the CEO where you have worked, the same one that suddenly decided to take revenge and simply got a blue screen at the system startup. That means the machine turns on and resets and resets and resets in an infinite loop that runs in parallel with your resignation letter printing which, by the way, has being printed on another PC. To debug this machine and see what is happening, and then save your project, your job, your dignity, your marriage, and why not, your life: you must configure the system to enter in Debug Mode so that our inseparable friend WinDbg can take action. But how about setting it to debug a machine that is not even starting? Today I will talk about the support that Windows offers to avoid such an embarrassing situation to connect a Debugger in a computer that has never its settings for Kernel Debugging enabled, either through BOOT.INI or BdcEdit.

This post assumes that you have already known how to do Kernel Debugging and uses some related terms with this regard. Since Windows 2000, if you press the F8 key while the machine is running the NT Loader, more precisely, 2 seconds before the system starts to loading up, the system will freeze up and displays the menu as it is shown below.

Select the “Debugging Mode” item. It will take us to the list of installed operating systems. Select the system and the rest is up to the WinDbg. Under these conditions, setting the serial connection would be applied a baud rate of 19200 on the higher serial port existing on your machine. That is, if your PC had two serial ports, then the connection would be made on COM2 at 19200. At least that’s what tells us the reference.

But in real life…

If you do some tests, will also conclude that we cannot believe everything we read. Both Windows 2000 and Windows XP always use COM2 port with 19200.

My computer is modern and it only has one serial port. Can I kill myself? That is it, even in theses cases, the system tries to use COM2, even if it does not exist. But don’t worry, life is beautiful and there is still hope. Some BIOS allow you to configure the base address and interrupt about the only existing serial port. This will help us greatly; after all, the NT Loader is not a Win32 application that requests a handle to the COM1 or COM2 device through the Object Manager. It simply follows the addresses adopted as standards.

  • COM1: Address 3F8h, IRQ 4
  • COM2: Address 2F8h, IRQ 3

In this way you can configure the only port (COM1) to answer for the addresses which are normally used for COM2. The BIOS usually has a list of features commonly used by serial ports. Thus, any autistic chimp could make this change.

But my computer is even more modern and has no serial port at all. Can I kill myself now? Hope it is the last to die. You can still install a PCI card Expander (PCMCIA in case of notebooks) that provides us with the needed serial ports. It is important to note that this board should create additional ports COM1 and COM2 at the above standard addresses.

You don’t understand, I am an unlucky bastard who bought a MacBook 13″ which, besides not having serial ports, also offers no PCMCIA or ExpressCard slot. Can I kill myself now? As I have mentioned in another post, serial ports created from USB ports are not an option for using in a TARGET machine during the Kernel Debugging. This connection is made by the NT Loader and serial ports that it knows and they are the only those ones the addresses mentioned above. OK, now you can kill yourself.

Anything that could get better?

Windows Vista ignores the documentation mercilessly. The default setting for Kernel Debugging when you press F8 during its Boot is for using  COM1 port with 115200. But if you used the Bcdedit application with the /DbgSettings to modify the connection settings for Kernel Debugging, then these same settings will be used  when F8 is pressed. That is, if you are an unlucky bastard that, like me, have configured the IEEE1397 port for debugging into your MacBook, then these are the settings used when you press F8.

Pode parecer brincadeira, mas é realmente frustrante ter que ir até à máquina do cliente onde seu driver está dando trabalho, armado dos seus vários aparatos tecnológicos, tais como notebook, porta FireWire, cabo serial e assim por diante, e não poder fazer nada simplesmente porque você não consegue conectar o depurador.

It may seem fun, but it’s really frustrating having to go to the customer machine where your driver is annoying, armed with all of your various technological devices such as laptop, FireWire port, serial cable and so on, and simply could not do anything because you cannot attach the debugger.

Once again, I hope I could help in anyway.
Cya!

My Personal GINA

Wednesday, August 8th, 2007

Due to my returning classes to the university, my time to write posts has now subsided, and once again, you will have to put up a post that says nothing about drivers. In fact, I wrote this GINA sample while I was writing a post about drivers. My friends Slug and Thiago have told me I should just leave this post and write one which could be applied to Windows Vista, since GINAs have not longer been supported on Windows Vista. Then, I have ended up forgetting this code over here. Poor thing… Anyway, as I have thought the result was at least funny, I’ll leave this Stub GINA here (sources included), that allows us to change the title of the dialogs presented.

What is a Stub GINA?

It would be even better to say what a GINA is. I have written a few things about this subject on the post that talks about how to use SoftIce, but in summary, GINA is the system component that implements the Graphical Interface for Network Authentication for users on the computer. Do you still want it more concise? It is the small screen for system logon. GINA is responsible for receiving the data that identifies a user and pass them to the components that can validate their password and generate the token with the user’s credentials. This token is used to create the session that the user is logging in and where your desktop will be created. GINA also implements the interface that makes the password changing, lockout and station shutdown. I will not detail all the steps here: everything is explained at the Platform SDK.

The original Windows GINA is implemented into a DLL named Msgina.dll that is into the System32 directory. To implement a new GINA, you must create a new DLL and “tell” the system that this DLL will be the new GINA via registry key. However, creating a GINA is not that easy as it seems to be. I have developed some of it and let’s say  documentation could be better. GINA has many responsibilities and if you just want to supplement or change any of its default behavior, you should simply create a stub GINA. Stub GINA is a DLL that exports all the functions GINA should do, but it passes the calls to the original system GINA, thus, giving us the option to only change the desired features.

This is not a Tutorial

If you want to learn how to develop a stub GINA and need a starting point, then go to the Platform SDK Samples folder and use the example that can be found at C:\MSSDK\Samples\Security\Gina\GinaStub. The project I’m leaving here performs some juggling to avoid too many repetitive codes and it also does not use the C/C++ Run Time, so that, it can be compiled using Visual Studio 2005 and still be able to run on a Windows NT 4.0.

Installing a GINA

To install a GINA, you must create a value called GinaDLL at the Winlogon registry key, as it is shown below. This value is queried by Winlogon.exe and, if this value does not exist, the default GINA is loaded, though. The GinaTitle value should contain the message that will appear at the dialog titles. Actually, this value has nothing to do with Windows: our stub GINA is the one that reads this value. From the source files, available for download at the end of this post, there is a script file that sets these registry keys to make your life easier.

Make a copy of Gina.dll file to the System32 directory. Make sure that everything is all right before rebooting the machine to make these changes take effect. If something is wrong and Winlogon.exe is not able to load the GINA, the window below appears before anything else.

This MessageBox design has improved greatly from Windows 2000. If the same problem happens on Windows NT 4.0, the following message would be displayed.

Useful tips for GINA coders

Writing GINA is the opportunity for User-Mode developers generating their own blue screens. Your DLL is loaded by Winlogon.exe, and thus, it runs on its process address space. This means that if you have an unhandled exception, this will bring this process down. Winlogon is a critical process and it cannot be overthrown. In short, the blue screen is shown up.

The next tip is kind of silly, but it’s worth being commented. During the process of developing a GINA, it is natural to have multiple builds and you will need to replace the GINA that is being used for the new one. You may have tried to override it, but as always, Winlogon.exe keeps it loaded and you cannot delete the current one. Like any DLL under these conditions, you can rename it while it is being used by a program. This lets you put a new version at the System32 directory without having to delete the one which is currently running. When the system is restarted, Winlogon will pick up the new GINA and drop the old one.

I hope you enjoyed the new toy. Now I need to continue that post.
Have fun!

TitleGina.zip