【问题标题】:Changing value in memory through an SO in C通过 C 中的 SO 更改内存中的值
【发布时间】:2009-10-26 22:07:04
【问题描述】:

我正在编写一个被另一个程序调用的 .SO,我希望能够通过 .SO 中的函数翻转内存中的值

到目前为止我所拥有的是:

int 
axptrace( int numArguments, char* pMessageBuffer, int* pMessageBufferSize,
  char* pData[], int* pDataLength[] )  
{  
printf("Beginning dump attempt..\n");  
unsigned int* wkptr =(int*)0x7f793db70040;  
printf("At %llx, the value was %d\n\n",(long long)wkptr,*wkptr);  
if(*wkptr == 1){  
    printf("Switching the value.\n");  
    *wkptr = 0;  
    printf("At %llx, the value is now %d\n\n",(long long)wkptr,*wkptr);  
    printf("Switched!\n\n");   
}  
    printf("Ending dump attempt..\n");  
}

程序运行时,我收到了我预期的消息:

开始转储尝试..
在 7f793db70040 时,值为 1

切换值。
在 7f793db70040,值现在是 0

切换!

结束转储尝试..

开始转储尝试..

在 7f793db70040,值为 0

结束转储尝试..

如果我再次运行相同的函数,而不是在第一部分看到值 0,我会再次看到值 1。我以为它改变了 0x7f793db70040 的值,但显然它又回到了旧值。

另外,0xf793db70040 是通过调试器获得的。有没有办法查看“符号”或类似的东西是否指向该地址,以及在我的代码中使用它的方法?

【问题讨论】:

  • 您究竟为什么要这样做?以这种方式使用常量内存地址在很多层面上都是错误的......你想达到什么目的?
  • 您是否知道根据您的操作系统,相同的逻辑地址可能会出现多次?几乎所有操作系统都进行内存映射,而您正在使用的操作系统也可能会这样做,至少我不知道没有 MM 的 64 位操作系统。因此,您启动的每个进程都会有一个“7f793db70040”,并且 ist 可能总是映射到不同的物理内存位置。如果您的进程结束,内存将被重新映射,您的更改将消失。

标签: c reflection memory struct


【解决方案1】:

您正在设置一个完全任意的内存地址,并且您希望发生有意义的事情?记忆无时无刻不在变化。除非您真的知道该内存的用途,否则您的戳入值会被覆盖也就不足为奇了。

现在,鉴于那里的高值,它可能是堆栈上的一个值,这意味着它将是:

  1. 经常更换
  2. 用于多种用途
  3. 在不同地址用于相同目的

如果有一个内存地址的符号(不会有堆栈或堆上的地址),并且它被导出(不太可能用于可执行文件),您可以使用dlsym 获取它 - 如果没有导出,并且可执行文件没有被剥离,您可能能够解析 ELF 标头以找到它(这非常困难。您实际上是在实现一个调试器)。

一般来说,像这样插入价值观几乎从来都不是正确的做事方式。事实上,通常在可执行文件中编辑代码比尝试像这样在内存中确定值要容易一些。您真正想达到什么目的?

编辑:如果要设置调试变量,两个更好的选择是:

  1. 全局调试变量放入.so。正常访问(即主应用只有extern int foo;.so有真正的int foo;
  2. 反过来;将 global 调试变量放入 exe,在.so 中使用extern int foo;,并且(重要!)将-Wl,-E 传递给gccg++ 以链接可执行文件(这将允许可执行文件反向导出符号)。
  3. 让可执行文件调用.so 中的函数,传递变量的地址。然后.so 可以将地址存储在以后可以找到的地方。此选项不要求变量是全局变量。

不要使用调试器派生的地址。它可能是错误的地址,即使它是正确的地址,如果你重新编译任何东西,它改变。由于ASLR,它甚至可能在同一系统上两次运行相同的二进制文件之间发生变化。你根本不能依赖这个工作。

【讨论】:

  • 地址不是任意的,我发现它是指向我的结构的指针。但我不得不用调试器手动“扫描”内存。我不相信值会在任何地方被重置,但话又说回来,我不知道代码,所以这很可能是问题所在。但是,在应用程序之外没有任何东西在该地址中推送旧值,IE glibc 强制执行某种类型的“保护”,以防止使用 dlopen 或类似的东西更改堆栈上的内容?我要做的是翻转一个布尔值,读取该值以确定是否应显示应用程序的内部调试信息。
  • 我为您的案例添加了一些更具体的建议。
【解决方案2】:

这太不对劲了,我的肾都疼了。

不要修改内存中的硬编码值。不要取消引用 0xf793db70040。你不知道这指向什么,而且到目前为止,像这样修改硬编码指针的最可能结果将是一场激烈的崩溃。如果你幸运的话。如果你不走运,你会以一种微妙的方式破坏你的程序,从而在几秒、几分钟或几小时后导致崩溃或数据丢失。

弄清楚你想要改变什么值,然后通过数据指针直接改变它。您的最后一句话倾向于正确的方式:找到该值对应的“符号”,并检查该值。

真正的问题是:你想做什么,你为什么要通过调试器来找到你想要改变的值?

【讨论】:

  • 这不是一个任意指针,我知道该值映射到什么结构。我不知道如何读取该值在符号表之外的位置,我想这是我的第二个问题。我有一个从该地址开始的结构,我想在运行时将第一个字节更改为 1。我正在使用调试器,因为我不知道在运行时找到该变量在哪里的方法。我知道一个函数在签名中具有该参数,因此我通过查看该函数的激活记录得到了该值写下地址。太糟糕了,它每次都会改变。
  • @Antonio,在这种情况下,您可能想尝试调用 dlsym()。或者简单地声明变量 extern 并像访问任何其他变量一样按名称访问它。
猜你喜欢
  • 2014-02-18
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 2021-12-14
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
相关资源
最近更新 更多