7
7
#include < vector>
8
8
#include < tuple>
9
9
10
+ #include < pe-builder/pe-builder.h>
10
11
#include < Zydis/Zydis.h>
11
12
12
13
namespace chum {
@@ -37,6 +38,12 @@ class binary {
37
38
// Create a new PE file from this binary.
38
39
bool create (char const * path) const ;
39
40
41
+ // Create a new PE file from this binary.
42
+ std::vector<std::uint8_t > create () const ;
43
+
44
+ // Create a new PE file from this binary.
45
+ bool create (pb::pe_builder& pe) const ;
46
+
40
47
// Get the entrypoint of this binary, if it exists.
41
48
basic_block* entrypoint () const ;
42
49
@@ -96,6 +103,9 @@ class binary {
96
103
import_routine* get_or_create_import_routine (
97
104
char const * module_name, char const * routine_name);
98
105
106
+ // Get the underlying Zydis decoder.
107
+ ZydisDecoder* decoder ();
108
+
99
109
public:
100
110
// Create a new instruction.
101
111
template <typename ... Args>
@@ -112,6 +122,9 @@ class binary {
112
122
template <typename T>
113
123
void instr_push_integer (instruction& instr, T const & value) const ;
114
124
125
+ // Encode and push a new instruction.
126
+ void instr_push_enc_req (instruction& instr, ZydisEncoderRequest const * enc_req) const ;
127
+
115
128
private:
116
129
// ---------------
117
130
// Remember to add any new members to the move constructor/assignment operator!
@@ -142,7 +155,7 @@ class binary {
142
155
143
156
// Create a new instruction.
144
157
template <typename ... Args>
145
- instruction binary::instr (Args&&... args) const {
158
+ inline instruction binary::instr (Args&&... args) const {
146
159
instruction new_instr = { 0 };
147
160
instr_push_item<0 >(new_instr, std::make_tuple (std::forward<Args>(args)...));
148
161
return new_instr;
@@ -151,18 +164,20 @@ instruction binary::instr(Args&&... args) const {
151
164
// This is a helper function for instr() that serializes a single item
152
165
// into the instruction that is currently being built.
153
166
template <std::size_t Idx, typename ... Args>
154
- void binary::instr_push_item (instruction& instr,
167
+ inline void binary::instr_push_item (instruction& instr,
155
168
std::tuple<Args...> const & tuple) const {
156
169
if constexpr (Idx < sizeof ...(Args)) {
157
170
// The current item that we are pushing to the instruction.
158
171
auto const item = std::get<Idx>(tuple);
159
172
using item_type = std::remove_const_t <decltype (item)>;
160
173
161
- static_assert (std::is_integral_v<item_type> ||
162
- std::is_same_v<item_type, symbol_id> ||
163
- std::is_same_v<item_type, symbol*> ||
164
- std::is_same_v<item_type, basic_block*> ||
165
- std::is_same_v<item_type, import_routine*> ||
174
+ static_assert (std::is_integral_v<item_type> ||
175
+ std::is_same_v<item_type, symbol_id> ||
176
+ std::is_same_v<item_type, symbol*> ||
177
+ std::is_same_v<item_type, basic_block*> ||
178
+ std::is_same_v<item_type, import_routine*> ||
179
+ std::is_same_v<item_type, ZydisEncoderRequest*> ||
180
+ std::is_same_v<item_type, ZydisEncoderRequest> ||
166
181
std::is_same_v<item_type, char const *>);
167
182
168
183
// Integral types should be converted to bytes.
@@ -176,6 +191,10 @@ void binary::instr_push_item(instruction& instr,
176
191
instr_push_integer (instr, item->sym_id .value );
177
192
else if constexpr (std::is_same_v<item_type, import_routine*>)
178
193
instr_push_integer (instr, item->sym_id .value );
194
+ else if constexpr (std::is_same_v<item_type, ZydisEncoderRequest*>)
195
+ instr_push_enc_req (instr, item);
196
+ else if constexpr (std::is_same_v<item_type, ZydisEncoderRequest>)
197
+ instr_push_enc_req (instr, &item);
179
198
// C-style strings are assumed to be a null-terminated array of bytes.
180
199
else if constexpr (std::is_same_v<item_type, char const *>) {
181
200
for (std::size_t i = 0 ; item[i]; ++i)
@@ -190,7 +209,7 @@ void binary::instr_push_item(instruction& instr,
190
209
// This is another helper function for serializing integer types, since
191
210
// it is done so often.
192
211
template <typename T>
193
- void binary::instr_push_integer (instruction& instr, T const & value) const {
212
+ inline void binary::instr_push_integer (instruction& instr, T const & value) const {
194
213
// We need the integer to be unsigned so that we can safely do bitwise
195
214
// operations on it (specifically, right-shift).
196
215
auto unsigned_value = static_cast <std::make_unsigned_t <T>>(value);
@@ -202,5 +221,16 @@ void binary::instr_push_integer(instruction& instr, T const& value) const {
202
221
}
203
222
}
204
223
224
+ // Encode and push a new instruction.
225
+ inline void binary::instr_push_enc_req (instruction& instr,
226
+ ZydisEncoderRequest const * const enc_req) const {
227
+ std::uint8_t bytes[15 ] = {};
228
+ std::size_t length = sizeof (bytes);
229
+
230
+ ZydisEncoderEncodeInstruction (enc_req, bytes, &length);
231
+ std::memcpy (instr.bytes , bytes, length);
232
+ instr.length = length;
233
+ }
234
+
205
235
} // namespace chum
206
236
0 commit comments