I am trying to implement a driver, which will read/write memory in the user-space process. For that, I need to get the process base address. I am using this function for that:
PVOID GetProcessModuleAdress(IN PEPROCESS __process,IN PUNICODE_STRING ModuleName)
{
KAPC_STATE kapc;
KeStackAttachProcess(__process, &kapc);
PPEB pPeb = PsGetProcessPeb(__process);
__int32 pid = PsGetProcessId(__process);
// Debug
for (PLIST_ENTRY pListEntry = pPeb->Ldr->InMemoryOrderModuleList.Flink; pListEntry != &pPeb->Ldr->InMemoryOrderModuleList; pListEntry = pListEntry->Flink)
{
PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
DbgPrintEx(0, 0, "Module: (%wZ)\n", pEntry->BaseDllName);
}
// End Debug
for (PLIST_ENTRY pListEntry = pPeb->Ldr->InMemoryOrderModuleList.Flink; pListEntry != &pPeb->Ldr->InMemoryOrderModuleList; pListEntry = pListEntry->Flink)
{
PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (&pEntry->BaseDllName == ModuleName)
{
KeUnstackDetachProcess(&kapc);
return (PVOID)pEntry;
}
}
}
And I found that this function gives BSOD with Invalid_Process_Attach. I assume that the KeStackAttachProcess function is responsible for this. But since this is default function in windows kernel, I doubt that error is in there. Something wrong is with parameters. KAPC_STATE is doubtfull here, because, it is being defined right in front of the function call. This leaves the PEPROCESS __process parameter. And it comes from:
NTSTATUS FindProcessByName(IN CHAR* process_name, IN PEPROCESS* process)
{
PEPROCESS sys_process = PsInitialSystemProcess;
PEPROCESS cur_entry = sys_process;
CHAR image_name[15];
do
{
RtlCopyMemory((PVOID)(&image_name), (PVOID)((uintptr_t)cur_entry + 0x450) /*EPROCESS->ImageFileName*/, sizeof(image_name));
if (strstr(image_name, process_name))
{
__int32 active_threads;
RtlCopyMemory((PVOID)&active_threads, (PVOID)((uintptr_t)cur_entry + 0x498) /*EPROCESS->ActiveThreads*/, sizeof(active_threads));
if (active_threads)
{
*process = cur_entry;
return STATUS_SUCCESS;
}
}
PLIST_ENTRY list = (PLIST_ENTRY)((uintptr_t)(cur_entry)+0x2F0) /*EPROCESS->ActiveProcessLinks*/;
cur_entry = (PEPROCESS)((uintptr_t)list->Flink - 0x2F0);
} while (cur_entry != sys_process);
return STATUS_NOT_FOUND;
}
My first assumption was, that it is not modifying the __process parameter, so I implemented a simple check for that:
if (FindProcessByName("someprocess.exe", &__process) != STATUS_SUCCESS)
{
DbgPrint("Process Not found");
goto end;
}
if (__process == temp)
{
DbgPrint("__process is not valid");
goto end;
}
But it seems to get past it and execute further. This is where I am stuck now. Most frustrating thing is that I am unable to launch full WinDbg in VirtualBox, because it can't run games, and I need to run this driver locally, without any breakpoints.
P.S. My structs are:
typedef struct _PEB_LDR_DATA
{
ULONG Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _PEB_LDR_DATA32
{
ULONG Length;
UCHAR Initialized;
ULONG SsHandle;
LIST_ENTRY32 InLoadOrderModuleList;
LIST_ENTRY32 InMemoryOrderModuleList;
LIST_ENTRY32 InInitializationOrderModuleList;
} PEB_LDR_DATA32, * PPEB_LDR_DATA32;
typedef struct _PEB
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR BitField;
PVOID Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PVOID ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
PVOID CrossProcessFlags;
PVOID KernelCallbackTable;
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
PVOID ApiSetMap;
} PEB, * PPEB;
typedef struct _PEB32
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR BitField;
ULONG Mutant;
ULONG ImageBaseAddress;
ULONG Ldr;
ULONG ProcessParameters;
ULONG SubSystemData;
ULONG ProcessHeap;
ULONG FastPebLock;
ULONG AtlThunkSListPtr;
ULONG IFEOKey;
ULONG CrossProcessFlags;
ULONG UserSharedInfoPtr;
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
ULONG ApiSetMap;
} PEB32, * PPEB32;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashLinks;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _LDR_DATA_TABLE_ENTRY32
{
LIST_ENTRY32 InLoadOrderLinks;
LIST_ENTRY32 InMemoryOrderLinks;
LIST_ENTRY32 InInitializationOrderLinks;
ULONG DllBase;
ULONG EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING32 FullDllName;
UNICODE_STRING32 BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY32 HashLinks;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY32, * PLDR_DATA_TABLE_ENTRY32;
P.S. Yea, this code is a bit pasted, I know. I am trying to learn kernel programming in practical way :) Would like to hear in detail, why this is failing.