flat assembler
Message board for the users of flat assembler.

Index > Windows > Running fasm Code in a Windows Kernel Mode Driver

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 04 Jan 2007, 22:09
Sorry for the length of this post, but it takes some explaining...

While this approach won't help smoke (sorry, my fasm skills aren't good enough to help write a driver totally in fasm), this technique will enable running fasm code in a Windows kernel mode driver. This approach involves using the Microsoft tools to create the driver and linking in fasm produced .lib files into that driver.
Microsoft and others in the Windows kernel development community insist that Windows drivers MUST be written with only the tools provided in the DDK (namely the MS assemblers ml.exe, etc.). I was advised numerous times to give up on trying to get fasm code compiled into the driver, but so far I haven't had any troubles, once I jumped through many M$ created hoops trying to get it to work.
There is one issue I haven't worked out yet, and that's the SAFESEH issue. SAFESEH is a safe exception handling structure that is default on all the new MS linkers and is designed to prevent security issues such as buffer overflows. In order to get my fasm based drivers to compile and link, I have to turn off SAFESEH checking (the method for turning SAFESEH off in the linker is undocumented and it took me quite a while to figure it out). MASM has a .SAFESEH directive and I'd like to work on providing one in fasm. Perhaps some of you can help.

Here goes:

Tools you will need:

fasm Cool
Windbg
Windows DDK
(Windbg and DDKs can be found here: http://www.microsoft.com/whdc/resources/downloads.mspx)
VMWare or Virtual PC

Beleive me, you'll want to test your drivers in a VM image, or on dedicated test machine because you will kill that test machine multiple times. VM images are easy and quick to re-do when you do hammer your machine.

Configuring your tools:

Windbg:
After installing Windbg:
1) open the Symbol Search Path dialog (File -> Symbol File Path)
2) configure Windbg to use MS’s online Symbol Server and cache debug symbols locally:
srv*c:\windows\symbols*http://msdl.microsoft.com/download/symbols
3) create a shortcut on your desktop to Windbg and specify the following command line:
windbg –b –k com:pipe,port=\\.\pipe\com_1,resets=0

VMWare:
1) open the Configuration Editor from the Settings menu
2) Click the Add button to open the Add Hardware Wizard
3) Select Serial Port and click Next
4) Select Use Named Pipe, and change the name to:
\\.\pipe\com_1
5) Select This end is the server
6) Select The other end is an application
7) Click on Advanced, and select Yield on CPU poll
8- Click Finish and then OK
9) When the VM boots (I use WinXP Pro) you need to edit the boot.ini file to read as follows:
[boot loader]
timeout=30
default-multi (0) disk (0) rdisk (0) partition (1) \WINDOWS

[operating systems]
multi (0) disk (0) rdisk (0) partition (1) \WINDOWS=”Microsoft Windows XP Professional” /fastdetect
multi (0) disk (0) rdisk (0) partition (1) \WINDOWS=”Microsoft Windows XP Professional” – DEBUG /fastdetect /debugport=com1 /baudrate=115200

(note: the above options should be on one line and not wrapped around)

Now, reboot the VMWare OS and while it’s booting, double click on the desktop shortcut to Windbg you created earlier to enter kernel mode debug.

Setup the DDK Directory:

1) create a new folder in the WINDDK\3790.1830\src directory to hold your source files and other files need to build the driver
2) copy a makefile into this new folder (use any of the example makefile – don’t edit)
3) use notepad to create a “SOURCES” file (no extension) and place it in the new folder. an example SOURCES file is:

TARGETNAME=<what you want to call the driver – no extension>
TARGETPATH=.\lib
TARGETTYPE=DRIVER
TARGETLIBS=<your lib filename.lib>
SOURCES=<list your source files (space separated)>
NO_SAFESEH=1

Note: the NO_SAFESEH=1 statement is needed to get around the safe exception handling checking on your fasm generated .lib files that is now default on M$ linkers. If you don’t include this line the driver won’t build because of linker errors “unable to create safeseh image”. It took me a day to find this undocumented command (the alternative is to use MASM and the .SAFESEH directive to create a safe exception handler driver ….. no thanks!).

It would be nice to have a SAFESEH capability for fasm so we don’t have to turn off” this safety feature to get our fasm based driver to compile…..

Writing the Code:

Driver code: I suggest starting with the source code for one of the sample drivers that comes with the DDK and plugging your code into that (call your fasm procs – be sure to declare your proc name as extern in the driver code). Use whatever editor you like but don’t compile the .c file. You need to use the DDK build utility to compile the source code (more on that later). Copy the .c file into the folder you created in the DDK directory earlier.

Here's a brief sample driver:
Code:
#include "ntddk.h"
#include "testdriver.h"

#define NT_DEVICE_NAME L"\\Device\\hypervista"
#define DOS_DEVICE_NAME L"\\DosDevices\\hypervista"

extern myproc();

/* Function Declarations */
NTSTATUS hypervistaOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS hypervistaClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
void hypervistaUnload(IN PDRIVER_OBJECT DriverObject);


NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
    PDEVICE_OBJECT deviceObject = NULL;
    NTSTATUS status;
    UNICODE_STRING NtNameString;
    UNICODE_STRING Win32NameString;

    KdPrint(("Hypervista driver entered!\n"));

/* Create string version of the device name */

    RtlInitUnicodeString(&NtNameString, NT_DEVICE_NAME);

/* Create Device Object */

    status = IoCreateDevice(DriverObject,
                                         0,
                                 &NtNameString,
                                 FILE_DEVICE_UNKNOWN,
                                 0,
                                         FALSE,
                                         &deviceObject);

        if (NT_SUCCESS(status))
        {
/* Create dispatch points for create/open, close, and unload */

    DriverObject->MajorFunction[IRP_MJ_CREATE] = hypervistaOpen;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = hypervistaClose;

    DriverObject->DriverUnload = hypervistaUnload;
    KdPrint(("Hypervista driver just about ready!\n"));

/* Create string version of the Win32 device name */

    RtlInitUnicodeString(&Win32NameString, DOS_DEVICE_NAME);

/* Create symbolic link between drive name and the Win32 namespace */

    status = IoCreateSymbolicLink(&Win32NameString, &NtNameString);
        if(!NT_SUCCESS(status))
        {
        KdPrint(("Hypervista driver couldn't create symbolic link\n"));
        IoDeleteDevice(DriverObject->DeviceObject);
        }
        else
        {
        KdPrint(("Hypervista driver initialized!\n"));
        }
        }
        else
        {
        KdPrint(("Hypervista drive couldn't create device.\n"));
        }
    return status;
}
NTSTATUS hypervistaOpen(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
        KdPrint(("Hypervista driver opened!\n"));
        KdPrint(("fasm Code is working!!  %d\n", myproc()));
        
        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Information = 0;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}

NTSTATUS hypervistaClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
        KdPrint(("Hypervista driver closed!\n"));
        
        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Information = 0;

        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        return STATUS_SUCCESS;
}

void hypervistaUnload(IN PDRIVER_OBJECT DriverObject)
{
        UNICODE_STRING Win32NameString;
        KdPrint(("Hypervista driver Unloading.\n"));

/* Create string version of our Win32 device name */

    RtlInitUnicodeString(&Win32NameString, DOS_DEVICE_NAME);

/* Delete the link from the device name to the Win32 namespace */

    IoDeleteSymbolicLink(&Win32NameString);

/* Delete device object */

    IoDeleteDevice(DriverObject->DeviceObject);
}
    


Here's my simple test program to exercise the driver:
Code:
#include "windows.h"
#include "stdio.h"

HANDLE hTest;

int main(int argc, char **argv)
{
   hTest = CreateFile("\\\\.\\hypervista", 
                GENERIC_READ | GENERIC_WRITE,
                0,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                NULL);

        if (hTest != INVALID_HANDLE_VALUE)
        {
                printf("Hypervista Driver Working Properly!!\n");
        CloseHandle(hTest);
        }
        else
        {
        printf("Can't get a handle to the Hypervista device....\n");
        }
        return 0;
}
    


Here's my quick and dirty test fasm proc (note: I had to "mangle the name by adding the @0 to the end of the name because the MS compiler mangled the original). Thanks to Quantum for this test code! (I copied it from him on another thread)
Code:
format MS COFF

public myproc as '_myproc@0'
myproc:
mov eax,5
ret
    


fasm code:
1) use the MS COFF file format in fasm and declare your procedures as public (public myproc as ‘_myproc’) and compile to .obj file
2) use the DDK lib.exe utility to create a .lib file (located in the winddk\3790.1830\bin\x86 directory)
lib /out:<what ever you want to call your filename.lib> <your filename.obj>
3) copy the resulting .lib file to the folder you created in the DDK directory earlier and add the .lib filename to the SOURCES file (TARGETLIBS=<.lib filename.lib> you created earlier.

Compiling the Driver:

1) open the command line DDK and go to the folder/directory you created in winddk\3970.1830\src\ earlier. this folder should contain the following files:
a. makefile
b. SOURCES
c. <your .lib file(s)>
d. <your .c driver source file(s)>
2) type “build [-options]”
Note: the options I like are: -cegZ (c=delete all object files, e=generate build log, g=display warnings in color, and Z=no dependency checking) (build –cegZ)

Note: if you get link errors like “unresolved symbol” or “unresolved function”, check the build log (which was placed in your DDK folder). Check to see if it’s the proc you wrote in fasm only with some extra characters ….. name mangling!!!! Yes, name mangling, even though the driver is a .c file not .cpp …. thanks a lot Microsoft!!! You’ll have to go back into your fasm source file, change the name of the proc to match the mangled one as listed in the build log, recompile, re-create .lib file, copy it to DDK directory and run the DDK build utility again …. like I said,… thanks Microsoft …

If all goes well, your driver will be built and placed into your DDK \<yourfoldername>\lib\i386 directory.

Installing and Testing the Driver:

1) start your VMWare OS
2) copy your driver to the ..\windows\system32\drivers folder
3) edit the registry as follows (there are utilities out there, but I did mine manually):

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services

Add a new node <your driver node name>

Description = REG_SZ Starts the <your driver name> driver>
DisplayName = REG_SZ <your driver name>
ErrorControl = REG_DWORD 0x00000001
ImagePath = REG_EXPAND_SZ System32\Dirvers\<your dirvername.sys>
Start = REG_DWORD 0x00000003
Type = REG_DWORD 0x00000001

4) restart the VMWare OS
5) start Windbg
6) go to Control Panel/Performance and Maintenance/System
7) click on the Hardware tab, click on the Device Manager button
8- click on View, and Show hidden devices
9) you will see a new device type show up the tree called Non-Plug and Play Drivers
10) expand that node and you should see your driver listed (if not, go back to regedit, change the Start = REG_DWORD value to 0x00000001, reboot, and repeat steps 5-8.
11) Right-click on your driver, click Properties, click the Driver tab, and click Start
12) check the Windbg window to see your driver start
13) Exercise your driver, checking Windbg for any KdPrint messages in your driver code.

That's it.
Post 04 Jan 2007, 22:09
View user's profile Send private message Visit poster's website Reply with quote
sylwek32



Joined: 27 Apr 2006
Posts: 339
sylwek32 05 Jan 2007, 00:36
wow hypervista. good work!
Thanks
Post 05 Jan 2007, 00:36
View user's profile Send private message Reply with quote
MichaelH



Joined: 03 May 2005
Posts: 402
MichaelH 05 Jan 2007, 01:55
Windows Kernel Mode Driver examples using fasm only -


Roki by okasvi

http://board.flatassembler.net/topic.php?t=5812


KMD stuff by AMD64

http://board.flatassembler.net/topic.php?t=648


r0pc by L.chemist

http://board.flatassembler.net/topic.php?t=3434



Of course jumping into kernel mode from user mode should be the preferred method for running kernel mode code..... well..., maybe not Wink
Post 05 Jan 2007, 01:55
View user's profile Send private message Reply with quote
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 05 Jan 2007, 02:44
Thanks MichaelH. smoke is interested in fasm only device driver. That's not my objective.
I think there is value in using the device driver tools and facilities provided by M$ (even though they can be a bit difficult sometimes). I wanted to demonstrate the ability to provide fasm power to M$ drivers, even though M$ strongly discourage it Razz
I also wanted to provide a brief tutorial on setting up for basic Windows driver development for fasmers who might be interested playing around with it.
I hope all is well with you there in NZ (summertime!!)
Post 05 Jan 2007, 02:44
View user's profile Send private message Visit poster's website Reply with quote
MichaelH



Joined: 03 May 2005
Posts: 402
MichaelH 05 Jan 2007, 03:37
Hi HyperVista

Quote:

I hope all is well with you there in NZ (summertime!!)


We've just had the coldest winter ever recorded and I usually get into my shorts to cool down in October, here it is January and I'm still cold Sad ..... Lucky this global warming thing is going to fix that Wink

Thanks for your efforts.
Post 05 Jan 2007, 03:37
View user's profile Send private message Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 05 Jan 2007, 06:11
HyperVista: post 2 very small driver examples, with and without SAFESEH, and we can reverse them to see what safeseh actually does.

some info here: http://msdn2.microsoft.com/en-us/library/9a89h429(VS.80).aspx

maybe it is enough to define and export those structures, but it is also possible that there is some flag in header set, and tomasz would have to add it to formatter.
Post 05 Jan 2007, 06:11
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 05 Jan 2007, 12:36
vid wrote:
Quote:
post 2 very small driver examples, with and without SAFESEH, and we can reverse them to see what safeseh actually does


will do.

I found the link you provided during my search for "the answer". I think the link of interest for us from that page is the link to .SAFESEH (MASM directive)
http://msdn2.microsoft.com/en-us/library/16aexws6(VS.80).aspx

Here's some interesting text and code from that page:

Code:
Microsoft Macro Assembler Reference  
.SAFESEH  

to register a safe exception handler, create a new MASM file (as follows), assemble with /safeseh, and add it to the linked objects.


.386
.model  flat
MyHandler   proto
.safeseh    MyHandler
end

    


it will be interesting to learn exactly what the MASM directive .safeseh does Wink
Post 05 Jan 2007, 12:36
View user's profile Send private message Visit poster's website Reply with quote
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 09 Feb 2007, 01:20
Update: here's a screen shot of kernel debugging via Windbg. it shows fasm code running in Windows XP device driver Smile. fasm code checking to see if processor is Intel, checking to see if VMX (hardware virtualization) is supported, checking and setting CR4.VMXE[13], checking the lock bit MSR[0x3A] bit 0, and checking VMXON Enable MSR[0x3A] bit 2. Next step is to set-up VMCS (virtual machine control structure) and launching VMXON.

Image


Last edited by HyperVista on 28 Aug 2007, 00:30; edited 2 times in total
Post 09 Feb 2007, 01:20
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 09 Feb 2007, 07:40
HyperVista: please assemble and send two short (preferably do-nothing) .obj files in MASM, one with SAFESEH and other without. i think we could find out enough info.

also, you can make SAFESEH for FASM procedures using MASM, as you mentioned, but i believe it's just matter of defining and exporting of structure, no big deal.

PS: Can't wait till you show those engineers they weren't right. But my quess is that they are just lazy.
Post 09 Feb 2007, 07:40
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 13 Feb 2007, 08:59
got it!!! It's described in MS COFF specs:

Quote:
83The .sxdata Section
The valid exception handlers of an object are listed in the .sxdata section of that object. The section is marked IMAGE_SCN_LNK_INFO. It contains the COFF symbol index of each valid handler, using 4 bytes per index.
Additionally, the compiler marks a COFF object as registered SEH by emitting the absolute symbol “@feat.00” with the LSB of the value field set to 1. A COFF object with no registered SEH handlers would have the “@feat.00” symbol, but no .sxdata section.


unfortunately i don't know how to specify "IMAGE_SCN_LNK_INFO" on section with FASM, and what does "emit absolute symbol" mean. I think Tomasz's intervence would be handy here.
Post 13 Feb 2007, 08:59
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 13 Feb 2007, 11:23
You specify IMAGE_SCN_LNK_INFO in MS COFF format with "linkinfo" flag in section statement (usually you combine it with "linkremove" flag, I don't know if this is the case, too).
And emitting the absolute symbol may look like:
Code:
@feat.00 = 1
public @feat.00    
Post 13 Feb 2007, 11:23
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 13 Feb 2007, 11:37
tomasz: still, the flags 00300200h is set. Section flags should be just 00000200h. What are those two extra flags?

don:

If you want to just get rid of linker complaining, add this to file:
Code:
@feat.00 = 1 
public @feat.00    


If you want to have some handler in assembly, you must also add '.sxdata' section, i will provide example soon.
Post 13 Feb 2007, 11:37
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8356
Location: Kraków, Poland
Tomasz Grysztar 13 Feb 2007, 11:51
300000h is IMAGE_SCN_ALIGN_4BYTES, as default section alignment made by fasm is 4 bytes.
Post 13 Feb 2007, 11:51
View user's profile Send private message Visit poster's website Reply with quote
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 13 Feb 2007, 19:41
Thank you vid and Tomasz. The @feat.# is exactly what I needed. I was able suppress the comiler errors by including "NO_SAFESEH=1" in the SOURCES file. That was a shortcut fix to the issue.

I set aside the SAFESEH issue to press forward with my fasm based hypervisor, concentrating instead on the VMX set-up and launch of VMXON. I thought I'd go back later and address the SAFESEH issue.

With the information you provided on @feat.#, I can write a legitimate SAFESEH handler and .sxdata section in fasm. This is important because with without proper SAFESEH handlers the chances of getting the driver signed are slim. Thanks.
Post 13 Feb 2007, 19:41
View user's profile Send private message Visit poster's website Reply with quote
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 13 Feb 2007, 22:54
The DDK compiler didn't like the SAFESEH fix. One thing I think is curious is the error message, "error 'jvc' is not a recognized as an internal or external command" .... jvc???

My test fasm code is on the right.

Image

I appreciate the help, but nevermind the SAFESEH solution for now. I'll address that when I get the hypervisor launched. I've suppressed the SAFESEH error during build by including NO_SAFESEH=1 in my SOURCES file. With that shortcut fix, I can move forward. I really fix it later.


Last edited by HyperVista on 14 Feb 2007, 01:35; edited 1 time in total
Post 13 Feb 2007, 22:54
View user's profile Send private message Visit poster's website Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3175
Location: Denmark
f0dder 13 Feb 2007, 23:25
HyperVista: a quick google for that error shows that the DDK build environment doesn't like paths with spaces in it Smile
Post 13 Feb 2007, 23:25
View user's profile Send private message Visit poster's website Reply with quote
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 14 Feb 2007, 01:33
Hi f0dder. Good to chat with you again. Thanks for the tip ... you are correct. When I underbarred the space between "Test" and "SAFESEH" those not so clear or helpful error messages disappeared. The DDK compilers are not very helpful.

It appears the addition of @feat.00 = 1 public @feat.00 doesn't stop the compiler from complaining about SAFESEH ...


Image

Thanks vid, Tomasz, and f0dder. I'll tackle the SAFESEH issue later.
Post 14 Feb 2007, 01:33
View user's profile Send private message Visit poster's website Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 23 Feb 2007, 15:31
here are examples of minimal COFF with and without SAFESEH, compiled with MASM. Could someone find any difference besides "@feat.00"? Or can someone produce same COFF file as the one with SAFESEH is?


Description:
Download
Filename: safeseh.zip
Filesize: 611 Bytes
Downloaded: 630 Time(s)

Post 23 Feb 2007, 15:31
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid 23 Feb 2007, 16:02
I see that this code in FASM:
Code:
a=1
public a as "@feat.00"    
produces symbol of type C_EXT (public symbol) ". MASM produces "@feat.00" as C_STAT (private static symbol). This could be problem.

Tomasz: I think this would require new keyword or flag to be added... any ideas?
Post 23 Feb 2007, 16:02
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
HyperVista



Joined: 18 Apr 2005
Posts: 691
Location: Virginia, USA
HyperVista 23 Feb 2007, 16:12
Quote:
produces symbol of type C_EXT (public symbol) ". MASM produces "@feat.00" as C_STAT (private static symbol). This could be problem.

yup! I think you are right vid.

I'll test both .obj out tonight by linking them separately into my driver to see what happens with the SAFESEH compile warnings. I'm at my "real" job now and my fasm hypervisor dev machine is at home... I'll let you know.
Post 23 Feb 2007, 16:12
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.