568 lines
13 KiB
C
568 lines
13 KiB
C
/*++
|
||
|
||
--*/
|
||
|
||
#include <ntddk.h>
|
||
#include <stdarg.h>
|
||
#include <ntverp.h> // Include to determine what version of NT
|
||
|
||
//
|
||
// This is a fix for changes in DDK releases.
|
||
//
|
||
#ifdef VER_PRODUCTBUILD
|
||
#define rmm VER_PRODUCTBUILD
|
||
#endif
|
||
|
||
#include "digifile.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
|
||
#if rmm > 528
|
||
#pragma message( "\n\\\\\n\\\\ Including PAGED CODE\n\\\\ \n" )
|
||
#pragma alloc_text( PAGEDIGIFILE, DigiOpenFile )
|
||
#pragma alloc_text( PAGEDIGIFILE, DigiCloseFile )
|
||
#pragma alloc_text( PAGEDIGIFILE, DigiMapFile )
|
||
#pragma alloc_text( PAGEDIGIFILE, DigiUnmapFile )
|
||
#endif
|
||
|
||
#endif
|
||
|
||
VOID DigiCheckMem( VOID );
|
||
|
||
//
|
||
// Describes an open DIGI file
|
||
//
|
||
|
||
typedef struct _DIGI_FILE_DESCRIPTOR
|
||
{
|
||
PVOID Data;
|
||
KSPIN_LOCK Lock;
|
||
BOOLEAN Mapped;
|
||
} DIGI_FILE_DESCRIPTOR, *PDIGI_FILE_DESCRIPTOR;
|
||
|
||
|
||
typedef struct _DIGI_MEM_DESCRIPTOR_
|
||
{
|
||
ULONG BeginTag;
|
||
ULONG Length;
|
||
LIST_ENTRY ListEntry;
|
||
} DIGI_MEM_DESCRIPTOR, *PDIGI_MEM_DESCRIPTOR;
|
||
|
||
//
|
||
// Global Data
|
||
//
|
||
ULONG TotalMemAllocated=0L;
|
||
ULONG DefaultPoolTag=(ULONG)('igiD');
|
||
LIST_ENTRY GlobalPagedMemQueue={&GlobalPagedMemQueue,&GlobalPagedMemQueue};
|
||
LIST_ENTRY GlobalNonPagedMemQueue={&GlobalNonPagedMemQueue,&GlobalNonPagedMemQueue};
|
||
KSPIN_LOCK GlobalMemSpinLock;
|
||
|
||
|
||
VOID DigiOpenFile( OUT PNTSTATUS Status,
|
||
OUT PHANDLE FileHandle,
|
||
OUT PULONG FileLength,
|
||
IN PUNICODE_STRING FileName,
|
||
IN PHYSICAL_ADDRESS HighestAcceptableAddress )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens a file for future mapping and reads its contents
|
||
into allocated memory.
|
||
|
||
Arguments:
|
||
|
||
Status - The status of the operation
|
||
|
||
FileHandle - A handle to be associated with this open
|
||
|
||
FileLength - Returns the length of the file
|
||
|
||
FileName - The name of the file
|
||
|
||
HighestAcceptableAddress - The highest physical address at which
|
||
the memory for the file can be allocated.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS NtStatus;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
HANDLE NtFileHandle;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
ULONG LengthOfFile;
|
||
WCHAR PathPrefix[] = L"\\SystemRoot\\system32\\drivers\\";
|
||
UNICODE_STRING FullFileName;
|
||
ULONG FullFileNameLength;
|
||
PDIGI_FILE_DESCRIPTOR FileDescriptor;
|
||
PVOID FileImage;
|
||
|
||
//
|
||
// This structure represents the data from the
|
||
// NtQueryInformationFile API with an information
|
||
// class of FileStandardInformation.
|
||
//
|
||
|
||
FILE_STANDARD_INFORMATION StandardInfo;
|
||
|
||
//
|
||
// Insert the correct path prefix.
|
||
//
|
||
|
||
FullFileNameLength = sizeof(PathPrefix) + FileName->MaximumLength;
|
||
|
||
FullFileName.Buffer = DigiAllocMem( NonPagedPool,
|
||
FullFileNameLength );
|
||
|
||
if (FullFileName.Buffer == NULL) {
|
||
*Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
return;
|
||
}
|
||
|
||
FullFileName.Length = sizeof (PathPrefix) - sizeof(WCHAR);
|
||
FullFileName.MaximumLength = (USHORT)FullFileNameLength;
|
||
RtlMoveMemory (FullFileName.Buffer, PathPrefix, sizeof(PathPrefix));
|
||
|
||
RtlAppendUnicodeStringToString (&FullFileName, FileName);
|
||
|
||
#if DBG
|
||
DbgPrint ("DIGIFILE: Attempting to open %wZ\n", &FullFileName);
|
||
#endif
|
||
|
||
InitializeObjectAttributes ( &ObjectAttributes,
|
||
&FullFileName,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL );
|
||
|
||
NtStatus = ZwCreateFile( &NtFileHandle,
|
||
SYNCHRONIZE | FILE_READ_DATA,
|
||
&ObjectAttributes,
|
||
&IoStatus,
|
||
NULL, // alloc size = none
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
FILE_SHARE_READ,
|
||
FILE_OPEN,
|
||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||
NULL, // eabuffer
|
||
0 ); // ealength
|
||
|
||
DigiFreeMem( FullFileName.Buffer );
|
||
|
||
if( !NT_SUCCESS(NtStatus) )
|
||
{
|
||
#if DBG
|
||
DbgPrint ("Error (0x%x) opening file\n", NtStatus);
|
||
#endif
|
||
*Status = DIGI_STATUS_FILE_NOT_FOUND;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Query the object to determine its length.
|
||
//
|
||
|
||
NtStatus = ZwQueryInformationFile( NtFileHandle,
|
||
&IoStatus,
|
||
&StandardInfo,
|
||
sizeof(FILE_STANDARD_INFORMATION),
|
||
FileStandardInformation );
|
||
|
||
if (!NT_SUCCESS(NtStatus)) {
|
||
#if DBG
|
||
DbgPrint ("Error querying info on file %x\n", NtStatus);
|
||
#endif
|
||
ZwClose( NtFileHandle );
|
||
*Status = NtStatus;
|
||
return;
|
||
}
|
||
|
||
LengthOfFile = StandardInfo.EndOfFile.LowPart;
|
||
|
||
#if DBG
|
||
DbgPrint ("File length is %d\n", LengthOfFile);
|
||
#endif
|
||
|
||
//
|
||
// Might be corrupted.
|
||
//
|
||
|
||
if( LengthOfFile < 1 )
|
||
{
|
||
#if DBG
|
||
DbgPrint ("Bad file length %d\n", LengthOfFile);
|
||
#endif
|
||
ZwClose( NtFileHandle );
|
||
*Status = DIGI_STATUS_ERROR_READING_FILE;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Allocate buffer for this file
|
||
//
|
||
|
||
FileImage = DigiAllocMem( NonPagedPool,
|
||
LengthOfFile );
|
||
|
||
if( FileImage == NULL )
|
||
{
|
||
#if DBG
|
||
DbgPrint ("Could not allocate buffer\n");
|
||
#endif
|
||
ZwClose( NtFileHandle );
|
||
*Status = DIGI_STATUS_ERROR_READING_FILE;
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Read the file into our buffer.
|
||
//
|
||
|
||
NtStatus = ZwReadFile( NtFileHandle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatus,
|
||
FileImage,
|
||
LengthOfFile,
|
||
NULL,
|
||
NULL );
|
||
|
||
ZwClose( NtFileHandle );
|
||
|
||
if( (!NT_SUCCESS(NtStatus)) || (IoStatus.Information != LengthOfFile) )
|
||
{
|
||
#if DBG
|
||
DbgPrint ("error reading file %x\n", NtStatus);
|
||
#endif
|
||
*Status = DIGI_STATUS_ERROR_READING_FILE;
|
||
DigiFreeMem( FileImage );
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Allocate a structure to describe the file.
|
||
//
|
||
|
||
FileDescriptor = DigiAllocMem( NonPagedPool,
|
||
sizeof(DIGI_FILE_DESCRIPTOR) );
|
||
|
||
if( FileDescriptor == NULL )
|
||
{
|
||
*Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
DigiFreeMem( FileImage );
|
||
return;
|
||
}
|
||
|
||
|
||
FileDescriptor->Data = FileImage;
|
||
KeInitializeSpinLock( &FileDescriptor->Lock );
|
||
FileDescriptor->Mapped = FALSE;
|
||
|
||
*FileHandle = (HANDLE)FileDescriptor;
|
||
*FileLength = LengthOfFile;
|
||
*Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID DigiCloseFile( IN HANDLE FileHandle )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine closes a file previously opened with DigiOpenFile.
|
||
The file is unmapped if needed and the memory is freed.
|
||
|
||
Arguments:
|
||
|
||
FileHandle - The handle returned by DigiOpenFile
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PDIGI_FILE_DESCRIPTOR FileDescriptor = (PDIGI_FILE_DESCRIPTOR)FileHandle;
|
||
|
||
DigiFreeMem( FileDescriptor->Data );
|
||
DigiFreeMem( FileDescriptor );
|
||
}
|
||
|
||
|
||
|
||
VOID DigiMapFile( OUT PNTSTATUS Status,
|
||
OUT PVOID * MappedBuffer,
|
||
IN HANDLE FileHandle )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine maps an open file, so that the contents can be accessed.
|
||
Files can only have one active mapping at any time.
|
||
|
||
Arguments:
|
||
|
||
Status - The status of the operation
|
||
|
||
MappedBuffer - Returns the virtual address of the mapping.
|
||
|
||
FileHandle - The handle returned by DigiOpenFile.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PDIGI_FILE_DESCRIPTOR FileDescriptor = (PDIGI_FILE_DESCRIPTOR)FileHandle;
|
||
KIRQL oldirql;
|
||
|
||
KeAcquireSpinLock (&FileDescriptor->Lock, &oldirql);
|
||
|
||
if (FileDescriptor->Mapped == TRUE) {
|
||
*Status = DIGI_STATUS_ALREADY_MAPPED;
|
||
KeReleaseSpinLock (&FileDescriptor->Lock, oldirql);
|
||
return;
|
||
}
|
||
|
||
FileDescriptor->Mapped = TRUE;
|
||
KeReleaseSpinLock (&FileDescriptor->Lock, oldirql);
|
||
|
||
*MappedBuffer = FileDescriptor->Data;
|
||
*Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID DigiUnmapFile( IN HANDLE FileHandle )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine unmaps a file previously mapped with DigiOpenFile.
|
||
The file is unmapped if needed and the memory is freed.
|
||
|
||
Arguments:
|
||
|
||
FileHandle - The handle returned by DigiOpenFile
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PDIGI_FILE_DESCRIPTOR FileDescriptor = (PDIGI_FILE_DESCRIPTOR)FileHandle;
|
||
KIRQL oldirql;
|
||
|
||
KeAcquireSpinLock (&FileDescriptor->Lock, &oldirql);
|
||
FileDescriptor->Mapped = FALSE;
|
||
KeReleaseSpinLock (&FileDescriptor->Lock, oldirql);
|
||
}
|
||
|
||
|
||
|
||
PVOID DigiInitMem( IN ULONG PoolTag )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
PoolTag - Tag to use when allocating memory.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
DefaultPoolTag = PoolTag;
|
||
InitializeListHead( &GlobalPagedMemQueue );
|
||
InitializeListHead( &GlobalNonPagedMemQueue );
|
||
KeInitializeSpinLock( &GlobalMemSpinLock );
|
||
|
||
return (NULL);
|
||
} // end DigiInitMem
|
||
|
||
|
||
|
||
#if DBG || DIGICHECKMEM
|
||
|
||
PVOID DigiAllocMem( IN POOL_TYPE PoolType, IN ULONG Length )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
KIRQL OldIrql;
|
||
PDIGI_MEM_DESCRIPTOR buf;
|
||
ULONG Len = ((Length + (sizeof(ULONG)-1)) & ~(sizeof(ULONG)-1));
|
||
|
||
//
|
||
// Check memory consistency.
|
||
//
|
||
DigiCheckMem();
|
||
|
||
// Override actual pool type to NonPagedPool
|
||
// since we play with pointers at DISPATCH_LEVEL
|
||
// that exist within the allocated buffer.
|
||
if( (buf = (PDIGI_MEM_DESCRIPTOR)ExAllocatePoolWithTag( NonPagedPool,
|
||
Len + sizeof(DIGI_MEM_DESCRIPTOR) + sizeof(ULONG),
|
||
DefaultPoolTag)) == NULL )
|
||
return(NULL);
|
||
|
||
buf->Length = Len;
|
||
buf->BeginTag = (ULONG)'lkir';
|
||
|
||
*(PULONG)((PUCHAR)buf + Len + sizeof(DIGI_MEM_DESCRIPTOR)) = (ULONG)'igid';
|
||
|
||
//
|
||
// Insert onto tail of global memory queue
|
||
//
|
||
|
||
KeAcquireSpinLock( &GlobalMemSpinLock, &OldIrql );
|
||
|
||
TotalMemAllocated += Len;
|
||
|
||
if( PoolType == PagedPool )
|
||
{
|
||
InsertTailList( &GlobalPagedMemQueue,
|
||
&(buf->ListEntry) );
|
||
}
|
||
else
|
||
{
|
||
InsertTailList( &GlobalNonPagedMemQueue,
|
||
&(buf->ListEntry) );
|
||
}
|
||
|
||
KeReleaseSpinLock( &GlobalMemSpinLock, OldIrql );
|
||
|
||
return( (PUCHAR)buf + (sizeof(DIGI_MEM_DESCRIPTOR)) );
|
||
|
||
} // end DigiAllocMem
|
||
|
||
|
||
|
||
VOID DigiFreeMem( IN PVOID Buf )
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Does consistency check on passed in memory block and free's the memory
|
||
block.
|
||
|
||
Arguments:
|
||
|
||
Buf - pointer to memory block which is to be freed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PDIGI_MEM_DESCRIPTOR RealBuf;
|
||
KIRQL OldIrql;
|
||
ULONG Length;
|
||
|
||
//
|
||
// Check memory consistency.
|
||
//
|
||
DigiCheckMem();
|
||
|
||
RealBuf = (PDIGI_MEM_DESCRIPTOR)((PUCHAR)Buf - sizeof(DIGI_MEM_DESCRIPTOR));
|
||
Length = RealBuf->Length;
|
||
|
||
if( RealBuf->BeginTag != (ULONG)'lkir' )
|
||
{
|
||
DbgPrint( "Memory has been corrupted!\n" );
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
if( *(PULONG)((PUCHAR)Buf + Length) != (ULONG)'igid' )
|
||
{
|
||
DbgPrint("Memory Overrun\n");
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
KeAcquireSpinLock( &GlobalMemSpinLock, &OldIrql );
|
||
TotalMemAllocated -= Length;
|
||
RemoveEntryList( &(RealBuf->ListEntry) );
|
||
KeReleaseSpinLock( &GlobalMemSpinLock, OldIrql );
|
||
|
||
ExFreePool( RealBuf );
|
||
} // end DigiFreeMem
|
||
|
||
|
||
VOID DigiCheckMem( VOID )
|
||
{
|
||
PLIST_ENTRY _DigiQueue;
|
||
KIRQL _OldIrql;
|
||
|
||
_DigiQueue = &GlobalNonPagedMemQueue;
|
||
|
||
KeAcquireSpinLock( &GlobalMemSpinLock, &_OldIrql );
|
||
|
||
while( _DigiQueue->Flink != &GlobalNonPagedMemQueue )
|
||
{
|
||
PDIGI_MEM_DESCRIPTOR _MemDesc;
|
||
PUCHAR _Buf;
|
||
|
||
_MemDesc = CONTAINING_RECORD( _DigiQueue->Flink,
|
||
DIGI_MEM_DESCRIPTOR,
|
||
ListEntry );
|
||
|
||
_Buf = (PUCHAR)_MemDesc + sizeof(DIGI_MEM_DESCRIPTOR);
|
||
if( (_MemDesc->BeginTag != (ULONG)'lkir') ||
|
||
(*(PULONG)(_Buf + _MemDesc->Length) != (ULONG)'igid') )
|
||
{
|
||
DbgPrint( "DigiCheckMem corruption found (0x%x)!n", _MemDesc );
|
||
DbgBreakPoint();
|
||
break;
|
||
}
|
||
|
||
_DigiQueue = _DigiQueue->Flink;
|
||
}
|
||
|
||
_DigiQueue = &GlobalPagedMemQueue;
|
||
|
||
while( _DigiQueue->Flink != &GlobalPagedMemQueue )
|
||
{
|
||
PDIGI_MEM_DESCRIPTOR _MemDesc;
|
||
PUCHAR _Buf;
|
||
|
||
_MemDesc = CONTAINING_RECORD( _DigiQueue->Flink,
|
||
DIGI_MEM_DESCRIPTOR,
|
||
ListEntry );
|
||
|
||
_Buf = (PUCHAR)_MemDesc + sizeof(DIGI_MEM_DESCRIPTOR);
|
||
if( (_MemDesc->BeginTag != (ULONG)'lkir') ||
|
||
(*(PULONG)(_Buf + _MemDesc->Length) != (ULONG)'igid') )
|
||
{
|
||
DbgPrint( "DigiCheckMem corruption found (0x%x)!n", _MemDesc );
|
||
DbgBreakPoint();
|
||
break;
|
||
}
|
||
|
||
_DigiQueue = _DigiQueue->Flink;
|
||
}
|
||
|
||
KeReleaseSpinLock( &GlobalMemSpinLock, _OldIrql );
|
||
}
|
||
|
||
#endif // end #if DBG || DIGICHECKMEM
|