unix 获取进程内存地址的值并修改

gtlvzcf8  于 2023-03-08  发布在  Unix
关注(0)|答案(1)|浏览(190)

我试图模仿Cheat Engine在Mac OS上从值中获取内存地址并修改它的做法。到目前为止,我已经做到了:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include <libproc.h>
#include <mach/mach_init.h>

// Get array of all process ids
uint32_t* get_pids(uint16_t* size) {
    uint32_t number_of_pids = proc_listpids(1, 0, NULL, 0);
    uint32_t* buffer = malloc(sizeof(uint32_t) * number_of_pids);
    uint8_t return_code = proc_listpids(1, 0, buffer, sizeof(buffer) * number_of_pids);
    uint16_t sum = 0;
    for(int i = 0; i < number_of_pids; i++) {
        if(buffer[i] != 0) {
            sum++;
        }
    }
    uint32_t* final = malloc(sizeof(uint32_t) * sum);
    for(int i = 0, t = 0; i < number_of_pids; i++) {
        if(buffer[i]) {
            final[t++] = buffer[i];
        }
    }
    *size = sum;
    return final;
}
int main() {
    uint16_t size;
    uint32_t* pids = get_pids(&size);
    uint16_t maxpathlength = 1024;
    uint16_t path_size = maxpathlength * 4;
    char path_buffer[path_size];

    uint32_t pid = 0;
    for(int i = 0; i < size; i++) {
        memset(path_buffer, '\0', sizeof(path_buffer));
        uint8_t return_code = proc_pidpath(pids[i], path_buffer, path_size);
        if(strstr(path_buffer, "Geometry Dash")) {
            pid = pids[i];
        }
        //printf("PID: %d, Process: %s\n", pids[i], path_buffer);

    }
    mach_port_name_t port = 0;
    if(task_for_pid(mach_task_self(), pid, &port)) {
        printf("Run as root!\n");
    }
    printf("%d\n", port);
    return 0;
}

所以我到了那里,现在有目标pid的mach端口,但是我不知道从这里去哪里,因为我发现几乎0关于mach_vm方法的好文档,我尝试的任何东西都失败了。我应该如何去做呢?

yacmzcpb

yacmzcpb1#

所以我找到了如何做到这一点,这是非常简单的,但同样几乎没有任何文档,要读取进程内存,你有这样的:

void* read_process_memory(vm_map_read_t task, mach_vm_address_t address, mach_vm_size_t size) {
    vm_offset_t data;
    mach_msg_type_number_t dataCnt;

    kern_return_t ret = mach_vm_read(task, address, size, &data, &dataCnt);
    if(ret != KERN_SUCCESS) {
        printf("mach_vm_read() failed: %s\n", mach_error_string(ret));
    }
    return (void*) data;
}

很明显,task是目标pid的端口,您可以通过简单的命令获得:

mach_port_t task;
kern_return_t kern_return = task_for_pid(mach_task_self(), pid, &task);

但是你必须运行sudo才能正常工作。data是读取内存将要进入的缓冲区,dataCnt是输入时读取内存的最大大小和输出时读取的实际内存大小。你还必须根据虚拟内存的数据类型进行适当的强制转换才能正确读取它。因此对于字符串,你必须将上述函数的返回值强制转换为char *,但是对于整数,它将是int *
将内存写入进程几乎是相同的:

void write_process_memory(vm_map_read_t task, mach_vm_address_t address, vm_offset_t data, mach_vm_size_t dataCnt) {

    kern_return_t ret = mach_vm_write(task, address, data, dataCnt);
    if(ret != KERN_SUCCESS) {
        printf("mach_vm_write() failed: %s\n", mach_error_string(ret));
    }
}

但是这次dataCnt是将要写入的输入的字节,而data保存您想要写入到目标进程虚拟存储器地址的字节。
示例:
从python进程内存读写字符串(48是python3中变量内存地址的实际字符串偏移量):

char* addy = read_process_memory(task, 0x1006c8130 + 48, 5);
printf("%s\n", addy);

以及

char* data = "pizza";
write_process_memory(task, 0x1006c8130 + 48, (vm_offset_t) data, 5);
    • 与整数**
uint32_t* addy = read_process_memory(task, 0x1048cc7b0 + 24, 4);
printf("%d\n", *addy);

以及

uint32_t data = 1000;
write_process_memory(task, 0x1048cc7b0 + 24, (vm_offset_t) &data, 4);

而24是偏移量,以从变量地址获得Python存储器中的实际整数。

相关问题