Skip to content

Commit 79f84d4

Browse files
refactor!: memory related apis
1 parent c248b31 commit 79f84d4

11 files changed

Lines changed: 441 additions & 249 deletions

File tree

include/blook/function.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include "blook/memo.h"
3+
#include "blook/process.h"
34
#include "blook/utils.h"
45

56
#include <cstddef>
@@ -122,7 +123,7 @@ class Function {
122123
}
123124

124125
Serializer serializer;
125-
void *pCodePage = Pointer::malloc_rwx(utils::estimateCodeSize(program));
126+
void *pCodePage = Process::self()->malloc(utils::estimateCodeSize(program), Process::MemoryProtection::rwx);
126127
if (auto err =
127128
serializer.serialize(program, reinterpret_cast<int64_t>(pCodePage));
128129
err != zasm::ErrorCode::None)

include/blook/memo.h

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <vector>
1818

1919

20+
#include "process.h"
21+
2022
namespace blook {
2123
class Process;
2224

@@ -40,34 +42,23 @@ class Pointer {
4042
friend MemoryPatch;
4143

4244
public:
45+
using MemoryProtection = Process::MemoryProtection;
46+
4347
std::shared_ptr<Process> proc = nullptr;
4448
bool is_self() const;
45-
static void *malloc_rwx(size_t size);
46-
47-
static void protect_rwx(void *p, size_t size);
48-
49-
static void *malloc_near_rwx(void *near, size_t size);
5049

5150
bool operator==(const Pointer &other) const = default;
5251

53-
enum class MemoryProtection {
54-
Read = 0x0001,
55-
Write = 0x0010,
56-
Execute = 0x0100,
57-
ReadWrite = Read | Write,
58-
ReadWriteExecute = Read | Write | Execute,
59-
ReadExecute = Read | Execute,
60-
rw = ReadWrite,
61-
rwx = ReadWriteExecute,
62-
rx = ReadExecute
63-
};
64-
6552
Pointer malloc(size_t size, void *near,
6653
MemoryProtection protection = MemoryProtection::rw);
6754

6855
Pointer malloc(size_t size,
6956
MemoryProtection protection = MemoryProtection::rw);
7057

58+
Pointer malloc_rx_near_this(size_t size);
59+
60+
void free(size_t size = 0);
61+
7162
std::optional<Thread> create_thread(bool suspended = false);
7263

7364
// Read operations
@@ -287,13 +278,13 @@ class Pointer {
287278
};
288279

289280
struct ScopedSetMemoryRWX {
290-
void *ptr;
281+
Pointer ptr;
291282
size_t size;
292-
void *old_protect;
283+
Process::MemoryProtection old_protect;
293284

294-
ScopedSetMemoryRWX(void *ptr, size_t size);
295-
ScopedSetMemoryRWX(const Pointer &p, size_t size)
296-
: ScopedSetMemoryRWX(p.data(), size) {}
285+
ScopedSetMemoryRWX(Pointer ptr, size_t size);
286+
ScopedSetMemoryRWX(void *ptr, size_t size)
287+
: ScopedSetMemoryRWX(Pointer(ptr), size) {}
297288
ScopedSetMemoryRWX(const ScopedSetMemoryRWX &) = delete;
298289
ScopedSetMemoryRWX &operator=(const ScopedSetMemoryRWX &) = delete;
299290
ScopedSetMemoryRWX(const MemoryRange &r);

include/blook/module.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include "process.h"
34
#include <filesystem>
45
#include <map>
56
#include <optional>

include/blook/process.h

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,62 @@
11
#pragma once
22

3-
#include "module.h"
4-
53
#include "platform_types.h"
6-
74
#include "utils.h"
85
#include <cstdint>
96
#include <expected>
107
#include <filesystem>
118
#include <iostream>
9+
#include <map>
10+
#include <memory>
1211
#include <optional>
1312
#include <span>
1413
#include <string>
1514
#include <vector>
1615

1716
namespace blook {
1817
class Pointer;
18+
class Module;
1919
struct Thread;
20-
class Process : public std::enable_shared_from_this<Process> {
21-
#ifdef _WIN32
20+
class Process;
2221

22+
using Allocator = struct ProcessAllocator {
23+
explicit ProcessAllocator(std::shared_ptr<Process> proc);
2324

24-
explicit Process(HANDLE h);
25+
std::optional<Pointer> allocate(size_t size, void *nearAddr = nullptr);
2526

26-
explicit Process(DWORD pid);
27+
void deallocate(Pointer addr);
2728

28-
#endif
29+
private:
30+
struct AllocatedPageData {
31+
size_t size;
32+
std::map<void *, size_t> allocated;
33+
};
34+
std::map<void *, AllocatedPageData> allocatedPages;
35+
std::shared_ptr<Process> proc;
36+
};
2937

30-
struct Allocator {
31-
explicit Allocator(std::shared_ptr<Process> proc);
38+
class Process : public std::enable_shared_from_this<Process> {
39+
public:
40+
enum class MemoryProtection {
41+
None = 0,
42+
Read = 0x0001,
43+
Write = 0x0010,
44+
Execute = 0x0100,
45+
ReadWrite = Read | Write,
46+
ReadWriteExecute = Read | Write | Execute,
47+
ReadExecute = Read | Execute,
48+
rw = ReadWrite,
49+
rwx = ReadWriteExecute,
50+
rx = ReadExecute
51+
};
3252

33-
std::optional<Pointer> allocate(size_t size, void *nearAddr = nullptr);
53+
#ifdef _WIN32
3454

35-
void deallocate(Pointer addr);
55+
explicit Process(HANDLE h);
3656

37-
private:
38-
struct AllocatedPageData {
39-
size_t size;
40-
std::map<void *, size_t> allocated;
41-
};
42-
std::map<void *, AllocatedPageData> allocatedPages;
43-
std::shared_ptr<Process> proc;
44-
};
57+
explicit Process(DWORD pid);
4558

46-
std::optional<Pointer> _memo{};
47-
std::optional<Allocator> _allocator{};
59+
#endif
4860

4961
explicit Process(std::string name, size_t skip = 0);
5062
bool is_self_cached;
@@ -53,17 +65,49 @@ class Process : public std::enable_shared_from_this<Process> {
5365
friend Module;
5466
friend Pointer;
5567

68+
std::shared_ptr<Pointer> _memo_ptr;
69+
std::shared_ptr<struct ProcessAllocator> _allocator_ptr;
70+
5671
public:
5772
CLASS_MOVE_ONLY(Process)
5873
#ifdef _WIN32
5974
DWORD pid;
6075
#endif
61-
[[nodiscard]] std::optional<std::vector<std::uint8_t>>
62-
read(void *addr, size_t size) const;
6376

64-
void *read(void *dest, void *addr, size_t size) const;
77+
// Memory APIs
78+
std::expected<void, std::string> try_read(void *dst, void *src,
79+
size_t size) const;
80+
void read(void *dst, void *src, size_t size) const;
81+
82+
std::expected<void, std::string> try_write(void *dst, const void *src,
83+
size_t size) const;
84+
void write(void *dst, const void *src, size_t size) const;
85+
86+
std::expected<bool, std::string> try_check_readable(void *addr,
87+
size_t size) const;
88+
bool check_readable(void *addr, size_t size) const;
89+
90+
std::expected<bool, std::string> try_check_writable(void *addr,
91+
size_t size) const;
92+
bool check_writable(void *addr, size_t size) const;
93+
94+
std::expected<MemoryProtection, std::string>
95+
try_set_memory_protect(void *addr, size_t size,
96+
MemoryProtection protect) const;
97+
MemoryProtection set_memory_protect(void *addr, size_t size,
98+
MemoryProtection protect) const;
99+
100+
std::expected<bool, std::string> try_check_valid(void *addr) const;
101+
bool check_valid(void *addr) const;
102+
103+
std::expected<void *, std::string>
104+
try_malloc(size_t size, MemoryProtection protect = MemoryProtection::rw,
105+
void *nearAddr = nullptr) const;
106+
void *malloc(size_t size, MemoryProtection protect = MemoryProtection::rw,
107+
void *nearAddr = nullptr) const;
65108

66-
std::expected<void, std::string> write(void *addr, std::span<uint8_t>) const;
109+
std::expected<void, std::string> try_free(void *addr, size_t size = 0) const;
110+
void free(void *addr, size_t size = 0) const;
67111

68112
[[nodiscard]] std::optional<std::shared_ptr<Module>>
69113
module(const std::string &name);
@@ -82,7 +126,7 @@ class Process : public std::enable_shared_from_this<Process> {
82126

83127
Pointer memo();
84128

85-
Allocator allocator();
129+
struct ProcessAllocator& allocator();
86130

87131
std::vector<Thread> threads();
88132

include/blook/utils.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
#pragma once
2+
23
#include "ctype.h"
34
#include "zasm/base/mode.hpp"
45
#include "zasm/decoder/decoder.hpp"
56
#include "zasm/zasm.hpp"
67

8+
#ifndef CLASS_MOVE_ONLY
79
#define CLASS_MOVE_ONLY(classname) \
8-
classname() = delete; \
9-
classname(classname &) = delete; \
10-
classname &operator=(classname &) = delete; \
10+
classname(const classname &) = delete; \
11+
classname &operator=(const classname &) = delete; \
1112
classname(classname &&) noexcept = default; \
1213
classname &operator=(classname &&) noexcept = default;
14+
#endif
1315

1416

1517
#if defined(__x86_64__) || defined(_M_X64)

src/function.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ void *Function::into_safe_function_pointer(void *func, bool thread_safety) {
5454
auto program = Program(utils::compileMachineMode());
5555
auto a = x86::Assembler(program);
5656

57-
auto ptr = ((Pointer)Pointer::malloc_near_rwx(func, 300));
57+
auto ptr = Pointer(Process::self(), Process::self()->malloc(300, Process::MemoryProtection::rwx, func));
5858
ptr.reassembly([=](auto a) {
5959
#ifdef BLOOK_ARCHITECTURE_X86_64
6060
auto sp = x86::rsp;

src/memory.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,16 @@ MemoryPatch::MemoryPatch(Pointer ptr, std::vector<uint8_t> buffer)
4646

4747
void MemoryPatch::swap() {
4848
const auto target = reinterpret_cast<void *>(ptr._offset);
49+
ScopedSetMemoryRWX protector(ptr, buffer.size());
4950
if (ptr.proc->is_self()) {
50-
ScopedSetMemoryRWX protector(ptr, buffer.size());
5151
std::vector<uint8_t> tmp(buffer.size());
5252
std::memcpy(tmp.data(), buffer.data(), buffer.size());
5353
std::memcpy(buffer.data(), target, buffer.size());
5454
std::memcpy(target, tmp.data(), tmp.size());
5555
} else {
5656
std::vector<uint8_t> tmp(buffer.size());
5757
ptr.proc->read(tmp.data(), target, buffer.size());
58-
if (!ptr.proc->write(target, buffer))
58+
if (!ptr.proc->try_write(target, buffer.data(), buffer.size()))
5959
throw std::runtime_error("Failed to write memory");
6060
buffer = std::move(tmp);
6161
}

0 commit comments

Comments
 (0)