Commit 897fb1fb authored by Chu's avatar Chu

new process.h, process.cpp

parent 740352d7
add_executable(inject main.cpp process.cpp process.h elf.cpp elf.h)
add_executable(inject main.cpp elf.cpp elf.h process.cpp process.h)
set_target_properties(inject PROPERTIES LINK_FLAGS "-static")
......@@ -3,7 +3,7 @@
#include <vector>
#include "elf.h"
#include "process.h"
#include "process_old.h"
void do_libc_dlopen_mode();
......
#include "process.h"
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include <regex>
#include "elf.h"
Process::~Process()
{
if (attached_)
detach();
}
std::pair<std::string, std::size_t> Process::find_libc()
std::pair<std::string, void *> Process::find_libc()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
filename += "/maps";
std::ifstream file(filename);
std::regex pattern(R"(^([0-9a-h]+)\-.*?(/.*libc\-[0-9\.]*?\.so)$)");
std::regex pattern(R"(^[0-9a-h]+\-.*?(/.*libc\-[0-9\.]*?\.so)$)");
std::string line;
std::smatch result;
while (std::getline(file, line))
{
if (std::regex_search(line, result, pattern))
return {result[2].str(), std::stoul(result[1].str(), nullptr, 16)};
return {result[1].str(), reinterpret_cast<void *>(std::stoul(line, nullptr, 16))};
}
throw std::runtime_error("libc.so not found in " + filename);
}
std::size_t Process::get_base()
unsigned char *Process::get_rx_area()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
filename += "/maps";
std::ifstream file(filename);
std::string line;
file >> line;
return std::stoul(line, nullptr, 16);
while (std::getline(file, line))
{
if (line.find(" r-x") != std::string::npos)
return reinterpret_cast<unsigned char *>(std::stoul(line, nullptr, 16));
}
throw std::runtime_error("rx area not found in " + filename);
}
std::string Process::get_execute()
unsigned char *Process::get_rw_area()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
filename += "/exe";
char execute[1024] = {0};
if (readlink(filename.c_str(), execute, 1023) != -1)
return execute;
throw std::runtime_error(std::strerror(errno));
}
std::size_t Process::get_entry_point()
{
Elf elf(get_execute());
elf.set_base(get_base());
return elf.get_entry();
}
void Process::call_shellcode(std::vector<unsigned char> shellcode)
{
std::cout << "[*] get target process's entry point\n";
auto entry_point = get_entry_point();
// replace `ret` with `int3`
if (shellcode[shellcode.size() - 1] == 0xc3)
shellcode[shellcode.size() - 1] = 0xcc;
// align
while (shellcode.size() % sizeof(void *) != 0)
shellcode.emplace_back(0x90);
std::cout << "[*] attach to target process\n";
attach();
std::cout << "[*] backup original code\n";
auto original_code = read_memory(entry_point, shellcode.size());
std::cout << "[*] backup original registers\n";
auto original_registers = get_registers();
std::cout << "[*] write shellcode to target process's entry point\n";
write_memory(entry_point, shellcode);
auto registers = original_registers;
registers.rip = entry_point;
std::cout << "[*] set %rip to target process's entry point\n";
set_registers(registers);
std::cout << "[*] continue and wait for trap\n";
continue_and_wait_for_trap();
std::cout << "[*] restore original code\n";
write_memory(entry_point, original_code);
std::cout << "[*] restore original registers\n";
set_registers(original_registers);
std::cout << "[*] detach target process\n";
detach();
filename += "/maps";
std::ifstream file(filename);
std::string line;
while (std::getline(file, line))
{
if (line.find(" rw") != std::string::npos)
return reinterpret_cast<unsigned char *>(std::stoul(line, nullptr, 16));
}
throw std::runtime_error("rw area not found in " + filename);
}
void Process::attach()
......@@ -96,6 +64,7 @@ void Process::attach()
if (ptrace(PTRACE_ATTACH, pid_, nullptr, nullptr) == -1)
throw std::runtime_error(std::strerror(errno));
wait(nullptr);
attached_ = true;
}
void Process::detach()
......@@ -103,46 +72,50 @@ void Process::detach()
if (ptrace(PTRACE_DETACH, pid_, nullptr, nullptr) == -1)
throw std::runtime_error(std::strerror(errno));
wait(nullptr);
attached_ = false;
}
std::vector<unsigned char> Process::read_memory(std::size_t address, std::size_t size)
void Process::write(unsigned char *address, std::vector<unsigned char> &data)
{
std::vector<unsigned char> data;
data.resize(size);
auto ptr = data.data();
std::size_t n = 0;
while (n != size)
check_for_attached();
auto data_ptr = data.data();
std::size_t total_wrote = 0;
while (total_wrote != data.size())
{
auto word = ptrace(PTRACE_PEEKTEXT, pid_, address, nullptr);
if (word == -1)
void *data_to_write = nullptr;
std::memcpy(&data_to_write, data_ptr, sizeof(data_to_write));
if (ptrace(PTRACE_POKETEXT, pid_, address, data_to_write) == -1)
throw std::runtime_error(std::strerror(errno));
auto to_copy = size - n > sizeof(void *) ? sizeof(void *) : size - n;
std::memcpy(ptr, &word, to_copy);
ptr += to_copy;
n += to_copy;
address += sizeof(void *);
address += sizeof(data_to_write);
data_ptr += sizeof(data_to_write);
total_wrote += sizeof(data_to_write);
}
return data;
}
void Process::write_memory(std::size_t address, std::vector<unsigned char> data)
std::vector<unsigned char> Process::read(unsigned char *address, std::size_t size)
{
auto ptr = data.data();
std::size_t n = 0;
while (n != data.size())
check_for_attached();
std::vector<unsigned char> data(size % sizeof(void *) == 0 ? size : size + (size - size % sizeof(void *)));
auto data_ptr = data.data();
std::size_t total_read = 0;
while (total_read != size)
{
void *to_write = nullptr;
std::memcpy(&to_write, ptr, sizeof(to_write));
if (ptrace(PTRACE_POKETEXT, pid_, address, to_write) == -1)
auto data_read = ptrace(PTRACE_PEEKTEXT, pid_, address, nullptr);
if (data_read == -1)
throw std::runtime_error(std::strerror(errno));
address += sizeof(to_write);
ptr += sizeof(to_write);
n += sizeof(to_write);
auto size_to_copy = size - total_read > sizeof(data_read) ? sizeof(data_read) : size - total_read;
std::memcpy(data_ptr, &data_read, size_to_copy);
address += size_to_copy;
data_ptr += size_to_copy;
total_read += size_to_copy;
}
data.resize(size);
return data;
}
user_regs_struct Process::get_registers()
{
check_for_attached();
user_regs_struct registers = {0};
if (ptrace(PTRACE_GETREGS, pid_, nullptr, &registers) == -1)
throw std::runtime_error(std::strerror(errno));
......@@ -151,10 +124,44 @@ user_regs_struct Process::get_registers()
void Process::set_registers(const user_regs_struct &registers)
{
check_for_attached();
if (ptrace(PTRACE_SETREGS, pid_, nullptr, &registers))
throw std::runtime_error(std::strerror(errno));
}
void Process::call_func(void *address, std::array<void *, 6> args)
{
check_for_attached();
// 0: 48 bb ef be ad de ef be ad de movabs $0xdeadbeefdeadbeef, %rbx
// a: ff d3 callq *%rbx
// c: cc int3
std::vector<unsigned char> shellcode = {0x48, 0xbb, 0xef, 0xbe, 0xad, 0xde, 0xef,
0xbe, 0xad, 0xde, 0xff, 0xd3, 0xcc};
std::memcpy(shellcode.data() + 2, &address, sizeof(address));
auto rx_addr = get_rx_area();
auto original_code = read(rx_addr, shellcode.size());
auto original_registers = get_registers();
write(rx_addr, shellcode);
auto registers = original_registers;
registers.rip = reinterpret_cast<decltype(registers.rip)>(rx_addr);
registers.rdi = reinterpret_cast<decltype(registers.rdi)>(args[0]);
registers.rsi = reinterpret_cast<decltype(registers.rsi)>(args[1]);
registers.rdx = reinterpret_cast<decltype(registers.rdx)>(args[2]);
registers.rcx = reinterpret_cast<decltype(registers.rdi)>(args[3]);
registers.r8 = reinterpret_cast<decltype(registers.rdi)>(args[4]);
registers.r9 = reinterpret_cast<decltype(registers.rdi)>(args[5]);
set_registers(registers);
continue_and_wait_for_trap();
write(rx_addr, original_code);
set_registers(original_registers);
}
void Process::check_for_attached()
{
if (!attached_)
throw std::runtime_error("process must be attach first");
}
void Process::continue_and_wait_for_trap()
{
if (ptrace(PTRACE_CONT, pid_, nullptr, nullptr) == -1)
......
#ifndef LINUX_LIBRARY_INJECT_PROCESS_H
#define LINUX_LIBRARY_INJECT_PROCESS_H
#include <sys/ptrace.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/user.h>
#include <array>
#include <string>
#include <utility>
#include <vector>
class Process final
{
public:
explicit Process(pid_t pid) : pid_(pid) {}
std::pair<std::string, std::size_t> find_libc();
std::size_t get_entry_point();
void call_shellcode(std::vector<unsigned char> shellcode);
private:
pid_t pid_;
std::size_t get_base();
std::string get_execute();
explicit Process(pid_t pid) : pid_(pid), attached_(false) {}
~Process();
std::pair<std::string, void *> find_libc();
unsigned char *get_rx_area();
unsigned char *get_rw_area();
void attach();
void detach();
std::vector<unsigned char> read_memory(std::size_t address, std::size_t size);
void write_memory(std::size_t address, std::vector<unsigned char> data);
void write(unsigned char *address, std::vector<unsigned char> &data);
std::vector<unsigned char> read(unsigned char *address, std::size_t size);
user_regs_struct get_registers();
void set_registers(const user_regs_struct &registers);
void call_func(void *address, std::array<void *, 6> args);
private:
pid_t pid_;
bool attached_;
void check_for_attached();
void continue_and_wait_for_trap();
};
......
#include "process_old.h"
#include <sys/wait.h>
#include <unistd.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include <regex>
#include "elf.h"
std::pair<std::string, std::size_t> Process::find_libc()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
filename += "/maps";
std::ifstream file(filename);
std::regex pattern(R"(^([0-9a-h]+)\-.*?(/.*libc\-[0-9\.]*?\.so)$)");
std::string line;
std::smatch result;
while (std::getline(file, line))
{
if (std::regex_search(line, result, pattern))
return {result[2].str(), std::stoul(result[1].str(), nullptr, 16)};
}
throw std::runtime_error("libc.so not found in " + filename);
}
std::size_t Process::get_base()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
filename += "/maps";
std::ifstream file(filename);
std::string line;
file >> line;
return std::stoul(line, nullptr, 16);
}
std::string Process::get_execute()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
filename += "/exe";
char execute[1024] = {0};
if (readlink(filename.c_str(), execute, 1023) != -1)
return execute;
throw std::runtime_error(std::strerror(errno));
}
std::size_t Process::get_entry_point()
{
Elf elf(get_execute());
elf.set_base(get_base());
return elf.get_entry();
}
void Process::call_shellcode(std::vector<unsigned char> shellcode)
{
std::cout << "[*] get target process's entry point\n";
auto entry_point = get_entry_point();
// replace `ret` with `int3`
if (shellcode[shellcode.size() - 1] == 0xc3)
shellcode[shellcode.size() - 1] = 0xcc;
// align
while (shellcode.size() % sizeof(void *) != 0)
shellcode.emplace_back(0x90);
std::cout << "[*] attach to target process\n";
attach();
std::cout << "[*] backup original code\n";
auto original_code = read_memory(entry_point, shellcode.size());
std::cout << "[*] backup original registers\n";
auto original_registers = get_registers();
std::cout << "[*] write shellcode to target process's entry point\n";
write_memory(entry_point, shellcode);
auto registers = original_registers;
registers.rip = entry_point;
std::cout << "[*] set %rip to target process's entry point\n";
set_registers(registers);
std::cout << "[*] continue and wait for trap\n";
continue_and_wait_for_trap();
std::cout << "[*] restore original code\n";
write_memory(entry_point, original_code);
std::cout << "[*] restore original registers\n";
set_registers(original_registers);
std::cout << "[*] detach target process\n";
detach();
}
void Process::attach()
{
if (ptrace(PTRACE_ATTACH, pid_, nullptr, nullptr) == -1)
throw std::runtime_error(std::strerror(errno));
wait(nullptr);
}
void Process::detach()
{
if (ptrace(PTRACE_DETACH, pid_, nullptr, nullptr) == -1)
throw std::runtime_error(std::strerror(errno));
wait(nullptr);
}
std::vector<unsigned char> Process::read_memory(std::size_t address, std::size_t size)
{
std::vector<unsigned char> data;
data.resize(size);
auto ptr = data.data();
std::size_t n = 0;
while (n != size)
{
auto word = ptrace(PTRACE_PEEKTEXT, pid_, address, nullptr);
if (word == -1)
throw std::runtime_error(std::strerror(errno));
auto to_copy = size - n > sizeof(void *) ? sizeof(void *) : size - n;
std::memcpy(ptr, &word, to_copy);
ptr += to_copy;
n += to_copy;
address += sizeof(void *);
}
return data;
}
void Process::write_memory(std::size_t address, std::vector<unsigned char> data)
{
auto ptr = data.data();
std::size_t n = 0;
while (n != data.size())
{
void *to_write = nullptr;
std::memcpy(&to_write, ptr, sizeof(to_write));
if (ptrace(PTRACE_POKETEXT, pid_, address, to_write) == -1)
throw std::runtime_error(std::strerror(errno));
address += sizeof(to_write);
ptr += sizeof(to_write);
n += sizeof(to_write);
}
}
user_regs_struct Process::get_registers()
{
user_regs_struct registers = {0};
if (ptrace(PTRACE_GETREGS, pid_, nullptr, &registers) == -1)
throw std::runtime_error(std::strerror(errno));
return registers;
}
void Process::set_registers(const user_regs_struct &registers)
{
if (ptrace(PTRACE_SETREGS, pid_, nullptr, &registers))
throw std::runtime_error(std::strerror(errno));
}
void Process::continue_and_wait_for_trap()
{
if (ptrace(PTRACE_CONT, pid_, nullptr, nullptr) == -1)
throw std::runtime_error(std::strerror(errno));
int status;
wait(&status);
if (WSTOPSIG(status) != SIGTRAP)
throw std::runtime_error(std::strerror(errno));
}
#ifndef LINUX_LIBRARY_INJECT_PROCESS_OLD_H
#define LINUX_LIBRARY_INJECT_PROCESS_OLD_H
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include <string>
#include <utility>
#include <vector>
class Process final
{
public:
explicit Process(pid_t pid) : pid_(pid) {}
std::pair<std::string, std::size_t> find_libc();
std::size_t get_entry_point();
void call_shellcode(std::vector<unsigned char> shellcode);
private:
pid_t pid_;
std::size_t get_base();
std::string get_execute();
void attach();
void detach();
std::vector<unsigned char> read_memory(std::size_t address, std::size_t size);
void write_memory(std::size_t address, std::vector<unsigned char> data);
user_regs_struct get_registers();
void set_registers(const user_regs_struct &registers);
void continue_and_wait_for_trap();
};
#endif // LINUX_LIBRARY_INJECT_PROCESS_OLD_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment