使用ptrace的远程mmap syscallLinux,C

如何解决使用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;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-