静下来,定好方向,好好干。
分类: WINDOWS
2008-05-12 08:51:26
//Device driver needs to write to Shared Memory
================================================
//
// Simple driver that demonstrates mapping physical memory into
// a user mode process's address space
//
#include "ntddk.h"
#include "..\mapmem.h"
#include "stdarg.h"
//
// The following was not included in the October release of the
// preliminary NT DDK, and is necessary when utilizing the
// ZwMapViewOfSection API.
//
#define SECTION_QUERY 0x0001
#define SECTION_MAP_WRITE 0x0002
#define SECTION_MAP_READ 0x0004
#define SECTION_MAP_EXECUTE 0x0008
#define SECTION_EXTEND_SIZE 0x0010
#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY | \
SECTION_MAP_WRITE | \
SECTION_MAP_READ | \
SECTION_MAP_EXECUTE | \
SECTION_EXTEND_SIZE)
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;
#define PAGE_NOACCESS 0x01 // winnt
#define PAGE_READONLY 0x02 // winnt
#define PAGE_READWRITE 0x04 // winnt
#define PAGE_WRITECOPY 0x08
#define PAGE_EXECUTE 0x10
#define PAGE_EXECUTE_READ 0x20
#define PAGE_EXECUTE_READWRITE 0x40
#define PAGE_EXECUTE_WRITECOPY 0x80
#define PAGE_GUARD 0x100
#define PAGE_NOCACHE 0x200
NTSTATUS
ZwMapViewOfSection(
IN HANDLE SectionHandle,
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN ULONG CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PULONG ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect
);
//
// Function prototypes for this module
//
NTSTATUS
MapMemCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
MapMemDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
MapMemMapTheMemory(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PVOID ioBuffer,
IN ULONG inputBufferLength,
IN ULONG outputBufferLength
);
#if DBG
#define MapMemDebugPrint(arg) DbgPrint arg
#else
#define MapMemDebugPrint(arg)
#endif
//
// The code...
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS ntStatus;
WCHAR deviceNameBuffer[] = L"";
UNICODE_STRING deviceNameUnicodeString;
MapMemDebugPrint(("MapMem: entering DriverEntry\n"));
RtlInitUnicodeString(&deviceNameUnicodeString,
deviceNameBuffer);
//
// Create the device object
//
ntStatus = IoCreateDevice(
DriverObject,
0,
&deviceNameUnicodeString,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&deviceObject
);
if (NT_SUCCESS(ntStatus))
{
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MapMemCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MapMemDispatch;
}
return ntStatus;
}
NTSTATUS
MapMemCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
//
// No need to do anything.
//
//
// Fill these in before calling IoCompleteRequest.
//
// DON'T get cute and try to use the status field of
// the irp in the return status. That IRP IS GONE as
// soon as you call IoCompleteRequest.
//
MapMemDebugPrint(("MapMemOpenClose: enter\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(
Irp,
IO_NO_INCREMENT
);
return STATUS_SUCCESS;
}
NTSTATUS
MapMemDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntStatus;
//
// Init to default settings- we only expect 1 type of
// IOCTL to roll through here, all others an error.
//
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Get the pointer to the input/output buffer and it's length
//
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength =
irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpStack->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (ioControlCode)
{
case IOCTL_MAPMEM_MAP_USER_PHYSICAL_MEMORY:
Irp->IoStatus.Status = MapMemMapTheMemory (DeviceObject,
ioBuffer,
inputBufferLength,
outputBufferLength
);
if (NT_SUCCESS(Irp->IoStatus.Status))
{
//
// Success! Set the following to sizeof(PVOID) to
// indicate we're passing valid data back.
//
Irp->IoStatus.Information = sizeof(PVOID);
MapMemDebugPrint(("MapMem: memory successfully mapped :)\n"));
}
else
MapMemDebugPrint(("MapMem: memory map failed :(\n"));
break;
default:
MapMemDebugPrint(("MapMem: unknown IRP_MJ_DEVICE_CONTROL\n"));
break;
} // switch (ioControlCode)
break;
}
//
// DON'T get cute and try to use the status field of
// the irp in the return status. That IRP IS GONE as
// soon as you call IoCompleteRequest.
//
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
//
// We never have pending operation so always return the status code.
//
return ntStatus;
}
NTSTATUS
MapMemMapTheMemory(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PVOID ioBuffer,
IN ULONG inputBufferLength,
IN ULONG outputBufferLength
)
{
PPHYSICAL_MEMORY_INFO ppmi = (PPHYSICAL_MEMORY_INFO) ioBuffer;
INTERFACE_TYPE interfaceType;
ULONG busNumber;
PHYSICAL_ADDRESS physicalAddress;
ULONG length;
UNICODE_STRING physicalMemoryUnicodeString;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE physicalMemoryHandle = NULL;
PVOID PhysicalMemorySection = NULL;
ULONG inIoSpace, inIoSpace2;
NTSTATUS ntStatus;
PHYSICAL_ADDRESS physicalAddressBase;
PHYSICAL_ADDRESS physicalAddressEnd;
PHYSICAL_ADDRESS viewBase;
PHYSICAL_ADDRESS mappedLength;
BOOLEAN translateBaseAddress;
BOOLEAN translateEndAddress;
PVOID virtualAddress;
if ( ( inputBufferLength < sizeof (PHYSICAL_MEMORY_INFO) ) ||
( outputBufferLength < sizeof (PVOID) ) )
{
MapMemDebugPrint(("MapMem: Insufficient input or output buffer\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
interfaceType = ppmi->interfaceType;
busNumber = ppmi->busNumber;
physicalAddress = ppmi->physicalAddress;
length = ppmi->length;
//
// Get a pointer to physical memory...
//
// - Create the name
// - Initialize the data to find the object
// - Open a handle to the oject and check the status
// - Get a pointer to the object
// - Free the handle
//
RtlInitUnicodeString(&physicalMemoryUnicodeString,
L"");
InitializeObjectAttributes (&objectAttributes,
&physicalMemoryUnicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
ntStatus = ZwOpenSection (&physicalMemoryHandle,
SECTION_ALL_ACCESS,
&objectAttributes);
if (!NT_SUCCESS(ntStatus))
{
MapMemDebugPrint(("MapMem: ZwOpenSection failed\n"));
goto done;
}
ntStatus = ObReferenceObjectByHandle (physicalMemoryHandle,
SECTION_ALL_ACCESS,
(POBJECT_TYPE) NULL,
KernelMode,
&PhysicalMemorySection,
(POBJECT_HANDLE_INFORMATION) NULL);
if (!NT_SUCCESS(ntStatus))
{
MapMemDebugPrint(("MapMem: ObReferenceObjectByHandle failed\n"));
goto close_handle;
}
//
// Have a second variable used for the second HalTranslateBusAddres call.
//
inIoSpace = inIoSpace2 = 0;
//
// Initialize the physical addresses that will be translated
//
physicalAddressEnd = RtlLargeIntegerAdd (physicalAddress,
RtlConvertUlongToLargeInteger(
length));
//
// Translate the physical addresses.
//
translateBaseAddress =
HalTranslateBusAddress (interfaceType,
busNumber,
physicalAddress,
&inIoSpace,
&physicalAddressBase);
translateEndAddress =
HalTranslateBusAddress (interfaceType,
busNumber,
physicalAddressEnd,
&inIoSpace2,
&physicalAddressEnd);
if ( !(translateBaseAddress && translateEndAddress) )
{
MapMemDebugPrint(("MapMem: HalTranslateBusAddress failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto close_handle;
}
//
// Calculate the length of the memory to be mapped
//
mappedLength = RtlLargeIntegerSubtract (physicalAddressEnd,
physicalAddressBase);
//
// If the mappedlength is zero, somthing very weird happened in the HAL
// since the Length was checked against zero.
//
if (mappedLength.LowPart == 0)
{
MapMemDebugPrint(("MapMem: mappedLength.LowPart == 0\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto close_handle;
}
length = mappedLength.LowPart;
//
// If the address is in io space, just return the address, otherwise
// go through the mapping mechanism
//
if (inIoSpace)
{
*((PVOID *) ioBuffer) = physicalAddressBase.LowPart;
}
else
{
//
// initialize view base that will receive the physical mapped
// address after the MapViewOfSection call.
//
viewBase = physicalAddressBase;
//
// Let ZwMapViewOfSection pick an address
//
virtualAddress = NULL;
//
// Map the section
//
ntStatus = ZwMapViewOfSection (physicalMemoryHandle,
(HANDLE) -1,
&virtualAddress,
0L,
length,
&viewBase,
&length,
ViewShare,
0,
PAGE_READWRITE | PAGE_NOCACHE);
if (!NT_SUCCESS(ntStatus))
{
MapMemDebugPrint(("MapMem: ZwMapViewOfSection failed\n"));
goto close_handle;
}
//
// Mapping the section above rounded the physical address down to the
// nearest 64 K boundary. Now return a virtual address that sits where
// we wnat by adding in the offset from the beginning of the section.
//
(ULONG) virtualAddress += (ULONG)physicalAddressBase.LowPart -
(ULONG)viewBase.LowPart;
*((PVOID *) ioBuffer) = virtualAddress;
}
ntStatus = STATUS_SUCCESS;
close_handle:
ZwClose(physicalMemoryHandle);
done:
MapMemDebugPrint(("\t ntStatus = %x\n"));
return ntStatus;
}
============================================================
typedef LONG NTSTATUS;
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef enum _SECTION_INHERIT
{
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT, *PSECTION_INHERIT;
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
#define InitializeObjectAttributes( p, n, a, r, s ) {\
(p)->Length = sizeof( OBJECT_ATTRIBUTES );\
(p)->RootDirectory = r;\
(p)->Attributes = a;\
(p)->ObjectName = n;\
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
// Interesting functions in NTDLL
typedef NTSTATUS (WINAPI *ZwOpenSectionProc)
(
PHANDLE SectionHandle,
DWORD DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes
);
typedef NTSTATUS (WINAPI *ZwMapViewOfSectionProc)
(
HANDLE SectionHandle,
HANDLE ProcessHandle,
PVOID *BaseAddress,
ULONG ZeroBits,
ULONG CommitSize,
PLARGE_INTEGER SectionOffset,
PULONG ViewSize,
SECTION_INHERIT InheritDisposition,
ULONG AllocationType,
ULONG Protect
);
typedef NTSTATUS (WINAPI *ZwUnmapViewOfSectionProc)
(
HANDLE ProcessHandle,
PVOID BaseAddress
);
typedef VOID (WINAPI *RtlInitUnicodeStringProc)
(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
// Global variables
static HMODULE hModule = NULL;
static HANDLE hPhysicalMemory = NULL;
static ZwOpenSectionProc ZwOpenSection;
static ZwMapViewOfSectionProc ZwMapViewOfSection;
static ZwUnmapViewOfSectionProc ZwUnmapViewOfSection;
static RtlInitUnicodeStringProc RtlInitUnicodeString;
// initialize
BOOL InitPhysicalMemory()
{
if (!(hModule = LoadLibrary("ntdll.dll")))
{
return FALSE;
}
// 以下从NTDLL获取我们需要的几个函数指针
if (!(ZwOpenSection = (ZwOpenSectionProc)GetProcAddress(hModule, "ZwOpenSection")))
{
return FALSE;
}
if (!(ZwMapViewOfSection = (ZwMapViewOfSectionProc)GetProcAddress(hModule, "ZwMapViewOfSection")))
{
return FALSE;
}
if (!(ZwUnmapViewOfSection = (ZwUnmapViewOfSectionProc)GetProcAddress(hModule, "ZwUnmapViewOfSection")))
{
return FALSE;
}
if (!(RtlInitUnicodeString = (RtlInitUnicodeStringProc)GetProcAddress(hModule, "RtlInitUnicodeString")))
{
return FALSE;
}
// 以下打开内核对象
WCHAR PhysicalMemoryName[] = L"";
UNICODE_STRING PhysicalMemoryString;
OBJECT_ATTRIBUTES attributes;
RtlInitUnicodeString(&PhysicalMemoryString, PhysicalMemoryName);
InitializeObjectAttributes(&attributes, &PhysicalMemoryString, 0, NULL, NULL);
NTSTATUS status = ZwOpenSection(&hPhysicalMemory, SECTION_MAP_READ, &attributes );
return (status >= 0);
}
// terminate -- free handles
void ExitPhysicalMemory()
{
if (hPhysicalMemory != NULL)
{
CloseHandle(hPhysicalMemory);
}
if (hModule != NULL)
{
FreeLibrary(hModule);
}
}
BOOL ReadPhysicalMemory(PVOID buffer, DWORD address, DWORD length)
{
DWORD outlen; // 输出长度,根据内存分页大小可能大于要求的长度
PVOID vaddress; // 映射的虚地址
NTSTATUS status; // NTDLL函数返回的状态
LARGE_INTEGER base; // 物理内存地址
vaddress = 0;
outlen = length;
base.QuadPart = (ULONGLONG)(address);
// 映射物理内存地址到当前进程的虚地址空间
status = ZwMapViewOfSection(hPhysicalMemory,
(HANDLE) -1,
(PVOID *)&vaddress,
0,
length,
&base,
&outlen,
ViewShare,
0,
PAGE_READONLY);
if (status < 0)
{
AfxMessageBox("ZwMapViewOfSection error");
return FALSE;
}
// 当前进程的虚地址空间中,复制数据到输出缓冲区
memmove(buffer, vaddress, length);
// 完成访问,取消地址映射
status = ZwUnmapViewOfSection((HANDLE)-1, (PVOID)vaddress);
return (status >= 0);
}
发现以上代码只能访问0x000000000~0x7fffffff,访问0xdfffe0000处时,ZwMapViewOfSection就返回错误了。
用IOMem后已经实现我所要的功能;
我想用VC xp下直接访问PCI卡的内存空间,通过读取它的配置空间,知道它被映射在了0xdffe0000~0xdffeffff物理地址处。现在我想用VC写个
应用程序直接可以访问到该地址空间。该如何实现?(用驱动来读取的话太麻烦,所以想应用程序可以直接读写);