Theodosius v3.0
Jit linker, symbol mapper, and obfuscator
recomp.cpp
Go to the documentation of this file.
1// Copyright (c) 2022, _xeroxz
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice,
8// this list of conditions and the following disclaimer.
9//
10// 2. Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13//
14// 3. Neither the name of the copyright holder nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28// POSSIBILITY OF SUCH DAMAGE.
29//
30
31#include <recomp/recomp.hpp>
32
33namespace theo::recomp {
35 allocator_t alloc,
36 copier_t copy,
37 resolver_t resolve)
38 : m_dcmp(dcmp), m_allocator(alloc), m_copier(copy), m_resolver(resolve) {}
39
41 // map code & data/rdata/bss sections first...
42 //
43 m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) {
44 switch (sym.type()) {
45 case decomp::sym_type_t::section:
46 case decomp::sym_type_t::function:
47 case decomp::sym_type_t::instruction: {
48 sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics));
49 break;
50 }
51 default:
52 break;
53 }
54 });
55
56 // then map data/rdata/bss symbols to the allocated sections...
57 //
58 m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) {
59 if (sym.type() == decomp::sym_type_t::data) {
60 // if the symbol has a section then we will refer to the allocation made
61 // for that section...
62 //
63 if (sym.scn()) {
64 auto scn_sym =
65 m_dcmp->syms()->sym_from_hash(m_dcmp->scn_hash_tbl()[sym.scn()]);
66
67 if (!scn_sym.has_value()) {
68 spdlog::error("failed to locate section: {} for symbol: {}",
69 sym.scn()->name.to_string(), sym.name());
70
71 assert(scn_sym.has_value());
72 }
73
74 sym.allocated_at(scn_sym.value()->allocated_at() + sym.offset());
75 } else { // else if there is no section then we allocate based upon the
76 // size of the symbol... this is only done for symbols that are
77 // bss...
78 //
79
80 // bss is read write...
81 //
82 coff::section_characteristics_t prot = {};
83 prot.mem_read = true;
84 prot.mem_write = true;
85
86 sym.allocated_at(m_allocator(sym.size(), sym.scn()->characteristics));
87 }
88 }
89 });
90}
91
92void recomp_t::resolve() {
93 // resolve relocations in all symbols...
94 //
95 m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) {
96 auto& relocs = sym.relocs();
97 std::for_each(relocs.begin(), relocs.end(), [&](reloc_t& reloc) {
98 if (reloc.offset() > sym.data().size()) {
99 spdlog::error(
100 "invalid relocation... writing outside of symbol length... offset: "
101 "{} sym size: {}",
102 sym.offset(), sym.data().size());
103
104 assert(reloc.offset() > sym.data().size());
105 }
106
107 // try and resolve the symbol by refering to the internal symbol table
108 // first... if there is no symbol then refer to the resolver...
109 //
110 auto reloc_sym = m_dcmp->syms()->sym_from_hash(reloc.hash());
111 auto allocated_at = reloc_sym.has_value()
112 ? reloc_sym.value()->allocated_at()
113 : m_resolver(reloc.name());
114
115 if (!allocated_at) {
116 spdlog::error("failed to resolve reloc from symbol: {} to symbol: {}",
117 sym.name(), reloc.name());
118
119 assert(allocated_at);
120 }
121
122 switch (sym.type()) {
124 auto scn_sym =
125 m_dcmp->syms()->sym_from_hash(m_dcmp->scn_hash_tbl()[sym.scn()]);
126
127 *reinterpret_cast<std::uintptr_t*>(scn_sym.value()->data().data() +
128 reloc.offset()) = allocated_at;
129 break;
130 }
132 *reinterpret_cast<std::uintptr_t*>(sym.data().data() +
133 reloc.offset()) = allocated_at;
134 break;
135 }
137 auto& transforms = reloc.get_transforms();
138 std::for_each(
139 transforms.begin(), transforms.end(),
140 [&](std::pair<obf::transform::transform_t*, std::uint32_t>& t) {
141 allocated_at = (*t.first)(allocated_at, t.second);
142 });
143
144 *reinterpret_cast<std::uintptr_t*>(sym.data().data() +
145 reloc.offset()) = allocated_at;
146 break;
147 }
148 default:
149 break;
150 }
151 });
152 });
153}
154
155void recomp_t::copy_syms() {
156 // copy symbols into memory using the copier supplied...
157 //
158 m_dcmp->syms()->for_each([&](theo::decomp::symbol_t& sym) {
159 m_copier(sym.allocated_at(), sym.data().data(), sym.data().size());
160 });
161}
162
163void recomp_t::allocator(allocator_t alloc) {
164 m_allocator = alloc;
165}
166
167void recomp_t::copier(copier_t copy) {
168 m_copier = copy;
169}
170
171void recomp_t::resolver(resolver_t resolve) {
172 m_resolver = resolve;
173}
174
175std::uintptr_t recomp_t::resolve(const std::string&& sym) {
176 auto res = m_dcmp->syms()->sym_from_hash(decomp::symbol_t::hash(sym));
177 return res.has_value() ? res.value()->allocated_at() : 0;
178}
179} // namespace theo::recomp