Commit ebdd7244 authored by Chu's avatar Chu

new method

parent c630fe56
......@@ -15,12 +15,12 @@ Elf::~Elf()
munmap(memory_, memory_length_);
}
void Elf::set_base(std::size_t base)
void Elf::set_base(const void *base)
{
base_ = base;
}
std::size_t Elf::find_symbol_address_by_name(std::string_view name)
const void *Elf::find_symbol_address_by_name(std::string_view name)
{
if (!memory_)
load_to_memory();
......@@ -34,7 +34,7 @@ std::size_t Elf::find_symbol_address_by_name(std::string_view name)
for (auto j = 0; j != shdr_[i].sh_size / sizeof(Elf64_Sym); ++j)
{
if (&str_tab[sym_tab->st_name] == name)
return base_ + sym_tab->st_value;
return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(base_) + sym_tab->st_value);
++sym_tab;
}
}
......@@ -69,15 +69,15 @@ void Elf::load_to_memory()
shdr_ = reinterpret_cast<Elf64_Shdr *>(memory_ + ehdr_->e_shoff);
}
std::size_t Elf::get_entry()
const void *Elf::get_entry()
{
if (!memory_)
load_to_memory();
return base_ + ehdr_->e_entry;
return reinterpret_cast<void *>(reinterpret_cast<std::size_t>(base_) + ehdr_->e_entry);
}
std::size_t Elf::get_func_size(std::size_t address)
std::size_t Elf::get_func_size(const void *address)
{
if (!memory_)
load_to_memory();
......@@ -89,7 +89,7 @@ std::size_t Elf::get_func_size(std::size_t address)
auto sym_tab = reinterpret_cast<Elf64_Sym *>(&memory_[shdr_[i].sh_offset]);
for (auto j = 0; j != shdr_[i].sh_size / sizeof(Elf64_Sym); ++j)
{
if (sym_tab->st_value == address)
if (sym_tab->st_value == reinterpret_cast<std::size_t>(address))
return sym_tab->st_size;
++sym_tab;
}
......
......@@ -11,14 +11,14 @@ class Elf final
public:
explicit Elf(std::string path) : path_(std::move(path)) {}
~Elf();
void set_base(std::size_t base);
std::size_t find_symbol_address_by_name(std::string_view name);
std::size_t get_entry();
std::size_t get_func_size(std::size_t address);
void set_base(const void *base);
const void *find_symbol_address_by_name(std::string_view name);
const void *get_entry();
std::size_t get_func_size(const void *address);
private:
std::string path_;
std::size_t base_ = 0;
const void *base_ = nullptr;
std::size_t memory_length_ = 0;
unsigned char *memory_ = nullptr;
Elf64_Ehdr *ehdr_ = nullptr;
......
#include <dlfcn.h>
#include <cstring>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
#include "elf.h"
#include "process_old.h"
#include "process.h"
void do_libc_dlopen_mode();
void do_libc_dlopen_mode(Process& process, const void* address, std::string_view path);
int main(int argc, char *argv[])
int main(int argc, char* argv[])
{
if (argc != 3)
{
......@@ -21,26 +25,36 @@ int main(int argc, char *argv[])
// find libc.so in target process
std::cout << "[*] find libc.so in target process\n";
auto [libc_path, libc_base] = process.find_libc();
std::cout << "[+] libc: " << libc_path << " 0x" << std::hex << libc_base << std::endl;
std::cout << "[+] libc: " << libc_path << " 0x" << std::hex << reinterpret_cast<std::size_t>(libc_base)
<< std::endl;
// find __libc_dlopen_mode in libc.so
std::cout << "[*] find __libc_dlopen_mode in " << libc_path << std::endl;
Elf libc(libc_path);
libc.set_base(libc_base);
auto libc_dlopen_mode = libc.find_symbol_address_by_name("__libc_dlopen_mode");
std::cout << "[+] __libc_dlopen_mode: 0x" << libc_dlopen_mode << std::endl;
std::cout << "[+] __libc_dlopen_mode: 0x" << reinterpret_cast<std::size_t>(libc_dlopen_mode) << std::endl;
// call __libc_dlopen_mode in target process
std::cout << "[*] get shellcode in current process\n";
auto do_libc_dlopen_mode_addr = reinterpret_cast<unsigned char *>(&do_libc_dlopen_mode);
auto do_libc_dlopen_mode_size = Elf(argv[0]).get_func_size(reinterpret_cast<std::size_t>(do_libc_dlopen_mode_addr));
std::cout << "[+] shellcode: 0x" << reinterpret_cast<std::size_t>(do_libc_dlopen_mode_addr) << " " << std::dec
<< do_libc_dlopen_mode_size << std::endl;
std::cout << "[*] execute shellcode in target process\n";
process.call_shellcode(std::vector(do_libc_dlopen_mode_addr, do_libc_dlopen_mode_addr + do_libc_dlopen_mode_size));
std::cout << "[*] call __libc_dlopen_mode in target process\n";
do_libc_dlopen_mode(process, libc_dlopen_mode, argv[2]);
std::cout << "[+] injected\n";
return 0;
}
void do_libc_dlopen_mode() {}
void do_libc_dlopen_mode(Process& process, const void* address, std::string_view path)
{
std::vector<unsigned char> data(path.data(), path.data() + path.size() + 1);
while (data.size() % sizeof(void*) != 0)
data.emplace_back(0x00);
process.attach();
auto path_addr = process.find_r_area();
auto original_data = process.read(path_addr, data.size());
process.write(path_addr, data);
auto flags = RTLD_LAZY;
process.call_func(address, {path_addr, reinterpret_cast<const void*>(flags), nullptr, nullptr, nullptr, nullptr});
process.write(path_addr, original_data);
process.detach();
}
......@@ -12,7 +12,7 @@ Process::~Process()
detach();
}
std::pair<std::string, void *> Process::find_libc()
std::pair<std::string, const void *> Process::find_libc()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
......@@ -24,12 +24,12 @@ std::pair<std::string, void *> Process::find_libc()
while (std::getline(file, line))
{
if (std::regex_search(line, result, pattern))
return {result[1].str(), reinterpret_cast<void *>(std::stoul(line, nullptr, 16))};
return {result[1].str(), reinterpret_cast<unsigned char *>(std::stoul(line, nullptr, 16))};
}
throw std::runtime_error("libc.so not found in " + filename);
}
unsigned char *Process::find_rx_area()
const void *Process::find_rx_area()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
......@@ -44,19 +44,15 @@ unsigned char *Process::find_rx_area()
throw std::runtime_error("rx area not found in " + filename);
}
unsigned char *Process::find_rw_area()
const void *Process::find_r_area()
{
std::string filename("/proc/");
filename += std::to_string(pid_);
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);
file >> line;
return reinterpret_cast<unsigned char *>(std::stoul(line, nullptr, 16));
}
void Process::attach()
......@@ -76,41 +72,43 @@ void Process::detach()
attached_ = false;
}
void Process::write(unsigned char *address, std::vector<unsigned char> &data)
void Process::write(const void *address, const std::vector<unsigned char> &data)
{
check_for_attached();
check_for_read_write_size(data.size());
auto address_ = static_cast<const char *>(address);
auto data_ptr = data.data();
std::size_t total_wrote = 0;
while (total_wrote != data.size())
{
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)
if (ptrace(PTRACE_POKETEXT, pid_, address_, data_to_write) == -1)
throw std::runtime_error(std::strerror(errno));
address += sizeof(data_to_write);
address_ += sizeof(data_to_write);
data_ptr += sizeof(data_to_write);
total_wrote += sizeof(data_to_write);
}
}
std::vector<unsigned char> Process::read(unsigned char *address, std::size_t size)
std::vector<unsigned char> Process::read(const void *address, std::size_t size)
{
check_for_attached();
std::vector<unsigned char> data(size % sizeof(void *) == 0 ? size : size + (size - size % sizeof(void *)));
check_for_read_write_size(size);
auto address_ = static_cast<const char *>(address);
std::vector<unsigned char> data(size);
auto data_ptr = data.data();
std::size_t total_read = 0;
while (total_read != size)
{
auto data_read = ptrace(PTRACE_PEEKTEXT, pid_, address, nullptr);
auto data_read = ptrace(PTRACE_PEEKTEXT, pid_, address_, nullptr);
if (data_read == -1)
throw std::runtime_error(std::strerror(errno));
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;
std::memcpy(data_ptr, &data_read, sizeof(data_read));
address_ += sizeof(data_read);
data_ptr += sizeof(data_read);
total_read += sizeof(data_read);
}
data.resize(size);
return data;
}
......@@ -126,11 +124,11 @@ 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))
if (ptrace(PTRACE_SETREGS, pid_, nullptr, &registers) == -1)
throw std::runtime_error(std::strerror(errno));
}
void Process::call_func(void *address, std::array<void *, 6> args)
void Process::call_func(const void *address, std::array<const void *, 6> args)
{
check_for_attached();
// 0: 48 bb ef be ad de ef be ad de movabs $0xdeadbeefdeadbeef, %rbx
......@@ -138,13 +136,16 @@ void Process::call_func(void *address, std::array<void *, 6> args)
// c: cc int3
std::vector<unsigned char> shellcode = {0x48, 0xbb, 0xef, 0xbe, 0xad, 0xde, 0xef,
0xbe, 0xad, 0xde, 0xff, 0xd3, 0xcc};
while (shellcode.size() % sizeof(void *) != 0)
shellcode.emplace_back(0x90);
std::memcpy(shellcode.data() + 2, &address, sizeof(address));
auto rx_addr = find_rx_area();
auto original_code = read(rx_addr, shellcode.size());
auto rx_area = find_rx_area();
auto original_code = read(rx_area, shellcode.size());
write(rx_area, shellcode);
auto original_registers = get_registers();
write(rx_addr, shellcode);
auto registers = original_registers;
registers.rip = reinterpret_cast<decltype(registers.rip)>(rx_addr);
// TODO why +0x2
registers.rip = reinterpret_cast<decltype(registers.rip)>(rx_area) + 0x2;
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]);
......@@ -153,7 +154,7 @@ void Process::call_func(void *address, std::array<void *, 6> args)
registers.r9 = reinterpret_cast<decltype(registers.rdi)>(args[5]);
set_registers(registers);
continue_and_wait_for_trap();
write(rx_addr, original_code);
write(rx_area, original_code);
set_registers(original_registers);
}
......@@ -163,6 +164,12 @@ void Process::check_for_attached()
throw std::runtime_error("process must be attach first");
}
void Process::check_for_read_write_size(std::size_t size)
{
if (size % sizeof(void *) != 0)
throw std::runtime_error("size % sizeof(void *) != 0");
}
void Process::continue_and_wait_for_trap()
{
check_for_attached();
......@@ -171,5 +178,5 @@ void Process::continue_and_wait_for_trap()
int status;
wait(&status);
if (WSTOPSIG(status) != SIGTRAP)
throw std::runtime_error(std::strerror(errno));
throw std::runtime_error("unknown sig");
}
......@@ -13,22 +13,23 @@ class Process final
public:
explicit Process(pid_t pid) : pid_(pid), attached_(false) {}
~Process();
std::pair<std::string, void *> find_libc();
unsigned char *find_rx_area();
unsigned char *find_rw_area();
std::pair<std::string, const void *> find_libc();
const void *find_rx_area();
const void *find_r_area();
void attach();
void detach();
void write(unsigned char *address, std::vector<unsigned char> &data);
std::vector<unsigned char> read(unsigned char *address, std::size_t size);
void write(const void *address, const std::vector<unsigned char> &data);
std::vector<unsigned char> read(const void *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);
void call_func(const void *address, std::array<const void *, 6> args);
private:
pid_t pid_;
bool attached_;
void check_for_attached();
static void check_for_read_write_size(std::size_t size);
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