VB6之扫雷克星

很久之前,那时候我还不太会玩(现在也不厉害)扫雷这个游戏,同学总在我面前炫耀自己的技术有多叼。“高级,99颗雷,只需三分钟。。。”,如此这般。也许确实需要天赋,我总要排查个半天才敢点下左键,然后就BOOM!

偶然一天,在网上浏览网页看到了一篇关于“扫雷外挂”的文章,记得那个人是用汇编写的,没记错的话应该是MASM32。文章大概意思是雷的布局是有标志的,雷区内目标值为0x8F的就是雷。要想找到所有雷的坐标,前提是先找到雷区的边界,即起始点、宽度和长度。如果不会反汇编(最起码能看懂二进制码),恐怕很难搞清楚。幸运的是那个高手就是这样的:他提供了雷区的基址。我这样的菜手只好拾人牙慧,拿来改改,用VB6实现了个“扫雷克星”。

注意:雷区的分布应该是在你点击第一下之后才确立的,所以玩的时候先打开扫雷随便点一个,再使用“扫雷克星”。

原理很简单,就不在赘述了,直接上代码:

‘_killboom.bas
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal nWidth As Long, _
    ByVal nHeight As Long, _
    ByVal hSrcDC As Long, _
    ByVal xSrc As Long, _
    ByVal ySrc As Long, _
    ByVal dwRop As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, _
    lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal dwProcessId As Long) As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, _
    lpBaseAddress As Any, _
    lpBuffer As Any, _
    ByVal nSize As Long, _
    lpNumberOfBytesWritten As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, _
    ByVal hdc As Long) As Long
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long
Private Const PROCESS_ALL_ACCESS = &H1F0FFF
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Const WM_RBUTTONDOWN = &H204
Private Const WM_RBUTTONUP = &H205
‘这些既是雷区的基址
Private Const total_addr = &H10056A4
Private Const height_addr = &H10056A8
Private Const width_addr = &H10056AC
Private Const area_addr = &H1005361

Public Function KillBoom() As Boolean
    ‘这个就是驱雷的函数了,废话 o.O!!
    Dim hwnd As Long

    hwnd = FindWindow("扫雷", vbNullString)
    If hwnd = 0 Then
        KillBoom = False
        Exit Function
    End If

    Dim hdc As Long
    Dim pid As Long
    Dim hp As Long

    hdc = GetWindowDC(hwnd)
    Call GetWindowThreadProcessId(hwnd, pid)
    hp = OpenProcess(PROCESS_ALL_ACCESS, 0&, pid)

    Dim total As Long
    Dim height As Long
    Dim width As Long

    Call ReadProcessMemory(hp, ByVal total_addr, ByVal VarPtr(total), 4&, 0&)
    Call ReadProcessMemory(hp, ByVal height_addr, ByVal VarPtr(height), 4&, 0&)
    Call ReadProcessMemory(hp, ByVal width_addr, ByVal VarPtr(width), 4&, 0&)

    Dim size As Long
    Dim mem() As Byte

    size = 32 * height + 16
    ReDim mem(size) As Byte
    Call ReadProcessMemory(hp, ByVal area_addr, ByVal VarPtr(mem(0)), size, 0&)

    Dim i As Long
    Dim x As Long
    Dim y As Long

    For i = 0 To size - 1
    ‘至于为什么这么算,我也忘了,因为写这个代码时候太久远了
    ‘应该是一点点测算出来的
    ‘比如,16是距离窗体左侧的距离
    ‘97是距离窗体上方的距离
        x = i Mod 32
        y = i \ 32

        x = 16 + x * 16
        y = 97 + y * 16 - 32
        If mem(i) = &H8F Then
            ‘如是雷,就插小红旗
            Call PostMessage(hwnd, WM_RBUTTONDOWN, 0&, MakeParam(x, y))
            Call PostMessage(hwnd, WM_RBUTTONUP, 0&, MakeParam(x, y))
        Else
            ‘不是雷,就点开它吧
            Call PostMessage(hwnd, WM_LBUTTONDOWN, 0&, MakeParam(x, y))
            Call PostMessage(hwnd, WM_LBUTTONUP, 0&, MakeParam(x, y))
        End If
    Next

    Erase mem
    Call CloseHandle(hp)
    Call ReleaseDC(hwnd, hdc)
    Call SetForegroundWindow(hwnd)
    KillBoom = True
End Function

Private Function MakeParam(ByVal LoWord As Long, ByVal HiWord As Long) As Long
  MakeParam = (HiWord * &H10000) Or (LoWord And &HFFFF&)
End Function

为了更优雅些,再加上热键。这样玩的时候,输入快捷键(Alt+Shift+K)就秒杀,哈哈(略邪恶):

‘_hotkey.bas
‘这个模块就是在网上找到,链接如下
‘@http://www.cnblogs.com/rosesmall/archive/2012/09/19/2693707.html
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, _
    ByVal nIndex As Long, _
    ByVal dwNewLong As Long) As Long
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, _
    ByVal nIndex As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
    ByVal hwnd As Long, _
    ByVal Msg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long
Public Declare Function RegisterHotKey Lib "user32" (ByVal hwnd As Long, _
    ByVal id As Long, _
    ByVal fskey_Modifiers As Long, _
    ByVal vk As Long) As Long
Public Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As Long, ByVal id As Long) As Long

Public Const WM_HOTKEY = &H312
Public Const MOD_ALT = &H1
Public Const MOD_CONTROL = &H2
Public Const MOD_SHIFT = &H4
Public Const GWL_WNDPROC = (-4)
Private Type taLong
   ll As Long
End Type
Private Type t2Int
   lWord As Integer
   hword As Integer
End Type

Public preWinProc As Long
Public Modifiers As Long, uVirtKey As Long, idHotKey As Long

Public Function CallbackWndproc(ByVal hwnd As Long, _
    ByVal Msg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long) As Long
    If Msg = WM_HOTKEY Then
       If wParam = idHotKey Then
         Dim lp As taLong, i2 As t2Int
         lp.ll = lParam
         LSet i2 = lp
         If (i2.lWord = Modifiers) And i2.hword = uVirtKey Then
            Call KillBoom
         End If
       End If
    End If
    CallbackWndproc = CallWindowProc(preWinProc, hwnd, Msg, wParam, lParam)
End Function

最后是窗体部分,注册热键然后隐藏自己:

Private Sub Form_Load()
‘this code refered from following link
‘@http://www.cnblogs.com/rosesmall/archive/2012/09/19/2693707.html
    preWinProc = GetWindowLong(Me.hwnd, GWL_WNDPROC)
    Call SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf CallbackWndproc)
    idHotKey = 1 ‘in the range &h0000 through &hBFFF
    Modifiers = MOD_ALT + MOD_SHIFT
    uVirtKey = vbKeyK
    Call RegisterHotKey(Me.hwnd, idHotKey, Modifiers, uVirtKey)
    Call Me.Hide
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Call SetWindowLong(Me.hwnd, GWL_WNDPROC, preWinProc)
    Call UnregisterHotKey(Me.hwnd, uVirtKey)
End Sub

搞定收工!另外,那个汇编大神请原谅我,因为实在记不清你文章的网址了,这里就没法贴出来了。

贴张图炫耀下:

终于能打败我同学了,可惜我已经毕业了。。。

PS:差点忘了,最好还是另外注册个热键(如Alt+Shift+Q)关闭自己,否则窗体隐藏了你也许会忘掉它的存在。我因为是在调试模式下,所以不需要 Orz

VB6之扫雷克星

时间: 2024-08-28 16:04:55

VB6之扫雷克星的相关文章

bzoj1088[SCOI2005]扫雷

bzoj1088[SCOI2005]扫雷 题意: 有一个n×2的棋盘,第一列里面某些格子是雷,而第二列没有雷.由于第一列的雷可能有多种方案满足第二列的信息的限制,求根据第二列的信息第一列雷有多少种摆放方案. 题解: 水题,因为每个第一行的格子可以根据前一个第二行的格子里的信息唯一确定是否有雷,所以只要枚举第一个格子有没有雷就行. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #

洛谷P2670 扫雷游戏

题目描述 扫雷游戏是一款十分经典的单机小游戏.在n行m列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格).玩家翻开一个非地雷格时,该格将会出现一个数字--提示周围格子中有多少个是地雷格.游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格. 现在给出n行m列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数. 注:一个格子的周围格子包括其上.下.左.右.左上.右上.左下.右下八个方向上与之直接相邻的格子. 输入输出格式 输入格式: 输入文件第一行是用一个

Vijos 1193 扫雷 【动态规划】

扫雷 描述 相信大家都玩过扫雷的游戏.那是在一个n*n的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了,"余"任过流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里面的数字表示和他8连通的格子里面雷的数目.现在棋盘是n*2的,第一列里某些格子是雷,而第二列没有雷,如:o 1* 2* 3* 2o 2* 2* 2 ('*'代表有雷,'o'代表无雷)由于第一类的雷有可能有多种方案满足第二列的数的限制,你的任务即根据第二列的信息求第一列雷有多少中摆放方案.

扫雷C++实现

1 #include <iostream> 2 #include<fstream> 3 #include <ctime> 4 #include <cmath> 5 #include <stdlib.h> 6 #include<stdio.h> //时间 //文件 7 #include <string> 8 #define random(x)(rand()%x) 9 using namespace std; 10 void

vb6转vb.net

一直在用vb6写软件,但最近系统要做web版,但之前的业务规则全在代码中写死了,没用使用存贮过程,如果在web端重写规则,则工作量太大,项目时间也不允许,只好把业务规则转到vb.net中.现在的vb.net版本已不支持从vb6转入,不过可以直接把业务规则复制到新的vb.net中,差异很小,基本改改就行.转换过程中以下几点要特别注意: 1.vb6中过程调用可以不用括号包围参数,如 add a,b这样是合法的,但vb.net中不支持这种写法,必须是add(a,b)这样变动. 2.vb6中支持感叹号(

VB一键扫雷

XP游戏,扫描内存,然后模拟鼠标点击 Private Sub Command1_Click() Dim lhwnd As Long Dim lpid As Long Dim lRet As Long Dim lhProcess As Long Dim bData(1024) As Byte Dim bXY(8) As Byte Dim x As Long Dim y As Long Dim temp As Long Dim k As Long '其中8F就表示雷,0F表示非雷,当非雷区被点击后如

BZOJ1088 [SCOI2005]扫雷Mine

Description 相信大家都玩过扫雷的游戏.那是在一个n*m的矩阵里面有一些雷,要你根据一些信息找出雷来.万圣节到了 ,“余”人国流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里面的数字 表示和它8连通的格子里面雷的数目.现在棋盘是n×2的,第一列里面某些格子是雷,而第二列没有雷,如下图: 由于第一列的雷可能有多种方案满足第二列的数的限制,你的任务即根据第二列的信息确定第一列雷有多少种摆放 方案. Input 第一行为N,第二行有N个数,依次为第二列的格子中

VB6 GDI+ 入门教程——图片

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://vistaswx.blogbus.com/logs/41225905.html VB自己的绘图语句都需要用LoadPicture载入图片,同样,GDI+中也需要. 1.载入(初始化)图片资源 (1)来自文件:GdipLoadImageFromFile 我们先来看看这个最简单基本的载入图片来自文件: [vb] view plain copy print? Dim img As Long, img_W As Long, i

Delphi - XP扫雷外挂制作

技术交流,DH讲解. 本来之前就在写这个文章,还写了War3挂的教程,后来因为一些事就没有弄了.现在过年在家又没有事就继续把这个写完吧.哈哈.不要以为写个挂很容易,要想写个挂肯定要了解游戏呀.我们现在来了解下地雷是怎么产生的?其实只是我自己猜想的,毕竟这个游戏不是我写的...1 用户选择了多大的棋盘,多少地雷后棋盘应该是用一个二维数组来存储的,地雷数肯定是用一个全局变量来存储的.这点儿有异议没有?没有我就继续往下说了...2 生成地雷,肯定是随机的,那么一定会调用Rand函数咯.a.首先判断地雷