C#制作内存修改器

长平狐 发布于 2012/12/10 17:21
阅读 806
收藏 1

先看效果图


下载地址

http://download.csdn.net/detail/crystal_lz/4555991

其实 搞这个东西 主要是因为 不久前看到一个C#写的外挂 顿时就来了兴趣

当时看了之后 觉得不爽的就是 那个地址是写死在程序里面的是固定的 而且是用其他东西扫出来的地址 顿时就觉得不爽了 要这个地址也是自己写的程序扫出来的那才有成就感

于是呼这东西就这样诞生了、、、

在做之前 我感觉这东西 应该很简单的 结果 尼玛还是搞了半天 途中总是遇到一些纠结的问题 比如什么内存溢出的  现在都还没解决 不过出现的几率不大 还有搜索效率问题

其实 想一下这东西是挺简单的 也就那么三个函数

VirtualQueryEx()

ReadProcessMemory()

WriteProcessMemory()

先用 VirtualQueryEx 去扫描内存块 遇到已经物理分配的内存 以及 是可读写内存 那么就把该区域的数据用ReadProcessMemory读取出来 然后与要查询的值比较

如果要修改值的话 就用WriteProcesMemory去修改相应地址的数据

 public class Win32
    {
        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 const int MEM_COMMIT = 0x1000;       //已物理分配
        public const int PAGE_READWRITE = 0x04;     //可读写内存

        [DllImport("kernel32.dll")]     //查询内存块信息
        public static extern int VirtualQueryEx(
            IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
        [DllImport("kernel32.dll")]
        public static extern bool ReadProcessMemory(
            IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int size, out int numBytesRead);
        [DllImport("kernel32.dll")]
        public static extern bool WriteProcessMemory(
            IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int size, out int numBytesWrite);
    }

如果要扫描内存块 做一个 0 - 0x7FFFFFFF 的循环就行了

Win32.MEMORY_BASIC_INFORMATION stMBI = new Win32.MEMORY_BASIC_INFORMATION();
int searchLen = Marshal.SizeOf(stMBI);
nBaseAddr = 0x000000;
int nReadSize = 0;      //实际读取字节数
while (nBaseAddr >= 0 && nBaseAddr <= 0x7fffffff && stMBI.RegionSize >= 0) {    //nBaseAddr >= 0 在这期间nBaseAddr 可能溢出int范围变成负数
	searchLen = Win32.VirtualQueryEx(hProcess, nBaseAddr, out stMBI, Marshal.SizeOf(stMBI));  //扫描内存信息 
	if (searchLen == Marshal.SizeOf(typeof(Win32.MEMORY_BASIC_INFORMATION))) {
		if (stMBI.State == Win32.MEM_COMMIT && stMBI.Protect == Win32.PAGE_READWRITE) {     //如果是已物理分配 并且是 可读写内存 那么读取内存
			byte[] byData = new byte[stMBI.RegionSize];
			if (Win32.ReadProcessMemory(hProcess, nBaseAddr, byData, stMBI.RegionSize, out nReadSize))
				if (nReadSize == stMBI.RegionSize)      //如果和实际读取数相符 那么搜索数据
					//搜索数据的代码
		}
	} else {
		break;
	}
	nBaseAddr += stMBI.RegionSize;      //设置基地址偏移
}

对于 ReadProcessMemory 和 WriteProcessMemory 两者都相当简单 签名也都一样

Read / WriteProcessMemory(进程句柄, 要操作的地址, 写入或者读取缓存区, 要操作的字节数, 实际操作的字节数)

哦 还有一个就是 把 数据 于 byte[] 数组进行转换的问题

把数组转换成数到十方便 可以用 BitConvert.ToIntXX(byte[],startIndex)

如果是要把 一个 int 转换成 byte[] 那么几个位移操作 就搞定比如

int nTest = 65535;
byte[] byTest = new byte[4];
byTest[0] = (byte)(nTest & 0x000000FF);				//从低8位开始存入
byTest[1] = (byte)((nTest & 0x0000FF00) >> 8);		//意思就是要倒过来 小端模式
byTest[2] = (byte)((nTest & 0x00FF0000) >> 16);
byTest[3] = (byte)((nTest & 0xFF000000) >> 24);
byTest = {255, 255, 0, 0}							//在内存中就是这样的 低位地直接高位高字节
当然也可以用循环的方式

int nTest = 65535
byte[] byTest = new byTest[4];
for(int i = 0; i < 4; i ++) {
	byTest[i] = (byte)((num & (0x000000FF << i * 8)) >> i * 8);	//先左移相应位数 做完操作 又右移回来
}

差不多 也就将这么多 想想上去 的确很简单

尼玛实际动手操作的时候 总是遇到一些纠结的问题 唉!、、

具体去下载 源码 看吧 放心不要分数

可以的话 大家一起讨论



原文链接:http://blog.csdn.net/crystal_lz/article/details/7957121
加载中
返回顶部
顶部