2017-09

浅谈外挂常识和如何防御 - https://www.cnblogs.com/xingzheai/p/16076865.html

图色脚本

图色可以做到的

一,凡文字信息都可以用二值化来达到100%准确获取,比如金币,疲劳度,等级,地区,等等。

二,怪物定位:要么自动锁定怪物,要么有tab键选怪,要么小地图有怪物图标供识别,要么游戏有召唤师职业不需要定位怪也能让召唤物打怪。

三,人物定位:要么有自动寻路,要么小地图有坐标,要么有能力识别小地图来反推人物坐标。

四,拾物定位:能定位怪物坐标就能定位掉宝坐标,因为怪物死亡的坐标(也就是怪物最后一次出现的坐标)就是掉宝坐标,关掉环境音,拾取的时候不断检测声音,无入包的声音就捡取完毕。

五,寻路:要么有自动寻路,要么有能力绘制地图加a*寻路,要求寻路过程中能不断获取到两个值,人物坐标,人物朝向,然后不断调整人物朝向往目的地前进就行(只知道人物初始朝向,然后不断维护这个值也可以,这样可以不用检测人物朝向,只需要算)。

这里要注意的一点是任何东西都可以不稳定,寻路算法不能不稳定,而稳定的寻路算法依赖于精确的人物定位,所以有人物坐标显示的游戏是最好

https://zhuanlan.zhihu.com/p/94302055 https://www.zhihu.com/search?q=%E5%9B%BE%E8%89%B2%E8%87%AA%E5%8A%A8%E5%8C%96&utm_content=search_suggestion&type=content

上牛刀

OpenCV

OpenCV 模版匹配: 简单方便, 缺点: 不具有旋转不变性、不具有尺度不变性; 特征匹配: 缩放/遮挡/旋转/透视形变, 均可处理!!

OCR

嫌字库麻烦可以上一些开源的OCR库, 例如: Paddle OCR

Lobe

https://www.lobe.ai/examples https://github.com/lobe

Lobe 是微软在 2018年收购的一家公司的产品,当然现在已经我们可以当作完全是微软的产品了,这是一款让非专业人士也能通过机器学习的方法来构建 AI 模型的应用。 智障级别的难度

Halcon

Halcon 工业级图像处理神器, 跟AI识别有关

键鼠模拟

windows 消息机制

Windows发出的一个通知,告诉应用程序某个事件发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。

Windows的消息系统是由3个部分组成的:

  1. 消息队列。Windows能够为所有的应用程序维护一个消息队列。应用程序必须从消息队列中获取 消息,然后分派给某个窗口。

  2. 消息循环。通过这个循环机制应用程序从消息队列中检索消息,再把它分派给适当的窗口,然 后继续从消息队列中检索下一条消息,再分派给适当的窗口,依次进行。

  3. 窗口过程。每个窗口都有一个窗口过程来接收传递给窗口的消息,它的任务就是获取消息然后 响应它。窗口过程是一个回调函数;处理了一个消息后,它通常要返回一个值给Windows。 注意: 回调函数是程序中的一种函数,它是由Windows或外部模块调用的。

Windows消息控制中心一般是三层结, 其顶Application对象。 第三级控制中心就是Windows窗体对象,每一个窗体都有一个端就是Windows内核。Windows内核维护着一个消息队列 第二级控制中心从这个消息队列中获取属于自己管辖的消息,后做出处理,有些消息直接处理掉,有些还要发送给下一级窗体(Window)或控件(Control)。第二级控制中心一般是各Windows应用程序的默认的窗体过程,这个过程负责处理各种接收到的消息。

一个消息从产生到被一个窗口响应,其中有5个步骤:

  1. 系统中发生了某个事件。
  2. Windows把这个事件翻译为消息,然后把它放到消息队列中。
  3. 应用程序从消息队列中接收到这个消息,把它存放在TMsg记录中。
  4. 应用程序把消息传递给一个适当的窗口的窗口过程。
  5. 窗口过程响应这个消息并进行处理。

步骤3和4构成了应用程序的消息循环。消息循环往往是Windows应用程序的核心,因为消息循环使一个应用程序能够响应外部的事件。消息循环的任务就是从消息队列中检索消息,然后把消息传递给适当的窗口。如果消息队列中没有消息,Windows就允许其他应用程序处理它们的消息。

[参考下: (windows 的各种钩子/消息钩子(Message Hook)) ]

OP 插件

https://github.com/WallBreaker2/op OP(operator & open)是一个开源插件(类似大漠插件).主要功能有:Windows消息模拟,后台截图,找图,字符识别(OCR)等。使用c++编写,源代码可编译为32/64位dll.op插件提供了两类接口:1)原生c++接口,可以让c/c++开发者方便调用;2)com接口,支持大多数编译型语言(c++,c#,vb,delphi等 以及脚本语言(python,lua等)的调用

源码编译

blackbone(静态编译,链接方式MT) 编译完成后,设置环境变量 BLACKBONE_ROOT 为源码根目录(例如D:\workspace\Blackbone) kiero(已在源码内,无需安装) minhook(已在源码内,无需安装) QT5.12(可选) 安装完成后设置环境变量QT_ROOT为Qt安装目录下的版本目录,例如D:\workspace\QT\5.12.12 Python32/64(可选) 安装完成后设置环境变量 PYTHON32_ROOT 为32位python安装目录,PYTHON64_ROOT 为64位python安装目录

  1. op 项目 git clone https://github.com/WallBreaker2/op.git

  2. 编译 Blackbone

git clone https://github.com/DarthTon/Blackbone.git

cd E:\projects-cpp\Blackbone\src
cmake . // 生成 vs 项目


set BLACKBONE_ROOT=E:\projects-cpp\Blackbone
set PYTHON64_ROOT=C:\Users\yang\AppData\Local\Programs\Python\Python39
cmake .

不注入DLL 游戏窗口 后台键盘模拟?

键盘模拟无外乎keybd_eventSendInput 很多游戏都用 DirectX ,利用 DirectInput 绕过Windows的消息机制直接和硬件打交道来接收按键信息的。这时候要在模拟键鼠消息就 只有注入游戏进程拦截 DirectInput 过滤API。

驱动模拟

64位版本的 Windows只加载设备驱动程序,这些驱动程序由一个公共CA签发的代码签名证书签署,如Verisign、Thawte等。WinIo64 除非获得了代码签名证书,否则系统不能部署在生产机器上。 驱动模拟只能全局且前台模拟… 博客园 书侍 - 模拟键盘按键

WinIo

WinIO程序库允许在32位的Windows应用程序中直接对I/O端口和物理内存进行存取操作。通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Windows系统的保护机制。

它这个驱动没有签名需要自己搞 利用winIO3.0进行windows10 64bit端口读取

Interception

它的驱动有数字签名, 甚至可以拦截 (CTRL+ALT+DELETE) Support is still Windows only (from Windows XP to Windows 10).嗯.. 支持到win10 但也是只能前台模拟..

官网 github - Interception

按键模拟

void passKey(){
    InterceptionContext context = interception_create_context();
    InterceptionKeyStroke keyStroke[2];
    keyStroke[0].code = MapVirtualKey('A', MAPVK_VK_TO_VSC);//a 键码; win32的 api
    keyStroke[0].state = INTERCEPTION_KEY_DOWN;//按下
    keyStroke[1].code = keyStroke[0].code;
    keyStroke[1].state = INTERCEPTION_KEY_UP;//弹起
    //发送
    interception_send(context, INTERCEPTION_KEYBOARD(0), (InterceptionStroke*)keyStroke, _countof(keyStroke));
 
    interception_destroy_context(context);
}

鼠标模拟

//鼠标移动到屏幕中间 右键
void muni(){
    //初始化上下文
    InterceptionContext context = interception_create_context();
 
    // 鼠标移动到屏幕中间
    InterceptionMouseStroke mouseStroke[3];
    mouseStroke[0].flags = INTERCEPTION_MOUSE_MOVE_ABSOLUTE;
    mouseStroke[0].x = 65535 / 2; // 坐标取值范围是0-65535
    mouseStroke[0].y = 65535 / 2;
    // 点击鼠标右键
    mouseStroke[1].state = INTERCEPTION_MOUSE_RIGHT_BUTTON_DOWN;
    mouseStroke[2].state = INTERCEPTION_MOUSE_RIGHT_BUTTON_UP;
    //发送
    interception_send(context, INTERCEPTION_MOUSE(0), (InterceptionStroke*)mouseStroke, _countof(mouseStroke));
    //销毁
    interception_destroy_context(context);
}

参考笔记 N_QT.md Interception N_QT

无解 必须DLL注入

xp下对dinput8.dll 游戏键盘输入的模拟 非函数hook

驱动级的模拟, 都是全局模拟, 不能指定句柄后台; 若想 hook DirectInput 输入, 必须DLL注入拦截dx接口函数;

其实原理很简单,拦截dx接口函数,就是让dx的函数在执行之前或之后,首先执行我们的代码, 比如你要读写屏,肯定要在其之前Hook 比如你要发送键盘鼠标消息,那就要在DInput的获取数据接口执行之后,替换其数据,让其传出我们的数据,就可以达到后台DX键盘或者鼠标了

对DInput的hook,鼠标和键盘以及手柄都是通过这个来获取数据的,hook目标:GetDeviceData,GetDeviceState,一个缓冲模式,一个立即模式,键盘,鼠标,手柄数值统统按照常量,定义在 DX SDK头文件中 参考: https://www.cnblogs.com/rogee/archive/2010/09/16/1828258.html

AutoHotkey

https://www.autohotkey.com/ https://wyagd001.github.io/v2/docs/index.htm

按键重映射

https://wyagd001.github.io/v2/docs/Hotkeys.htm#combo

短按3键 映射为 长按F键300毫秒

#Requires AutoHotkey v2.0
3::
{
    ; 阻止3键的默认功能
    ; 按下F键
    Send "{f Down}"
    ; 保持300毫秒
    Sleep 300
    ; 释放F键
    Send "{f Up}"
}
 

如果3秒之前按过[CTRL键], 则将[空格键]输入 映射为 [CTRL键] + [空格键] 否则保持原来的[空格键]输入

#Requires AutoHotkey v2.0
turnJumpActiveTimestampe := 0
turnJumpActiveTimestampeTimeout := 3000
;(~)前缀用于表示:当热键触发时,不阻止该按键的原始功能
~Ctrl::
{
    global turnJumpActiveTimestampe
    turnJumpActiveTimestampe := A_TickCount
    return
}
;重映射 Space
$Space::
{
    global turnJumpActiveTimestampe,turnJumpActiveTimestampeTimeout
	if A_TickCount - turnJumpActiveTimestampe < turnJumpActiveTimestampeTimeout
    {
        turnJumpActiveTimestampe := A_TickCount
		Send "^{Space}"
    }
    else
    {
        Send "{Space}"
    }
    return
}

$ 脚本使用 Send 函数发送包含了热键自身的按键时才需要使用此符号, 此时可以避免触发它自己.

#HotIf WinActive("new 1 - Notepad++")

寻路算法

1. A*算法

A算法是一种启发式搜索算法,它利用启发函数(heuristic function)来评估节点的估价函数(estimated cost function),从而寻找最短路径。A算法综合考虑了节点的实际代价和到目标节点的预计代价,因此能够快速而准确地寻找最短路径; 不一定最短,A*算法并不一定能够找到最短路径,但它通常可以找到接近最短路径的解决方案

把一张地图分为一个二维数组,每一个格子代表一个路点;

A B C
D E F
G H I

假设最小方格的边长是 10;

10 10 10 
10 10 10
10 10 10

从 E 格子出发,到达 A 格子的距离为 (10^2 + 10^2) 的开方, 这里可以简化为14 (忽略浮点数, 简化算法的计算难度)

评估值 F

每一个路点都有一个评估值F,其中 F = G + H

G 值是起点移动到指定方格(或者说是下一个点)的移动代价 H 是指定的方格移动到终点的估算成本 (注意该值, 不需要考虑障碍,只需考虑起始点和目标点即可)

H值计算方式

H值的计算方式有如下两种:

  1. 计算横向和纵向移动的距离,不能斜着走

  2. 比如该点和目标点 为对角顶点组成的矩行的边长是a 和 b,那么H值是 min(a,b) * 14 + abs(a - b) * 10

算法思路

这个算法需要两个数组,openList 和 closeList openList 里面存放的是当前状态可以到达的路点 closeList 存放不能到达的路点和已经经过判断的路点;具体步骤如下:

  1. 从当前选中路点a出发,总共有8个路点可能到达,假设可到达的节点为b 如果b是障碍点,则直接加入closeList; 如果b在openList中,当且仅当b的G值小于点a的G值(下一点的代价)时,更新a的G值,并且将路点b的父节点设置为当前a; 如果b在closeList中,则跳过该点的判断

  2. 如果目标点进入了 openList,则遍历停止,找到可到达路径; 由于每个节点都保存着到达自己的父节点,所以拿到目标点,一直拿到它的父节点就可以找到到达路径; 如果 openList 为空时还没找都目标路点,则不可到达,算法结束;否则进入下一个步骤;

  3. 遍历 openList 的路点,选出F值最小的那个点,如果有多个最小值,可以选择第一个最小值,也可以选择多个最小值中的最后一个,最后的表现就是到达目标点的最短路径可能有多条; 然后把这个点当做选中路点,进行步骤1;

A星算法的理解以及算法过程的动图演示

2. Dijkstra算法

Dijkstra算法是一种贪心算法,它从起点开始,每次选择当前代价最小的节点作为下一个节点。通过不断更新节点的代价,最终可以找到起点到终点的最短路径。

3. Bellman-Ford算法

Bellman-Ford算法是一种动态规划算法,它通过不断更新节点的代价,直到收敛到最短路径。相比于Dijkstra算法,Bellman-Ford算法能够处理负权边的情况。

4. Floyd-Warshall算法

Floyd-Warshall算法是一种动态规划算法,它能够计算出图中任意两点之间的最短路径。Floyd-Warshall算法通过不断更新节点之间的代价,直到收敛到最短路径。

关于区域内的寻路

一般人会将区域网格化,这样会有至少几万个结点,然后在里面用a*来寻路,这个是很常见的做法。 较科学的做法是可视图寻路,

本来地图里面是只有障碍物和起终点的,现在将所有障碍物的顶点两两用直线连接起来,前提是它们之间没有障碍物阻挡,包括起点和终点也要参与连接,这个新图里面的顶点数是所有障碍物的顶点再加上2(起点和终点),然后在这个图里面寻路

一些零碎的经验之谈 - https://zhuanlan.zhihu.com/p/157927242