A forum for reverse engineering, OS internals and malware analysis 

Ask your beginner questions here.
 #9204  by noppy
 Mon Oct 17, 2011 12:37 pm
hello
I trying to write a driver to enumerate memory map of process I attach to specific process and use ZwQueryVirtualMemory
but I get C0000005 error code mean 'STATUS_ACCESS_VIOLATION', anybody have any idea why this api not work
this is snipped code, I know it is undocumented, not export API, but didn't find other way to do:
Code: Select all
KeAttachProcess(eproc);
		
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
client_id.UniqueProcess = (HANDLE) pid;
client_id.UniqueThread = NULL;
Status = ZwOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION, &ObjectAttributes, &client_id);
if (!NT_SUCCESS(Status)){
	DbgPrint("cannot get process handle, ERROR CODE = %08X\n", Status);
	KeDetachProcess();
	IoStatus->Status = STATUS_UNSUCCESSFUL;
	return IoStatus->Status;
}
DbgPrint("process handle = %08X\n", hProcess);
		
Status = ZwQueryVirtualMemory(hProcess, (PVOID) 0x400000, MemoryBasicInformation, &mem_info, sizeof(MEMORY_BASIC_INFORMATION), NULL);
if (!NT_SUCCESS(Status)){
	DbgPrint("cannot query memory, ERROR CODE = %08X\n", Status);
	ZwClose(hProcess);
	KeDetachProcess();
	IoStatus->Status = STATUS_UNSUCCESSFUL;
	return IoStatus->Status;
}
		
DbgPrint("base address: %08X\n", mem_info.BaseAddress);
DbgPrint("real base address: %08X\n", mem_info.AllocationBase);
DbgPrint("region size: %08X\n", mem_info.RegionSize);
		
KeDetachProcess();
thanks
 #9205  by EP_X0FF
 Mon Oct 17, 2011 12:48 pm
Hello,

what is this KeAttachProcess/KeDetachProcess and what this doing here in this scenario?
 #9206  by noppy
 Mon Oct 17, 2011 1:32 pm
I use it to access address space of specific process, before KeAttachProcess there is PsLookupProcessByProcessId to get eprocess, is it correct?
 #9208  by EP_X0FF
 Mon Oct 17, 2011 1:42 pm
What sense? You use ZwOpenProcess, ZwQueryVirtualMemory get a HANDLE of process as input parameter.
 #9210  by noppy
 Mon Oct 17, 2011 1:54 pm
yes, sorry, no sense here, I change my code many time and I missed them to delete,
but anyway without that APIs I get same error again :?
 #9211  by EP_X0FF
 Mon Oct 17, 2011 2:12 pm
From where do you call this code? Can you post complete function code?
 #9220  by noppy
 Mon Oct 17, 2011 9:28 pm
herer is the code:
Code: Select all
#include <ntddk.h>

const WCHAR deviceLinkBuffer[]  = L"\\DosDevices\\my_driver";
const WCHAR deviceNameBuffer[]  = L"\\Device\\my_driver";

PDEVICE_OBJECT g_Device;

typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;

#pragma pack(1)
typedef struct ServiceDescriptorEntry
{
	DWORD *KiServiceTable;
	DWORD *CounterBaseTable;
	DWORD *nSystemCalls;
	DWORD *KiArgumentTable;
}SDE, *PSDE;
#pragma pack()

typedef struct ServiceDescriptorTable
{
	SDE ServiceDescriptor[4];
} SDT;

__declspec(dllimport) SDE KeServiceDescriptorTable;

#define STANDARD_RIGHTS_REQUIRED         (0x000F0000L)
#define PROCESS_TERMINATE         (0x0001)  
#define PROCESS_CREATE_THREAD     (0x0002)  
#define PROCESS_VM_OPERATION      (0x0008)  
#define PROCESS_VM_READ           (0x0010)  
#define PROCESS_VM_WRITE          (0x0020)  
#define PROCESS_DUP_HANDLE        (0x0040)  
#define PROCESS_CREATE_PROCESS    (0x0080)  
#define PROCESS_SET_QUOTA         (0x0100)  
#define PROCESS_SET_INFORMATION   (0x0200)  
#define PROCESS_QUERY_INFORMATION (0x0400)  
#define PROCESS_ALL_ACCESS        (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
                                   0xFFF)


#pragma pack(1)
typedef struct sPTE {
	unsigned char P:1;		// 0:	Present
	unsigned char RW:1;		// 1:	Read/Write
	unsigned char US:1;		// 2:	User/Supervisor
	unsigned char PWT:1;	// 3:	Write-Through
	unsigned char PCD:1;	// 4:	Cache Disable
	unsigned char A:1;		// 5:	Access
	unsigned char D:1;		// 6:	Dirty
	unsigned char PAT:1;	// 7:	Page Attribute
	unsigned char G:1;		// 8:	Global
	unsigned char CoW:1;	// 9:	Copy-On-Write
	unsigned int UUU:22;	// 
}PTE_ST, *pPTE_ST;
#pragma pack()

typedef enum _MEMORY_INFORMATION_CLASS {
	MemoryBasicInformation, 
	MemoryWorkingSetList,
	MemorySectionName,
	MemoryBasicVlmInformation
} MEMORY_INFORMATION_CLASS;

typedef struct _MEMORY_BASIC_INFORMATION { // Information Class 0
	PVOID BaseAddress;
	PVOID AllocationBase;
	ULONG AllocationProtect;
	ULONG RegionSize;
	ULONG State;
	ULONG Protect;
	ULONG Type;
}  MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

typedef NTSTATUS

 (NTAPI *MyZwQueryVirtualMemory)(
	IN HANDLE ProcessHandle,
	IN PVOID BaseAddress,
	IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
	OUT PVOID MemoryInformation,
	IN ULONG MemoryInformationLength,
	OUT PULONG ReturnLength OPTIONAL
	);

NTSTATUS Unload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS Dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
NTSTATUS DeviceControl(IN PFILE_OBJECT FileObject, IN PVOID InputBuffer, IN ULONG InputBufferLength, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject);
VOID NTAPI KeAttachProcess(IN PEPROCESS);
VOID NTAPI KeDetachProcess();
NTSTATUS PsLookupProcessByProcessId( IN ULONG ProcessId, OUT PEPROCESS  *Process );
NTSTATUS defaultDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIRP);

#define FILE_DEVICE	0x0000584e
#define IOCTL_DEVICECONTROL (ULONG) CTL_CODE(FILE_DEVICE, 0x01, METHOD_BUFFERED, FILE_WRITE_ACCESS)

typedef struct _ioctlparams {
	ULONG pid;
	ULONG Reverse1;
	ULONG Reverse2;
} IOCTLPARAMS;

NTSTATUS DriverEntry(
   IN PDRIVER_OBJECT  DriverObject,
   IN PUNICODE_STRING RegistryPath )
{
	NTSTATUS ntStatus;
	UNICODE_STRING deviceNameUnicodeString;
	UNICODE_STRING deviceLinkUnicodeString;
	int i;
	
	DbgPrint("Driver Started...\n");

	RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer );
	RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer );
	
	ntStatus = IoCreateDevice ( DriverObject,
                                0, 
                                &deviceNameUnicodeString,
                                FILE_DEVICE,
                                0,
                                TRUE,
                                &g_Device );
	
								
	if(! NT_SUCCESS(ntStatus))
	{
        DbgPrint(("Failed to create device!\n"));
        return ntStatus;
    }
	
	ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
                                        &deviceNameUnicodeString );
										
	
	if(! NT_SUCCESS(ntStatus)) 
	{
		IoDeleteDevice(DriverObject->DeviceObject);
        DbgPrint("Failed to create symbolic link!\n");
        return ntStatus;
    }
	
	for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; ++i)
	{
		DriverObject->MajorFunction[i] = defaultDispatch;
	}
	
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch;
	DriverObject->DriverUnload = Unload;

	return STATUS_SUCCESS;
}

NTSTATUS defaultDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIRP)
{
	pIRP->IoStatus.Status = STATUS_SUCCESS;
	pIRP->IoStatus.Information = 0;
	IoCompleteRequest(pIRP,IO_NO_INCREMENT);
	return (STATUS_SUCCESS);
}

NTSTATUS Unload(IN PDRIVER_OBJECT DriverObject)
{
    UNICODE_STRING deviceLinkUnicodeString;
	PDEVICE_OBJECT p_NextObj;
	
	DbgPrint("Driver Unload...\n");

	p_NextObj = DriverObject->DeviceObject;

	if (p_NextObj != NULL)
	{
		RtlInitUnicodeString(&deviceLinkUnicodeString, deviceLinkBuffer);
		IoDeleteSymbolicLink(&deviceLinkUnicodeString);
		IoDeleteDevice(DriverObject->DeviceObject);
		return STATUS_SUCCESS;
	}
	return STATUS_SUCCESS;
}

NTSTATUS Dispatch(
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP Irp 
    )
{
	PIO_STACK_LOCATION irpStack;
    PVOID inputBuffer;
    PVOID outputBuffer;
    ULONG inputBufferLength;
    ULONG outputBufferLength;
    ULONG ioControlCode;
    NTSTATUS ntstatus;
	
	ntstatus = Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;
	irpStack = IoGetCurrentIrpStackLocation(Irp);
	inputBuffer = Irp->AssociatedIrp.SystemBuffer;
	inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
    outputBuffer = Irp->AssociatedIrp.SystemBuffer;
    outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
	
	switch (irpStack->MajorFunction){
		case IRP_MJ_DEVICE_CONTROL:
			if (ioControlCode == IOCTL_DEVICECONTROL){
				ntstatus = DeviceControl(irpStack->FileObject,
				inputBuffer, inputBufferLength, 
				outputBuffer, outputBufferLength,
				&Irp->IoStatus, DeviceObject);
			}
			break;
	}
	
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return ntstatus;  
}

NTSTATUS DeviceControl(
    IN PFILE_OBJECT FileObject, 
    IN PVOID InputBuffer, 
    IN ULONG InputBufferLength, 
    OUT PVOID OutputBuffer, 
    IN ULONG OutputBufferLength, 
    OUT PIO_STATUS_BLOCK IoStatus, 
    IN PDEVICE_OBJECT DeviceObject 
    )
{
	IOCTLPARAMS *params;
	ULONG pid;
	HANDLE hProcess;
	OBJECT_ATTRIBUTES ObjectAttributes;
	CLIENT_ID client_id;
	NTSTATUS Status;
	MEMORY_BASIC_INFORMATION mem_info = {0};
	ULONG *systemCallTable = (ULONG*)KeServiceDescriptorTable.KiServiceTable;
	MyZwQueryVirtualMemory ZwQueryVirtualMemory = (MyZwQueryVirtualMemory)(systemCallTable[0xB2]);;
	
	if ((InputBufferLength < sizeof(int) * 3) || (InputBuffer == NULL))
	{
		IoStatus->Status = STATUS_INVALID_BUFFER_SIZE;
		return IoStatus->Status;
	}
	
	params = (IOCTLPARAMS *)InputBuffer;
	pid = params->pid;
	
	DbgPrint("pid = %X\n", pid);
		
	InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
	client_id.UniqueProcess = (HANDLE) pid;
	client_id.UniqueThread = NULL;
	Status = ZwOpenProcess(&hProcess, PROCESS_QUERY_INFORMATION, &ObjectAttributes, &client_id);
	if (!NT_SUCCESS(Status)){
		DbgPrint("cannot get process handle, ERROR CODE = %08X\n", Status);
		IoStatus->Status = STATUS_UNSUCCESSFUL;
		return IoStatus->Status;
	}
	DbgPrint("process handle = %08X\n", hProcess);
		
	Status = ZwQueryVirtualMemory(hProcess, (PVOID) 0x400000, MemoryBasicInformation, &mem_info, sizeof(MEMORY_BASIC_INFORMATION), NULL);
	if (!NT_SUCCESS(Status)){
		DbgPrint("cannot query memory, ERROR CODE = %08X\n", Status);
		ZwClose(hProcess);
		IoStatus->Status = STATUS_UNSUCCESSFUL;
		return IoStatus->Status;
	}
		
	DbgPrint("base address: %08X\n", mem_info.BaseAddress);
	DbgPrint("real base address: %08X\n", mem_info.AllocationBase);
	DbgPrint("region size: %08X\n", mem_info.RegionSize);
		
	ZwClose(hProcess);
	
	return IoStatus->Status;
}
and usermode:
Code: Select all
#include <winternl.h>
#include <Windows.h>
#include <stdio.h>

#define FILE_DEVICE	0x0000584e
#define IOCTL_DEVICECONTROL (ULONG) CTL_CODE(FILE_DEVICE, 0x01, METHOD_BUFFERED, FILE_WRITE_ACCESS)

typedef struct _ioctlparams {
	ULONG pid;
	ULONG Reverse1;
	ULONG Reverse2;
} IOCTLPARAMS;

int wmain(int argc, wchar_t *argv[])
{
	if (argc != 2){
		fwprintf(stderr, L"usage: %s  pid\n", argv[0]);
		exit(1);
	}
	
	int PID = _wtoi(argv[1]);
	HANDLE hFile = CreateFile(L"\\\\.\\my_driver", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE){
		fwprintf(stderr, L"cannot get handle from symbol\n");
		exit(1);
	}

	IOCTLPARAMS param;
	DWORD d_bytesRead;
	DWORD success;

	param.pid = PID;
	
	success = DeviceIoControl(hFile, IOCTL_DEVICECONTROL, &param, sizeof(IOCTLPARAMS), NULL, 0, &d_bytesRead, NULL);
	if (success){
		fwprintf(stderr, L"pid send successfully\n");
	}else{
		fwprintf(stderr, L"cannot send pid\n");
	}
	CloseHandle(hFile);
}
 #9224  by r2nwcnydc
 Tue Oct 18, 2011 3:10 am
BlZbB wrote:
Code: Select all
   MyZwQueryVirtualMemory ZwQueryVirtualMemory = (MyZwQueryVirtualMemory)(systemCallTable[0xB2]);
You are calling NtQueryVirtualMemory not ZwQueryVirtualMemory. The Zw functions set the previous mode of a call before calling the function, and should only be used when you have allocated or verified the values being passed in. The reason you are getting access denied, is most likely because the current process does not have access to read the memory of the requested process. To fix this try setting the previous mode your self.

Here is a previous post that explains this in more detail:
http://www.kernelmode.info/forum/viewto ... =14&t=1147