-
-
[旧帖] [原创]新思路。自写[仙剑奇侠传4]无限物品修改器过程及代码 0.00雪花
-
发表于: 2010-7-11 10:12 1440
-
这个是半年多前写的了,今天第一次发贴,看看能不能混个邀请码。嘿嘿嘿嘿嘿嘿嘿嘿嘿嘿
有天同学下了一个仙剑奇侠传4,我也就顺手拿来玩完了。刚开始还好,东西啊什么的都够用,到后来就麻烦了,打BOSS时东西总是不够吃,无奈拿出金山游侠修改,郁闷的是竟然找不到内存地址,试了几次还是不行,后来上网找了个FPE修改器终于找到了,哈哈,然后我把物品的数量调到几万,本来想着这辈子都吃不完了,谁知道当我用了一个之后,他竟然变成99个了,看来有限制。想想还是算了,以后用修改器锁定就行了,然后保存地址,关机。等到晚上再来玩时,发现修改器竟然不能修改了,我以为是修改器的问题,可是试了很多次还是不行,上网看了看,才发现是因为游戏的地址会变的缘故,有些人还提供了一些地址,说是有50%的机会是对的,可是我试了很多次就是没办法修改。
后来想到一种方法,就是你内存地址会变,难道你游戏代码还会变么?只要找到你修改内存的代码在哪不是就行了么?于是用OD载入,进入游戏之后用FPE找出现在内存的地址,回到OD中,去到刚才找到的地址下内存写入断点,回到游戏中使用一次那个物品(后来发现使用什么都可以),游戏被OD断了,记下那个地址。这时已经可以很清楚的看到ECX寄存器中就是我们使用的物品的数量了,下面就简单了,写个小程序在那里下断点,断下来之后修改ECX寄存器的内容就行了。
我写了一个,但是好像这里不可以上传附件,那我还是贴一段代码吧,DELPHI7+WINXP下正常。技术有限,代码写得很差,大家将就着看吧。
对了,还有一个问题,这个游戏好像加过壳,用OD可以跟到入口点,但是脱壳时会弹出一个框框,大意就是什么打击盗版之类的话,然后OD就挂了。壳脱不了就不脱了,在写的程序里加了一段代码,就是等你壳脱完了在修改代码下断点,哈哈,偷懒了。。
program PAL4change;
uses
windows,SysUtils;
{$R *.res}
var
hOpen:thandle;
function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall;external 'kernel32' name 'OpenThread';
function Find:bool;
var
read:byte;
lpNumberOfBytesWritten: DWORD;
begin
result:=true;
while true do
begin
ReadProcessMemory(hOpen,pointer($4C6B03),@read,1,lpNumberOfBytesWritten);
if read=$5D then
begin
read:=$cc;
writeprocessmemory(hOpen,pointer($4C6B03),@read,1,lpNumberOfBytesWritten);
exit;
end;
sleep(1000); //每过一秒钟检查一次是否脱完壳,反正从开始到进入游戏时间长的很
end;
end;
var
si:STARTUPINFO;
pi:PROCESS_INFORMATION;
cc:context;
d:DEBUG_EVENT;
ht:thandle;
write:byte;
lpNumberOfBytesWritten: DWORD;
id: DWORD;
begin
ZeroMemory(@si, sizeof(si) );
si.cb := sizeof(si);
CreateProcess( nil,'PAL4.exe',nil,nil,FALSE,DEBUG_PROCESS,nil,nil,si,pi );
hOpen:=OpenProcess(process_all_access,FALSE,pi.dwProcessId);
if hopen<>0 then
begin
Createthread(nil,0,@find,nil,0,id);
WaitForDebugEvent(d,INFINITE);
while d.dwDebugEventCode<>EXIT_PROCESS_DEBUG_EVENT do
begin
if d.dwDebugEventCode=EXCEPTION_DEBUG_EVENT then
begin
ht:=OpenThread($FF,FALSE,d.dwThreadId);
cc.ContextFlags:=CONTEXT_FULL;
GetThreadContext(ht,cc);
if cc.Eip=$4C6B04 then
begin
cc.Ecx:=1234567;
write:=$5d;
writeprocessmemory(hOpen,pointer($4C6B03),@write,1,lpNumberOfBytesWritten);
write:=$cc;
writeprocessmemory(hOpen,pointer($4C6B04),@write,1,lpNumberOfBytesWritten);
cc.Eip:=cc.Eip-1;
SetThreadContext(ht,cc);
end;
if cc.Eip=$4C6B05 then
begin
write:=$cc;
writeprocessmemory(hOpen,pointer($4C6B03),@write,1,lpNumberOfBytesWritten);
write:=$89;
writeprocessmemory(hOpen,pointer($4C6B04),@write,1,lpNumberOfBytesWritten);
cc.Eip:=cc.Eip-1;
SetThreadContext(ht,cc);
end;
end;
ContinueDebugEvent(d.dwProcessId,d.dwThreadId,DBG_CONTINUE);
WaitForDebugEvent(d,INFINITE);
end;
ContinueDebugEvent(d.dwProcessId,d.dwThreadId,DBG_CONTINUE);
end;
end.
有天同学下了一个仙剑奇侠传4,我也就顺手拿来玩完了。刚开始还好,东西啊什么的都够用,到后来就麻烦了,打BOSS时东西总是不够吃,无奈拿出金山游侠修改,郁闷的是竟然找不到内存地址,试了几次还是不行,后来上网找了个FPE修改器终于找到了,哈哈,然后我把物品的数量调到几万,本来想着这辈子都吃不完了,谁知道当我用了一个之后,他竟然变成99个了,看来有限制。想想还是算了,以后用修改器锁定就行了,然后保存地址,关机。等到晚上再来玩时,发现修改器竟然不能修改了,我以为是修改器的问题,可是试了很多次还是不行,上网看了看,才发现是因为游戏的地址会变的缘故,有些人还提供了一些地址,说是有50%的机会是对的,可是我试了很多次就是没办法修改。
后来想到一种方法,就是你内存地址会变,难道你游戏代码还会变么?只要找到你修改内存的代码在哪不是就行了么?于是用OD载入,进入游戏之后用FPE找出现在内存的地址,回到OD中,去到刚才找到的地址下内存写入断点,回到游戏中使用一次那个物品(后来发现使用什么都可以),游戏被OD断了,记下那个地址。这时已经可以很清楚的看到ECX寄存器中就是我们使用的物品的数量了,下面就简单了,写个小程序在那里下断点,断下来之后修改ECX寄存器的内容就行了。
我写了一个,但是好像这里不可以上传附件,那我还是贴一段代码吧,DELPHI7+WINXP下正常。技术有限,代码写得很差,大家将就着看吧。
对了,还有一个问题,这个游戏好像加过壳,用OD可以跟到入口点,但是脱壳时会弹出一个框框,大意就是什么打击盗版之类的话,然后OD就挂了。壳脱不了就不脱了,在写的程序里加了一段代码,就是等你壳脱完了在修改代码下断点,哈哈,偷懒了。。
program PAL4change;
uses
windows,SysUtils;
{$R *.res}
var
hOpen:thandle;
function OpenThread(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall;external 'kernel32' name 'OpenThread';
function Find:bool;
var
read:byte;
lpNumberOfBytesWritten: DWORD;
begin
result:=true;
while true do
begin
ReadProcessMemory(hOpen,pointer($4C6B03),@read,1,lpNumberOfBytesWritten);
if read=$5D then
begin
read:=$cc;
writeprocessmemory(hOpen,pointer($4C6B03),@read,1,lpNumberOfBytesWritten);
exit;
end;
sleep(1000); //每过一秒钟检查一次是否脱完壳,反正从开始到进入游戏时间长的很
end;
end;
var
si:STARTUPINFO;
pi:PROCESS_INFORMATION;
cc:context;
d:DEBUG_EVENT;
ht:thandle;
write:byte;
lpNumberOfBytesWritten: DWORD;
id: DWORD;
begin
ZeroMemory(@si, sizeof(si) );
si.cb := sizeof(si);
CreateProcess( nil,'PAL4.exe',nil,nil,FALSE,DEBUG_PROCESS,nil,nil,si,pi );
hOpen:=OpenProcess(process_all_access,FALSE,pi.dwProcessId);
if hopen<>0 then
begin
Createthread(nil,0,@find,nil,0,id);
WaitForDebugEvent(d,INFINITE);
while d.dwDebugEventCode<>EXIT_PROCESS_DEBUG_EVENT do
begin
if d.dwDebugEventCode=EXCEPTION_DEBUG_EVENT then
begin
ht:=OpenThread($FF,FALSE,d.dwThreadId);
cc.ContextFlags:=CONTEXT_FULL;
GetThreadContext(ht,cc);
if cc.Eip=$4C6B04 then
begin
cc.Ecx:=1234567;
write:=$5d;
writeprocessmemory(hOpen,pointer($4C6B03),@write,1,lpNumberOfBytesWritten);
write:=$cc;
writeprocessmemory(hOpen,pointer($4C6B04),@write,1,lpNumberOfBytesWritten);
cc.Eip:=cc.Eip-1;
SetThreadContext(ht,cc);
end;
if cc.Eip=$4C6B05 then
begin
write:=$cc;
writeprocessmemory(hOpen,pointer($4C6B03),@write,1,lpNumberOfBytesWritten);
write:=$89;
writeprocessmemory(hOpen,pointer($4C6B04),@write,1,lpNumberOfBytesWritten);
cc.Eip:=cc.Eip-1;
SetThreadContext(ht,cc);
end;
end;
ContinueDebugEvent(d.dwProcessId,d.dwThreadId,DBG_CONTINUE);
WaitForDebugEvent(d,INFINITE);
end;
ContinueDebugEvent(d.dwProcessId,d.dwThreadId,DBG_CONTINUE);
end;
end.
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
看原图
赞赏
雪币:
留言: