我正在使用Ubuntu Linux编写两个程序。我试图从另一个进程更改一个整数的值。我的第一个进程(A)是一个简单的程序,它永远循环并将值显示在屏幕上。此程序按预期工作,只是将值-1430532899(0xAABBCCDD)显示在屏幕上。
#include <stdio.h>
int main()
{
//The needle that I am looking for to change from another process
int x = 0xAABBCCDD;
//Loop forever printing out the value of x
int counter = 0;
while(1==1)
{
while(counter<100000000)
{
counter++;
}
counter = 0;
printf("%d",x);
fflush(stdout);
}
return 0;
}
在一个单独的终端中,我使用ps -e
命令列出进程并记下进程(A)的进程ID。接下来作为root用户(sudo)运行下一个程序(B)并输入我从进程(A)中记下的进程ID。
程序基本上搜索内存向后的针(DD CC BB AA)找到针,并记下地址。然后它尝试将十六进制值(0xEEEEEEEE)写入同一位置,但是当errno设置为14
时,我收到错误的地址错误。奇怪的是在地址空间稍晚,我能够成功地将值写入地址(0x601000),但是针(0xAABBCCDD)在0x6005DF处的地址我不能写在那里。 (但显然可以阅读,因为那是我找到针头的地方)
#include <stdio.h>
#include <iostream>
#include <sys/uio.h>
#include <string>
#include <errno.h>
#include <vector>
using namespace std;
char getHex(char value);
string printHex(unsigned char* buffer, int length);
int getProcessId();
int main()
{
//Get the process ID of the process we want to read and write
int pid = getProcessId();
//Lists of addresses where we find our needle 0xAABBCCDD and the addresses where we simply cannot read
vector<long> needleAddresses;
vector<long> unableToReadAddresses;
unsigned char buf1[1000]; //buffer used to store memory values read from other process
//Number of bytes read, also is -1 if an error has occurred
ssize_t nread;
//Structures used in the process_vm_readv system call
struct iovec local[1];
struct iovec remote[1];
local[0].iov_base = buf1;
local[0].iov_len = 1000;
remote[0].iov_base = (void * ) 0x00000; //start at address 0 and work up
remote[0].iov_len = 1000;
for(int i=0;i<10000;i++)
{
nread = process_vm_readv(pid, local, 1, remote, 1 ,0);
if(nread == -1)
{
//errno is 14 then the problem is "bad address"
if(errno == 14)
unableToReadAddresses.push_back((long)remote[0].iov_base);
}
else
{
cout<<printHex(buf1,local[0].iov_len);
for(int j=0;j<1000-3;j++)
{
if(buf1[j] == 0xDD && buf1[j+1] == 0xCC && buf1[j+2] == 0xBB && buf1[j+3] == 0xAA)
{
needleAddresses.push_back((long)(remote[0].iov_base+j));
}
}
}
remote[0].iov_base += 1000;
}
cout<<"Addresses found at...";
for(int i=0;i<needleAddresses.size();i++)
{
cout<<needleAddresses[i]<<endl;
}
//How many bytes written
int nwrite = 0;
struct iovec local2[1];
struct iovec remote2[1];
unsigned char data[] = {0xEE,0xEE,0xEE,0xEE};
local2[0].iov_base = data;
local2[0].iov_len = 4;
remote2[0].iov_base = (void*)0x601000;
remote2[0].iov_len = 4;
for(int i=0;i<needleAddresses.size();i++)
{
cout<<"Attempting to write "<<printHex(data,4)<<" to address "<<needleAddresses[i]<<endl;
remote2[0].iov_base = (void*)needleAddresses[i];
nwrite = process_vm_writev(pid,local2,1,remote2,1,0);
if(nwrite == -1)
{
cout<<"Error writing to "<<needleAddresses[i]<<endl;
}
else
{
cout<<"Successfully wrote data";
}
}
//For some reason THIS will work
remote2[0].iov_base = (void*)0x601000;
nwrite = process_vm_writev(pid,local2,1,remote2,1,0);
cout<<"Wrote "<<nwrite<<" Bytes to the address "<<0x601000 <<" "<<errno;
return 0;
}
string printHex(unsigned char* buffer, int length)
{
string retval;
char temp;
for(int i=0;i<length;i++)
{
temp = buffer[i];
temp = temp>>4;
temp = temp & 0x0F;
retval += getHex(temp);
temp = buffer[i];
temp = temp & 0x0F;
retval += getHex(temp);
retval += ' ';
}
return retval;
}
char getHex(char value)
{
if(value < 10)
{
return value+'0';
}
else
{
value = value - 10;
return value+'A';
}
}
int getProcessId()
{
int data = 0;
printf("Please enter the process id...");
scanf("%d",&data);
return data;
}
底线是我无法修改另一个进程的重复打印整数。
答案 0 :(得分:2)
我至少可以看到这些问题。
没有人保证在进程的可写内存中的任何地方都有0xAABBCCDD。编译器可以完全优化它,或者放入寄存器。确定变量的一种方法是放在主存储器中,将其声明为volatile
。
volatile int x = 0xAABBCCDDEE;
没有人能保证在进程的只读内存中某处没有 0xAABBCCDD。相反,人们可以确定实际上存在这样的价值。程序还可以在哪里获得它来初始化变量?初始化可能转换为与此类似的汇编指令
mov eax, 0xAABBCCDD
不出所料,包含与0xAABBCCDD匹配的位模式。地址0x6005DF可能位于.text部分。它不太可能在堆栈上,因为堆栈地址通常接近地址空间的顶部。
64位进程的地址空间很大。没有希望在合理的时间内遍历所有这些。人们需要以某种方式限制地址范围。