C# 实现游戏修改器Word下载.docx
《C# 实现游戏修改器Word下载.docx》由会员分享,可在线阅读,更多相关《C# 实现游戏修改器Word下载.docx(13页珍藏版)》请在冰点文库上搜索。
[DllImport("
kernel32.dll"
SetLastError=true)]
staticexternboolReadProcessMemory(
IntPtrhProcess,
IntPtrlpBaseAddress,
[Out]byte[]lpBuffer,
intdwSize,
outintlpNumberOfBytesRead
);
[DllImport("
staticexternboolWriteProcessMemory(
IntPtrhProcess,
IntPtrlpBaseAddress,
byte[]lpBuffer,
uintnSize,
outintlpNumberOfBytesWritten);
名字很直观:
读/写进程内存。
两个方法签名基本相同,我这里简单解释一下:
hProcess:
进程句柄
lpBaseAddress:
基地址,也就是起始地址(起始位置)
lpBuffer:
从基地址起读取或要写入的内存值
nSize:
读取或写入的数量,单位是字节
lpNumberOfBytesRead、lpNumberOfBytesWritten:
用作传出,表示实际读取或写入的数量
好了!
开始实战吧!
创建一个C#的Windowsforms项目
在窗体上我这样布局:
为类添加如下几个成员:
List<
Process>
_windowedProcesses=newList<
();
//存放有窗体的进程集合
privateList<
IntPtr>
_addrList=newList<
//存放作为结果的地址列表
boolisFirstSearch=true;
//是否是第一次搜索
Process_selectedProcess;
//所选进程
还要获取有窗体的进程并列出来,让使用者选择需要的进程
privatevoidRefreshProcessList()
{
listBox1.Items.Clear();
_windowedProcesses.Clear();
textBox2.Enabled=false;
//在没得到唯一的地址前不能写入
foreach(varpinSystem.Diagnostics.Process.GetProcesses())
if(p.MainWindowHandle!
=IntPtr.Zero)//进程有窗口
if(!
string.IsNullOrEmpty(p.MainWindowTitle))//窗体名不为空。
因为有些时候会有一些进程如iexplorer.exe,它有窗口,但窗口没名称且没显示。
所以应该排除一下
listBox1.Items.Add(p.MainWindowTitle);
_windowedProcesses.Add(p);
}
于是可以在我们的窗体装载和单击刷新按钮时调用该方法
privatevoidForm1_Load(objectsender,EventArgse)
RefreshProcessList();
privatevoidbtnRefreshPList_Click(objectsender,EventArgse)
为什么要区别是否是第一次搜索?
因为第一次搜索是在整个进程可访问内存范围内查找,而之后的查找是基于第一次找到的地址。
这样做不是唯一的,但是最好的方法。
下面是搜索按钮单击的事件处理代码:
privatevoidbutton1_Click(objectsender,EventArgse)
if(_selectedProcess==null)return;
if(isFirstSearch)
uintbaseAddr=0x00010000;
uintendAddr=
0x7ffeffff;
for(uinti=baseAddr;
i<
endAddr;
i+=(4*1024))
varaddrs=CreateAddrList(newIntPtr(i),int.Parse(textBox1.Text));
if(addrs!
=null)
_addrList.AddRange(addrs);
isFirstSearch=false;
else
RefreshAddrList(int.Parse(textBox1.Text));
label2.Text="
找到结果”+_addrList.Count.ToString()+"
个"
;
if(_addrList.Count==1)
textBox2.Enabled=true;
很明显CreateAddrList是第一次查找掉用的方法,RefreshAddrList是之后查找调用的方法。
在第一次查找中,我们以4KB作一次跳跃。
为什么查找的地址范围如此本文开始已作说明,这里就不再赘述。
好了,现在来看看CreateAddrList方法:
privateList<
CreateAddrList(IntPtrbaseAddr,intvalue)
intbytesRead;
byte[]buffer=newbyte[4096];
boolok;
List<
result=newList<
ok=ReadProcessMemory(_selectedProcess.Handle,baseAddr,buffer,4096,outbytesRead);
ok)
returnnull;
intcurrentVal;
for(inti=0;
4096-3;
i++)
currentVal=BitConverter.ToInt32(buffer,i);
if(currentVal==value)
IntPtraddr=newIntPtr(baseAddr.ToInt32()+i);
result.Add(addr);
i+=3;
}
returnresult;
该方法用以创建地址列表。
它接受2个参数,分别是基地址和要查找的值。
我们用ReadProcessMemory一次读取4KB的值,并把它存放在buffer中。
由于buffer是byte[],所以需要用BitConverter.ToInt32()把buffer中的一部分值转成Int32以和要查找的值进行比对。
如果值匹配,则把对应地址添加到该方法的result中以供方法返回。
接下来是RefreshAddrList方法:
.
privatevoidRefreshAddrList(intvalue)
varla=_addrList.ToList();
_addrList.Clear();
byte[]buffer=newbyte[4];
foreach(variinla)
ReadProcessMemory(_selectedProcess.Handle,i,buffer,4,outbytesRead);
if(BitConverter.ToInt32(buffer,0)==value)
_addrList.Add(i);
因为要根据第一次查找的地址结果进行查找并要更新主地址列表,所以要用addrList.ToList()得到一份主地址列表的拷贝。
接下来再在作为第一次搜索结果的地址表中查找新的值。
如果等于之前的值的地址中的数据现在还等于新的值,那么就添加到地址列表。
回看查找按钮的事件处理代码可以发现:
反复多次,直到地址列表中只有一个地址时,就可以确定这就是我们要的地址,此时,我们就可以修改它了。
privatevoidbutton2_Click(objectsender,EventArgse)
intvalue;
int.TryParse(textBox2.Text,outvalue))
MessageBox.Show("
输入值太大!
小心溢出!
请重新输入!
"
);
return;
varbuffer=BitConverter.GetBytes(value);
intbytesWritten;
WriteProcessMemory(_selectedProcess.Handle,_addrList[0],buffer,4,out
bytesWritten);
哈哈!
这样就完成了。
按下F5我又IMBA了一回
代码下载:
ProgramMemoryEditor
该程序搜索值的数据类型是Int32,若我们要修改的程序的某个数据是以其他数据类型存储的,则需要小修改下我们的修改器。
笔者水平有限,若有疑问或更好的建议,务必不吝赐教。
cyclone_dll
关注-0
粉丝-4
荣誉:
微软社区精英
关注博主
13
0
(请您对文章做出评价)
«
上一篇:
Silverlight捕获摄像头
postedon2010-12-2300:
47cyclone_dll阅读(1277)评论(15)编辑收藏所属分类:
.NetFramework
Feedback
1995141
#1楼
2010-12-2301:
02|阳光沙滩海岸线
有意思,支持一下~
回复 引用 查看
#2楼
13|IT鸟
不是web版的哦
#3楼
36|Greatest
用来[url=
#4楼
37|Greatest
用VirtualQueryEx来实现CreateAddrList
#5楼
2010-12-2304:
46|持剑人
用C++应该更好
#6楼
2010-12-2308:
34|欧阳寒玟
我也做过相关外挂用C#,查找内存,写入汇编,调用内存汇编代码实现CALL,其实这些用2.0就够了。
其次process方法确实便利了一点,但是个人觉得如果用findwindow/finwindowex这样的函数是不是更简单,直接返回你要的窗口的进程信息。
当然用C更为方便,但既然学了C#,他也能做,那么我们就可以做嘛。
另外System.Runtime.InteropServices提供了很多操作非托管代码的相关程式,特别是数据转换特别方便。
自己收集了一些win32Api的C#申明,基本够用的,可是后来由于工作关系没能继续做下去了。
#7楼
44|NicolasZhang
强!
#8楼
47|无道(东)
菜虫学习学习
#9楼
48|贺臣
前不久玩植物大战僵尸,不停地玩啊玩,也通关了
你玩通关了,不可能吧,这个里面最后是一个无尽版,用程序的角度来说就是一个死循环,怎么可能玩通关啊!
#10楼
2010-12-2309:
19|seiya027848
非常有意思
#11楼
35|小城故事
以前在CSDN上见过
#12楼
42|爱风
for(inti=0;
{
if(currentVal==value)
IntPtraddr=newIntPtr(baseAddr.ToInt32()+i);
result.Add(addr);
i+=3;
楼主"
”这样是不对的
当你在"
22222"
中查找"
2222"
时,只找了前面一个,却跳过了后面一个