【文章标题】: 原子球 - 游戏修改器
【文章作者】: Suyana
【作者邮箱】: Suyasha@163.com
【作者QQ号】: 517949855(请注明来自看雪论坛)
【软件名称】: 原子球
【下载地址】: "幻想游戏"里的一个游戏
【使用工具】: OD
【作者声明】: 本文原创于Suyana, 转载请注明作者并保持文章的完整, 谢谢!
--------------------------------------------------------------------------------
【详细过程】
一、选关
这比较简单,用游戏修改器找到Level的地址,有很多处,碰运气吧!随便选一个改一下。偶的运气还好
,第一次就找到了。有两处,01A9FD8和01A9FDC(每次都不一样)。上一个地址是真正的关数,后一个是显示的屏幕的关数。下内存写入断点。玩一下,过关后中断在:
00432B80 /$ 8B91 C8000000 mov edx, [ecx+C8]
00432B86 |. 8B81 CC000000 mov eax, [ecx+CC]
00432B8C |. 42 inc edx ; 关数加1
00432B8D |. 40 inc eax
00432B8E |. 8991 C8000000 mov [ecx+C8], edx ;中断在这里
00432B94 |. 8981 CC000000 mov [ecx+CC], eax
00432B9A |. C781 6C010000>mov dword ptr [ecx+16C], 190
--------------------------------------------------------------------------------------
二、风扇可用
不知你注意了没有,当数能被5整除时风扇都不可用。在玩游戏时要是把01A9FD8改成5,风扇也会立刻不能用。就从这里入手。在01A9FD8下内存访问断点。一切入游戏,立刻中断在:
00433285 |. 8B86 C8000000 mov eax, [esi+C8] ;取关数
0043328B |. 99 cdq
0043328C |. B9 05000000 mov ecx, 5
00433291 |. F7F9 idiv ecx ;除以5
00433293 |. 85D2 test edx, edx ;edx=0为整除
00433295 |. 0F84 8A000000 je 00433325 ;跳到0043325,使风扇不能用
0043329B |> D986 28010000 fld dword ptr [esi+128]
来到00433325,一共有两个跳转跳到这里。一个是00433277, 00433295,只要让这两个跳转不成立就可以了。但是用一次后能量就没有了,虽然还可以用,但威力很小。明白了,就是要锁定能量。![]()
在这要好好说一下,修改游戏其实最重要的是怎样找到数据的地址,在完的时候发现有ice的球,激活后就不会生成新的球了。想随便找一下,想不到一下找到了很多东西! ^_^![]()
偶是从分数上入手的。用游戏修改器找到分数的地址,不两入,在以01******开头的(上面的关数也是这样开头的)地址下内存写入断点(下断点会游戏立马就卡,哎!偶的机器),消掉一组后中断在
004325A3 |. 8986 BC010000 mov [esi+1BC], eax
返回到:
00412696 |> \8B7D F4 mov edi, [ebp-C]
这里可以说是整个游戏的核心了。游戏大部分的功能都在这里了,其他的就不说了。
在写第三步时发现
004126B6 /75 09 jnz short 004126C1
改为jmp时每消一组就会加上能量
或把004126B8 mov byte ptr [esi+358], 1改成
mov byte ptr [esi+358], 0 也可以
----------------------------------------------------------------------------------
三、过关
004122FD /0F85 17010000 jnz 0041241A 跳转不跳就是过关了
00412437 /0F85 24010000 jnz 00412561 这个也可以
00412578 /0F85 18010000 jnz 00412696 这个也可以
随便哪一个不跳就可以了
-------------------------------------------------------------------------------
四、不生成新的球
004126B1 8A5D FF mov bl, [ebp-1]
nop掉就不会有球生成,舒服吧!(偶然间知道的)![]()
------------------------------------------------------------------------------------
有了上面这4步,相信不会玩不了了吧!再玩不了偶也没办法了。现在做一下修改器,因为所有的地址都是动态的,这就要改代码了。因为还要恢复改过的代码,所以就不能用KeyMaker的内存补丁。
附件:
游戏修改器源代码(MASM32编写)
我还没养成写注释的习惯,看代码可能要费些时间,Sorry,我会养成写注释的习惯D。
代码:.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include Comctl32.inc
includelib Comctl32.lib
ModifyData STRUCT
dwSize DWORD ?
Pos DWORD ?
Old BYTE 25 dup (?)
New BYTE 25 dup (?)
ModifyData ENDS
.data?
hInstance dd ?
dwProcessId dd ?
hProcess dd ?
stPass ModifyData <?> ;过关
stNoBall ModifyData <?> ;不生成球
stFan1 ModifyData <?> ;风扇可用
stFan2 ModifyData <?> ;风扇可用
stEnergy ModifyData <?>
stSelect ModifyData <?> ;选关
.data
szClass db 'MainWindow',0
szCaption db 'Atomica Deluxe 2.52',0
szStRun db '正在运行',0
szStNoRun db '没有运行',0
szStErr db '错误',0
Flag db 0
szLarge db '不能大于40,否则不能玩',0
szDataNoMatch db '数据不匹配,可能是版本不对',13,10
db '本人用的版本是:',13,10
db 'ATOMICA Deluxe',13,10
db 'version 2.52',13,10
db 'March 17, 2003',13,10,13,10
db 'by PopCap Games',0
szPass db 0Fh,85h,17h,01,00,00,0
szNoBall db 8Ah,5Dh,0FFh,0
szFan1 db 0Fh,85h,0A8h,00,00,00,0
szFan2 db 0Fh,84h,8Ah,00,00,00,0
szEnergy db 75h,0
szModifyEnergy db 0ebh,0
szModify db 90h,90h,90h,90h,90h,90h,0
szOldSelect db 8Bh, 91h,0C8h,77h,77h,77h, 8Bh,81h, 0CCh,77h, 77h, 77h, 42h,40h,89h, 91h,0C8h,77h,77h,77h,0
szNewSelect db 0B8h,99h,99h,99h,99h,90h,90h, 90h,90h, 90h,90h,90h,90h,90h,89h, 81h,0C8h,99h,99h,99h,0
szBtnSelect db '选关(&S)',0
szBtnHuifu db '恢复代码',0
bBtn db 1
.code
Modify proc uses ebx hWnd,lpst,action
local szBuf[50]:byte
mov ebx,lpst
assume ebx:ptr ModifyData
.if action ;action is true then modify
invoke RtlZeroMemory,addr szBuf,sizeof szBuf
invoke ReadProcessMemory,hProcess,[ebx].Pos,addr szBuf,[ebx].dwSize,NULL
invoke lstrcmp,addr szBuf,addr [ebx].Old
.if eax
invoke MessageBox,hWnd,addr szDataNoMatch,addr szStErr,MB_ICONERROR
xor eax,eax
dec eax
.else
invoke WriteProcessMemory,hProcess,[ebx].Pos,addr[ebx].New,[ebx].dwSize,NULL
.endif
.else
invoke WriteProcessMemory,hProcess,[ebx].Pos,addr[ebx].Old,[ebx].dwSize,NULL
.endif
ret
Modify endp
ModifyEnable proc hwnd,flag
invoke GetDlgItem,hwnd,1000
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,1001
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,1002
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,1004
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,1005
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,1006
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,21
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,24
invoke EnableWindow,eax,flag
invoke GetDlgItem,hwnd,26
invoke EnableWindow,eax,flag
ret
ModifyEnable endp
FindProgram proc hWnd
invoke FindWindow,addr szClass,NULL
.if eax
push eax
invoke SetDlgItemText,hWnd,11,addr szStRun
invoke ModifyEnable,hWnd,TRUE
pop eax
.if Flag==0
invoke GetWindowThreadProcessId,eax,addr dwProcessId
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwProcessId
.if eax
mov hProcess,eax
mov Flag,1
.else
invoke SetDlgItemText,hWnd,11,addr szStErr
invoke ModifyEnable,hWnd,FALSE
.endif
.endif
.else
invoke SetDlgItemText,hWnd,11,addr szStNoRun
invoke ModifyEnable,hWnd,FALSE
.endif
ret
FindProgram endp
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
LOCAL szBuffer[20]:byte
mov eax,wMsg
.if eax == WM_CLOSE
invoke EndDialog,hWnd,NULL
.elseif eax == WM_INITDIALOG
invoke LoadIcon,hInstance,1
invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
invoke SendMessage,hWnd,WM_COMMAND,1003,NULL
lea ebx,stPass
assume ebx:ptr ModifyData
mov [ebx].dwSize,6
mov [ebx].Pos,004122FDh
invoke lstrcpy,addr [ebx].Old,addr szPass
invoke lstrcpyn,addr [ebx].New,addr szModify,13
lea ebx,stNoBall
assume ebx:ptr ModifyData
mov [ebx].dwSize,3
mov [ebx].Pos,004126B1h
invoke lstrcpy,addr [ebx].Old,addr szNoBall
invoke lstrcpyn,addr [ebx].New,addr szModify,7
lea ebx,stFan1
assume ebx:ptr ModifyData
mov [ebx].dwSize,6
mov [ebx].Pos,00433277h
invoke lstrcpy,addr [ebx].Old,addr szFan1
invoke lstrcpyn,addr [ebx].New,addr szModify,13
lea ebx,stFan2
assume ebx:ptr ModifyData
mov [ebx].dwSize,6
mov [ebx].Pos,00433295h
invoke lstrcpy,addr [ebx].Old,addr szFan2
invoke lstrcpyn,addr [ebx].New,addr szModify,13
lea ebx,stEnergy
assume ebx:ptr ModifyData
mov [ebx].dwSize,1
mov [ebx].Pos,004126B6h
invoke lstrcpy,addr [ebx].Old,addr szEnergy
invoke lstrcpy,addr [ebx].New,addr szModifyEnergy
lea ebx,stSelect
assume ebx:ptr ModifyData
mov [ebx].dwSize,20
mov [ebx].Pos,00432B80h
invoke lstrcpy,addr [ebx].Old,addr szOldSelect
lea ebx,[ebx].Old
mov word ptr[ebx+3],0
mov byte ptr [ebx+5],0
mov word ptr[ebx+9],0
mov byte ptr [ebx+11],0
mov word ptr[ebx+17],0
mov byte ptr [ebx+19],0
.elseif eax == WM_COMMAND
mov eax,wParam
.if ax == IDOK
invoke SendMessage,hWnd,WM_CLOSE,NULL,NULL
.elseif ax==1003
invoke FindProgram,hWnd
.elseif ax==1001 ;选关
invoke GetDlgItemInt,hWnd,1000,NULL,FALSE
.if eax>40
invoke MessageBox,hWnd,addr szLarge,addr szStErr,0
ret
.endif
push eax
lea ebx,stSelect
assume ebx:ptr ModifyData
invoke lstrcpy,addr [ebx].New,addr szNewSelect
pop eax
lea ebx,[ebx].New
mov byte ptr [ebx+1],al
mov byte ptr [ebx+2],ah
rol eax,16
mov byte ptr [ebx+3],al
mov byte ptr [ebx+4],ah
mov word ptr[ebx+17],0
mov byte ptr [ebx+19],0
.if bBtn
invoke Modify,hWnd,addr stSelect,1
invoke SetDlgItemText,hWnd,1001,addr szBtnHuifu
mov bBtn,0
.else
invoke Modify,hWnd,addr stSelect,0
invoke SetDlgItemText,hWnd,1001,addr szBtnSelect
mov bBtn,1
.endif
.elseif ax==1007
invoke Modify,hWnd,addr stSelect,0
.elseif ax==1002 ;风扇总可用
invoke IsDlgButtonChecked,hWnd,1002
.if eax == BST_CHECKED
;启用风扇
invoke Modify,hWnd,addr stFan2,1
invoke Modify,hWnd,addr stFan1,1
inc eax
.if eax==0
invoke CheckDlgButton,hWnd,1002,BST_UNCHECKED
.endif
.else
;取消风扇
invoke Modify,hWnd,addr stFan1,0
.endif
.elseif ax==1004 ;每消一组就增加能量
invoke IsDlgButtonChecked,hWnd,1004
.if eax == BST_CHECKED
;每消一组就增加能量
invoke Modify,hWnd,addr stEnergy,1
inc eax
.if eax==0
invoke CheckDlgButton,hWnd,1004,BST_UNCHECKED
.endif
.else
;每消一组就增加能量
invoke Modify,hWnd,addr stEnergy,0
.endif
.elseif ax==1005 ;过关
invoke IsDlgButtonChecked,hWnd,1005
.if eax == BST_CHECKED
;启用过关
invoke Modify,hWnd,addr stPass,1
inc eax
.if eax==0
invoke CheckDlgButton,hWnd,1005,BST_UNCHECKED
.endif
.else
;取消过关
invoke Modify,hWnd,addr stPass,0
.endif
.elseif ax==1006 ;不生成新的球
invoke IsDlgButtonChecked,hWnd,1006
.if eax == BST_CHECKED
;不生成新的球
invoke Modify,hWnd,addr stNoBall,1
inc eax
.if eax==0
invoke CheckDlgButton,hWnd,1006,BST_UNCHECKED
.endif
.else
;生成新的球
invoke Modify,hWnd,addr stNoBall,0
.endif
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
start:
invoke InitCommonControls
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,101,NULL,offset _ProcDlgMain,NULL
invoke ExitProcess,NULL
end start
--------------------------------------------------------------------------------
【经验总结】
写游戏修改器基本上都是搜索出地址,进行分析。仅限于单机版,我决定不玩网络游戏,所以也不想研究了,也不知道网游
是不是这样(应该有极少数是这样的吧)。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
------------------------------------------------------------------
文章写于2007-08-29