//-----------------------------------------------------------------------------
// ProcessEnvironmentBlock 
// (built upon examples in Bill Blunden's Rootkit Arsenal, 1st Ed)
//-----------------------------------------------------------------------------
#include "windows.h"
#include "Winternl.h"	// from the SDK
#include "stdio.h"		// for printf()
#include <stdint.h>		// for uint32_t, etc.

#define NTSTATUS LONG
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

// The following struct is defined by Winternl.h but left here for reference:
/*
typedef struct _RTL_USER_PROCESS_PARAMETERS
{
	BYTE Reserved1[56];
	UNICODE_STRING ImagePathName;
	UNICODE_STRING CommandLine;
	BYTE Reserved2[92];
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
*/

// A definition of the PEB structure with slightly more information than what
// is given in the SDK. There is actually more information about this struct
// in the SDK documentation than in the SDK headers.
typedef struct _MY_PEB
{
	BYTE Reserved1[2];
	BYTE BeingDebugged;
	BYTE Reserved2[9];
	PPEB_LDR_DATA LoaderData;	// this is what we are interested in, see above
	PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
	BYTE Reserved3[448];
	ULONG SessionId;
} MY_PEB, *MY_PPEB;

// A definition of the PEB_LDR_DATA structure with slightly more information
// than what is given in the SDK headers. For more information see:
// http://sandsprite.com/CodeStuff/Understanding_the_Peb_Loader_Data_List.html
typedef struct _MY_PEB_LDR_DATA
{
	/* 0x00 */ uint32_t Length;
	/* 0x04 */ uint8_t Initialized[4];
	/* 0x08 */ uint32_t SsHandle;
	/* 0x0C */ LIST_ENTRY InLoadOrderModuleList;	// each of these is a pointer
	/* 0x14 */ LIST_ENTRY InMemoryOrderModuleList;  // to a different linked list of 
	/* 0x1C */ LIST_ENTRY InInitOrderModuleList;    // LDR_DATA_TABLE_ENTRY elements
	/* 0x24 */ uint8_t EntryInProgress;
} MY_PEB_LDR_DATA, *MY_PPEB_LDR_DATA;

// A definition of the LDR_DATA_TABLE_ENTRY structure with slightly more 
// information than what is given in the SDK headers.
typedef struct _MY_LDR_DATA_TABLE_ENTRY
{
	/* 0x00 */ LIST_ENTRY InLoadOrderLinks;
	/* 0x08 */ LIST_ENTRY InMemoryOrderLinks;
	/* 0x10 */ LIST_ENTRY InInitOrderLinks;
	/* 0x18 */ uint32_t DllBase;	// base address of module
	/* 0x1C */ uint32_t EntryPoint;
	/* 0x1F */ uint32_t Reserved;
	/* 0x24 */ UNICODE_STRING FullDllName;
	BYTE Reserved4[20];
	ULONG Checksum;
	ULONG TimeDateStamp;
	BYTE Reserved5[12];
} MY_LDR_DATA_TABLE_ENTRY, *MY_PLDR_DATA_TABLE_ENTRY;

typedef NTSTATUS (WINAPI *NtQueryInformationProcessPtr) (HANDLE ProcessHandle, 
														 PROCESSINFOCLASS ProcessInformationClass, 
														 PVOID ProcessInformation, 
														 ULONG ProcessInformationLength, 
														 PULONG ReturnLength);

// Each LIST_ENTRY is at an offset within the LDR_DATA_TABLE_ENTRY. To get the
// address of the enclosing LDR_DATA_TABLE_ENTRY itself, you subtract this offset.
#define LIST_ENTRY_OFFSET_MEM_ORDER 8
#define LIST_ENTRY_OFFSET_LOAD_ORDER 0

// Function declarations:
PEB* getPEB();
PEB* getPEBWithASM();
void walkDLLList(MY_PEB* mpeb);
void promoteToFirstLoadedDLL(MY_PEB* mpeb, const DWORD ourBaseAddress);
void promoteToFirstInMemDLL(MY_PEB* mpeb, const DWORD ourBaseAddress);