使用process_vm_readv从另一个过程中修改整数值

Modifying integer value from another process using process_vm_readv

本文关键字:过程中 修改 整数 另一个 process vm readv 使用      更新时间:2023-10-16

我正在使用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)找到针头,并注意地址。然后,它会尝试将十六进制值(0xeeeeeee)写入同一位置,但是当将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;
}

底线是我无法修改另一个过程重复打印的整数。

我至少可以看到这些问题。

  1. 没有人保证该过程的可写入内存中的任何地方都有0xaabbccdd。编译器可以将其完全优化或放入寄存器中。ensure的一种方法将在主内存中放置一个变量是将其声明为 volatile

    volatile int x = 0xAABBCCDDEE;
    
  2. 没有人保证有 no 0xaabbccdd在 read-nolly 内存中的某个地方。相反,可以很确定那里确实存在这样的价值。该程序还可以在哪里获取它来初始化变量?初始化可能转化为类似于此

    的汇编指令
    mov eax, 0xAABBCCDD
    

    毫不奇怪,它包含与0xaabbccdd匹配的位模式。地址0x6005DF很可能在.TEXT部分中。它不太可能在堆栈上,因为堆栈地址通常靠近地址空间的顶部。

  3. 64位过程的地址空间很大。没有希望在合理的时间内遍历这一切。一个人需要以某种方式限制地址的范围。