【问题标题】:Modifying integer value from another process using process_vm_readv使用 process_vm_readv 从另一个进程修改整数值
【发布时间】:2018-02-16 09:22:45
【问题描述】:

我正在使用 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;
}

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

【问题讨论】:

    标签: c++ c linux process system-calls


    【解决方案1】:

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

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

      volatile int x = 0xAABBCCDDEE;
      
    2. 没有人保证在进程的只读内存中某处存在no 0xAABBCCDD。相反,人们可以非常肯定那里实际上存在这样的价值。程序还能在哪里获得它来初始化变量?初始化可能会转换为类似于此的汇编指令

      mov eax, 0xAABBCCDD
      

      不出所料,其中包含与 0xAABBCCDD 匹配的位模式。地址 0x6005DF 很可能在 .text 部分中。它极不可能在堆栈上,因为堆栈地址通常靠近地址空间的顶部。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-05
      • 2015-04-22
      • 2019-01-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多