请问如何获得某个程序在内存中的地址

请教怎么获得某个程序在内存中的地址
想实现金山游戏修改游戏的类似功能

------解决方案--------------------
LS那样是不行的,指针在跨越进程的时候没有意义,可以看看这个API :ReadProcessMemory
------解决方案--------------------
游戏修改器的基本工作原理
所谓游戏修改器,主要是通过修改游戏程序的内存数据或存盘文件来修改游戏中的相关数据,使之达到“无敌”等效果。

游戏修改器主要分为两类:单一游戏的修改器和通用游戏修改器。顾名思义,前者只能修改特定的游戏,此类修改器也叫“无敌引导程序”或“游戏作弊器”;而后者则能够以“不变应万变”,可以修改大多数的游戏。本文主要讨论后者,相比之下,前者是后者只留下修改功能的“简化版”。

总的来说,游戏修改器主要的功能便是反复搜索并筛选某一特定内存地址并将其按照固定的周期修改为特定的值(所谓的“锁定”),当然,将“内存”换为“文件”便可以以同样的方式搜索文件了。

搜索和筛选是如何实现的呢?假如我们已经可以访问游戏的内存,我们将游戏的内存分块读入一个缓冲区,然后借由下面的函数搜索:

//在一个内存块中搜索内容
//成功返回位置
//失败返回-1
//(SE:现在我发现这个顺序查找函数完全可以用 STL 的 std::find() 函数取代,原因是写文章的时候我还不太了解 STL:)
int MemFind(int iStartPosition, LPBYTE pDestBuffer, int iDestBufferLength, LPBYTE pPatternBuffer, int iPatternBufferLength)
{
signed int iFoundPosition, i;
iFoundPosition = -1;
if(iStartPosition > iDestBufferLength)return -1;
for(i = iStartPosition; i < (iDestBufferLength + 1); i++)
{
if(memcmp(&pDestBuffer[i], pPatternBuffer, iPatternBufferLength) == 0)
{
iFoundPosition = i;
break;
}
}
return iFoundPosition;
}

由于游戏在内存或文件中保存的数据是二进制格式,因此,当我们搜索一个为123的整数时应用如下的格式:
int nPattern = 123;
dwOffset = MemFind(nStartPosition, pDestBuffer, nDestBufferLength, (LPBYTE)(&nPattern), sizeof(nPattern))
同样,可以这样搜索浮点类型:
float rPattern = 123;
dwOffset = MemFind(nStartPosition, pDestBuffer, nDestBufferLength, (LPBYTE)(&rPattern), sizeof(rPattern))

由于内存中肯定会存在许多相同的数据,所以第一次我们肯定会搜索到许多地址,而真正我们要找的地址一定包含在其中。所以,我们建立一个临时文件将这些地址保存起来,并设置“有效”标志,如下代码所示:
struct CTempItem
{
DWORD dwAddress;
BOOL bEnable;
};
CTempItem item;
item.dwAddress = ?????????;
item.bEnable = TRUE;
fwrite(&item, sizeof(item), 1, fp);
接下来,当用户进行第二次搜索时,将这些保存在临时文件中的数据取出来,先看item.bEnable若等于FALSE则跳过,否则读取item.dwAddress所指示的游戏内存,并于用户第二次输入的数值相比较,若发现相同,则设置item.bEnable = TRUE;若不同设置item.bEnable=FALSE,表示废弃。完成之后,再次把item写回文件,当所有item分析完之后,我们就完成了第二次搜索。再接下来,bEnable=TRUE的地址还有很多,则仍然用第二次搜索的方式反复搜索,直到剩下1-2个地址为止。 (SE:应用读写缓冲区,即成批地读写,可以大大加快速度)

由以上介绍可以看出,游戏修改器的搜索分为2个阶段:第一次搜索和第2、3、4……次搜索,游戏修改器在第一次搜索出的很多地址中分析出与用户输入的数据始终相同的地址。当我们有了目标地址,就可以按照用户的意愿定时或手动方式写入用户指定的数据,这便是游戏修改器的基本原理。

当然,这只是基本原理,当具体编写修改器将遇到许多具体的技术困难,以下章节将为您一一解答。

如何访问游戏程序的内存
当我们的修改器运行于Windows时,首先遇到的问题便是如何访问游戏的内存。

首先,在访问游戏的内存前我们还必须获得游戏进程的句柄,这可以通过ToolHelp函数获取系统中当前运行的所有进程的列表和各进程的ID,经由用户选择之后通过OpenProcess函数来获取。若您的修改器运行于后台,而前台是游戏的话,可以在用户按下“弹出”热键时使用GetForegroundWindow函数获取游戏窗口的HWND,再使用GetWindowThreadProcessId转换成游戏进程的ID,再使用OpenProcess函数获取游戏进程的句柄。

有了游戏进程的句柄之后,便可以使用Windows提供的ReadProcessMemory和WriteProcessMemory这两个API来读写游戏的内存了。但是,在Windows9x中每个进程均拥有各自独立的1GB虚拟地址空间,而在Win2000/XP下更是达到了2GB。显然,搜索这样大的地址空间是不现实的,而且游戏也仅仅用了其中的几十到几百MB。所以,我们需要使用VirtualQueryEx这个函数来查询哪些是已经分配的地址,哪些是未用的地址。以下查询与搜索相结合的示范代码:

DWORD dwBaseAddress;
SYSTEM_INFO si;
GetSystemInfo(si);
dwBaseAddress = si.lpMinimumApplicationAddress;
while(dwBaseAddress < si.lpMaximumApplicationAddress)
{
mbi.BaseAddress = (LPVOID)dwBaseAddress;
ProcessMem.Query((PVOID)dwBaseAddress, &mbi);
VirtualQueryEx(hProcess, (LPVOID)dwAddress), mbi, sizeof(mbi)
dwBaseAddress = (DWORD)mbi.BaseAddress + mbi.RegionSize;
if(mbi.State != MEM_COMMIT || mbi.AllocationProtect != PAGE_READWRITE); //跳过未分配或不可读写的区域
{
continue;
}
//搜索这块内存区域
}

资源:请到 http://alphasun.betajin.com下载我写的一个很“简陋”的游戏修改器——GameProbe的源程序。