?? windows掃雷游戲 .txt
字號:
Windows掃雷游戲
相關的例子:下載>>> 作者:Zoologist 于2008-7-19上傳
--------------------------------------------------------------------------------
Windows自帶了一個掃雷游戲,很好玩。網上也有很多介紹作弊的方法,之前的Win98中,紀錄保存在
INI文件中,XP的保存在注冊表中。但是,這些方法對于我們程序員來說“太沒有技術含量”了,我們要通過
編程序來“作弊”。網上也有很多“掃雷機”,今天我們就從頭開始打造一個自己的掃雷機。
Windows XP 的掃雷程序在 windows\system32\ 目錄下,名字為 Winmine.exe。運行界面如下:
我們現(xiàn)用Spy++看看上面都有什么“元件”。可以看出來,界面上是一整塊的,就是說我們看到的類似于
按鈕的東西實際上是繪制出來的,并不是 Button 排列出來的。如果是我編寫的話,沒準會用很多按鈕之類的。
不過,Windows中的確確實實是畫出來的窗口,畫出來的按鈕。網上的資料說可以從隨機數(shù)生成入手,我們
也從這個門。拿出OllyDBG.EXE,加載Winmine.exe,滾動到最上面,有一張“導出表”。它的用途就是調用
系統(tǒng)API。告訴程序,我要調用 XXX 的 API,這個API在系統(tǒng)的什么地方。
上圖中,光標停在 srand ,它是VC中指定隨機種子的函數(shù),下面rand是使用這個種子生成隨機數(shù)的
函數(shù)。我們使用右鍵彈出的菜單 Find references to 中的 Selected address 功能查找看看誰在使用srand
函數(shù)。
我們先看看srand函數(shù),找到如下的程序段:
這段話的意思就是,用GetTickCount函數(shù)取一下當前系統(tǒng)的tick數(shù),將這個作為種子,交給srand。
再看看 rand 函數(shù),這個函數(shù)要求輸入給定生成隨機數(shù)的范圍:
再查找誰在調用這個位置,結果如下:
更具體的描述可以參考附件中的文章。
應該有更簡單的方法吧?可以想象一下,如果程序員編寫這個游戲的時候,有很多參數(shù),最最
簡單的方法是使用 int x,y; 這樣定義游戲中的參數(shù)... ...只要我們試驗足夠多,還是很容易知道
這些參數(shù)的位置的。在程序的開頭,有一片看起來“貌似”數(shù)據(jù)的控件,我們觀察這個位置就好了。
觀察數(shù)據(jù)的具體分布是需要耐心經驗和運氣的,附件中的文章對于如何修改驗證也描述的很詳細,
在這里我就不再重復了。下面就是編寫讀取“地雷分布”。讀取內存要用到如下的API:
ReadProcessMemory Function
Reads data from an area of memory in a specified process. The entire area to be read must be accessible or the operation fails.
讀取給定進程的特定內存偏移。讀取的區(qū)域必須是可以訪問的,否則會失敗。
BOOL WINAPI ReadProcessMemory(
__in HANDLE hProcess,
__in LPCVOID lpBaseAddress,
__out LPVOID lpBuffer,
__in SIZE_T nSize,
__out SIZE_T* lpNumberOfBytesRead
);
Parameters
hProcess
A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process.
要讀取內存進程的handle。必須已經使用 PROCESS_VM_READ 打開。
lpBaseAddress
A pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible the function fails.
指向要讀取內存的地址。
lpBuffer
A pointer to a buffer that receives the contents from the address space of the specified process.
取得內存內容之后的拷貝到緩沖區(qū)
nSize
The number of bytes to be read from the specified process.
要讀取的字節(jié)數(shù)。
lpNumberOfBytesRead
A pointer to a variable that receives the number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.
指向已經讀取到給定緩沖區(qū)的字節(jié)數(shù),如果 lpNumberOfBytesRead 為 NULL,將會忽略這個參數(shù)。
Return Value
If the function succeeds, the return value is nonzero.
成功返回非零值。
If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError.
讀取失敗,返回0。
我們已經知道程序使用關鍵數(shù)據(jù)的結構如下:
ds:[1005334] x方向上的格子數(shù)
ds:[1005338] y方向上的格子數(shù)
ds:[1005330] 地雷總數(shù)
byte flag[32 *24 ] 雷區(qū),實際上最大是 32(X方向) 24 (Y方向)
程序清單如下:
;MASMPlus 代碼模板 - 控制臺程序
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
include gdi32.inc
includelib gdi32.lib
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
MAXMINER equ 768 ;30*24
.data
lpMsg db "Hello World!",0
hSweep dd 0
dcSweep dd 0
pID dd 0
pHandle dd 0
szCr db 0Dh,0Ah,0
mNum dd 0
mineBuf db MAXMINER dup(0)
.data?
szBuffer db MAX_PATH dup(?)
pAddr dd ?
xValue dd ?
yValue dd ?
x dd ?
y dd ?
.CODE
START:
invoke FindWindow,NULL, CTXT('掃雷') ;查找掃雷游戲
mov hSweep,eax
.if hSweep ==0
invoke wsprintf,addr szBuffer,CTXT("請啟動‘掃雷游戲’")
invoke lstrcat,addr szBuffer,addr szCr
invoke StdOut,offset szBuffer
jmp exitprog
.endif
invoke GetWindowThreadProcessId,hSweep, addr pID
invoke OpenProcess,PROCESS_VM_READ,FALSE, pID
mov pHandle,eax
mov pAddr,10056ACh
invoke ReadProcessMemory, pHandle, pAddr, offset xValue, 4,NULL
mov pAddr,10056A8h
invoke ReadProcessMemory, pHandle, pAddr, offset yValue, 4, NULL
mov pAddr,1005330h ;開局時的地雷總數(shù)
invoke ReadProcessMemory, pHandle, pAddr, offset mNum, 4, NULL
mov pAddr,1005361h ;地雷分布
invoke ReadProcessMemory, pHandle, pAddr,offset mineBuf, MAXMINER, NULL
invoke wsprintf,addr szBuffer,CTXT("橫向:%d 縱向:%d 地雷總數(shù) %d"),xValue,yValue,mNum
invoke StdOut,offset szBuffer
invoke StdOut,addr szCr
mov esi,offset mineBuf
xor eax,eax
mov y,eax
nextY:
xor eax,eax
mov x,eax
nextX:
mov al,[esi]
inc esi
cmp al,8Fh
jNz @f
invoke wsprintf,addr szBuffer,CTXT("1 ")
jmp gonext
@@:
invoke wsprintf,addr szBuffer,CTXT("0 ")
gonext:
invoke StdOut,offset szBuffer
inc x
mov eax,x
.if eax<xValue
jmp nextX
.endif
invoke StdOut,addr szCr
mov eax,32
sub eax,xValue
add esi,eax
inc y
mov eax,y
.if eax<yValue
jmp nextY
.endif
exitprog:
invoke wsprintf,addr szBuffer,CTXT(".....程序結束,回車鍵退出")
invoke StdOut,offset szBuffer
;暫停顯示,回車鍵關閉
invoke StdIn,addr szBuffer,sizeof szBuffer
invoke ExitProcess,0
end START
程序運行結果
我們可以看出,程序給出了地雷的分布。在后面,我們還會繼續(xù)介紹對掃雷程序的修改。
--------------------------------------------------------------------------------
歡迎訪問AoGo匯編小站:http://www.aogosoft.com 下一篇>>>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -