Skip to content

Instantly share code, notes, and snippets.

@sraboy
Created December 7, 2017 12:39
Show Gist options
  • Save sraboy/5c23d59e1a29d0681553cf28c2485d0a to your computer and use it in GitHub Desktop.
Save sraboy/5c23d59e1a29d0681553cf28c2485d0a to your computer and use it in GitHub Desktop.
Win32 Kernel Mode Webserver
// Pulled from https://www.osronline.com/showthread.cfm?link=164161
/*
Kernel mode web server for Windows.
Copyright (C) 2006 Bo Brantén.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/
#include <ntddk.h>
#include <ksocket.h>
HANDLE dopen(PUNICODE_STRING dirName)
{
HANDLE dirHandle;
OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS status;
IO_STATUS_BLOCK iosb;
KdPrint(("khttpd: opendir %.*S\n", dirName->Length / 2, dirName->Buffer));
InitializeObjectAttributes(
&objectAttributes,
dirName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
status = ZwCreateFile(
&dirHandle,
FILE_LIST_DIRECTORY | FILE_TRAVERSE,
&objectAttributes,
&iosb,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_DIRECTORY_FILE |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
return (NT_SUCCESS(status) ? dirHandle : NULL);
}
HANDLE fopen(char *fileName, HANDLE rootDir)
{
ANSI_STRING afileName;
UNICODE_STRING ufileName;
HANDLE fileHandle;
OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS status;
IO_STATUS_BLOCK iosb;
KdPrint(("khttpd: fopen %s\n", fileName));
RtlInitAnsiString(
&afileName,
fileName
);
status = RtlAnsiStringToUnicodeString(
&ufileName,
&afileName,
TRUE
);
if (!NT_SUCCESS(status))
{
return NULL;
}
InitializeObjectAttributes(
&objectAttributes,
&ufileName,
OBJ_CASE_INSENSITIVE,
rootDir,
NULL
);
status = ZwCreateFile(
&fileHandle,
GENERIC_READ,
&objectAttributes,
&iosb,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE |
FILE_SEQUENTIAL_ONLY |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
RtlFreeUnicodeString(&ufileName);
return (NT_SUCCESS(status) ? fileHandle : NULL);
}
int fread(HANDLE fileHandle, void *buf, int len)
{
NTSTATUS status;
IO_STATUS_BLOCK iosb;
status = ZwReadFile(
fileHandle,
NULL,
NULL,
NULL,
&iosb,
buf,
len,
NULL,
NULL
);
return (NT_SUCCESS(status) ? iosb.Information : status);
}
static NTSTATUS fread_mn_mdl_completion(PDEVICE_OBJECT deviceObject, PIRP irp,
PVOID context)
{
*irp->UserIosb = irp->IoStatus;
if (irp->PendingReturned)
{
KeSetEvent(irp->UserEvent, IO_NO_INCREMENT, FALSE);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
int fread_mn_mdl(PFILE_OBJECT fileObject, PLARGE_INTEGER offset, ULONG len, PMDL
*mdl)
{
PDEVICE_OBJECT devObj;
KEVENT event;
PIRP irp;
PIO_STACK_LOCATION ioStack;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
*mdl = NULL;
devObj = IoGetRelatedDeviceObject(fileObject);
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoAllocateIrp(devObj->StackSize, FALSE);
if (irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
irp->UserIosb = &iosb;
irp->UserEvent = &event;
irp->Flags = IRP_READ_OPERATION;
irp->RequestorMode = KernelMode;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = fileObject;
ioStack = IoGetNextIrpStackLocation(irp);
ioStack->MajorFunction = IRP_MJ_READ;
ioStack->MinorFunction = IRP_MN_MDL;
ioStack->DeviceObject = devObj;
ioStack->FileObject = fileObject;
ioStack->Parameters.Read.Length = len;
ioStack->Parameters.Read.ByteOffset = *offset;
IoSetCompletionRoutine(irp, fread_mn_mdl_completion, 0, TRUE, TRUE, TRUE);
status = IoCallDriver(devObj, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = iosb.Status;
}
*mdl = irp->MdlAddress;
IoFreeIrp(irp);
return NT_SUCCESS(status) ? iosb.Information : status;
}
int fread_mn_mdl_complete(PFILE_OBJECT fileObject, PMDL mdl)
{
PDEVICE_OBJECT devObj;
KEVENT event;
PIRP irp;
PIO_STACK_LOCATION ioStack;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
devObj = IoGetRelatedDeviceObject(fileObject);
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoAllocateIrp(devObj->StackSize, FALSE);
if (irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
irp->UserIosb = &iosb;
irp->UserEvent = &event;
irp->MdlAddress = mdl;
irp->Flags = IRP_READ_OPERATION;
irp->RequestorMode = KernelMode;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = fileObject;
ioStack = IoGetNextIrpStackLocation(irp);
ioStack->MajorFunction = IRP_MJ_READ;
ioStack->MinorFunction = IRP_MN_COMPLETE_MDL;
ioStack->DeviceObject = devObj;
ioStack->FileObject = fileObject;
IoSetCompletionRoutine(irp, fread_mn_mdl_completion, 0, TRUE, TRUE, TRUE);
status = IoCallDriver(devObj, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = iosb.Status;
}
IoFreeIrp(irp);
return status;
}
void fclose(HANDLE fileHandle)
{
ZwClose(fileHandle);
}
int send_file(int sock, char *header, HANDLE fileHandle)
{
char* buf;
int len, sendHeader = 1;
buf = ExAllocatePool(PagedPool, PAGE_SIZE*15);
if (!buf)
{
return -1;
}
do {
len = fread(fileHandle, buf, PAGE_SIZE*15);
if (len > 0)
{
if (sendHeader)
{
sendHeader = 0;
send(sock, header, strlen(header), 0);
}
send(sock, buf, len, 0);
}
} while(len == PAGE_SIZE*15);
ExFreePool(buf);
return 0;
}
NTSTATUS lock_mdl_chain(PMDL mdl)
{
PMDL nextMdl;
NTSTATUS status;
for (nextMdl = mdl; nextMdl != NULL; nextMdl = nextMdl->Next)
{
__try
{
MmProbeAndLockPages(nextMdl, KernelMode, IoReadAccess);
status = STATUS_SUCCESS;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
}
if (!NT_SUCCESS(status))
{
break;
}
}
return status;
}
VOID unlock_and_free_mdl_chain(PMDL mdl)
{
PMDL currentMdl, nextMdl;
for (currentMdl = mdl; currentMdl != NULL; currentMdl = nextMdl)
{
nextMdl = currentMdl->Next;
if (currentMdl->MdlFlags & MDL_PAGES_LOCKED)
{
MmUnlockPages(currentMdl);
}
IoFreeMdl(currentMdl);
}
}
int send_file_mdl(int sock, char *header, HANDLE fileHandle)
{
char* buf;
int len, sendHeader = 1;
PMDL headerMdl, fileMdl;
NTSTATUS status;
buf = ExAllocatePool(PagedPool, PAGE_SIZE*15);
if (!buf)
{
return -1;
}
do {
len = fread(fileHandle, buf, PAGE_SIZE*15);
if (len > 0)
{
fileMdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
if (!fileMdl)
{
ExFreePool(buf);
return -1;
}
if (sendHeader)
{
sendHeader = 0;
headerMdl = IoAllocateMdl((void*) header, strlen(header),
FALSE, FALSE, NULL);
if (!headerMdl)
{
unlock_and_free_mdl_chain(fileMdl);
ExFreePool(buf);
return -1;
}
headerMdl->Next = fileMdl;
fileMdl = headerMdl;
}
status = lock_mdl_chain(fileMdl);
if (!NT_SUCCESS(status))
{
unlock_and_free_mdl_chain(fileMdl);
ExFreePool(buf);
return -1;
}
send_mdl(sock, fileMdl, 0);
unlock_and_free_mdl_chain(fileMdl);
}
} while(len == PAGE_SIZE*15);
ExFreePool(buf);
return 0;
}
int send_file_mn_mdl(int sock, char *header, HANDLE fileHandle)
{
int len, sendHeader = 1;
PMDL headerMdl, fileMdl;
PFILE_OBJECT fileObject;
NTSTATUS status;
LARGE_INTEGER currentOffset;
currentOffset.QuadPart = 0;
status = ObReferenceObjectByHandle(
fileHandle,
FILE_READ_ACCESS,
*IoFileObjectType,
KernelMode,
&fileObject,
0
);
if (!NT_SUCCESS(status))
{
return -1;
}
do {
len = fread_mn_mdl(fileObject, &currentOffset, PAGE_SIZE*15, &fileMdl);
currentOffset.QuadPart += PAGE_SIZE*15;
if (len > 0 && fileMdl)
{
if (sendHeader)
{
headerMdl = IoAllocateMdl((void*) header, strlen(header),
FALSE, FALSE, NULL);
if (!headerMdl)
{
fread_mn_mdl_complete(fileObject, fileMdl);
ObDereferenceObject(fileObject);
return -1;
}
status = lock_mdl_chain(headerMdl);
if (!NT_SUCCESS(status))
{
unlock_and_free_mdl_chain(headerMdl);
fread_mn_mdl_complete(fileObject, fileMdl);
ObDereferenceObject(fileObject);
return -1;
}
headerMdl->Next = fileMdl;
fileMdl = headerMdl;
}
send_mdl(sock, fileMdl, 0);
if (sendHeader)
{
sendHeader = 0;
fread_mn_mdl_complete(fileObject, fileMdl->Next);
fileMdl->Next = NULL;
unlock_and_free_mdl_chain(fileMdl);
}
else
{
fread_mn_mdl_complete(fileObject, fileMdl);
}
}
} while(len == PAGE_SIZE*15);
ObDereferenceObject(fileObject);
return 0;
}
typedef struct _COMPLETION_CONTEXT {
PMDL mdl;
PFILE_OBJECT file_object;
WORK_QUEUE_ITEM work_item;
BOOLEAN sending_header;
} COMPLETION_CONTEXT, *PCOMPLETION_CONTEXT;
static void send_file_mn_mdl_async_work_item(void *context)
{
PCOMPLETION_CONTEXT ctx = (PCOMPLETION_CONTEXT) context;
if (ctx->sending_header)
{
fread_mn_mdl_complete(ctx->file_object, ctx->mdl->Next);
ctx->mdl->Next = NULL;
unlock_and_free_mdl_chain(ctx->mdl);
}
else
{
fread_mn_mdl_complete(ctx->file_object, ctx->mdl);
}
ObDereferenceObject(ctx->file_object);
ExFreePool(ctx);
}
static void send_file_mn_mdl_async_complete(int status, void *context)
{
PCOMPLETION_CONTEXT ctx = (PCOMPLETION_CONTEXT) context;
ExInitializeWorkItem(&ctx->work_item, send_file_mn_mdl_async_work_item,
ctx);
ExQueueWorkItem(&ctx->work_item, DelayedWorkQueue);
}
int send_file_mn_mdl_async(int sock, char *header, HANDLE fileHandle)
{
PCOMPLETION_CONTEXT ctx;
int len, sendHeader = 1;
PMDL headerMdl, fileMdl;
PFILE_OBJECT fileObject;
NTSTATUS status;
LARGE_INTEGER currentOffset;
currentOffset.QuadPart = 0;
status = ObReferenceObjectByHandle(
fileHandle,
FILE_READ_ACCESS,
*IoFileObjectType,
KernelMode,
&fileObject,
0
);
if (!NT_SUCCESS(status))
{
return -1;
}
do {
ctx = ExAllocatePool(NonPagedPool, sizeof(COMPLETION_CONTEXT));
if (!ctx)
{
ObDereferenceObject(fileObject);
return -1;
}
ctx->file_object = fileObject;
ctx->sending_header = FALSE;
len = fread_mn_mdl(fileObject, &currentOffset, PAGE_SIZE*15,
&ctx->mdl);
currentOffset.QuadPart += PAGE_SIZE*15;
if (len > 0 && ctx->mdl)
{
if (sendHeader)
{
sendHeader = 0;
ctx->sending_header = TRUE;
headerMdl = IoAllocateMdl((void*) header, strlen(header),
FALSE, FALSE, NULL);
if (!headerMdl)
{
fread_mn_mdl_complete(fileObject, ctx->mdl);
ObDereferenceObject(fileObject);
ExFreePool(ctx);
return -1;
}
status = lock_mdl_chain(headerMdl);
if (!NT_SUCCESS(status))
{
unlock_and_free_mdl_chain(headerMdl);
fread_mn_mdl_complete(fileObject, ctx->mdl);
ObDereferenceObject(fileObject);
ExFreePool(ctx);
return -1;
}
headerMdl->Next = ctx->mdl;
ctx->mdl = headerMdl;
}
ObReferenceObject(fileObject);
send_mdl_async(sock, ctx->mdl, 0, send_file_mn_mdl_async_complete,
ctx);
}
else
{
ObDereferenceObject(fileObject);
ExFreePool(ctx);
return -1;
}
} while(len == PAGE_SIZE*15);
ObDereferenceObject(fileObject);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment