如何读取C程序的堆栈段?

3

我正在开发一个业余操作系统,为了了解Linux中的内存分配机制,我创建了一个简单的C程序,定义了一些十六进制数字的unsigned char并在一个空的无限循环中运行,这样可以让进程保持活动状态。然后我使用pmap命令获取页面映射信息。现在我知道了堆栈段的位置,并创建了一个程序,使用process_vm_readv系统调用读取该地址的内容,但是当我读取堆栈段的内容时,只看到一串00和一些随机数。我应该如何找出数组是如何存储在堆栈段中的?

如果可能的话,我该如何分析十六进制流以提取有意义的信息?


@Someprogrammerdude,操作系统正在从头开始构建,到目前为止我已经构建了基本的I/O、堆和显示驱动程序。现在我要开始处理用户空间,所以想深入了解一些Linux使用的实践方法。 - Narasimha Prasanna HN
1
@Gerhardh 强制将其放入堆栈的方法是取其地址。 - S.S. Anne
1
我假设你已经有了堆栈段的起始地址。为了读取自动变量(无符号字符)的内容,你还需要知道堆栈帧结构。 - Ajith C Narayanan
3
你可能需要将你的char数组声明为volatile。如果不这样做,编译器会检测到你没有对数组内部的数据进行任何操作,并将其优化掉。 - th33lf
1
@NarasimhaPrasannaHN,不清楚您想要实现什么。操作系统只是为程序“分配”栈空间。类似于在堆栈中放置单个变量的位置或堆栈本身的组织方式等决策由程序自身制定。在您的情况下,这些决策是由编译器制定的。操作系统只是为您分配一块内存,并让您的程序运行。 - th33lf
显示剩余5条评论
1个回答

3

我这里为大家演示如何访问远程进程的地址空间,有两个程序local.c和remote.c,local.c将读写remote.c程序中的变量(这些程序假设sizeof(int)==4

local.c程序如下:

#define _GNU_SOURCE
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>

int main()
{
    char buf[4];
    struct iovec local[1];
    struct iovec remote[1];
    int pid;
    void *addr;

    printf("Enter remote pid\n");
    scanf("%d",&pid);

    printf("Enter remote address\n");
    scanf("%p", &addr);

    local[0].iov_base = buf;
    local[0].iov_len = 4;

    remote[0].iov_base = addr;
    remote[0].iov_len = 4;



    if(syscall(SYS_process_vm_readv,pid,local,1,remote,1,0) == -1) {
    perror("");
        return -1;
    }
    printf("read : %d\n",*(int*)buf);

    *(int*)buf = 4321;

    if(syscall(SYS_process_vm_writev,pid,local,1,remote,1,0) == -1) {
    perror("");
        return -1;
    }
    return 0;
}

remote.c

#define _GNU_SOURCE
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>

int main()
{

    int a = 1234;

    printf("%d  %p\n",getpid(),&a);
    while(a == 1234);

    printf ("'a' changed to %d\n",a);
    return 0;
}

如果您在Linux机器上运行此命令,

[ajith@localhost Desktop]$ gcc remote.c -o remote -Wall
[ajith@localhost Desktop]$ ./remote
4574  0x7fffc4f4eb6c
'a' changed to 4321
[ajith@localhost Desktop]$


[ajith@localhost Desktop]$ gcc local.c -o local -Wall
[ajith@localhost Desktop]$ ./local
Enter remote pid
4574
Enter remote address
0x7fffc4f4eb6c
read : 1234
[ajith@localhost Desktop]$

使用类似的方法,您可以读取堆栈帧到io-vectors,但是您需要知道堆栈帧结构格式以从堆栈帧解析本地变量的值。堆栈帧包含函数参数、返回地址、本地变量等。


1
为什么要使用syscall而不是直接调用process_vm_readv - Chris Dodd
一些Linux发行版没有暴露process_vm_readv()系统调用 @ChrisDodd - Ajith C Narayanan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接