使用ptrace的远程mmap syscallLinux,C

问题描述

我已经被这个问题困扰了好几天了,但是仍然没有设法解决它。基本上,我想从攻击者程序到目标进行远程系统调用。但是在显示代码之前,我认为介绍我的思维过程是一个好主意,因为此时问题可能出在任何地方。 我正在通过以下步骤进行此远程syscall:

  1. 解析/ proc / / maps文件获取可执行区域。
  2. 将数据存储在可执行区域中,并写入一个自定义缓冲区以对其进行系统调用
  3. 存储旧寄存器并设置新寄存器以进行系统调用
  4. 写入新寄存器并继续执行
  5. 在syscall之后,目标程序将中断,这将使我获得mmap的输出,回退旧的寄存器,从而恢复旧的执行流程。

我正在使用我的内存库来解析mmap文件获取进程ID和进程信息等。就我而言,它可以正常工作。无论如何,这是来源:https://github.com/rdbo/libmem

还有我用来拨打电话的代码

mem_voidptr_t allocate_ex(mem_process_t process,mem_size_t size,mem_alloc_t allocation)
{
    mem_voidptr_t alloc_addr = (mem_voidptr_t)MEM_BAD_RETURN;
    if(!mem_process_is_valid(&process)) return alloc_addr;
    int status;
    int mmap_syscall = __NR_mmap;
    struct user_regs_struct old_regs,regs;
    mem_byte_t injection_buf[] = 
    {
        0x0f,0x05,//syscall
        0xcc        //int3
    };


    //Parse /proc/<process.pid>/maps to get executable region

    char path_buffer[64];
    snprintf(path_buffer,sizeof(path_buffer),"/proc/%i/maps",process.pid);
    int fd = open(path_buffer,O_RDONLY);
    if(fd == -1) return alloc_addr;

    int read_check = 0;
    mem_size_t file_size = 0;
    mem_string_t file_buffer = mem_string_init();

    for(char c; (read_check = read(fd,&c,1)) != -1 && read_check != 0; file_size++)
    {
        mem_string_resize(&file_buffer,file_size);
        mem_string_c_set(&file_buffer,file_size,c);
    }

    mem_size_t   injection_address_pos,injection_address_end;
    mem_string_t injection_address_str = mem_string_init();
    mem_voidptr_t injection_address = (mem_voidptr_t)MEM_BAD_RETURN;

    injection_address_pos = mem_string_find(&file_buffer,"r-xp",0);
    injection_address_pos = mem_string_rfind(&file_buffer,"\n",injection_address_pos);
    if(injection_address_pos == file_buffer.npos) return alloc_addr;

    injection_address_end = mem_string_find(&file_buffer,"-",injection_address_pos);
    injection_address_str = mem_string_substr(&file_buffer,injection_address_pos,injection_address_end);
    injection_address = (mem_voidptr_t)strtoull(mem_string_c_str(&injection_address_str),NULL,16);
    if(injection_address == (mem_voidptr_t)MEM_BAD_RETURN || injection_address == (mem_voidptr_t)0)
        return alloc_addr;

    printf("Injection address: %p\n",injection_address);

    //Store the old data at 'injection_address' and write the injection buffer to it

    mem_byte_t old_data[sizeof(injection_buf)];
    mem_ex_read(process,injection_address,(mem_voidptr_t)old_data,sizeof(old_data));
    mem_ex_write(process,(mem_voidptr_t)injection_buf,sizeof(injection_buf));

    //Attach to process and store current registers

    ptrace(PTRACE_ATTACH,process.pid,NULL);
    ptrace(PTRACE_GETREGS,&old_regs);
    memcpy(&regs,&old_regs,sizeof(regs));

    //Setup syscall registers

    regs.rax = mmap_syscall;          //syscall number
    regs.rdi = 0;                     //address        (arg0)
    regs.rsi = size;                  //length         (arg1)
    regs.rdx = allocation.protection; //protection     (arg2)
    regs.r10 = allocation.type;       //flags          (arg3)
    regs.r8  = -1;                    //fd             (arg4)
    regs.r9  = 0;                     //offset         (arg5)

    regs.rip = (unsigned long long)injection_address; //next instruction to execute

    //Call mmap on external process

    ptrace(PTRACE_SETREGS,&regs);
    ptrace(PTRACE_CONT,NULL);
    waitpid(process.pid,&status,WSTOPPED);

    //Get the registers after syscall to store the return of mmap

    ptrace(PTRACE_GETREGS,&regs);
    alloc_addr = (mem_voidptr_t)regs.rax; //store the return of mmap

    //Restore the original buffer at 'injection_address'

    mem_ex_write(process,sizeof(old_data));

    //Continue the original execution

    ptrace(PTRACE_SETREGS,&old_regs);
    ptrace(PTRACE_CONT,NULL);

    //Return allocation address,if valid
    if((mem_uintptr_t)alloc_addr >= (mem_uintptr_t)-2048)
        alloc_addr = (mem_voidptr_t)MEM_BAD_RETURN;
    return alloc_addr;
}

以及攻击者程序的主要功能

int main()
{
    mem_pid_t pid = mem_ex_get_pid(mem_string_new("target"));
    mem_process_t process = mem_ex_get_process(pid);

    int buffer = 10;
    mem_alloc_t allocation = mem_alloc_init();
    allocation.protection = PROT_READ | PROT_WRITE;
    allocation.type       = MAP_ANON  | MAP_PRIVATE;
    mem_voidptr_t alloc_addr = allocate_ex(process,sizeof(buffer),allocation);
    printf("Allocation Address: %p\n",alloc_addr);
    if(alloc_addr == (mem_voidptr_t)MEM_BAD_RETURN)
    {
        printf("Invalid allocation\n");
        return -1;
    }

    //Check if worked by reading/writing to that buffer
    int read_buffer = 0;
    mem_ex_write(process,alloc_addr,&buffer,sizeof(buffer));
    mem_ex_read(process,&read_buffer,sizeof(read_buffer));
    printf("Read buffer: %i\n",read_buffer);
    if(read_buffer == buffer)
        printf("Success!\n");

    return 0;   
}

目标程序:

int main()
{
    printf("Waiting for injection\n");
    while(1);
}

攻击者程序的输出为:

Injection address: 0x55f6e104a000
Allocation Address: (nil)
Read buffer: 0

,并且在目标程序上引发了分段错误。可执行区域有效(我手动检查过),该过程也有效。 另外,我在调试目标程序时遇到了一些麻烦,显然GDB不允许ptrace从攻击者程序中执行其工作。运行Arch Linux。这两个程序都是用clang(x64)编译的。有什么想法吗?

解决方法

原来的问题是我正在使用process_vm_read和process_vm_write读取/写入内存。我通过将读取/写入方法更改为ptrace PEEK / POKE数据来使其工作。固定代码(包含在我的内存库中):

mem_voidptr_t injection_address;
    struct user_regs_struct old_regs,regs;
    int status;

    const mem_byte_t injection_buffer[] = 
    {
        0x0f,0x05,//syscall
        0xcc        //int3 (SIGTRAP)
    };

    mem_byte_t old_data[sizeof(injection_buffer)];

    //Find injection address

    char path_buffer[64];
    snprintf(path_buffer,sizeof(path_buffer),"/proc/%i/maps",process.pid);
    int fd = open(path_buffer,O_RDONLY);
    if(fd == -1) return alloc_addr;

    int read_check = 0;
    mem_size_t file_size = 0;
    mem_string_t file_buffer = mem_string_init();

    for(char c; (read_check = read(fd,&c,1)) != -1 && read_check != 0; file_size++)
    {
        mem_string_resize(&file_buffer,file_size);
        mem_string_c_set(&file_buffer,file_size,c);
    }

    mem_size_t   injection_address_pos,injection_address_end;
    mem_string_t injection_address_str = mem_string_init();
    injection_address = (mem_voidptr_t)MEM_BAD_RETURN;

    injection_address_pos = mem_string_find(&file_buffer,"r-xp",0);
    injection_address_pos = mem_string_rfind(&file_buffer,"\n",injection_address_pos);
    if(injection_address_pos == file_buffer.npos) return alloc_addr;

    injection_address_end = mem_string_find(&file_buffer,"-",injection_address_pos);
    injection_address_str = mem_string_substr(&file_buffer,injection_address_pos,injection_address_end);
    injection_address = (mem_voidptr_t)strtoull(mem_string_c_str(&injection_address_str),NULL,16);
    if(injection_address == (mem_voidptr_t)MEM_BAD_RETURN || injection_address == (mem_voidptr_t)0) return alloc_addr;

    //Inject
    ptrace(PTRACE_ATTACH,process.pid,NULL);

    //Store data at injection_address
    for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
        ((mem_byte_t*)old_data)[i] = (mem_byte_t)ptrace(PTRACE_PEEKDATA,injection_address + i,NULL);

    //Write injection buffer to injection address
    for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
        ptrace(PTRACE_POKEDATA,((mem_byte_t*)injection_buffer)[i]);

    ptrace(PTRACE_GETREGS,&old_regs);
    regs = old_regs;

    regs.rax = __NR_mmap;                        //syscall number
    regs.rdi = (mem_uintptr_t)0;                 //arg0 (void* address)
    regs.rsi = (mem_uintptr_t)size;              //arg1 (size_t size)
    regs.rdx = (mem_uintptr_t)protection;        //arg2 (int protection)
    regs.r10 = MAP_PRIVATE | MAP_ANON;           //arg3 (int flags)
    regs.r8  = -1;                               //arg4 (int fd)
    regs.r9  = 0;                                //arg5 (off_t offset)
    regs.rip = (mem_uintptr_t)injection_address; //next instruction

    ptrace(PTRACE_SETREGS,&regs);
    ptrace(PTRACE_CONT,NULL);
    waitpid(process.pid,&status,WSTOPPED);
    ptrace(PTRACE_GETREGS,&regs);
    alloc_addr = (mem_voidptr_t)regs.rax;

    //Restore old execution
    ptrace(PTRACE_SETREGS,&old_regs);

    for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
        ptrace(PTRACE_POKEDATA,((mem_byte_t*)old_data)[i]);

    //ptrace(PTRACE_CONT,NULL);
    ptrace(PTRACE_DETACH,NULL);

    if(alloc_addr == (mem_voidptr_t)__NR_mmap)
        alloc_addr = (mem_voidptr_t)MEM_BAD_RETURN;

    return alloc_addr;