using Magic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace BlackMagicTest
{
public enum MemoryAllocationProtectionType : int
{
[Description("PAGE_NOACCESS")]
PAGE_NOACCESS = 0x1,
[Description("PAGE_READONLY")]
PAGE_READONLY = 0x2,
[Description("PAGE_READWRITE")]
PAGE_READWRITE = 0x4,
[Description("PAGE_WRITECOPY")]
PAGE_WRITECOPY = 0x8,
[Description("PAGE_EXECUTE")]
PAGE_EXECUTE = 0x10,
[Description("PAGE_EXECUTE_READ")]
PAGE_EXECUTE_READ = 0x20,
[Description("PAGE_EXECUTE_READWRITE")]
PAGE_EXECUTE_READWRITE = 0x40,
[Description("PAGE_EXECUTE_WRITECOPY")]
PAGE_EXECUTE_WRITECOPY = 0x80,
[Description("PAGE_GUARD")]
PAGE_GUARD = 0x100,
[Description("PAGE_NOCACHE")]
PAGE_NOCACHE = 0x200,
[Description("PAGE_WRITECOMBINE")]
PAGE_WRITECOMBINE = 0x400,
[Description("PAGE_CANREAD")]
PAGE_CANREAD = PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE
// Or PAGE_EXECUTE_READ Or PAGE_EXECUTE_READWRITE
}
public enum MemoryAllocationType : int
{
MEM_IMAGE = 0x1000000,
MEM_MAPPED = 0x40000,
MEM_PRIVATE = 0x20000
}
public enum MemoryAllocationState : int
{
Commit = 0x1000,
Reserve = 0x2000,
Decommit = 0x4000,
Release = 0x8000,
Reset = 0x80000,
Physical = 0x400000,
TopDown = 0x100000,
WriteWatch = 0x200000,
LargePages = 0x20000000
}
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION{
public int BaseAddress;
public int AllocationBase;
public int AllocationProtect;
public int RegionSize;
public int State;
public int Protect;
public int lType;
}
public struct SYSTEM_INFO
{
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}
public class MemoryReader
{
[DllImport("kernel32.dll")]
public static extern int VirtualQueryEx(
int hProcess,
int lpAddress,
[MarshalAs(UnmanagedType.Struct)] ref MEMORY_BASIC_INFORMATION lpBuffer,
int dwLength
);
[DllImport("kernel32.dll")]
public static extern void GetSystemInfo(ref SYSTEM_INFO pSI);
[DllImport("kernel32.dll")]
public static extern int VirtualProtectEx(
int hProcess,
int lpAddress,
int dwSize,
int flNewProtect,
int lpflOldProtect);
public void AnalyzeRam(int _targetProcessHandle)
{
Console.WriteLine("Starting analizing: 0x{0:X08}", _targetProcessHandle);
MEMORY_BASIC_INFORMATION _mbi = default(MEMORY_BASIC_INFORMATION);
IntPtr _addr = IntPtr.Zero;
//could use _sysInfo.lpMinProcAddr
SYSTEM_INFO _sysInfo = default(SYSTEM_INFO);
GetSystemInfo(ref _sysInfo);
double regionCounter = 0;
//'useful API. Tells us things like # of processors, ram page size, more ram stuff.
do
{
int sizeOfMBI = System.Runtime.InteropServices.Marshal.SizeOf(_mbi);
VirtualQueryEx(_targetProcessHandle, (int)_addr, ref _mbi, sizeOfMBI);
if ((int)_mbi.State == (int)MemoryAllocationState.Commit)
{
//this region of ram actively being used by process (commited at least..)
if ((int)_mbi.Protect == (int)MemoryAllocationProtectionType.PAGE_READWRITE)
{
Console.WriteLine("Base: 0x{0:X08} Size: 0x{0:X08}", _mbi.BaseAddress , _mbi.RegionSize);
// Application.DoEvents();
regionCounter++;
//'elsee
//'VirtualProtectEx() :: and restore old protections when finished
}
}
//'increment _addr to next region
_addr = (IntPtr)(_mbi.BaseAddress + _mbi.RegionSize);
} while (_addr.ToInt32() < _sysInfo.lpMaximumApplicationAddress);
}
public IntPtr[] ScanForBytes(int _targetProcessHandle, byte[] buff)
{
List<IntPtr> _rtns = new List<IntPtr>();
_rtns.Capacity = 1000;
buff.Reverse();
//endianness of ram
MEMORY_BASIC_INFORMATION _mbi = default(MEMORY_BASIC_INFORMATION);
SYSTEM_INFO _sysInfo = default(SYSTEM_INFO);
Int32 _mbiSize = System.Runtime.InteropServices.Marshal.SizeOf(_mbi);
GetSystemInfo(ref _sysInfo);
IntPtr _addr = IntPtr.Zero;
byte[] _readBuff = new byte[_sysInfo.dwPageSize];
byte[] _bigBuff = new byte[1];
Int32 _actualBytesRead = 0;
//'actual length of bytes copied during ReadProcessMemory()
UInt32 _oldPageProtection = 0;
//'To restore old VirtualProtectEx() values after ReadProcessMemory
bool _didWeChangeProtection = false;
bool _mbiIsReadable = false;
double regionCoutuer = 0;
do
{
VirtualQueryEx(_targetProcessHandle, (int)_addr, ref _mbi, _mbiSize);
Console.WriteLine(regionCoutuer++ + " --------- 0x{0:X08} --------------", _addr);
Console.WriteLine("_mbi.State: 0x{0:X08}: ", _mbi.State);
Console.WriteLine("_mbi.Protect: 0x{0:X08}: ", _mbi.Protect);
Console.WriteLine("_mbi.RegionSize: 0x{0:X08}: ", _mbi.RegionSize);
Console.WriteLine("_sysInfo.dwPageSize: 0x{0:X08}: ", _sysInfo.dwPageSize);
if (!((int)_mbi.State == (int)MemoryAllocationState.Commit && (int)_mbi.lType == (int)MemoryAllocationType.MEM_PRIVATE))
{
Console.WriteLine("[System Page]");
//DoOutput("Base: " & _addr.ToString("X") & "[system page]")
}
else
{
//this region of ram actively being used by process (commited at least..)
//'bitwise mask checking
if ((_mbi.Protect & (int)MemoryAllocationProtectionType.PAGE_CANREAD) == 0)
{
//page isn't parked as readable (ie. PAGE_READONLY, PAGE_READWRITE, etc. Maybe is PAGE_GUARD

int pageRW = (int)MemoryAllocationProtectionType.PAGE_READWRITE;
if ( (VirtualProtectEx(_targetProcessHandle, (int)_addr, (int)_mbi.RegionSize, pageRW, (int)_oldPageProtection) ) != 0)
{
Console.WriteLine("Patching->0x{0:X08}", _addr);
_didWeChangeProtection = true;
}
else
{
Console.WriteLine("Patching->0x{0:X08} {}" , _addr , " FAIL. RPM about to fail..");
// System.Threading.Thread.Sleep(2000);
}
}
if ((int)_mbi.RegionSize <= _sysInfo.dwPageSize)
{
//small page. Read entire page into buffer.
Console.WriteLine("Small Page");
byte[] bData = SMemory.ReadBytes(new IntPtr(_targetProcessHandle), (uint)_mbi.BaseAddress, (int)_sysInfo.dwPageSize);
//if (ReadProcessMemory(_targetProcessHandle, _mbi.BaseAddress, _readBuff, _mbi.RegionSize, _actualBytesRead))
if (bData != null && bData.Length > 0)
{
//if ((_actualBytesRead != _mbi.RegionSize))
if ((bData.Length != _mbi.RegionSize))
{
//not able to read all data, handle gracefully. do nothing

Console.WriteLine("ScanForBytes() RPM->ActualBytesRead too low!");
}
else
{
for (Int32 xx = 0; xx <= _mbi.RegionSize - buff.Length; xx++)
{
for (Int32 yy = 0; yy <= buff.Length - 1; yy++)
{
if (buff[yy] == _readBuff[xx + yy])
{
if (yy == buff.Length - 1)
{
//found it
_rtns.Add(_addr);
}
}
else
{
break; // TODO: might not be correct. Was : Exit For
}
}
}
}
}
else
{
Console.WriteLine("ScanForBytes::ReadProcessMemory FAIL at 0x{0:X08}" , _mbi.BaseAddress);
//System.Threading.Thread.Sleep(2000);
}
}
else
{
//large page. Read page in chunks.
Console.WriteLine("Large Page");
_bigBuff = SMemory.ReadBytes(new IntPtr(_targetProcessHandle), (uint)_mbi.BaseAddress, (int)_mbi.RegionSize);
// _bigBuff = ReadLargeRamChunk(_addr, IntPtr.Add(_addr, _mbi.RegionSize.ToInt32));
if (_bigBuff != null)
{
for (Int32 xx = 0; xx <= _bigBuff.Length - buff.Length; xx++)
{
for (Int32 yy = 0; yy <= buff.Length - 1; yy++)
{
if (buff[yy] == '?' || buff[yy] == _bigBuff[xx + yy])
{
if (yy == buff.Length - 1)
{
//found it
_rtns.Add(_addr + xx);
}
}
else
{
break; // TODO: might not be correct. Was : Exit For
}
}
}
}
else
{
Console.WriteLine("Large Page -> Read Null");
}
}
//did we change the page's access protection? Change it back.
if (_didWeChangeProtection)
{
Console.WriteLine("unPatching->0x{0:X08}", _addr);
VirtualProtectEx(_targetProcessHandle, (int)_addr, (int)_mbi.RegionSize, (int)_oldPageProtection, 0);
_didWeChangeProtection = false;
//if this fails..is very weird because it succeeded the first time (ie. "UnGUARDing")
}
}
//'increment _addr to next region
_addr = (IntPtr)(_mbi.BaseAddress + _mbi.RegionSize);
} while (_addr.ToInt32() < _sysInfo.lpMaximumApplicationAddress);
return _rtns.ToArray();
}
}
}