You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从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*类型,但乱码问题仍未解决。


问题分析与修复方案

你的代码存在几个关键错误,直接导致乱码:

  1. format变量未初始化
    定义char format[255];后未赋值,它指向栈上的随机垃圾数据,_vsnprintf会将其当作格式字符串解析,必然输出乱码。

  2. va_list使用违规
    va_start的第二个参数必须是函数的最后一个固定参数,你直接传入std::string rV,不符合可变参数的使用规则,导致va_list指向的内存完全错误。

  3. 函数调用顺序错误
    如果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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 07:45:37