as a proof of concept, here is a programmatic way to read the memory of another process or the kernel using physical memory. also features a cheezy way to page in the memory if it also paged out.
this is windows specific and would not be portable (it exploits the windows mmu behavior). one particularly cool thing about it is that it can handle prototype ptes (e.g., can find the physical page representing a shared virtual address). if you actually write to this page, you can instantly hook all processes using that page (very nice way to hook code in shared pages).
a sample is here:
http://www.cybertech.net/~sh0ksh0k/projects/DumpCPU
the main functionality is here:
http://www.cybertech.net/~sh0ksh0k/projects/win32toolkit/kernel.c
you can resolve any exported variable in an loaded kernel module by adding it to KernelModuleImports[] array in kernel.c:
KERNEL_EXPORT NtoskrnlExports[] =
{
// This doesn't work properly on WinXPSP2.. still need to find out why
// The virtual address is correct, but the physical page returned is wrong
//{ "PsInitialSystemProcess", FALSE, PAGE_SIZE, (BYTE **)&PsInitialSystemProcess, NULL },
{ "KeServiceDescriptorTable", TRUE, sizeof(KSERVICE_TABLE_DESCRIPTOR), (BYTE **)&KeServiceDescriptorTable, NULL },
{ NULL, FALSE, 0, NULL, NULL }
};
KERNEL_MODULE_IMPORT KernelModuleImports[] =
{
{ "NTOSKRNL.EXE", NULL, 0, 0, 0, (KERNEL_EXPORT *)NtoskrnlExports },
{ NULL, NULL, 0, 0, 0, NULL }
};
to read the memory of another process, you need to find it's page directory base, the steps are basically:
PageDirectoryBase = GetPageDirectoryBase(ProcessID);
PhysicalAddress = GetPhysicalAddress(BlahVirtualAddress, PageDirectoryBase);
ptr = MapPhysicalMemory(PhysicalAddress, sizeof(struct blah), &BaseAddress, PAGE_READWRITE);
now ptr points to the physical memory of 'blah' and you can write to it directly. when finished, call UnmapPhysicalMemory(BaseAddress)
if you need to use any offsets into an undocumented structure, use WinDbg "dt nt!_XXXX" for each OS you want to support, then add it to OSOffsets[]:
OS offsets you can get using WinDbg 'dt nt!_STRUCT_YOU_WANT' and then add it to OS_OFFSETS structure
then add an entry into OSOffsets like this:
{
5, 0, OSTYPE_WIN50, // Win2K
0x1FC, // EPROCESS.ImageFileName
0x9C, // EPROCESS.UniqueProcessId
0xA0, // EPROCESS.ActiveProcessLinks
0x18, // EPROCESS.DirectoryTableBase
0x20, // EPROCESS.LdtDescriptor
0x128, // EPROCESS.ObjectTable
0x12C, // EPROCESS.Token
0x50, // EPROCESS.ThreadListHead
0x38, // KPCR.IDT
0x3C, // KPCR.GDT
0x40, // KPCR.TSS
0x124, // KPCR.CurrentThread
0x12C, // KPCR.IdleThread
0x800 // KPCR.DpcListHead
},
to read the structure cross-platform, you can do this:
Offset = GetOSOffsets(NtMajorVersion, NtMinorVersion);
CR3 = READ_DWORD(PsInitialSystemProcess, Offset->DirectoryTableBase)
where READ_DWORD is like:
#define READ_DWORD(base, off) \
*((DWORD *)((ULONG_PTR)(base) + (off))
if you see any strange behavior let me know what OS you use and how much RAM you hvae. in some cases the virtual address is resolving to a physical page, but the contents on the page don't match what you would see in softice. i don't have a lot of machines to test with, so i can't figure out if this is due to a MMU change between windows 2000 and windows xp sp2, or if it depends on how much memory (i see the weird behavior on a machine with 1GB ram). but at least on a machine with < 1GB RAM and running windows 2000, this seems to work peffectly. on xpsp2 with > 1GB RAM, i see this bug with certain addresses.






