【问题标题】:Accesing values of another program访问另一个程序的值
【发布时间】:2013-03-17 00:10:30
【问题描述】:

所以,我一直想知道如何使用我的 c++ 代码访问不同程序的值。

我知道我必须知道内存位置并以某种方式访问​​它,但我真的不知道如何。

假设我有一个游戏,我的角色有一定的生命值,我想用我的 c++ 代码读取该生命值(类似于使用作弊引擎程序读取不同值的方法)。

我将如何做到这一点?

为了清楚起见:操作系统是 windows

【问题讨论】:

  • 您应该查看共享内存

标签: c++ windows reverse-engineering


【解决方案1】:

如果不使用特定的IPC 机制,您不应写入另一个进程的内存空间。操作系统通常会出于明显的原因阻止这种情况。相反,您需要使用目标应用程序的扩展机制,或反编译/修改/十六进制编辑来实现您想要的更改。话虽如此,这样做可能违反了您正在使用的软件的服务条款。

需要明确的是,代码可以很好地编译,让您可以设置指向您想要的任意地址的指针,但是一旦您尝试读取或写入该地址,操作系统就会介入并导致错误情况。

如果您这样做并没有违反软件的EULA,这里有一些提示,可以帮助您找到可能需要修改的内容:

  • 如果可以将代码反编译成某种可读的源代码形式,请在此处进行修改。
  • 使用十六进制编辑器编辑编译后的二进制文件,查找明确定义的值并更改它们(max_health 是否总是从 25 开始?这可能足够独特,可以定位和修改)。关于这一点的注意事项:确保您要插入的值与原始值在同一空间中,否则您会破坏事物并产生未定义的结果。
  • 应用程序是否提供扩展机制,例如脚本 API 或模组支持?如果是这样,这可能是导致您想要的系统更改类型的向量。

【讨论】:

  • 我编辑了我的第一篇文章,阅读价值很好。我真的不需要写信给它。
  • @Ron 那么像this 这样的程序是如何工作的呢?我过去用它来定位/查看/修改任意进程中的值。
  • 嗯,我猜任何版本的 Windows 都不能提供这些基本的内存保护。再有一个理由远离那个平台:-)
  • @Ron 它声称可以在 95 以后的所有版本的 Windows 上工作。我可以保证它在 XP 上工作。
【解决方案2】:

您可以使用ReadProcessMemory/VirtualQuery(比ReadProcessMemory 更安全)和WriteProcessMemory 函数。

如果你很聪明,你可以注入一个 DLL,然后你可以在你的代码中使用指针

int * money = 0x00400000+0x00ABCDEF;//pointer to money address
*money = 5000;//set money to 5000.

如果您需要 DLL 示例,这里有一些:

Red Alert 3 Player Information Mod

Need for Speed: Underground 2 cheat mod

有时指针可以改变它们指向的内容,这对应用程序而言可能是“危险的”。

当您访问指向受保护内存区域、不可访问内存、而不是指向您想要的内容或无效位置的指针时,您的应用程序可能会崩溃。我不知道作弊引擎是如何阻止它的,但您有几个选择,我建议:

  • 优雅地退出应用程序并让用户知道您无法处理它
  • 改用 try / catch 块来处理问题? (一定要捕获正确的错误)
  • 硬退出应用程序
  • 什么都不做,让应用程序表现异常/崩溃
  • ...越来越多

我自己也编写了指针类,它处理解引用并在遇到错误时停止(返回 null)

//null as last parameter automaticly "Dereferences"
template<class T = DWORD, class S = DWORD> struct Pointer
{
private:
    std::vector<S> params;
    S variable;
    bool MoreThanOne;
public:
    //null as last parameter automaticly "Dereferences"
    template<class... Args> 
    Pointer(Args... args) 
    {  
        std::array<S, sizeof...(args)> list = {args...};
        for( auto i : list)
            params.push_back(i);
        if(params.size() > 1)
            MoreThanOne = true;
        else
            MoreThanOne = false;
    }
    T ResolvePointer() 
    {  
        variable = params[0];
        if(!MoreThanOne)
            return (T)variable;
        try
        {
            auto it = params.begin();
            ++it;  
            for(; it != params.end(); ++it)
            {
                if(*reinterpret_cast<S*>(variable) == NULL)
                    return static_cast<T>(NULL);
                variable = *reinterpret_cast<S*>(variable) + *it;
            }
        }
        catch(...)
        {   
            return static_cast<T>(NULL);
        }
        return (T)variable;
    }
    T operator()()
    {
        return ResolvePointer();
    }
};

用法:

unsigned long ipaddr = htonl(Pointer<unsigned long>(0x00400000+0x008E3A74,0x04,0x38,NULL)());//pointer to players IP address
if(ipaddr != NULL)//....

【讨论】:

  • 这种方法通常还应采取其他预防措施。
  • 哇。这些东西有效,这太荒谬了 - 附加到的进程是否需要不遗余力地公开访问权限?
  • @RonDahlgren,关于 DLL 注入,您无能为力。我相信这不会发生在特权不足的令牌上。至少玩起来很有趣。请记住,许多钩子都使用 DLL 注入。
  • 我已经有一段时间没有研究它了,当我做的时候并没有做很多事情,但是有一些 QueryBlahBlahBlah 函数,可能在其他中,有助于确保内存已验证。不过,我不确定 Cheat Engine 的扫描功能是否比这些功能和所有可能地址的组合更聪明。
  • 啊,是的,VirtualQuery
【解决方案3】:

您不能在另一个进程中访问变量,除非:

  1. 您的程序使用“调试函数”来访问这些值。
  2. 您使用某种 IPC(共享内存、管道、消息队列)来共享/传输数据。

每个进程都有自己的地址空间[1],如果没有某种机制来访问它,就无法访​​问另一个进程的地址空间。

[1] 假设我们谈论的是使用适当内存管理的“真实”操作系统。在某些操作系统(例如传统 DOS)中,进程之间没有内存保护。但是,除非系统运行在非常微弱的处理器和少量内存下,否则没有理智的人可以使用这些操作系统。

【讨论】:

  • OP 说他使用的是 Windows。
  • 是的,如果我不把脚注放在那里,有人会指出其他一些操作系统(如 DOS)没有内存保护。
  • @Mats 那么像this 这样的程序是如何工作的呢?我过去用它来定位/查看/修改任意进程中的值。
  • 我希望它使用调试功能 - 与“WinDBG”或 Visual Studio 的调试器功能相同。我使用过(甚至编写过)调试器,但我没有使用过您所链接的任何东西,更不用说分析这些产品的功能了。我不玩游戏——我当然不会在一个游戏中作弊。
  • @MatsPetersson,但乐趣在于努力工作并慢慢克服错误,直到作弊有效,而不是作弊本身;)无论如何,不​​同的游戏对这类事情采取不同的措施。当然,当你通过它作弊时,游戏并不好玩。
猜你喜欢
  • 1970-01-01
  • 2012-06-14
  • 2011-09-02
  • 1970-01-01
  • 2021-01-15
  • 2016-03-11
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
相关资源
最近更新 更多