Skip to content

About

CS1.6外挂学习笔记

Resources

Stars

25 stars

Watchers

3 watching

Forks

Repository files navigation

CounterStrike

跟着 ascotbe 的《CSGO破解学习》系列练手写的一个 cstrike.exe(Esai 汉化版离线 CS 1.6 整合包) 修改器,分两条技术路线,界面上都在同一个窗口里:

  1. 外部修改器:直接读写游戏进程内存(OpenProcess + ReadProcessMemory / WriteProcessMemory), 不用注入、不用驱动。就是风灵月影那种「一行一个功能,填个数,勾上锁定」的用法。
  2. 注入渲染 Hook:把 CounterStrikeHook.dll 注进游戏进程,钩 wglSwapBuffers, 在游戏自己的画面上用 OpenGL 画人物方框、开透视、给 mp.dll 打固定伤害补丁 (这三条纯外部读写做不到,CT 表里也是靠注入/脚本实现的)。

仅供离线 / 单机环境学习练手,不要拿到对战平台、联机服务器上使用。

仓库只提交源码和文档:game\(游戏本体)、ct_tables\(CT 表)、tools\(调试脚本) 和 tmp\(截图 / 临时产物)都只在本地放着,禁止提交到 git(详见「仓库约定」一节)。

偏移全部来自仓库 Ascotbe/Image 里 CSGO 目录下的 CT 表 (CSGO1.6-1 ~ CSGO1.6-8),游戏压缩包也在同一个目录(CSGO_v2728.7z.001 等 3 个分卷)。 CT 表里的静态地址和实测不一定一样,本项目按实测校正过(见下面「偏移表」一节)。

目录

怎么用(先看这节)

一句话:先开游戏,再用管理员身份开修改器;游戏外的功能在左边勾,要注入的在右下角注入。

  1. 开游戏(第一次进要 CD-KEY,见下一节):

    # 在仓库根目录下执行(game\ 是本地解压出来的,不进 git)
    cd game\extracted\Cs1.6
    .\cstrike.exe -console -window +maxplayers 16 +map de_dust2

    窗口化设置和「鼠标被拽回窗口中间」的问题看后面两节。

  2. 开修改器(没编过就先看「编译」一节):用管理员权限运行 CounterStrike\Release\CounterStrike.exe(相对仓库根目录;CounterStrikeHook.dll 跟它放在同一个 Release\ 目录里,注入时找的就是它,别把 exe 单独拷走):

    # 在仓库根目录下、以管理员身份执行
    .\CounterStrike\Release\CounterStrike.exe
  3. 用游戏外的功能(钱 / 血 / 子弹 / 速度……):左边功能表一行一条,填「锁定数值」, 点 - / + 按步长加减,或者直接勾「锁定」;也可以切回游戏按 F1~F12 开关。 改乱了点「全部取消锁定」「数值恢复默认」。

  4. 用注入功能(游戏内方框 / 透视 / 固定伤害 / 解锁鼠标):右下角注入面板点「注入 DLL」 → 勾「启用 Hook」→ 再勾要的功能。指针链不用填,DLL 自己扫人物、自己找基址。

  5. 收工:面板里点「卸载 DLL」(会把固定伤害补丁按原字节还原),再关修改器和游戏。

设置存在 exe 同目录的 CounterStrike.ini 里,下次启动自动读回来。 每行功能的具体行为和逐条实测结果见「界面说明」「功能一览」两节。

进游戏要用到的 CD-KEY

整合包是 Esai 汉化版,进游戏会要你输序列号(CD-KEY)。这个包的 key 在安装日志里, game\extracted\Cs1.6\INSTALL.LOG 里那两行 RegDB Val: / RegDB Old::

5RP2E-EPH3K-BR3LG-KMGTE-FN8PY

进游戏弹「输入 CD-KEY」的框直接粘这一串就行。(本机注册表里 HKCU\Software\Valve\Half-Life\Settings 下只有加密过的 yeK1 / yeK2,明文就是上面这串。)

怎么进游戏(窗口化 + 启动参数)

游戏默认是全屏,全屏的时候修改器的窗口会被压在下面,切来切去很难受。改成小窗口的办法:

  1. 窗口化开关在注册表里(游戏自己存设置的地方),HKCU\Software\Valve\Half-Life\Settings:

    值 设成 作用
    ScreenWindowed 1 窗口化
    ScreenWidth 1024 窗口宽
    ScreenHeight 768 窗口高
    ScreenBPP 32 色深
  2. 启动参数(-console 会顺手开控制台,找地图/加机器人都在里面敲):

    # 在仓库根目录下执行(game\ 是本地解压出来的,不进 git)
    cd game\extracted\Cs1.6
    .\cstrike.exe -console -window +maxplayers 16 +map de_dust2

    +maxplayers 16 别省:默认人数太少的话进图会报 server is full (1/1); de_dust2 换成别的图也行(cstrike\maps 里有的)。

  3. 想加机器人:控制台里敲 bot_quota 8(人数)、bot_add(马上加一个), bot_stop 1 可以让机器人站着不动,方便试功能。

修改器窗口本身是普通窗口(不是全屏,也没最大化),直接双击 CounterStrike\Release\CounterStrike.exe 就行,要用管理员权限,否则打不开游戏进程。

鼠标一直被拽回窗口中间怎么办

这是客户端自己的行为,不是你鼠标坏了:窗口化进游戏之后引擎每帧都会干两件事

  1. ClipCursor(窗口矩形) —— 把光标夹在窗口里;
  2. SetCursorPos(窗口中心的 X, 窗口中心的 Y) —— 把光标硬拽回窗口正中(Quake 那套鼠标增量做法)。

实测这个客户端传参还是反的:它调的是 SetCursorPos(Y=窗口中心Y, X=窗口中心X), 而且用的是整个窗口(含标题栏)的中心,不是客户区中心。所以判定的时候 「客户区中心」「整个窗口中心」×「正常顺序 / XY 反着传」四种情况全都算上了,不然挡不住。

解决办法在界面右下角注入面板里:「解锁鼠标」勾上(默认就是勾上的,注入 DLL 之后生效)。 DLL 把 ClipCursor 和 SetCursorPos 都钩住:

  • ClipCursor 直接返回 TRUE(假装夹住了);
  • SetCursorPos 只有当目标点就是「窗口中间那个点」(±8 像素)时才假装成功、实际不动它, 别的坐标(菜单、控制台、窗口居中那些)一律放行 —— 游戏里该有的操作不受影响。

注意 SetCursorPos 在 user32 里是 FF 25 xx xx xx xx 这种转发桩,只有 6 字节, 以前只认 5 字节热补丁序言,所以钩子装不上、「解锁鼠标」勾了也没用;现在两种序言都认。

效果在状态栏最后一行能直接看到: 光标复位:挡了 N 次 / 想复位 M 次(最近要 X=.. Y=..,客户区中心 X=.. Y=..,窗口中心 X=.. Y=..)。 游戏在前台时这两个数会一直涨,说明引擎每次想拽回中间都被挡掉了(实测挡掉率 99.99%)。

界面说明

左边一列是功能表,一行一条,列是:热键 / 功能 / 锁定数值 / 减/加(每次点多少)/ 锁定。

  • 锁定数值:想锁多少填多少,改完按回车或点一下别的地方立刻生效,锁定中的功能马上按新值写进游戏。
  • - / +:按这一行的步长加减,加减按钮上直接写着步长(金钱是 -100 +100,血量 -10 +10, 移动速度 -50 +50,左键冷却 -0.5 +0.5……),点一下立刻生效。
  • 锁定:等于 CE 的「锁定地址」,勾上之后每 15 毫秒写一次;也可以直接在游戏里按对应的 F 键开关。
  • 全部锁定 / 全部取消锁定 / 数值恢复默认:列表下面,一键操作。
  • 当前客户端版本没收录的偏移会自动置灰,功能名后面标「(未收录)」(v2728 里只有 F12 免疫伤害)。

右边从上到下:

  • 实时状态:血量 / 护甲 / 金钱 / 坐标 / 阵营 / 移动速度 / 被攻击减速 / 机器人个数 / 全局阵营 / 武器标记 / 手雷 / 准星指向 / 指向的角色编号 / CT「所有人物」的血量。
  • 人物位置雷达:不用扫描,直接按坐标画点,绿点=自己或队友、红点=敌人、黄点=身份没读到。
  • 人物框框:外部方框(画在游戏窗口上的透明置顶层)的设置,还有敌人框色 / 队友框色 (填 6 位 RRGGBB,比如 FF3C3C,改完注入的 DLL 下一次读设置就生效)。
  • 注入渲染 Hook:注入 / 卸载 DLL、游戏内方框、方框上写血量、透视(两档)、 固定伤害 + 补丁地址、解锁鼠标、自动找基址、立即找一次、抓游戏内截图、画调试十字。
  • 日志:连接、F 键开关、数值修改、方框颜色改动、报错,都写在这里。

窗口默认开成屏幕工作区 70% 高、居中,不会一启动就占满整个屏幕(界面本身是按 1160x1036 的「画布」摆的)。窗口比画布小的时候右边会出现滚动条,鼠标滚轮也能上下翻页, 窗口随便拉大拉小(最小 760x420),拉到够大就整页显示。

所有设置(版本、每行数值、锁定状态、人物框框参数、方框颜色、补丁地址)都会存到 exe 同目录的 CounterStrike.ini,点「保存设置」写入,下次启动自动读回来。

功能一览(含逐条实测结果)

下表是 v2728 客户端上一条一条实测过的结果(在游戏里改内存、再回游戏内存里读回来核对):

热键 功能 默认值 步长 范围 实测
F1 金钱(实际 + 显示) 16000 100 0 ~ 100000 ✅ 填 20000,游戏里 p2+0x1CC 读到 20000
F2 主武器子弹 30 10 0 ~ 2000 ✅ 填 99,[武器+0xCC] 读到 99
F3 血量 200 10 1 ~ 10000 ✅ 填 150,读到 150.0
F4 护甲 100 10 0 ~ 1000 ✅ 填 99,读到 99.0
F5 移动速度 400 50 1 ~ 3000 ✅ 填 500,p1+0x290 读到 500.0
F6 无限购物 3 1 0 ~ 3 ✅ 锁 0 时读到 0,解锁回 3
F7 随地下包 3 1 0 ~ 3 ✅ 同上
F8 视角切换 3 1 0 ~ 3 ✅ 填 1,p1+0x2C4 读到 1(第三人称)
F9 光速攻击(左键冷却) -1 0.5 -5 ~ 50 ✅ 填 0.1,[武器+0xB8] 读到 0.09(游戏自己在往下走)
F10 被攻击不减速 1 0.1 0 ~ 10 ✅ 锁 1 读到 1.0
F11 无后座力 / 手枪连发 0 1 0 ~ 1 ✅ 锁 1 时 [武器+0x100] 在 0/1 之间跳(游戏每帧自己写这个位)
F12 免疫伤害(是否掉血) 0 1 0 ~ 10 ❌ v2728 没收录(见下)

默认值和范围写在 gui.cpp 的 BuildFeatures() 里,想改默认值改那张表就行。

F12 免疫伤害为什么是「未收录」

CT 表里免疫伤害那条链算出来的字段,在 v2728 客户端里实测是 2.0 这种值,跟 CT 表里「锁 0 就不掉血」 的形状对不上,硬锁反而可能把别的字段改坏,所以干脆没收进 v2728 的偏移表(v3248 有)。 想不挨打就用 F3 血量锁:把血量锁成一个高值,被打掉的血每 15 毫秒会被写回去,效果一样。

金钱那栏的「显示」是怎么回事

  • 「实际」= 游戏真正的金钱字段(p2+0x1CC),买东西、算奖励用的就是它,这个是准的。
  • 「显示」= 游戏 HUD 右上角那个 $xxxxx。客户端里还留着一份自己的拷贝,只有游戏自己发 「金钱变化」事件(开局、买单、拿人头奖励)的时候才会同步过去。我们直接改内存不发这个事件, 所以锁上之后 HUD 上的数字可能要等到下一次金钱变化才跟着变(实测里见过 $13337 这种 「锁的钱 + 回合奖励」的数字,说明它确实会跟上,只是慢一拍)。买东西不受影响。

游戏内注入(Hook)都在干什么

注入面板最下面那一行就是 DLL 的实时状态,比如:

DLL:已注入  Hook:6 个  渲染帧数 34855  上一帧方框 1 个 / 角色 3 个  固定伤害:生效中  透视:没生效
  • Hook:6 个 = 装上去了 6 个钩子:渲染 4 个(wglSwapBuffers、glBegin、glDrawArrays、 glDrawElements)+ 鼠标 2 个(ClipCursor、SetCursorPos,见上面那节)。
  • 渲染帧数 = 钩子已经跑过多少帧,不动就说明没钩上(游戏不是 OpenGL 渲染时会提示)。
  • 上一帧方框 N 个 / 角色 M 个 = 游戏里这一帧画了几个框、扫到几个角色。只有角色在镜头前面 (投影 w > 0)才会画框,所以大部分时间这个数是 0 是正常的;镜头前有人时会跳成 1、2、3…… 实测抓到过「方框 1 个」的画面,截图里那根红框像素是精确的 RGB(255,60,60)(和游戏自己画的 红色玩家名 RGB(255,63,63) 能区分开)。

游戏内人物方框

  • 勾上「启用 Hook」+「游戏内画人物方框」,DLL 会在游戏渲染完世界之后、交换缓冲之前, 用 OpenGL 在游戏画面上画框(队友绿框、敌人红框、阵营不明的黄框,勾「方框上写血量」框上还有血量)。
  • 不用填任何链:DLL 在游戏进程里自己扫人物对象(按对象指纹扫,一秒刷新一次、 每三秒分片扫一遍内存),扫到的人直接拿来画。界面上的状态会写「自己扫到了 N 个角色」。
  • 颜色可以在界面「人物框框」那里改(敌人框色 / 队友框色,6 位 RRGGBB), 改完 DLL 下一次读设置就生效 —— 这条也验过:界面填 FF00FF 之后, 游戏进程里的共享内存设置块里读到的就是 enemy=0x00FF00FF。
  • 想让界面上那行小字显示出来,勾「画调试十字」,游戏屏幕正中会画一个黄色小十字、左上角一行 CSTRAINER HOOK ON boxes=N entities=M,一眼能看出钩子到底在不在工作。
  • 实测(用 DLL 自己的「抓游戏内截图」抓的游戏画面,逐像素数过): 队友在镜头里时框是 RGB(80,220,120)、框上面写着血量 100; 敌人那侧抓到的框是 RGB(255,60,60)。颜色就是界面上填的那两个值。

透视(wallhack)

CT 表里的做法是钩 glBegin,画人物批次的时候把深度测试关掉,本项目照做,还多一档 「激进:所有批次」(glDrawArrays / glDrawElements 这些批处理也一起关)。 老实说:这是「尽力而为」的做法 —— 能不能穿透要看这个客户端当帧是怎么提交批次 (有的批次关了深度就正常透出来,有的还是会被人/墙挡)。要稳的透视得按游戏引擎的 实体列表去单独重画人物,那是另一个工程量。状态栏里的「透视:生效中/没生效」反映的是 钩子里有没有真的关过深度测试。

固定伤害

CT 表里这是一段 Auto Assembler 脚本,打在 mp.dll+0x5ACA1 上(原指令是 fsub dword ptr [esp+54] + fstp dword ptr [eax+160]),把伤害值改成 200。 DLL 直接把这个偏移上的立即数改成界面里填的值(默认 200),卸载时按原字节还原。 状态栏里「固定伤害:生效中」就是补丁已经打上了。地址那一栏可以改(模块+偏移 格式)。

抓游戏内截图 / 自动找基址

  • 抓游戏内截图:DLL 用 glReadPixels 把后缓冲(已经画了方框的那一帧)读出来, 写成 BMP 到下面那个路径(默认 CounterStrike\Release\game_shot.bmp;想留档就再挪到 tmp\)。 游戏窗口用 GDI/PrintWindow 是抓不到的(OpenGL 直接画在前台缓冲区上),只有这个办法能抓到 带方框的画面,验证方框有没有画出来就靠它。
  • 自动找基址 / 立即找一次:不用自己用 CE 扫人物基址。DLL 按人物对象指纹扫整个用户空间内存, 找到之后把静态地址填到界面上,还会把血/钱/甲/子弹/坐标读出来给你看。 v2728 这个客户端实测扫出来的是 cstrike.exe+1100ABC(不是 CT 表里的 D6E63C)。

偏移表(v2728 实测)

界面上「自动找基址」找到的静态地址是 cstrike.exe+1100ABC,三条链长这样:

静态 1100ABC -> p1 = [1100ABC]
                p2 = [p1 + 0x7C]        (引擎对象 E;[E+4] == p1+0x80 是很硬的指纹)
                p3 = [p2 + 0x04]
功能 实测链 类型
血量 +7C +04 +160 float
护甲 +7C +04 +1BC float
金钱 +7C +1CC int
阵营 +7C +1C8 int(1=恐怖分子 2=反恐精英)
坐标 x / y / z +7C +04 +08 / +0C / +10 float
主武器子弹 +7C +5E8 +CC int
左键冷却 +7C +5E8 +B8 float
无后座力位 +7C +5E8 +100 int
移动速度 +290 float
无限购物 +7C +3C4 int
随地下包 +7C +3C0 int
视角切换 +2C4 int
被攻击减速 +7C +1B0 float
血量(DLL 扫描用) 对象 +1E0 float
坐标(DLL 扫描用) 对象 +88 / 8C / 90 float

有个坑必须说一下:CT 表 v2728 那几篇里的 cstrike.exe+D6E63C 在这份客户端上是个「像人物但 不是自己」的对象;cstrike.exe+102D480 也拿得过一份很像人物的数据(实测是机器人的), 早期版本照着它锁金钱/血量,看着像生效了其实锁的是别的角色,HUD 一点动静都没有。 现在程序里用的都是实测确认过的那条(1100ABC),DLL 自动找基址还会额外做一次 「离摄像机太远就再找找」的过滤(>150 单位就只当备选)。

编译

游戏进程是 32 位的,必须编 Win32(x86),x64 配置会在编译期用 static_assert 提醒你。

# 改 gui.cpp / 训练器时;注入的 DLL 会被自动带编(CounterStrike.vcxproj 依赖 Hook.vcxproj)
# MSBuild 用本机 VS / Build Tools 自带的:Developer PowerShell 里直接敲 msbuild,
# 或者用 VS 安装目录下 MSBuild\Current\Bin\MSBuild.exe 的完整路径
msbuild CounterStrike\CounterStrike.vcxproj /nologo /p:Configuration=Release /p:Platform=Win32

产物(都相对仓库根目录):

  • CounterStrike\Release\CounterStrike.exe(界面程序,管理员运行)
  • CounterStrike\Release\CounterStrikeHook.dll(注入用,和 exe 放同一个目录,别拆开)

编完跑起来(在仓库根目录下、以管理员身份执行):

.\CounterStrike\Release\CounterStrike.exe

没游戏的时候想先自测钩子,可以编 HookTestHost(假游戏),跑 HookTestHost\Release\TestHost.exe。

改 CounterStrikeHook\hook.cpp 的时候先把 DLL 从游戏里卸下来再编(「卸载 DLL」按钮), 不然正在被游戏加载的 dll 文件是锁着的,链接会失败。

已知限制(老实说)

  • F12 免疫伤害:v2728 没收录(原因见上)。
  • 透视:尽力而为,见上面「透视」一节。
  • 金钱 HUD 显示:慢一拍,见上面「金钱那栏的显示」一节。
  • 方框只在角色进画面时才出现:本来就该这样(方框是给人看的),想看「上一帧方框 N 个」 这个数动起来,就转着圈找人,或者用 bot_add 加点机器人往你跟前送。
  • 注入的是 OpenGL 渲染路径:这个整合包用 hw.dll(OpenGL/软件渲染)。如果换成 D3D 渲染的客户端,wglSwapBuffers 就钩不到了(界面会提示「一直没等到 wglSwapBuffers」), 固定伤害补丁不受影响。

仓库约定(什么不进 git)

这个仓库只提交源码和文档,下面这些只在本地放着,不进 git (.gitignore 里已经排掉了,不要用 git add -f 之类的方式硬塞):

目录 是什么
game\ 游戏本体(整合包分卷 + 解压出来的 Cs1.6),别传
ct_tables\ Ascotbe 的 CT 表(第三方参考资料),别传
tools\ 本地调试脚本(.ps1 / .cs)和 dump 出来的文本,别传
tmp\ 截图、抓图、调试图片、一切临时产物,都丢这里,别传

截图往哪放:软件截图、游戏抓图、调试图片一律放 tmp\,根目录和源码目录里不要留图片。

文件结构

文件 作用
CounterStrike\main.cpp 程序入口,只负责把界面跑起来
CounterStrike\gui.cpp / gui.h 图形界面:功能表、自定义数值、步长按钮、快捷键、实时状态、雷达、日志、方框设置、注入面板、ini 存档
CounterStrike\config.cpp / config.h v2728 / v3248 两个版本的偏移表、默认值、外部方框参数
CounterStrike\role.cpp / role.h 指针链解析、读写内存、每个功能的「锁定」函数
CounterStrike\esp.cpp / esp.h 外部人物框框:收集人物 + 视角矩阵投影 + 透明置顶层画框
CounterStrike\hook_client.cpp / hook_client.h 注入 / 卸载 DLL、和 DLL 之间的共享内存(hook_shared.h)
CounterStrikeHook\hook.cpp 注入进去的那个 DLL:装钩子、扫人物、游戏内画框、透视、固定伤害、抓图、解锁鼠标、自动找基址
HookTestHost\TestHost.cpp 没有游戏时自测用的「假游戏」(32 位):把注入 / 渲染钩子 / 固定伤害补丁整条路跑通
AGENTS.md 仓库约定(git 禁传目录、编译方式、改代码要求),动手前先看
tmp\ 临时产物(截图 / 调试图片 / dump),不进 git
game\ 本地游戏(分卷 + 解压出来的 Cs1.6),不进 git
ct_tables\ CT 表资料(本地参考),不进 git
tools\ 本地调试脚本 / 文本 dump,不进 git

相关文章

CSGO破解学习(一)

CSGO破解学习(二)

CSGO破解学习(三)

CSGO破解学习(四)

CSGO破解学习(五)

CSGO破解学习(六)

CSGO破解学习(七)

CSGO破解学习(八)

About

CS1.6外挂学习笔记

Resources

Stars

25 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages