- 注册
- 2025/01/17
- 消息
- 7
- 反馈评分
- 78
- 点数
- 13
- 勋章
- 3
CS2 - PrintToChat
我看B站FA脚本showcase 有的LUA作者用say指令打印hitlog
这个教程会讲讲怎么直接将字符串输出到Chat 而不是发送给所有人
* 阅读本文需要逆向基础 *
逆向教程: 1337bbs.com/threads/ida-cs-2-reversing-cs-2-cs-go-reversing-dll-so.186
FA版本代码实现在最后(游戏更新后将失效)
本文插图上传至Github 裸连可能无法加载
逆 向 教 程
我们在CS2 SDK中
进入{SDK}/game/client文件夹
通过模糊搜索 找到了CBaseHudChat类中一个名为ChatPrintf的函数
我们现在理清思路
我们invoke这个函数的必要条件
就是需要获取到CBaseHudChat类的指针
我们注意到这个类中有个静态成员函数
我们在CS2 SDK中
进入{SDK}/game/client文件夹
通过模糊搜索 找到了CBaseHudChat类中一个名为ChatPrintf的函数
我们现在理清思路
我们invoke这个函数的必要条件
就是需要获取到CBaseHudChat类的指针
我们注意到这个类中有个静态成员函数
static CBaseHudChat *GetHudChat( void );
但我们发现这个函数很难下手(因为他只返回了一个变量 且是静态函数 基本没有切入点)
我们直接搜索 CBaseHudChat *
看看有没有别的办法能获取到 CBaseHudChat 类的指针
发现这里有个很有意思的东西GET_HUDELEMENT
我们注意到这个宏
主要是调用了CHud::FindElement
我们发现这个函数有十分美妙的切入点:字符串引用
我们进入IDA
在client.dll中搜索这个字符串
发现可以找到这个字符串
我们定位进去 CTRL+X打开引用列表
(你们打开列表看到的肯定不是FindElement+偏移,这个是被我改了名字所以这样)
我们定位进去发现这个函数只需要传入字符串即可
我们为这个函数生成签名
我们稍后调用这个函数 便可以获取到CBaseHudChat的指针了
我们接下来需要做的是找到ChatPrintf函数
我们直接搜索ChatPrintf
发现CBaseHudChat::MsgFunc_SayText中调用了ChatPrintf函数
发现下面有字符串引用
我们在IDA中搜索到这个字符串后查看引用
我们发现三个引用中 其中一个函数
与在SDK中看到的CBaseHudChat::MsgFunc_SayText函数结构类似
因此我们猜测箭头所指(被我命名为maybe_ChatPrintf的)的函数就是我们要找的ChatPrintf函数
(原因: 参数个数能对上, 两个函数的类指针相同, "%s"字符串引用)
我们定位进去 发现这个函数接受"..."类型 (代表参数个数可变)
所以我们应该是找对了
然后我们为这个函数生成签名
LUA & FFI 教 程
我们查找CS2 FA的API 发现在utils中有个名为find_pattern的接口
我们通过调用这个API 便可以获取到函数签名的内存地址
然后我们通过ffi.cdef 定义函数指针
然后我们将获取到的内存地址转换为函数指针
然后我们便可以调用该函数
实现ChatPrintf的调用同理
我们查找CS2 FA的API 发现在utils中有个名为find_pattern的接口
我们通过调用这个API 便可以获取到函数签名的内存地址
然后我们通过ffi.cdef 定义函数指针
然后我们将获取到的内存地址转换为函数指针
然后我们便可以调用该函数
实现ChatPrintf的调用同理
代 码 实 现
代码:
local ffi = require('ffi')
ffi.cdef [[
typedef void*(__fastcall* FindElement_t_c_r)(const char*);
]]
local sig_FindElement = '40 55 48 83 EC 20 48 83 3D EA 40 0E 01 00'
local adr_FindElement = utils.find_pattern("client.dll", sig_FindElement) -- 签名 -> FindElement内存地址
local hudElement = ffi.cast("FindElement_t_c_r", adr_FindElement) -- 地址 -> 函数指针
local CHudChatDelegate = hudElement("HudChatDelegate"); -- CHudChatDelegate
ffi.cdef [[
typedef void*(__cdecl* ChatPrintf_t_c_r)(void*, unsigned int, const char*, ...);
]]
local sig_ChatPrintf = '4C 89 44 24 18 4C 89 4C 24 20 53 B8 40 10 00 00'
local adr_ChatPrintf = utils.find_pattern("client.dll", sig_ChatPrintf) -- 签名 -> ChatPrintf内存地址
local chatPrintf = ffi.cast("ChatPrintf_t_c_r", adr_ChatPrintf) -- 地址 -> 函数指针
local function printToChat(index, f, ...)
chatPrintf(CHudChatDelegate, index, string.format(f, ...))
end
--[[
--printToChat调用实例:
printToChat(-1, "Hello, %s!", "world")
]]

