Created
December 7, 2017 12:39
-
-
Save sraboy/5c23d59e1a29d0681553cf28c2485d0a to your computer and use it in GitHub Desktop.
Win32 Kernel Mode Webserver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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, ¤tOffset, 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, ¤tOffset, 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