如何从DLL中正确调用_vsnprintf实现游戏聊天文本输出
游戏聊天窗口输出乱码问题
我通过IDA定位到游戏中调用_vsnprintf的地址(0xA739FF),现在能调用它输出内容到聊天窗口,但显示的是随机乱码。修改ArgList会改变乱码内容,但始终无法正常显示文本。
定位到的函数定义
_vsnprintf函数
int __cdecl _vsnprintf(char *const Buffer, const size_t BufferCount, const char *const Format, va_list ArgList) //0xA739FF
调用_vsnprintf的print_to_chat函数
int __cdecl print_to_chat(char *Buffer, size_t BufferCount, char *Format, char ArgList) //0x51D020
当前使用的代码
namespace bo2 { constexpr uintptr_t say = 0x7EB870; constexpr uintptr_t printf = 0xA739FF; using say_t = void(*)(); using printf_t = void(*)(char* const Buffer, const size_t BufferCount, const char* const Format, va_list ArgList); } BOOL APIENTRY DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { if (reason == DLL_PROCESS_ATTACH) { const auto say = reinterpret_cast<bo2::say_t>(bo2::say); const auto printf = reinterpret_cast<bo2::printf_t>(bo2::printf); char buf[255], format[255]; size_t size = 256; std::string rV = "does this work now??????"; va_list list; va_start(list, rV); say(); printf(buf, size, format, list); } }
已尝试的操作
- 修改
Format参数,无效果 - 修改
ArgList会改变乱码内容,但问题依旧
编辑说明:目前仅直接调用_vsnprintf,不再调用print_to_chat,且使用va_list替代const char*或char*类型,但乱码问题仍未解决。
问题分析与修复方案
你的代码存在几个关键错误,直接导致乱码:
format变量未初始化
定义char format[255];后未赋值,它指向栈上的随机垃圾数据,_vsnprintf会将其当作格式字符串解析,必然输出乱码。va_list使用违规va_start的第二个参数必须是函数的最后一个固定参数,你直接传入std::string rV,不符合可变参数的使用规则,导致va_list指向的内存完全错误。函数调用顺序错误
如果say是负责将缓冲区内容输出到聊天窗口,你现在先调用say再填充buf,顺序完全颠倒,输出的自然是未初始化的垃圾数据。
修复后的代码示例
namespace bo2 { constexpr uintptr_t say = 0x7EB870; constexpr uintptr_t vsnprintf_addr = 0xA739FF; // 注意_vsnprintf的返回值是int,不要错误定义为void using vsnprintf_t = int(*)(char* const Buffer, const size_t BufferCount, const char* const Format, va_list ArgList); // 假设say函数接收格式化后的字符串,需根据实际函数签名调整 using say_t = void(*)(const char*); } BOOL APIENTRY DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { if (reason == DLL_PROCESS_ATTACH) { const auto vsnprintf_func = reinterpret_cast<bo2::vsnprintf_t>(bo2::vsnprintf_addr); const auto say_func = reinterpret_cast<bo2::say_t>(bo2::say); char buf[256]; const char* format = "%s"; // 正确的格式字符串,用于输出普通字符串 const char* msg = "does this work now??????"; va_list args; va_start(args, format); // 以最后一个固定参数format初始化va_list vsnprintf_func(buf, sizeof(buf), format, args); va_end(args); // 必须调用va_end完成清理 // 先填充缓冲区,再调用say输出到聊天窗口 say_func(buf); } return TRUE; }
额外注意事项
- 确认
say函数的实际参数类型:如果say内部逻辑依赖特定参数(比如宽字符、额外参数),需对应调整函数指针定义。 - 检查游戏字符编码:若游戏使用UTF-16编码,需将字符串转为宽字符,调用
_vsnwprintf替代_vsnprintf,否则会出现乱码。 - 验证
print_to_chat的函数签名:你之前定义的ArgList为char类型明显错误,实际应为va_list或可变参数类型,若要调用它需修正签名。 - 确保缓冲区大小足够:避免因缓冲区溢出导致的内存异常或乱码。
内容的提问来源于stack exchange,提问作者drilager60
相关产品推荐
相关产品推荐

