[英]Remote mmap syscall using ptrace (Linux, C)
I've been stuck with this problem for some days, and still haven't manage to fix it.我已经被这个问题困扰了几天,仍然没有设法解决它。 Basically, I want to do a remote syscall from an attacker program to the target.基本上,我想从攻击者程序到目标进行远程系统调用。 But before showing the code, I think it'd be a good idea to present my thought process, as the problem could be anything at this point.但在展示代码之前,我认为展示我的思考过程是个好主意,因为此时问题可能是任何问题。 I am doing this remote syscall through the following steps:我正在通过以下步骤执行此远程系统调用:
I am using my memory lib to parse the mmap files, get process id and process information, etc. As far as I am concerned, it is working properly.我正在使用我的 memory 库来解析 mmap 文件,获取进程 ID 和进程信息等。就我而言,它工作正常。 In any case, here's the source: https://github.com/rdbo/libmem无论如何,这里的来源: https://github.com/rdbo/libmem
And the code I am using to do the call:我用来进行通话的代码:
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, injection_address, (mem_voidptr_t)injection_buf, sizeof(injection_buf));
//Attach to process and store current registers
ptrace(PTRACE_ATTACH, process.pid, NULL, NULL);
ptrace(PTRACE_GETREGS, process.pid, NULL, &old_regs);
memcpy(®s, &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, process.pid, NULL, ®s);
ptrace(PTRACE_CONT, process.pid, NULL, NULL);
waitpid(process.pid, &status, WSTOPPED);
//Get the registers after syscall to store the return of mmap
ptrace(PTRACE_GETREGS, process.pid, NULL, ®s);
alloc_addr = (mem_voidptr_t)regs.rax; //store the return of mmap
//Restore the original buffer at 'injection_address'
mem_ex_write(process, injection_address, (mem_voidptr_t)old_data, sizeof(old_data));
//Continue the original execution
ptrace(PTRACE_SETREGS, process.pid, NULL, &old_regs);
ptrace(PTRACE_CONT, process.pid, NULL, 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;
}
and the main function of the attacker program:以及攻击者程序的主要function:
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, alloc_addr, &read_buffer, sizeof(read_buffer));
printf("Read buffer: %i\n", read_buffer);
if(read_buffer == buffer)
printf("Success!\n");
return 0;
}
The target program:目标程序:
int main()
{
printf("Waiting for injection\n");
while(1);
}
The output of the attacker program is:攻击者程序的output为:
Injection address: 0x55f6e104a000
Allocation Address: (nil)
Read buffer: 0
and a Segmentation Fault is raised on the target program.并且在目标程序上引发了分段错误。 The executable region is valid (I manually checked) and the process is valid too.可执行区域有效(我手动检查)并且该过程也有效。 Also, I am having some trouble debugging the target program, apparently GDB wouldn't let ptrace do its job from the attacker program.另外,我在调试目标程序时遇到了一些麻烦,显然 GDB 不会让 ptrace 从攻击者程序中完成它的工作。 Running Arch Linux.运行拱 Linux。 Both programs are compiled with clang (x64).这两个程序都是用 clang (x64) 编译的。 Any ideas?有任何想法吗?
Turns out the problem was that I was reading/writing the memory using process_vm_read and process_vm_write.原来问题是我正在使用 process_vm_read 和 process_vm_write 读/写 memory。 I got it to work by changing the read/write method to ptrace PEEK/POKE data.我通过将读/写方法更改为 ptrace PEEK/POKE 数据来使其工作。 Fixed code (included on my memory lib):固定代码(包含在我的 memory 库中):
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, 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, process.pid, injection_address + i, NULL);
//Write injection buffer to injection address
for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
ptrace(PTRACE_POKEDATA, process.pid, injection_address + i, ((mem_byte_t*)injection_buffer)[i]);
ptrace(PTRACE_GETREGS, process.pid, NULL, &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, process.pid, NULL, ®s);
ptrace(PTRACE_CONT, process.pid, NULL, NULL);
waitpid(process.pid, &status, WSTOPPED);
ptrace(PTRACE_GETREGS, process.pid, NULL, ®s);
alloc_addr = (mem_voidptr_t)regs.rax;
//Restore old execution
ptrace(PTRACE_SETREGS, process.pid, NULL, &old_regs);
for(mem_size_t i = 0; i < sizeof(injection_buffer); i++)
ptrace(PTRACE_POKEDATA, process.pid, injection_address + i, ((mem_byte_t*)old_data)[i]);
//ptrace(PTRACE_CONT, process.pid, NULL, NULL);
ptrace(PTRACE_DETACH, process.pid, NULL, NULL);
if(alloc_addr == (mem_voidptr_t)__NR_mmap)
alloc_addr = (mem_voidptr_t)MEM_BAD_RETURN;
return alloc_addr;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.