您的位置:首页 > 软件问答

连发程序exe(让你的RX470 570 秒变 580。教你打磨显卡二 让你的矿卡跑分20W)

导读连发程序exe文章列表:1、让你的RX470 570 秒变 580。教你打磨显卡二 让你的矿卡跑分20W2、今天 你黑屏了吗?解决全屏切换黑屏问题3、Python Apex Legends 武器自动识别与压枪

连发程序exe文章列表:

连发程序exe(让你的RX470 570 秒变 580。教你打磨显卡二 让你的矿卡跑分20W)

让你的RX470 570 秒变 580。教你打磨显卡二 让你的矿卡跑分20W

本文主要补充之前的发文,以及回答条友的疑问。

还是那张200元的574黑狼

首先直接上干货。刷新教程:

第一步:下载AMDWINFLASH最新2.93版本

地址为:https://www.techpowerup.com/download/ati-atiflash/

第二步:选择适合你的显卡BIOS

地址为:https://www.techpowerup.com/vgabios/

第三步:了解刷新命令

直接再命令提示符下运行amdvbflash回车即可得到所有命令以及解释

常用的命令例子 amdvbflashWin -p -f 0 XXX.rom

其中P为刷新 F为强制 0为显卡1 如果是显卡2则用1 XXX.ROM为BIOS。

另外带WIN的则为WIN下的EXE,不带的为DOS下的。

了解了如何刷新,那么我们来做一下准备工作:

首先了解一下供电,用自己的显卡拍了张图给大家:

双6PIN=225W

单8PIN=225W

8 6PIN=300W

其次了解一下自己的显存以及SP

然后根据情况选择自己的BIOS,并查看是否对应。

需要注意的是,2048SP的580 BIOS目前比较少,而2048的470 570只有刷入2048SP版本呢的BIOS才能变身成功,2304则不行。

来个案例,比如我们想刷入蓝宝石的1411频率的584的BIOS,那么先来看一下参数

可以看到,这个BIOS为蓝宝石的是2304SP的584,现存为自动检测,可以是尔必达也可以是海力士,我们的XFX 574是尔必达,所以可以刷。

那么在再看!不同显存的错误例子:

这个BIOS和上面那个一样,但!显存是三星的,则不能刷。

了解了这些之后,我们来对比下几个BIOS的表现:

首先我们来刷入蓝宝石2048SP 584的BIOS:

直接BAT搞起:

刷新成功。

GPU-Z FURMARK 鲁大师3连发:(AMD从POWERTUNE之后FURMARK已经不满载了,学精了)

总结:完美的BIOS调教,风扇1100RPM也很安静。功耗噪音与性能的综合首选。

然后我们来刷入XFX 574的原版BIOS(之前有备份):

惯例3连发:

总结:性能版BIOS,温度高,转速高,功耗高,原版BIOS的温度墙为90度,原装散热不仅仅直升机而已直接撞墙,即使更换更强大的风扇和7921硅脂也依然无法拯救噪音,吃鸡的时候压力更高,长时间仍然有撞墙的危险。

贴下以前原版BIOS原版散热的吃鸡图:(平均温度82 83就是因为反复撞墙,如果一直FURMARK则永远停留再89)

最后我们俩刷入蓝宝石574 1411版功耗实际增加几乎100W的版本,甚至偶尔极限情况还会因为过流保护直接自动重启的版本:

老套路三连发:

总结:最高性能版BIOS,默认即可跑分18W,甚至偶尔吃鸡的时候会直接超过供电极限而自动重启,(只有过一次,应该是主板75W供电保护,因为我这里PCI-E不仅仅接了显卡)。毕竟吃鸡的压力更大,功耗也更高,FURMARK 的时候230W,吃鸡用这个BIOS经常过300.

本文测试都是基于PCI-E 3.0 8X的结果。

因为本文只是回应群友和条友的教程,不是极限OC测试,所以默认跑个鲁大师就溜了。不冲击20W 了。

文章到这里就结束了。祝群友和条友能找到适合自己的BIOS。

而我。。。。也要去刷回584 2048SP的变身BIOS了。长夜漫漫。。

漫漫。。

漫漫。。

没有了拖拉机。。

依然。。

无心睡眠。

今天 你黑屏了吗?解决全屏切换黑屏问题

很多玩家在登录过久以后 切屏会出现失败的情况

还有的玩家 全屏后 不小心弹回桌面就切不回去了 (如下图)

其实这都是腾讯自己的插件 Cross搞的鬼 由于该插件 随DNF启动 当DNF变化时 这插件跟不上变化 因此DNF黑屏无法切换

下面上教程!

首先找到 地下城与勇士startCrossCoreStable 文件夹 CrossProxy.exe文件

四项禁止以后 确定上游戏即可 随意切换无卡顿 无黑屏

而且不会再出现直播框了

但是wegame换装和连发可能会失灵

建议还是用WEgame 登录 连发就用盒子之类的

换装已经死了 没啥猴戏了 就不用了

来自掌游宝投稿—蓝幻冰峰

Python Apex Legends 武器自动识别与压枪

文章目录

环境准备

操纵键鼠

驱动安装 链接库加载 代码准备和游戏外测试

toolkit.py

游戏内测试

键鼠监听

武器识别

如何简单且高效判断是否在游戏内

如何简单且高效判断背包状态 无武器/1号武器/2号武器

如何简单且高效判断武器子弹类别

如何简单且高效判断武器名称

如何简单且高效判断武器模式 全自动/连发/单发

何时触发识别

压枪思路

组织数据

第一阶段实现 能自动识别出所有武器

cfg.py

toolkit.py

apex.py

第二阶段实现 能自动识别出所有武器并采用对应压枪参数执行压枪

第三阶段实现 放弃抖枪术 转常规后座抵消法

本文为下面参考文章的学习与实践

[原文] FPS游戏自动枪械识别 压枪(以PUBG为例)

环境准备

Python Windows 开发环境搭建

说明

基础环境

从 python 官网下载安装包并安装, 配置环境变量后, 在命令行内可以执行 python 命令

包管理工具

pip: 一个现代的,通用的 Python 包管理工具。提供了对 Python 包的查找、下载、安装、卸载的功能。注:pip 已内置于 Python 3.4 和 2.7 及以上版本,其他版本需另行安装。

虚拟环境

python 基础环境下, 不同的依赖只能存在一个版本, 而不同的项目可能依赖了同一个包的不同版本, 这样的项目就可能无法在同一个 python 基础环境下运行. 基于基础环境创建的虚拟环境是相互隔离的, 第三方依赖包可根据项目要求自行下载, 不同项目运行在不同的虚拟环境几下就可以避免以来冲突等问题

虚拟环境只能基于本地存在的基础环境来创建, 会继承基础环境自带的库, 可以选择是否继承基础环境的已安装的第三方包

我觉得可以借鉴学习 java maven 的依赖管理理念, 告别虚拟环境

虚拟环境管理工具

virtualenv: virtualenv可以为每个项目创建一套隔离的Python环境, 再使用pip进行包管理

venv: python 3.3 起自带的虚拟环境管理工具

pipenv:

virtualenvwrapper:

virtualenvwrapper-win:

virtualenv-burrito:

autoenv:

pyvenv:

pyenv:

CONDA

Conda
Conda
Miniconda
Anaconda

Conda 是一个开源的 环境和包管理系统, 它可以创建并管理完全隔离的不同版本的 python 环境, 也可以创建并管理某 python 版本的完全隔离的虚拟环境, 用了它就不必再安装基础环境了

默认配置下, Conda 可以安装和管理由 Anaconda® 构建、审查和维护的数千个包。版本通常低于最新版

Anaconda: Anaconda是一个打包的集合,里面预装好了 Conda、Python、众多数据科学和机器学习相关的包、科学计算工具等等,所以也称为Python的一种发行版。

Miniconda: Miniconda 是一个免费的 conda 最小安装程序。 它是 Anaconda 的一个小型引导版本,仅包含 Conda、Python、它们所依赖的包以及少量其他有用的包,包括 pip、zlib 和其他一些包。

Anaconda Navigator: Anaconda 的 GUI 管理工具

基础环境搭建

Python 官网
Python Windows 下载

到官网找到 Windows 最新版下载并安装

pip 是 Python 包管理工具,该工具提供了对Python 包的查找、下载、安装、卸载的功能。

什么是 Python Launcher?


python 安装程序会自动在 path 环境变量中添加这两条目录

目录结构说明

vc dll 结构体_python的安装目录结构

python.exe: python 解释器, 运行时会弹出控制台窗口

pythonw.exe: 无窗口的python可执行程序, 代码在后台运行

DLLs: 包含 python 的 *.pyd(Python动态模块)文件与几个Windows的 *.dll(动态链接库)文件
pyd 文件是由 D 语言编写的一种 dll 文件, 可以保护 python 文件的源码不被暴露

Doc: 帮助文档

include: python 的 C 语言接口头文件(.h结尾), 当在 C 程序中集成 python 时, 会用到这个目录下的头文件
C语言中, 后缀为 .h 的文件是头文件, 内含函数声明、宏定义、结构体定义等内容。 后缀为 .c 的文件是源文件, 内含函数实现,变量定义等内容。 为什么要有头文件? C/C 编译的时候先扫描整个文件有没有语法错误, 然后将C语句转化为汇编, 当碰到不认识的变量、类、函数、对象的命名时, 首先查找它有没有声明, 如果没有声明直接报错, 如果有,则根据对应的定义空出一定的存储空间并进行相关的指令转化。

Lib: python 自带的标准库/包/测试套件等

Lib/site-packages: 存放安装的第三方库, pip install 安装的第三方库就放在这里

libs: python 的 C 语言接口库文件

Scripts: 脚本文件, 如 pip.exe 包管理器等

TCL: python 与 TCL 的结合

Tools: 一些工具

Miniconda 环境搭建

Miniconda


红字提示, 不推荐勾选添加环境变量, 因为可能会导致因路径被添加到靠前的位置而造成问题. 如果是首次安装 python 相关环境, 可以选择添加到环境变量选项, 如果已经有在用的其他配置了 PATH 的 Conda 或者 Python 则不建议


确实在用户环境变量 PATH 里加了很多目录, 查看这些目录下都有哪些 exe, 根目录下有 python.exe

使用方式

安装完成后, 从开始菜单中找到并打开 [Anaconda Prompt], 运行 [conda list] 命令, 如果正确安装, 则会出现已安装的包列表

常用命令

Command reference
conda常用命令:安装,更新,创建,激活,关闭,查看,卸载,删除,清理,重命名,换源,问题
Anaconda /Miniconda 常用命令CONDA集合

查看帮助

conda -hconda --helpconda install -hconda install --helpconda env -h12345

查看信息

conda info # 包含 conda, python, pip 等, 还有当前在 conda 命令行中激活的环境1

列出环境

conda env listconda info -e12


新安装的 Conda 只有 base 基础环境, 没有虚拟环境

配置源

windows环境下conda更换为国内清华镜像源

编辑用户目录下的 .condarc 文件即可更换 conda 默认源。

# Windows 用户无法直接创建名为 .condarc 的文件,需要先执行如下命令,生成该文件后再修改。C:Users用户名.condarc# 设置搜索时显示通道地址conda config --set show_channel_urls yes123

修改文件内容

channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/menpo/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/bioconda/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/ - defaultsshow_channel_urls: true12345678910

运行 conda clean -i 清除索引缓存,保证用的是镜像站提供的索引。

运行 conda config --show 确认源信息

虚拟环境

# 创建虚拟环境conda create -hconda create -n testenvconda create -n testenv2 python=3.8conda create -n testenv3 python=3.10.7 # 貌似不能下 Anaconda 库中没有的 python 版本, 表现就是转圈很久conda create -p C:mrathenadevelopworkspacepycharmyolov5-6.2venv# 查看环境包conda list # 查看当前激活环境的包, 默认激活的是 base 基础环境conda list -n testenv # 查看指定虚拟环境的包# 激活虚拟环境conda activate testenvconda activate C:mrathenadevelopworkspacePyCharmyolov5-6.2venv# 反激活conda deactivate # 退出虚拟环境, 重新激活 base 基础环境# 删除虚拟环境conda remove -n testenv --allconda remove -p C:mrathenadevelopworkspacepycharmyolov5-6.2venv --all1234567891011121314151617

如果报错如下, 检查是否有开代理工具, 关闭代理, 重开工具就可以了

CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/win-64/current_repodata.json>1

创建虚拟环境的注意点

创建虚拟环境时, 一定要指定一个不同于 base python 版本的 python 版本

不然的话, 新的虚拟环境基本等同于没有创建, 使用的仍然是 base 环境, 执行 pip install 会污染 base 环境, 真是恶心

创建了一个不同于 base python 版本的虚拟环境后, 在虚拟环境中会实打实包含类似 base 的目录结构, 也包含对应的 pip.exe, 这时候再执行 pip install 就不会影响到 base 环境了

IDE pycharm

pycharm的virtualenv、pipenv、conda详解

下载最新版如 pycharm-professional-2021.2.3.exe

以下选项自选

Create Desktop Shortcut, 64-bit launcher, 创建64位启动器的桌面快捷方式, 非常建议

Update context menu, Add “Open Folder as Project”, 在上下文菜单(文件夹右键)添加"以项目的方式打开该文件夹"选项, 可选

Create Associations, .py, 创建 .py 文件的关联, 默认使用 PyCharm 打开 .py 文件, 非常建议

Download and install JRE x86 by JetBrains, 下载 JRE? 不确定做什么, 不选

Update PATH variable(restart needed), Add “bin” folder to the PATH, 更新 PATH 环境变量, 将启动器目录添加到 PATH, 不选

创建工程时, 建议每个工程都创建新的虚拟环境, 通过 Conda

测试


在 conda 命令行中也能看到 pycharm 中创建的虚拟环境, 但是没有名字

插件

Chinese (Simplified) Language Pack / 中文语言包

寻找文档

Pypi

在官网输入包名, 找到包, 点进去, 里面一般都会有项目说明, GitHub, 文档等内容

conda create -n apex python=3.91

操纵键鼠

由于绝地求生屏蔽了硬件驱动外的其他鼠标输入,因此我们无法直接通过py脚本来控制游戏内鼠标操作。为了实现游戏内的鼠标下移,我使用了罗技鼠标的驱动(ghub),而py通过调用ghub的链接库文件,将指令操作传递给ghub,最终实现使用硬件驱动的鼠标指令输入给游戏,从而绕过游戏的鼠标输入限制。值得一提的是,我们只是通过py代码调用链接库的接口将指令传递给罗技驱动的,跟实际使用的是何种鼠标没有关系,所以即便用户使用的是雷蛇、卓威、双飞燕等鼠标,对下面的代码并无任何影响。

驱动安装 链接库加载 代码准备和游戏外测试

罗技驱动使用 LGS_9.02.65_X64(请自行找资源安装,官网新版罗技驱动没找到对应的链接库文件),链接库文件在项目链接里面可以找到。下面是载入链接库的代码。

罗技驱动分LGS(老)和GHub(新), 必须装指定版本的LGS驱动(如已安装GHub可能需要卸载), 不然要么报未安装, 要么初始化成功但调用无效

LGS_9.02.65_x64_Logitech.exe, 网盘下载
其他地址1
其他地址2

try: gm = CDLL(r'./ghub_device.dll') gmok = gm.device_open() == 1 if not gmok: print('未安装ghub或者lgs驱动!!!') else: print('初始化成功!')except FileNotFoundError: print('缺少文件')123456789

装了该驱动后, 无需重启电脑, 当下就生效了. 遗憾的是, 没有对应的文档, 只能猜测参数了

toolkit.py

import timefrom ctypes import CDLLimport win32api # conda install pywin32try: driver = CDLL(r'mouse.device.lgs.dll') # 在Python的string前面加上‘r’, 是为了告诉编译器这个string是个raw string(原始字符串),不要转义backslash(反斜杠) '' ok = driver.device_open() == 1 if not ok: print('初始化失败, 未安装lgs/ghub驱动')except FileNotFoundError: print('初始化失败, 缺少文件')class Mouse: @staticmethod def move(x, y, absolute=False): if ok: mx, my = x, y if absolute: ox, oy = win32api.GetCursorPos() mx = x - ox my = y - oy driver.moveR(mx, my, True) @staticmethod def down(code): if ok: driver.mouse_down(code) @staticmethod def up(code): if ok: driver.mouse_up(code) @staticmethod def click(code): """ :param code: 1:左键, 2:中键, 3:右键, 4:侧下键, 5:侧上键, 6:DPI键 :return: """ if ok: driver.mouse_down(code) driver.mouse_up(code)class Keyboard: @staticmethod def press(code): if ok: driver.key_down(code) @staticmethod def release(code): if ok: driver.key_up(code) @staticmethod def click(code): """ :param code: 'a'-'z':A键-Z键, '0'-'9':0-9, 其他的没猜出来 :return: """ if ok: driver.key_down(code) driver.key_up(code)12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970

游戏内测试

在游戏里面试过后, 管用, 但是不准, 猜测可能和游戏内鼠标灵敏度/FOV等有关系

from toolkit import Mouseimport pynput # conda install pynputdef onClick(x, y, button, pressed): if not pressed: if pynput.mouse.Button.x2 == button: Mouse.move(100, 100)mouseListener = pynput.mouse.Listener(on_click=onClick)mouseListener.start()mouseListener.join()123456789101112

键鼠监听

前面说到,要实现压枪就要对各种配件、状态做出识别。那么在写识别的函数之前,我们先要解决的是何时识别的问题。如果识别使用多线程多进程的一直持续检测,无疑是一种巨大的开销,因此就需要对键盘、鼠标的状态进行监听。只有按下特定按键时,才触发特定相应的识别请求。

这里我使用的钩子是Pynput,其他可使用的库还有Pyhook3

Pynput 说明

def onClick(x, y, button, pressed): print(f'button {button} {"pressed" if pressed else "released"} at ({x},{y})') if pynput.mouse.Button.left == button: return False # 正常不要返回False, 这样会结束监听并停止监听线程, 在关闭程序前返回False就好了listener = pynput.mouse.Listener(on_click=onClick)listener.start()def onRelease(key): print(f'{key} released') if key == pynput.keyboard.Key.end: return False # 正常不要返回False, 这样会结束监听并停止监听线程, 在关闭程序前返回False就好了listener = pynput.keyboard.Listener(on_release=onRelease)listener.start()1234567891011121314

Listener中绑定on_press和on_release的函数( on_key_press、on_key_release),它们返回False的时候是结束监听,下文鼠标监听的函数同理,所以不要随便返回False

键盘的特殊按键采用keyboard.Key.tab这种写法,普通按键用keyboard.KeyCode.from_char(‘c’)这种写法

这里有一点非常坑,on_press和on_release的参数只能有一个key,这个key就是对应键盘按下的哪颗按键。但这是不足以满足我们的需求的,因为我们应该在钩子函数内部,在按下指定按键时对信号量做出修改,但因为参数的限制,我们无法把信号量传进函数内部,这里我也是想了很久,最后才想到用嵌套函数的写法解决这个问题。

另外,钩子函数本身是阻塞的。也就是说钩子函数在执行的过程中,用户正常的键盘/鼠标操作是无法输入的。所以在钩子函数里面必须写成有限的操作(即O(1)时间复杂度的代码),也就是说像背包内配件及枪械识别,还有下文会讲到的鼠标压枪这类时间开销比较大或者持续时间长的操作,都不适合写在钩子函数里面。这也解释了为什么在检测到Tab(打开背包)、鼠标左键按下时,为什么只是改变信号量,然后把这些任务丢给别的进程去做的原因。

武器识别

如何简单且高效判断是否在游戏内

找几个特征点取色判断, 血条左上角和生存物品框左下角

一般能用于取色的点, 它的颜色RGB都是相同的, 这种点的颜色非常稳定

我原本以为屏幕点取色应该不会超过1ms的耗时, 结果万万没想到, 取个色居然要1-10ms, 效率奇低, 暂无其他优雅方法

如何简单且高效判断背包状态 无武器/1号武器/2号武器

看武器边框上红色圈住的部分颜色, 灰色说明没有武器, 上下不同色, 说明使用2号武器, 上下同色说明使用1号武器

如何简单且高效判断武器子弹类别

可以和上面的放在一起, 同一个点直接判断出背包状态和武器子弹类别

如何简单且高效判断武器名称

在分类后的基础上, 通过 背包状态 确定要检查颜色的位置(1号位/2号位), 通过 武器子弹类别 缩小判断范围, 在每个武器的名字上找一个纯白色的点, 确保这个点只有这把武器是纯白色, 然后逐个对比

如何简单且高效判断武器模式 全自动/连发/单发


需要压枪的只有全自动和半自动两种模式的武器, 单发不需要压枪(后面有可能做自动单发, 到时候在考虑), 喷子和狙不需要压枪

所以需要找一个能区分三种模式的点(不同模式这个点的颜色不同但是稳定), 且这个点不能受和平和三重的特殊标记影响

收起武器, 部分武器可以通过[V]标判断, 放弃

何时触发识别

键盘 1/2/3/E/V 释放, 鼠标 右键 按下, 这个如果不影响开枪就这个了, 影响的话就改成侧下键. 键位和键在游戏内的功能不冲突的

压枪思路

apex 的压枪有两个思路, 因为 apex 不同武器的弹道貌似是固定的, 其他游戏也是??

左右抖动抵消水平后坐力, 下拉抵消垂直后坐力. 这种方法简单, 但是画面会抖动, 效果也不是很好

根据武器配件等测试不同情况下的武器后坐力数据, 然后做反向抵消.
可以通过取巧的方式, 只做无配件状态下的反向抵消, 还省了找配件的麻烦
这种方法太难太麻烦了, 但是做的好的话, 基本一条线, 强的离谱

我先试试 抖枪大法

组织数据

武器数据, 通过子弹类型分组, 组里的每个成员指定序号, 名称, 压枪参数等信息

配置数据, 按分辨率分组, 再按是否在游戏中, 是否有武器, 武器位置, 武器子弹类型, 武器索引等信息分类

信号数据, 程序运行时, 进程线程间通讯

第一阶段实现 能自动识别出所有武器

目前测试下来, 一波识别大概六七十毫秒的样子, 最多也不超过一百毫秒, 主要耗时在取色函数(1-10ms), 性能已经够用了

cfg.py

mode = 'mode'name = 'name'game = 'game'data = 'data'pack = 'pack' # 背包color = 'color'point = 'point'index = 'index'bullet = 'bullet' # 子弹differ = 'differ'positive = 'positive' # 肯定的negative = 'negative' # 否定的# 检测数据detect = { "3440:1440": { game: [ # 判断是否在游戏中 { point: (236, 1344), # 点的坐标, 血条左上角 color: 0x00FFFFFF # 点的颜色, 255, 255, 255 }, { point: (2692, 1372), # 生存物品右下角 color: 0x959595 # 149, 149, 149 } ], pack: { # 背包状态, 有无武器, 选择的武器 point: (2900, 1372), # 两把武器时, 1号武器上面边框分界线的上半部分, y 1 就是1号武器上面边框分界线的下半部分 color: 0x808080, # 无武器时, 灰色, 128, 128, 128 '0x447bb4': 1, # 轻型弹药武器, 子弹类型: 1/2/3/4/5/6/None(无武器) '0x839b54': 2, # 重型弹药武器 '0x3da084': 3, # 能量弹药武器 '0xce5f6e': 4, # 狙击弹药武器 '0xf339b': 5, # 霰弹枪弹药武器 '0x5302ff': 6, # 空投武器 }, mode: { # 武器模式, 全自动/半自动/单发/其他 point: (3148, 1349), '0xf8f8f8': 1, # 全自动 '0xfefefe': 2 # 半自动 }, name: { # 武器名称判断 color: 0x00FFFFFF, '1': { # 1号武器 '1': [ # 轻型弹药武器 (2959, 1386), # 1: RE-45 自动手枪 (2970, 1385), # 2: 转换者冲锋枪 (2972, 1386), # 3: R-301 卡宾枪 (2976, 1386), # 4: R-99 冲锋枪 (2980, 1386), # 5: P2020 手枪 (2980, 1384), # 6: 喷火轻机枪 (2987, 1387), # 7: G7 侦查枪 (3015, 1386), # 8: CAR (轻型弹药) ], '2': [ # 重型弹药武器 (2957, 1385), # 1: 赫姆洛克突击步枪 (2982, 1385), # 2: 猎兽冲锋枪 (2990, 1393), # 3: 平行步枪 (3004, 1386), # 4: 30-30 (3015, 1386), # 5: CAR (重型弹药) ], '3': [ # 能量弹药武器 (2955, 1386), # 1: L-STAR能量机枪 (2970, 1384), # 2: 三重式狙击枪 (2981, 1385), # 3: 电能冲锋枪 (2986, 1384), # 4: 专注轻机枪 (2980, 1384), # 5: 哈沃克步枪 ], '4': [ # 狙击弹药武器 (2969, 1395), # 1: 哨兵狙击步枪 (2999, 1382), # 2: 充能步枪 (2992, 1385), # 3: 辅助手枪 (3016, 1383), # 4: 长弓 ], '5': [ # 霰弹枪弹药武器 (2957, 1384), # 1: 和平捍卫者霰弹枪 (2995, 1382), # 2: 莫桑比克 (3005, 1386), # 3: EVA-8 ], '6': [ # 空投武器 (2958, 1384), # 1: 克雷贝尔狙击枪 (2983, 1384), # 2: 敖犬霰弹枪 (3003, 1383), # 3: 波塞克 (3014, 1383), # 4: 暴走 ] }, '2': { differ: 195 } } }, "2560:1440": { }, "2560:1080": { }, "1920:1080": { }}# 武器数据weapon = { '1': { # 轻型弹药武器 '1': { name: 'RE-45 自动手枪', }, '2': { name: '转换者冲锋枪', }, '3': { name: 'R-301 卡宾枪', }, '4': { name: 'R-99 冲锋枪', }, '5': { name: 'P2020 手枪', }, '6': { name: '喷火轻机枪', }, '7': { name: 'G7 侦查枪', }, '8': { name: 'CAR (轻型弹药)', } }, '2': { # 重型弹药武器 '1': { name: '赫姆洛克突击步枪', }, '2': { name: '猎兽冲锋枪', }, '3': { name: '平行步枪', }, '4': { name: '30-30', }, '5': { name: 'CAR (重型弹药)', } }, '3': { # 能量弹药武器 '1': { name: 'L-STAR能量机枪', }, '2': { name: '三重式狙击枪', }, '3': { name: '电能冲锋枪', }, '4': { name: '专注轻机枪', }, '5': { name: '哈沃克步枪', }, }, '4': { # 狙击弹药武器 '1': { name: '哨兵狙击步枪', }, '2': { name: '充能步枪', }, '3': { name: '辅助手枪', }, '4': { name: '长弓', }, }, '5': { # 霰弹弹药武器 '1': { name: '和平捍卫者霰弹枪', }, '2': { name: '莫桑比克', }, '3': { name: 'EVA-8', }, }, '6': { # 空投武器 '1': { name: '克雷贝尔狙击枪', }, '2': { name: '敖犬霰弹枪', }, '3': { name: '波塞克', }, '4': { name: '暴走', }, }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206

toolkit.py

import mss # pip install mssimport ctypesfrom ctypes import CDLLimport cfgfrom cfg import detect, weapon# 全局 dlluser32 = ctypes.windll.user32gdi32 = ctypes.windll.gdi32hdc = user32.GetDC(None)try: driver = CDLL(r'mouse.device.lgs.dll') # 在Python的string前面加上‘r’, 是为了告诉编译器这个string是个raw string(原始字符串),不要转义backslash(反斜杠) '' ok = driver.device_open() == 1 if not ok: print('初始化失败, 未安装lgs/ghub驱动')except FileNotFoundError: print('初始化失败, 缺少文件')class Mouse: @staticmethod def point(): return user32.GetCursorPos() @staticmethod def move(x, y, absolute=False): if ok: mx, my = x, y if absolute: ox, oy = user32.GetCursorPos() mx = x - ox my = y - oy driver.moveR(mx, my, True) @staticmethod def moveHumanoid(x, y, absolute=False): """ 仿真移动(还没做好) """ if ok: ox, oy = user32.GetCursorPos() # 原鼠标位置 mx, my = x, y # 相对移动距离 if absolute: mx = x - ox my = y - oy tx, ty = ox mx, oy my print(f'({ox},{oy}), ({tx},{ty}), x:{mx},y:{my}') # 以绝对位置方式移动(防止相对位置丢失精度) adx, ady = abs(mx), abs(my) if adx <= ady: # 水平方向移动的距离短 for i in range(1, adx): ix = i if mx > 0 else -i temp = int(ady / adx * abs(ix)) iy = temp if my > 0 else -temp Mouse.move(ox ix, oy iy, absolute=True) # time.sleep(0.001) else: # 垂直方向移动的距离短 for i in range(1, ady): iy = i if my > 0 else -i temp = int(adx / ady * abs(iy)) ix = temp if mx > 0 else -temp Mouse.move(ox ix, oy iy, absolute=True) # time.sleep(0.001) @staticmethod def down(code): if ok: driver.mouse_down(code) @staticmethod def up(code): if ok: driver.mouse_up(code) @staticmethod def click(code): """ :param code: 1:左键, 2:中键, 3:右键, 4:侧下键, 5:侧上键, 6:DPI键 :return: """ if ok: driver.mouse_down(code) driver.mouse_up(code)class Keyboard: @staticmethod def press(code): if ok: driver.key_down(code) @staticmethod def release(code): if ok: driver.key_up(code) @staticmethod def click(code): """ 键盘按键函数中,传入的参数采用的是键盘按键对应的键码 :param code: 'a'-'z':A键-Z键, '0'-'9':0-9, 其他的没猜出来 :return: """ if ok: driver.key_down(code) driver.key_up(code)class Monitor: """ 显示器 """ sct = mss.mss() @staticmethod def grab(region): """ region: tuple, (left, top, width, height) pip install mss """ left, top, width, height = region return Monitor.sct.grab(monitor={'left': left, 'top': top, 'width': width, 'height': height}) @staticmethod def pixel(x, y): """ 效率很低且不稳定, 单点检测都要耗时1-10ms 获取颜色, COLORREF 格式, 0x00FFFFFF 结果是int, 可以通过 print(hex(color)) 查看十六进制值 可以通过 print(color == 0x00FFFFFF) 进行颜色判断 """ # hdc = user32.GetDC(None) return gdi32.GetPixel(hdc, x, y) class Resolution: """ 分辨率 """ @staticmethod def display(): """ 显示分辨率 """ w = user32.GetSystemMetrics(0) h = user32.GetSystemMetrics(1) return w, h @staticmethod def virtual(): """ 多屏幕组合的虚拟显示器分辨率 """ w = user32.GetSystemMetrics(78) h = user32.GetSystemMetrics(79) return w, h @staticmethod def physical(): """ 物理分辨率 """ # hdc = user32.GetDC(None) w = gdi32.GetDeviceCaps(hdc, 118) h = gdi32.GetDeviceCaps(hdc, 117) return w, hclass Game: """ 游戏工具 """ @staticmethod def game(): """ 是否在游戏内 太耗时了, 所以不能调的多了 """ w, h = Monitor.Resolution.display() data = detect.get(f'{w}:{h}').get(cfg.game) for item in data: x, y = item.get(cfg.point) if Monitor.pixel(x, y) != item.get(cfg.color): return False return True @staticmethod def index(): """ 武器索引和子弹类型索引 :return: 武器位索引, 1:1号位, 2:2号位, None:无武器, 拳头(这个暂时无法判断) 子弹类型索引, 1:轻型, 2:重型, 3:能量, 4:狙击, 5:霰弹, 6:空投, None:无武器 """ w, h = Monitor.Resolution.display() data = detect.get(f'{w}:{h}').get(cfg.pack) x, y = data.get(cfg.point) color = Monitor.pixel(x, y) if data.get(cfg.color) == color: return None, None else: bullet = data.get(hex(color)) return (1, bullet) if color == Monitor.pixel(x, y 1) else (2, bullet) @staticmethod def weapon(index, bullet): """ 通过武器位和子弹类型识别武器, 参考:config.detect.name :param index: 武器位, 1:1号位, 2:2号位 :param bullet: 子弹类型, 1:轻型, 2:重型, 3:能量, 4:狙击, 5:霰弹, 6:空投 :return: """ w, h = Monitor.Resolution.display() data = detect.get(f'{w}:{h}').get(cfg.name) color = data.get(cfg.color) if index == 1: lst = data.get(str(index)).get(str(bullet)) for i in range(len(lst)): x, y = lst[i] if color == Monitor.pixel(x, y): return i 1 elif index == 2: differ = data.get(str(index)).get(cfg.differ) lst = data.get(str(1)).get(str(bullet)) for i in range(len(lst)): x, y = lst[i] if color == Monitor.pixel(x differ, y): return i 1 return None @staticmethod def mode(): """ 武器模式 :return: 1:全自动, 2:半自动, None:其他 """ w, h = Monitor.Resolution.display() data = detect.get(f'{w}:{h}').get(cfg.mode) x, y = data.get(cfg.point) color = Monitor.pixel(x, y) return data.get(hex(color)) @staticmethod def detect(): """ 决策是否需要压枪, 向信号量写数据 """ if Game.game() is False: print('not in game') return index, bullet = Game.index() if (index is None) | (bullet is None): print('no weapon') return if Game.mode() is None: print('not in full auto or semi auto mode') return arms = Game.weapon(index, bullet) if arms is None: print('detect weapon failure') return # 检测通过, 需要压枪 print(weapon.get(str(bullet)).get(str(arms)).get(cfg.name)) return weapon.get(str(bullet)).get(str(arms)).get(cfg.name)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277

apex.py

import timeimport pynput # conda install pynputimport toolkitExitFlag = Falsedef down(x, y, button, pressed): global ExitFlag if ExitFlag: print(ExitFlag) return False # 结束监听线程 if pressed: # 按下 if pynput.mouse.Button.right == button: toolkit.Game.detect()mouseListener = pynput.mouse.Listener(on_click=down)mouseListener.start()def release(key): if key == pynput.keyboard.Key.end: print('end') global ExitFlag ExitFlag = True return False if key == pynput.keyboard.KeyCode.from_char('1'): toolkit.Game.detect() elif key == pynput.keyboard.KeyCode.from_char('2'): toolkit.Game.detect() elif key == pynput.keyboard.KeyCode.from_char('3'): toolkit.Game.detect() elif key == pynput.keyboard.KeyCode.from_char('e'): toolkit.Game.detect() elif key == pynput.keyboard.KeyCode.from_char('v'): toolkit.Game.detect()keyboardListener = pynput.keyboard.Listener(on_release=release)keyboardListener.start()keyboardListener.join()123456789101112131415161718192021222324252627282930313233343536373839404142434445

第二阶段实现 能自动识别出所有武器并采用对应压枪参数执行压枪

第三阶段实现 放弃抖枪术 转常规后座抵消法

1

植物大战僵尸β版更新日志

更新日志

β6.20.3 (2021-05-12)

(需要补充)

β6.20.2 (2021-05-08)

(需要补充)

β6.20.1 (2021-05-03)

(需要补充)

β6.20 (2021-05-03)

(需要补充)

β6.15-1 (2020-10-01)

更新内容:染色

β6.15 (2020-10-01)

更新内容:

添加9个隐藏关卡 添加隐藏关卡:卡槽危机添加隐藏关卡:风雪大战(关闭3d加速可以不看雪)添加隐藏关卡:吓与天2添加隐藏关卡:园艺大师添加隐藏关卡:周二围三添加隐藏关卡:求生2添加隐藏关卡:无尽辣火添加隐藏关卡:僵群[烦人的小僵]添加隐藏关卡:卡片保龄球

优化了隐藏关卡进入方式

添加了部分提示弹窗

修复了若干个bug

β6.10-1 (2020-07-08)

更新内容:修复矿工bug

β6.10 (2020-07-06)

更新内容:

添加了7个隐藏关卡

修改宝石迷阵ex豌豆不飞了(避免崩溃)

修改需要wsad的关卡暂停时无法输入wsad而可以输入其他指令

修改求生hardQQ时精英蹦极存在10s后消失

添加指令break来取消窗口标题的持续修改(给一些用脚本的人用的)

为第5页部分关卡添加提醒

优化选卡中蹦极的位置(以后点礼物盒不会再被这玩意挡了)

ex模式进迷你关卡会有提示

现在可以查看冷却中的植物还要多久才完成冷却

打开同文件目录下的 betainstall.ini,将 KO=0 的值改为 1 即可不弹出启动窗口,直接进入游戏

β6.05-1 (2020-05-31)

更新内容:调整巨人之怒平衡性

β6.05 (2020-05-31)

更新内容:

关卡类:

添加隐藏关“森然巨化,WSAD,上帝正在看你打僵尸,魔术时间,宝石迷阵:现世,手操保龄球,吓与天,视觉失调3,手操保龄球 2,真实之雾,巨人之怒”

调整辣个窝瓜不出精英撑杆

修改砸罐关卡不出现幽灵小丑

EXmode僵尸无尽调整

增强盒子僵尸的复仇(消失次数由15»>8)

修改套僵尸中推车路障和精英铁桶无效果

修改黄油爆米花中持枪僵尸无效果

植物/僵尸类:

修改僵尸无视ex三叶草

增强雪人头保龄球(僵尸伤害判定增加,不能被僵尸啃食)

修改魔术豆不出模仿者

植物僵尸卡牌显示

游戏体验改善:

ex模式的存档分隔开,避免存档混乱导致奇奇怪怪的bug

添加一部分视觉上的效果

播放自定义bgm,方法:在关卡游戏中输入song,然后仔细看弹出的注意事项

关卡内输入turn开启阵型保存和读取(具体看输入后的注意事项)

实装难度显示(仅隐藏关卡,不同难度的关卡关卡名字就不一样颜色)

现在僵尸可魅惑 只有开sun才可以勾选了

移除萌新弹窗

优化开头进入β版的选择界面

bug 修复:

修复ex机枪往旁边两路发射的子弹无法击中僵尸的bug

修复ex模式打开宝石迷阵旋风会崩溃的bug

优化某个全屏的问题

修复7-10可能崩溃的bug

修复水池不动的bug

修复ex豌豆和雪人头保龄球可能崩溃的bug

β6.00 (2020-05-03)

更新内容:

关卡类:

添加5个隐藏关卡(禁止失车,不灭之星,视觉失调 2,光标危机,盒子僵尸的复仇)

关卡自定义中添加自定义关卡名的途径:切换特性模式,右键阳光菇显示文本输入框,输入完后左键阳光菇进行确认

关卡自定义特性模式中键阳光菇可以全部清空已经做过的修改

关卡自定义礼物盒不消失

削弱雷厉风行(冰车→铁桶)

修改7-x蹦极为坚果头

修改无尽矿工不聪明

修改选卡界面打开礼物盒时隐藏无用卡片按钮

植物类:

削弱模仿胆小菇(0.75s→0.9s)

削弱寒冰射手(10连发后的连射改成15连发后连射)

优化玉米加农炮的发射

bug 修复:

修复关卡自定义点击菜单到选关界面会崩溃的bug

修复地刺 地刺王 仙人掌击退僵王错位bug

修复黄油/冰冻僵尸后僵尸会鬼畜的bug

修复大炮天会崩溃的bug

其他:

替换鼠标以及图标

添加了大量彩蛋,当然现在无法触发,要到比较特别的时候才会触发

添加hide指令:开启/取消右键显示僵尸血量标签

修复大炮天会崩溃的bug

添加冒险模式跳关的途径:通关冒险模式2次以上时,对主菜单冒险模式进行右键操作,并注意弹出窗口说明的相关事项,就可以进行冒险模式跳关了

现在右击全屏按钮可以控制窗口的大小,并针对全屏不会疯狂闪(需要先alt tab切出) (注意:非800*600情况下,1234567890选卡将不可用或者错位)

修改cheat模式下可以随意放置植物

EX mode:

ex模式打开方式:在帮助或纸条界面右键下方按钮即可开启(或者把exconfig.txt的第一个值改成1),ex植物特性若要开启请自行将植物对应的0改成1,若要关闭将对应的1改成0

ex模式僵尸精英机制:僵尸将有概率生成特殊的僵尸,特殊的僵尸将拥有特殊的能力

添加HardQQ指令,该指令只能在ex mode使用 作用:使几乎所有的僵尸变成精英(除了一些特殊僵尸有特殊判定以外)

β5.85 (2020-04-10)

更新内容:

选卡界面添加选择隐藏卡片的按钮(条件:购买所有紫卡 模仿者)

修复打赢过一些隐藏关莫名其妙获得紫卡,花园物品,智慧树突然变高等的bug

优化选卡界面的礼物盒按钮(并添加右键清空选卡)

优化选关界面(你可以在正常的选关界面玩到松鼠了),并添加隐藏关卡选择界面,方法:鼠标右键长按“第3页”这个按钮

现在,右键按住僵尸可以看僵尸血量(当然在7-5就不要这样子做了)

点击奖杯可以考虑是否开启7-x(无论金银)

添加5个隐藏关卡

修复了随机砸罐最后抽到礼盒无法过关的bug

火炬树被啃食会被扣血,但是会解除僵尸的冰冻状态(反弹树同理,不过反弹树被啃食扣血会更多)

增加新植物,双生樱桃,在额外卡槽选择后可以使用(迷你樱桃禁止被携带因此价格昂贵,且冷却巨高)

添加了一些有趣的东西

修改开头萌新弹窗出现方式

一些植物的调整(冰豆不能冻结僵王,红色和紫色火球溅射伤害调成原来的)

从该版本开始,存档的机制会发生变化(仅影响游戏存档,不影响用户存档)做此更改是避免β版的存档会影响到原版

从此版本开始,游戏将可以多开

大键盘 1234567890 变成卡槽选择,1左边的点换成铲子(必须英文输入法)

自定义关卡添加存档读档功能,在关卡自定义这关对右下角的图鉴/商店按钮进行右键操作来存档和读档,文件和exe在同一目录,名字为 beta.pvzdiy

注意事项:

选择非隐藏卡的植物后按钮会消失,且选择的隐藏卡片在当前选卡界面不能收回(这是特性)

因为火炬树桩的火焰极其不稳定,因此,僵尸吃火炬死亡被冰冻乃特性

β版存档位于 C:ProgramDataPopCap GamesPlantsVsZombiesbetasavesavex_x

β5.80 (2020-03-20)

更新内容:

三叶草现在可以驱逐僵尸豌豆

现在僵尸豌豆如果用豌豆击杀坚果会直接引爆坚果(包括两个隐藏坚果,不包括高坚果)

双发机枪改成10%概率紫火豌豆(80伤害),10%概率火豌豆(40伤害)

寒冰射手连射时往上下两行发射冻结(1.5s)冰豆(改成每隔10发子弹连射3次,但只往上下发射1次)

修改普通火焰子弹(伤害40)穿过火炬树桩变成红色火焰子弹(伤害60)

现在,当豌豆僵尸(包括机枪),被减速时,攻击间隔增加(150→300)

1437攻击间隔200→180

添加隐藏植物,冰冻巧克力,输入冰激凌的同僚食物进入

削弱豌豆僵尸的子弹速度(3→2)

优化自动收集(不捡卡片等)

重做坚果保龄球,并且添加一旗(保龄球2也是)

削弱拉霸

开局出怪密度从2恢复为4个

图鉴会变得更有趣

加了点彩蛋

自定义关卡特性更新(事先选玉米加农炮切换选择模式):土豆雷:左键:僵尸无视植物,中键:The World,右键:大蒜天模式寒冰射手:左键:黄油爆米花,中键:击弹模式,右键:LS模式(谁笑到最后)大嘴花:左键:波数 1,中键:波数改成100,右键:波数-1双发射手:左键:僵尸速度 1倍,中键:还原僵尸速度 ,右键:僵尸速度-1倍小喷菇:左键:出怪密度 1倍,中键:还原出怪密度 ,右键:出怪密度-1倍

隐藏关卡:冻次打次提示:僵尸快跑的僵尸很“ ** ”(6个字母),在这关输入指令进入隐藏关冻次打次

隐藏关卡:快乐的小**,提示:植物僵尸2,名字(与PVZ一棵植物有关)

隐藏关卡:瓜分天下,在跳跳舞会输入。提示:倭瓜很*(英文5个字母)

隐藏关卡:辣个窝瓜,在植物僵尸输入会使人产生痛觉的植物的英文进入

修复 bug

β5.75 (2020-03-08)

更新内容:

添加雪人的头(保龄球),同坚果保龄球

修复保龄球场景bug: 可在六路地图中正常运转,种在屋顶有奇效 指令提示:某个僵尸的英文(条件:关卡游玩中卡槽内存在无用紫卡)

添加唱片机介绍:美妙的音乐可以吸引周围的僵尸,并让一些僵尸脱下自己的防具/或者忘记自己所做的事情指令提示:唱,跳,RAP,篮球,——(条件:关卡游玩中卡槽内存在无用紫卡)

添加植物窝窝瓜:阳光125,冷却30s,种下后立即消失,并使周围十字植物变窝瓜指令提示:窝瓜经常被?(6个字母)

添加植物魔术豆(某咕咕黑的创意):阳光0,冷却50s,可以种在很多植物上,并使这些植物立即消失变成卡片,指令提示:这个植物真“神奇”

冰叶草对蹦极的buff从无限冰冻改成直接秒杀

三叶草伤害降低(60→40→50),但对气球僵尸提高(60→100),冷却略微提升(7.5s→10s),不过在小僵尸不麻烦有特判(60伤害,能一下吹死小僵尸)

胆小菇冷却不变(15s→20s→15s),模仿者胆小菇攻击间隔缩短(1.5s→0.9s→0.75s),但无法白嫖阳光

1437攻击间隔略微提高(1.5s→2s)

萝卜伞反弹豌豆和机枪僵尸子弹(但不能攻击僵尸),但若套上南瓜头,或者离上述僵尸太近,则不能触发此效果,冷却提高(7.5s→15s)

路灯花冷却提高(30s→50s),但能使场上的撑杆僵尸弃杆(不过会使撑杆攻击判定增大),并移除僵尸头上的路障

冰焰豌豆减速时间翻倍(1s→2s)

大喷喷射特效修改(把方块改为一行喷雾)

西瓜冰瓜消耗阳光修改(西瓜300→225,冰瓜200→175)

修改仙人掌,有概率(=本行僵尸数 * 40/1000(总概率为1))暴击(子弹伤害(20) * 2=40) 击退僵尸(对于气球击退3格)

僵尸菇调整:变成一次性植物,种植后消失并生产3张魅惑僵尸卡

大蒜中毒僵尸变绿

地刺和地刺王可以种在屋顶右4列(克制冰车);屋顶,月夜选卡不黑

全是一个波数降低(60→50)

植物僵尸1修改:豌豆带破烂铁门,小丑不会炸伤植物,被魅惑爆炸改为冻结僵尸等,修改了此关卡很多僵尸的特性,现在植物僵尸变成了全新的关卡(注意:跳跳僵尸未进行修改)

降低了开局僵尸的出怪密度(÷2)

自定义关卡模式:基本方式:进入upsell关卡,点击模仿者,开启关卡自定义模式选择对应植物卡片,修改出怪,波数,场景出怪:豌豆~卷心菜投手按顺序设置波数:香蒲~地刺王按顺序设置(1旗,2旗,3旗,4旗)场景:玉米投手~忧郁蘑菇按顺序设置花盆:清空出怪玉米加农炮:切换选择模式(未来可以添加新的关卡特性,但现在暂时没加)中途退出关卡存档过后可以进入关卡选择界面的“禅境花园”再次进入自定义关卡存档传送带模式:在关卡自定义模式点击模仿者,切换传送带选择模式选择选卡界面的植物,点击右下角的图鉴和商店调整卡片权重(显示在阳光那里)调整完后点击模仿者,切换为原来的关卡自定义模式若想清空传送带残留存档,在关卡自定义模式选玉米加农炮后选择豌豆射手进行清空特性自定义:(注:以下内容均要先点击玉米加农炮切换选择模式)初始阳光自定义:点击向日葵,鼠标中键清空或者还原初始阳光,左键初始阳光 25,右键初始阳光-25(初始阳光范围0~9990)调用冰冻关卡名称(方便修改文本):鼠标左键点击樱桃炸弹极限出怪模式:鼠标右键点击樱桃炸弹狂捶模式:鼠标中键点击樱桃炸弹(目前有bug,不能过关,输入win就行)雷厉风行模式:鼠标左键点击坚果墙小僵尸模式:鼠标右键点击坚果墙柱子模式:鼠标中键点击坚果墙

魅惑巨人捶击伤害提高5倍(50→100→500)

sun value开启字幕 开sun阳光颜色修改

防止多带同一张隐藏卡片

hardH:大睡天(生产植物等特殊植物不睡)

β5.70 (2020-02-24)

更新内容:

修复7-x僵尸饰品不显示的bug

调整关卡瓜瓜乐(生产植物生产间隔提高)

修复路灯花在睡觉时超模的bug

修LS无尽bug

玉米加农炮炸梯范围减小到樱桃

冒险6-10和7-10bgm改成僵王BGM

输入隐藏植物指令时取消该植物冷却(减少等待时间)

求生开头戴夫说话

修复了魅惑僵尸造成的bug

修复了无用紫卡植物有时候不能变成隐藏植物的bug

西瓜和冰西瓜可以打气球僵尸了

墓碑吞噬者和咖啡豆可以战术型配合使用了

添加新植物(目前开启新植物均为同火炬豌豆的方式):僵尸菇 种下之后具有神奇的功能,即每一个僵尸卡片都有魅惑的效果。 指令提示:阳光菇pak中某一图片名字中的6个字母

添加新植物:小盆菇 ≈小喷菇,但是能直接种在**(指令提示)上,自然消失后必定掉小阳光

吸金磁吸的钱翻倍,阳光略微增加

添加新植物:冰叶草 ≈飓风甘蓝,但是有一些(其实是很多)变动 指令提示:三叶草某部位的英文

添加新植物:反弹树桩 =樱桃反弹布丁 指令提示:反弹树桩的作用?

加强了裂荚射手(相当于1转水管)

隐藏关卡:雷厉风行 提示:在僵尸快跑输入某个动物的英文(4个字母)即可进入

添加指令stop:暂停出怪

β5.65 (2020-02-12)

更新内容:

增强磁力菇:每当磁铁吸够5次铁具后,会对全屏范围内进行5秒的铁具消除,注意在进行铁具消除的时候的铁具也会被算入吸铁次数。当技能期间再吸满8次将会重置铁具消除的时间(5s) 磁力菇的阳光价格将改为125

实装手套指令,并修复了关于手套的诸多bug,提示:5个字母,无多余提示

替换大喷的喷射特效(适配将来的pak)

更改辣椒的显示特效

实装hardG指令:迷雾模式(可以通过指令ctrlfog来调节浓雾大小)

路灯花功能修改:种下去让僵尸眩晕(停留)3s

实装显示/隐藏卡槽指令,提示:6个字母,无多余提示

幼苗现在对大喷,1437也有效了,且修复忧郁菇bug

增强寒冰菇:现在寒冰菇冻住小丑和辣椒会使其在寒冰菇赋予的冰冻时间里不会爆炸,除非是小丑的特殊爆炸

添加隐藏关卡:有果有因 进入方法,在花园输入另一个和死有关的东西

添加隐藏关卡:乐 指令提示:在植物僵尸2输入pvz中最惨植物的英文即可进入关卡乐

小黄的骚话更多了

β5.60 (2020-02-04)

温馨提示:从这个版本开始,为了修复一些莫名其妙的崩溃问题及加入开头弹窗,一些杀毒软件可能会报毒(但其实无毒,而且那些崩溃问题也有效解决了) 更新内容:

实装随机砸罐彩蛋:进入方法提示—— 15P 10Z=?小丑√ 坚果×t[I]me [T]ime [T]ime

优化部分关卡文本(指的阳光无限制,cheat模式下也会显示)

小黄(主菜单左下角的文字,可以告诉你一些奇怪的东西)装上了

(7-10BOSS)彩蛋关实装(进入方法就是打败boss的同时且XXXX)

增强巨人(7-10BOSS)的分身

开启阳光铲(指令类似僵尸掉阳光,5个字母)

实装ip(我是植物)模式,关卡进入提示: 植物max随机砸罐无聊

Ls添加无尽选项(谁笑到最后)

冒险模式削弱了豌豆僵尸的出怪比重(1→2),就是现在豌豆的出怪比重和路障的一样。(也就是6-6之类的存在豌豆僵尸的冒险关卡变简单了)

按1呼出铲子有声音了

β5.55 (2020-01-22)

更新了两个隐藏植物的特性,加强隐藏植物的两个坚果,橄榄球啃咬了也会爆炸

修复隐藏关卡某文本

card 现在更加美观了

关卡 7-6 7-7 的灾难目前可以正常发生,发生在第 29 轮,大幅度削弱 7-6 7-7

添加了萌新提醒

按 1 呼出铲子(非小键盘)

移除7-10的红

关卡 7-8 7-9 灾祸实装

关卡 7-10 的 boss 目前已经实装了

7-x开启隐藏植物

地刺击退恢复特效 修改地刺击退代码

现在,如果僵尸出现在不对的地方会直接死亡

修复传送带 bug

加强部分弱势植物(数值调整) 机枪射速 150→100豌豆射手、双发射手、裂荚射手射速 150→125

7-8,7-9灾祸效果: 满溢之灾祸,阳光迅速不断增加,但是阳光过多时刷怪极大加快

修复bug

(施工中)

谈谈Office Moniker类漏洞和公式编辑器类漏洞

在近几年出现的诸多office漏洞中,有两类漏洞是很值得谈谈的,第一类是Moniker导致的逻辑漏洞,第二类是公式编辑器漏洞。

对于第一类漏洞,其重点在于攻击者和微软安全团队之间的攻防过程,了解这类漏洞攻防过程对威胁追踪与研究较有益处:

    第一回合:CVE-2017-0199,用URL Moniker加载远程HTA文件实现远程代码执行;

    第二回合:CVE-2017-8570,用compositeMoniker、FileMoniker、NewMoniker、scriptletfile实现远程代码执行;

    第三回合:CVE-2017-8759,用office文档加载.Net组件漏洞,实现远程代码执行;

    第四回合:CVE-2018-8174,用office文档加载IE VBScript组件漏洞,实现远程代码执行;

    第五回合:CVE-2020-0674,用office文档加载IE JavaScript组件漏洞,实现远程代码执行。

对于第二类漏洞,其难点在于对相似漏洞之间的区分。从CVE-2017-11882开始,到CVE-2018-0802,再到CVE-2018-0798,三个都是非常相似的漏洞,在静态层面不容易区分,本文将分享一个在动态层面区分它们的方法。

下面跟随笔者一起来看一下这两类漏洞。

Moniker类漏洞

第一回合:CVE-2017-0199

2017年4月7日,著名office漏洞研究员李海飞发布了一篇在野0day攻击预警,首度披露了CVE-2017-0199漏洞的在野攻击。随后,2017年4月11日和12日,FireEye连发两篇文章,披露了他们捕获到的CVE-2017-0199漏洞样本细节。后续的披露表明这几篇文章中披露的漏洞是一种借助URL Moniker特性加载远程hta文件的新型漏洞,这是一个由于开发者对office文件加载机制设计不合理导致的逻辑漏洞,且要求触发环境安装IE10/IE11。漏洞触发过程不需要用户交互,但在触发的过程中会弹出一个对话框,不点击或者点击任意该对话框的按钮都不影响执行过程,对话框样式如下:

该漏洞的发现者之一李海飞曾经在Syscan360 2017会议上做过题为《Moniker Magic: Running Scripts Directly in Microsoft Office》的演讲,里面详细介绍了CVE-2017-0199的细节,包括:

    微软在CVE-2017-0199的补丁中修复了两个漏洞,分别是被在野利用的RTF URL Moniker加载远程HTA文件的远程代码执行漏洞,和李海飞独立发现的PPSX Script Moniker远程代码执行漏洞;

    office安全团队在这两个漏洞的基础上设计了一类针对Moniker的黑名单机制,禁用了一些他们觉得不安全的Moniker。

Moniker本身是office的一个特性,可以用来链接一些本地或远程对象,其本身不属于漏洞,漏洞发生在office软件对远程链接的文件的执行策略上。譬如,如果远程加载的是一个Excel文件,直接打开没问题;但如果加载的是HTA文件和Script这类脚本文件时,直接执行就存在问题了,导致了漏洞。

第二回合:CVE-2017-8570

在对CVE-2017-0199补丁的研究过程中,李海飞发现(上面也已经提到):

office安全团队在这CVE-2017-0199的补丁中设计了一类针对Moniker的黑名单机制,禁用了一些他们觉得不安全的Moniker。

于是他开始寻找那些还没有被禁用的Moniker,尝试用那些没有被禁用的Moniker构造出另一个逻辑漏洞,结果确实找到一个,即CVE-2017-8570。

在CVE-2017-0199中,用到的Moniker是下面这两个:

3050F4D8-98B5-11CF-BB82-00AA00BDCE0B // htafile06290BD3-48AA-11D2-8432-006008C3FBFC // scriptlet(or ScriptMoniker)

而在CVE-2017-8570中,用到的Moniker是下面这几个:

00000309-0000-0000-C000-000000000046 // CompositeMoniker00000303-0000-0000-C000-000000000046 // FileMonikerECABAFC6-7F19-11D2-978E-0000F8757E2A // NewMoniker06290BD2-48AA-11D2-8432-006008C3FBFC // scriptletfile(or ScripletFactory)

可以看到CVE-2017-8570利用未被加入黑名单的Moniker绕过了CVE-2017-0199的补丁。

不过,许多分析过CVE-2017-8570的读者可能会观察到一个奇怪的现象:漏洞中触发时script脚本中的代码会被执行两次。这是为什么呢?原来,在这个漏洞的触发逻辑中,会涉及到wwlib.dll库中的一个函数调用,该函数内部会顺序调用ole32!CDefLink::BindToSource和ole32!CDefLink::Update两个函数,如下(以office 2010为例):

而这两个函数最终都会调用kernel32!CreateProcessW创建进程,所以script脚本中的代码会被执行两次。其中ole32!CDefLink::BindToSource创建进程的栈回溯如下:

0:000> k 50ChildEBP RetAddr 0013a5b4 729cd2f5 kernel32!CreateProcessW0013a63c 729cd5f7 wshom!CreateNewProcessW 0x6f0013a69c 76da3e75 wshom!CWshShell::Exec 0x19a0013a6bc 76da3cef OLEAUT32!DispCallFunc 0x1650013a74c 729d0267 OLEAUT32!CTypeInfo2::Invoke 0x23f...cut...0013ae9c 7705b5dc comsvcs!CNewMoniker::BindToObject 0x14f0013aed0 770c3cc6 ole32!CCompositeMoniker::BindToObject 0x105 [d:w7rtmcomole32commoniker2ccompmon.cxx @ 1104]0013af3c 68ee87ce ole32!CDefLink::BindToSource 0x1bf [d:w7rtmcomole32ole232stdimpldeflink.cpp @ 4637]0013af80 68a61429 wwlib!wdGetApplicationObject 0x69230 // 第一处调用0013b010 68a23b2c wwlib!DllGetLCID 0x4753b3...cut...

而ole32!CDefLink::Update创建进程的栈回溯如下:

0:000> k 50ChildEBP RetAddr 0013a57c 729cd2f5 kernel32!CreateProcessW0013a604 729cd5f7 wshom!CreateNewProcessW 0x6f0013a664 76da3e75 wshom!CWshShell::Exec 0x19a0013a684 76da3cef OLEAUT32!DispCallFunc 0x1650013a714 729d0267 OLEAUT32!CTypeInfo2::Invoke 0x23f...cut...0013ae68 7705b5dc comsvcs!CNewMoniker::BindToObject 0x14f0013ae9c 770c3c55 ole32!CCompositeMoniker::BindToObject 0x105 [d:w7rtmcomole32commoniker2ccompmon.cxx @ 1104]0013af08 7710f7ee ole32!CDefLink::BindToSource 0x14e [d:w7rtmcomole32ole232stdimpldeflink.cpp @ 4611]0013af30 7710f42a ole32!CDefLink::Update 0x62 [d:w7rtmcomole32ole232stdimpldeflink.cpp @ 5347]0013af44 68ee8830 ole32!CDefLink::Update 0x33 [d:w7rtmcomole32ole232stdimpldeflink.cpp @ 2695]0013af80 68a61429 wwlib!wdGetApplicationObject 0x69292 // 第二处调用 0013b010 68a23b2c wwlib!DllGetLCID 0x4753b3...cut...

第三回合:CVE-2017-8759

在CVE-2017-8570漏洞被修复后,累计有如下这些Moniker被加入黑名单:

3050F4D8-98B5-11CF-BB82-00AA00BDCE0B // htafile06290BD3-48AA-11D2-8432-006008C3FBFC // scriptlet(or ScriptMoniker)00000309-0000-0000-C000-000000000046 // CompositeMoniker00000303-0000-0000-C000-000000000046 // FileMonikerECABAFC6-7F19-11D2-978E-0000F8757E2A // NewMoniker06290BD2-48AA-11D2-8432-006008C3FBFC // scriptletfile(or ScripletFactory)

在前面几个Moniker不能使用之后,攻击者又注意到了下面这个Moniker:

ecabb0c7-7f19-11d2-978e-0000f8757e2a // SOAPMoniker

SOAP Moniker可以用来加载一个远程的SOAP配置文件,当Word进程远程加载这个配置文件时,.Net组件会被加载用来解析对应的配置文件,并按照配置自动生成一个C#文件,再自动将该C#文件编译得到一个动态链接库并执行。攻击者借助.Net SOAP WSDL模块中的一个代码注入漏洞(CVE-2015-8759),将恶意脚本代码注入到了待编译的C#文件中,从而让编译得到的动态链接库包含恶意代码并自动执行。

从CVE-2017-8759开始,攻击者开始借助office组件与其他Windows组件之间的交互进行攻击。.Net的漏洞本身不属于office的范围,却可以借助office文档进行触发,这种攻击方式当时给笔者留下了深刻的印象。

第四回合:CVE-2018-8174

CVE-2017-8759被修复后,Moniker黑名单又得到了更新:

3050F4D8-98B5-11CF-BB82-00AA00BDCE0B // htafile06290BD3-48AA-11D2-8432-006008C3FBFC // scriptlet(or ScriptMoniker)00000309-0000-0000-C000-000000000046 // CompositeMoniker00000303-0000-0000-C000-000000000046 // FileMonikerECABAFC6-7F19-11D2-978E-0000F8757E2A // NewMoniker06290BD2-48AA-11D2-8432-006008C3FBFC // scriptletfile(or ScripletFactory)ecabb0c7-7f19-11d2-978e-0000f8757e2a // SOAPMoniker

在上面这些Moniker都不可用之后,攻击者又想出了一种新的攻击方式:借助URL Moniker去加载远程html文件,这样就可以借助office加载IE漏洞。攻击者首先用URL Moniker CVE-2014-6332的组合试了一下该方案的可行性,笔者追溯到的这方面的最早样本为2018年1月17日的下面这个文件(以及相关文件):

// CVE-2014-6332Document MD5: A9D3F7A1ACD624DE705CF27EC699B6B6URL Moniker: hxxp://s.dropcanvas[.]com/1000000/940000/939574/akw.htmlakw.html MD5: C40A128AE7AEFFA3C1720A516A99BBDF

到了2018年4月,攻击者终于按捺不住了,借助URL Moniker IE VBScript 0day的方式对特定目标进行了攻击,这次攻击所用漏洞就是著名的CVE-2018-8174,相关样本如下:

// CVE-2018-8174Document MD5: b48ddad351dd16e4b24f3909c53c8901URL Moniker: hxxp://autosoundcheckers[.]com/s2/search[.]php?who=7search.htm MD5: 15eafc24416cbf4cfe323e9c271e71e7

CVE-2018-8174出现后,微软安全团队并未直接将office加载VBScript脚本的功能进行限制。随后,在2018年7月,攻击者又借助另一个IE VBScript 0day(CVE-2018-8173),用相同的方式实施了攻击。

这下微软不淡定了,赶紧对Office加载VBScript脚本进行了限制。

第五回合:CVE-2020-0674

故事到这里就结束了吗?当然没有。此时,微软依然没有限制office加载JavaScript脚本,所以IE浏览器的两个JavaScript引擎:JScript和JScript9依然可以通过此种方式进行攻击。

其一,据笔者所知,在2018年的天府杯上,针对office项目的攻击采用了URL Moniker IE JScript9 0day的组合。

其二,2019年-2020年,由于几个JScript漏洞被相继披露,陆续有APT攻击组织使用URL Moniker JScript 1day的方式实施攻击,相关样本如下:

// CVE-2020-0674Document MD5: 90403dfafa3c573c49aa52c5fe511169URL Moniker: hxxp://tsinghua.gov-mil[.]cn/images/A96961AA/36604/1836/65449576/ab8feeeab8feee MD5: 1892D293030E81D0D1D777CB79A0FDBE// CVE-2020-0968Document MD5: 60981545a5007e5c28c8275d5f51d8f0URL Moniker: hxxp://94.156.174[.]7/up/a1a.htma1a.htm MD5: 293916af3a30b3d7a0dc2949115859a6

于是微软在高版本office中(office2016及以上版本)也加入了对JScript9脚本和JScript脚本的加载限制。

至此,攻击者针对Moniker的所有尝试都被微软进行了封堵,此后未观察到针对Moniker的新攻击方式。

公式编辑器漏洞

2017年11月补丁日,国外安全公司_embedi发表了一篇《SKELETON IN THE CLOSET: MS Office vulnerability you didn’t know about》详细描述了他们发现office公式编辑器漏洞CVE-2017-11882的整个过程(笔者发现这家公司的官网已经挂了…)。

属于office公式编辑器漏洞的时代至此开启。

由于组件源码的丢失,微软的补丁开发人员花了较长时间来修复这一漏洞,并且以一种近乎炫技的方式,直接在二进制层面对程序作了修补,在没有重新编译源码的情况下修复了漏洞,并添加了ASLR支持。

然而,一时激起千层浪,CVE-2017-11882出现后,广大安全研究员蜂拥而至,都开始关注office公式编辑器这一组件,这直接导致微软在2018年1月的更新中砍掉了公式编辑器组件。

在第二次修复的诸多office公式编辑器漏洞中,有两个漏洞比较值得注意,这两个漏洞分别为CVE-2018-0802和CVE-2018-0798,三个漏洞并称为office公式编辑器漏洞领域的“三驾马车”,

由于笔者经常看到分析人员对这三个漏洞的样本进行误判,所以这里分享一种在动态层面区分这三个漏洞的方法。

首先跟随笔者来了解一下这三个漏洞的具体成因,下文中的汇编代码基于以下公式编辑器组件:

eqnedt32.exe 2000.11.9.0

在office中,公式编辑器的数据被存储在一个OLE文件的“Equation Native”流中,三个公式编辑器漏洞都是在处理这个流的数据时出现的问题。

CVE-2017-11882

首先来看一下CVE-2017-11882。

该漏洞的成因为:在读入“Equation Native”流中的Font Name Record数据时,在将Name拷贝到某个局部变量的时候没有对Name的长度做校验,从而造成栈缓冲区溢出,漏洞发生点如下图所示:

从下图可以看出,函数给SrcStr变量分配的大小是0x24个字节,Name长度超过该大小就会造成栈溢出。

CVE-2017-11882的触发逻辑如下所示:

CVE-2018-0802

再来看一下CVE-2018-0802。

该漏洞的成因为:在将“Equation Native”流中的Font Name Record数据拷贝到一个LOGFONT结构体(位于栈上)内的lfFaceName成员(它是一个以空结尾的char型字符串,最大长度为0x20,其中包含终止符NULL),没有对Name的长度做校验,从而造成栈缓冲区溢出,漏洞发生点如下图所示:

CVE-2018-0802漏洞的触发路径和CVE-2017-11882有很大的重叠,下图可以做一个直观的比对:

由于某些限制,CVE-2018-0802在未打CVE-2017-11882补丁的版本上只会造成crash,但在打了补丁的版本上可以实现远程代码执行。

CVE-2018-0798

最后看一下CVE-2018-0798。

该漏洞的成因为:在读入“Equation Native”流中的Matrix Record数据时,存在一处while循环内的数据读取操作,由于未对Matrix的行和列两个参数进行校验,从而使攻击者可以控制由此计算得到的拷贝长度,导致栈缓冲区溢出:

上述汇编片段描述了一个while循环,反汇编成伪代码如下,攻击者可以控制伪码中v2的大小,从而导致了数据读写越界:

上述代码位于sub_443F6C函数内,所以理论上只要调用sub_443F6C函数的地方均存在CVE-2018-0798漏洞。作为与之前两个漏洞的对比,在之前两个漏洞的基础上加入CVE-2018-0798的触发路径如下:

动态区分三个公式编辑器漏洞

以上笔者已经介绍了三个公式编辑器漏洞的成因,借助上述知识,很容易在调试器中确认特定样本使用的漏洞,判定方式如下:

// CVE-2017-11882.text:00411655 C1 E9 02 shr ecx, 2 // 获取此偏移处的ecx值,若ecx的值位于(0x20, 0x94]区间,即为CVE-2017-11882.text:00411658 F3 A5 rep movsd.text:0041165A 8B C8 mov ecx, eax.text:0041165C 83 E1 03 and ecx, 3// CVE-2018-0802.text:00421E5B C1 E9 02 shr ecx, 2 // 获取此偏移处的ecx值,若ecx的值大于0x94,即为CVE-2018-0802.text:00421E5E F3 A5 rep movsd.text:00421E60 8B C8 mov ecx, eax.text:00421E62 83 E1 03 and ecx, 3.text:00421E65 F3 A4 rep movsb// CVE-2018-0798.text:00443F79 8D 04 45 02 00 00 00 lea eax, ds:2[eax*2].text:00443F80 83 C0 07 add eax, 7.text:00443F83 C1 F8 03 sar eax, 3.text:00443F86 66 89 45 08 mov [ebp arg_0], ax // 获取此偏移处的eax值,若eax的值大于4,即为CVE-2018-0798

有些样本会同时满足上述两个或三个条件,因为这些样本中内嵌多个公式编辑器漏洞利用。

延伸

细心的读者会发现2020年极棒大赛上使用的某国产软件公式编辑器漏洞和CVE-2018-0798基本一样,有兴趣的读者可以自行对比研究。

参考链接

https://www.mcafee.com/blogs/other-blogs/mcafee-labs/critical-office-zero-day-attacks-detected-wild/
https://www.fireeye.com/blog/threat-research/2017/04/cve-2017-0199-hta-handler.html
https://www.fireeye.com/blog/threat-research/2017/04/cve-2017-0199_useda.html
https://0b3dcaf9-a-62cb3a1a-s-sites.googlegroups.com/site/zerodayresearch/Moniker_Magic_final.pdf
http://justhaifei1.blogspot.com/2017/07/bypassing-microsofts-cve-2017-0199-patch.html
https://www.fireeye.com/blog/threat-research/2017/09/zero-day-used-to-distribute-finspy.html
https://securelist.com/root-cause-analysis-of-cve-2018-8174/85486/
https://ti.dbappsecurity.com.cn/blog/index.php/2020/07/13/sidewinder-new-attack-target-cn/
https://ti.dbappsecurity.com.cn/blog/index.php/2020/09/18/operation-domino/
https://support.microsoft.com/en-us/help/4058123/security-settings-for-com-objects-in-office
https://www.anquanke.com/post/id/87311
https://www.anquanke.com/post/id/94210
https://www.freebuf.com/vuls/160409.html

免责声明:本文由用户上传,如有侵权请联系删除!