我尝试修改存储在某个内存地址的值。
地址存储在某个指针中,但用新的int改变它会改变内存地址(当然)。
int *toModify = (int *)(foo+5); //foo is a adress of a function.
//The val to alter is 5bytes after it
int newVal = 5;
toModify = &newVal;
//implementation of foo
int foo(){
return 42;
}
让我们说toModify有价值42.我想把它改为5。 如何在toModify的地址中存储更改?
答案 0 :(得分:3)
您无法以符合标准的便携式方式执行此操作。即使您希望以非可移植的方式执行此操作(您可以通过直接操作机器代码来执行此操作),foo
可能在只读内存中,因此无法修改。
最好定义foo
来访问可以更改的全局变量或静态变量。例如:
static int n = 42;
int foo() {
return n;
}
// when you want to modify it
n = 5;
答案 1 :(得分:1)
而不是
toModify = &newVal;
使用
*toModify = 5;
答案 2 :(得分:1)
假设foo
是函数的名称,那么首先执行此操作:
int *toModify = (int *)((char *) foo + 5);
首先将foo
从指向函数的指针转换为指向char
的指针。这允许您将其作为指针使用。通常,您不能使用指向函数的指针执行算术运算,因此您需要一个指向对象类型的指针。 C标准不保证此转换将起作用,因此您必须确保C实现支持它。
我们将其转换为指向char
的指针,以便添加五个字节,而不是五个字节的另一个对象类型。然后我们将总和转换为指向int
的指针,以便将其分配给toModify
。
然后这样做:
int newVal = 5;
memcpy(toModify, &newVal, sizeof newVal);
这会尝试将值为{的int
复制到toModify
指向的位置。这避免了尝试直接使用*toModify = 5;
分配值时的一个问题,即分配将字节置为违反C标准规则的别名,因此行为不是由标准定义的,尽管它可能是一些C实现支持。但是,它还有其他问题。
首先,程序可能无法写入此地址的字节数。现代操作系统通常使用内存保护来防止代码被不正确地修改,这种保护会导致memcpy
失败。
其次,即使字节是可写的并且memcpy
修改它们,也不能保证执行指令的处理器部分会看到它们。指令流中的字节通常由现代处理器缓存,并且更改内存中的字节不会更改缓存中的字节。通常,必须执行特殊指令来刷新指令缓存。执行此操作的方法取决于目标处理器和操作系统。
如果您这样做是为了尝试修改代码只是作为一种学习练习,除非您在支持此功能的特殊嵌入式环境中工作,否则这不是正确的方法。如果你出于另一个原因试图这样做,你几乎肯定应该放弃它并寻求另一种方法。
答案 3 :(得分:0)
Perreal的(删除)答案是正确的:
*toModify = newVal;
...但是......你正在尝试在应用程序的代码空间中编写代码,现代操作系统会竭尽全力阻止这种情况,因为这是主要的安全风险。这可能就是你可能会遇到分段错误的原因。
另外,你在一个地址(foo+5)
上写了一个int(你的系统可能是一个4字节的值?),它没有与4字节边界对齐。同样,您的硬件可能不支持此功能,
如果你想修改一个字节,你需要这个。
char * toModify;
答案 4 :(得分:0)
代码在unix上通常是只读的。它通常在嵌入式系统上是只读的,因为它实际上位于闪存中。
在UNIX上,您可以使用ptrace()和PTRACE_POKETEXT来解决这个问题。
答案 5 :(得分:0)
我通过修改存储在mprotect中的值存储页面来解决它。然后你可以访问该地址并写信给它