Rizin
unix-like reverse engineering framework and cli tools
create.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2021 RizinOrg <info@rizin.re>
2 // SPDX-FileCopyrightText: 2021 deroad <wargio@libero.it>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
9 #include <rz_flirt.h>
10 #include <rz_util.h>
11 
12 #define starts_with_flag(b, c) (!strncmp(b, c, strlen(c)))
13 
14 extern void module_free(RzFlirtModule *module);
15 extern ut16 flirt_crc16(const ut8 *data_p, size_t length);
16 
17 static inline void flirt_function_sanitize_name(RzFlirtFunction *function) {
18  for (ut32 i = 0; i < RZ_FLIRT_NAME_MAX; ++i) {
19  char ch = function->name[i];
20  if (ch > ' ' && ch <= '~') {
21  continue;
22  } else if (!ch) {
23  break;
24  }
25  function->name[i] = '?';
26  }
27 }
28 
29 static RzFlirtFunction *flirt_function_new(const char *name, bool is_local, ut64 offset, ut64 address) {
30  if (name) {
31  if (starts_with_flag(name, "sym.")) {
32  name += strlen("sym.");
33  } else if (starts_with_flag(name, "flirt.")) {
34  name += strlen("flirt.");
35  }
36  }
37 
38  ut32 namelen = name ? strlen(name) : 0;
39  if (namelen >= RZ_FLIRT_NAME_MAX) {
40  RZ_LOG_WARN("FLIRT: function at %08" PFMT64x " exceeds the max name length (%u >= %u)\n", offset, namelen, RZ_FLIRT_NAME_MAX);
41  namelen = (RZ_FLIRT_NAME_MAX - 1);
42  }
43 
45  if (!function) {
46  RZ_LOG_ERROR("FLIRT: cannot allocate function\n");
47  return NULL;
48  }
49 
50  if (namelen > 0) {
51  strncpy(function->name, name, namelen);
53  } else {
54  rz_strf(function->name, "fcn.%08" PFMT64x, offset);
55  }
56 
57  function->offset = address - offset;
58  function->negative_offset = offset < address;
59  function->is_local = is_local;
60  return function;
61 }
62 
63 static RzFlirtModule *flirt_module_new(RzAnalysis *analysis, RzAnalysisFunction *func, const ut8 *buffer, const ut8 *mask, ut64 b_size, bool tail_bytes) {
65  if (!module) {
66  RZ_LOG_ERROR("FLIRT: cannot allocate module\n");
67  return NULL;
68  }
69 
70  module->tail_bytes = rz_list_newf((RzListFree)free);
71  if (!module->tail_bytes) {
72  RZ_LOG_ERROR("FLIRT: cannot allocate module tail list\n");
73  goto fail;
74  }
75 
76  module->public_functions = rz_list_newf((RzListFree)free);
77  if (!module->public_functions) {
78  RZ_LOG_ERROR("FLIRT: cannot allocate module public function list\n");
79  goto fail;
80  }
81 
82  module->referenced_functions = rz_list_newf((RzListFree)free);
83  if (!module->referenced_functions) {
84  RZ_LOG_ERROR("FLIRT: cannot allocate module referenced function list\n");
85  goto fail;
86  }
87 
88  if (b_size > 0 && buffer) {
89  // the crc should be generated only for when the buffer is > RZ_FLIRT_MAX_PRELUDE_SIZE
90  module->crc_length = RZ_MIN(b_size, 0xFF);
91  module->crc16 = flirt_crc16(buffer, module->crc_length);
92  }
93 
95 
96  if (tail_bytes) {
97  for (ut32 i = 0; i < RZ_MIN(b_size, 0xFF); ++i) {
98  if (mask[i] != 0xff) {
99  continue;
100  }
102  if (!tb || !rz_list_append(module->tail_bytes, tb)) {
103  RZ_LOG_ERROR("FLIRT: cannot allocate or append tail byte to module list\n");
104  free(tb);
105  goto fail;
106  }
107  tb->offset = i;
108  tb->value = buffer[i];
109  }
110  }
111 
112  RzFlirtFunction *function = flirt_function_new(func->name, false, func->addr, func->addr);
113  if (!function || !rz_list_append(module->public_functions, function)) {
114  RZ_LOG_ERROR("FLIRT: cannot append function to public list\n");
115  free(function);
116  goto fail;
117  }
118 
119  return module;
120 
121 fail:
123  return NULL;
124 }
125 
126 static RzFlirtNode *flirt_create_child(const ut8 *buffer, const ut8 *mask, ut32 b_size) {
127  RzFlirtNode *child = RZ_NEW0(RzFlirtNode);
128  if (!child) {
129  RZ_LOG_ERROR("FLIRT: cannot allocate child node.\n");
130  goto fail;
131  }
132 
134  if (!child->child_list) {
135  RZ_LOG_ERROR("FLIRT: cannot allocate child module list.\n");
136  goto fail;
137  }
138 
140  if (!child->module_list) {
141  RZ_LOG_ERROR("FLIRT: cannot allocate child module list.\n");
142  goto fail;
143  }
144 
147  if (!child->pattern_bytes || !child->pattern_mask) {
148  RZ_LOG_ERROR("FLIRT: cannot allocate child pattern buffer.\n");
149  goto fail;
150  }
151 
152  if (b_size < RZ_FLIRT_MAX_PRELUDE_SIZE) {
153  memcpy(child->pattern_bytes, buffer, b_size);
154  memcpy(child->pattern_mask, mask, b_size);
155  child->length = b_size;
156  } else {
160  }
161 
162  child->variant_mask = 0;
163  for (ut32 i = 0; i < child->length; ++i) {
164  child->variant_mask <<= 1;
165  if (child->pattern_mask[i] != 0xff) {
166  child->variant_mask |= 1;
167  }
168  }
169 
170  return child;
171 
172 fail:
174  return NULL;
175 }
176 
177 static RzFlirtNode *flirt_create_child_from_analysis(RzAnalysis *analysis, RzAnalysisFunction *func, const ut8 *buffer, const ut8 *mask, ut32 b_size, bool tail_bytes) {
178  RzFlirtNode *child = NULL;
180 
181  child = flirt_create_child(buffer, mask, b_size);
182  if (!child) {
183  goto fail;
184  }
185 
186  if (b_size <= RZ_FLIRT_MAX_PRELUDE_SIZE) {
187  module = flirt_module_new(analysis, func, NULL, NULL, 0, false);
188  } else {
190  }
191 
192  if (!module) {
193  goto fail;
194  } else if (!rz_list_append(child->module_list, module)) {
196  RZ_LOG_ERROR("FLIRT: cannot append module to child.\n");
197  goto fail;
198  }
199 
200  return child;
201 
202 fail:
204  return NULL;
205 }
206 
207 static inline bool is_valid_mask_prelude(const ut8 *buffer, ut32 b_size) {
208  for (ut32 i = 0; i < RZ_MIN(RZ_FLIRT_MAX_PRELUDE_SIZE, b_size); ++i) {
209  if (buffer[i] == 0xff) {
210  return true;
211  }
212  }
213  return false;
214 }
215 
216 static int flirt_compare_module(const RzFlirtModule *a, const RzFlirtModule *b) {
217  if (a->length != b->length) {
218  return a->length - b->length;
219  }
220  const RzFlirtFunction *af = rz_list_first(a->public_functions);
221  const RzFlirtFunction *bf = rz_list_first(b->public_functions);
222  return strcmp(af->name, bf->name);
223 }
224 
226  if (a->pattern_mask[0] == 0xFF && b->pattern_mask[0] == 0xFF) {
227  return memcmp(a->pattern_bytes, b->pattern_bytes, RZ_MIN(a->length, b->length));
228  }
229  return a->pattern_mask[0] == 0xFF ? -1 : 1;
230 }
231 
233  if (from < 1) {
234  return;
235  }
236  node->length -= from;
237  memmove(node->pattern_bytes, node->pattern_bytes + from, node->length);
238  memmove(node->pattern_mask, node->pattern_mask + from, node->length);
239 
240  ut64 upper_mask = ~(UT64_MAX << node->length);
241  node->variant_mask &= upper_mask;
242 }
243 
245  RzListIter *it;
246  RzFlirtNode *child;
247  RzFlirtNode *middle_node;
248  ut32 i;
249 
250  rz_list_foreach (root->child_list, it, child) {
251  for (i = 0; i < child->length && i < node->length; ++i) {
252  if (child->pattern_mask[i] != 0xFF && node->pattern_mask[i] != 0xFF) {
253  continue;
254  } else if (child->pattern_mask[i] != node->pattern_mask[i] ||
255  child->pattern_bytes[i] != node->pattern_bytes[i]) {
256  break;
257  }
258  }
259  if (i == 0) {
260  continue;
261  } else if (child->length == i && node->length == child->length) {
262  // same pattern just merge.
263  rz_list_join(child->module_list, node->module_list);
266  return true;
267  } else if (child->length == i) {
268  // partial pattern match but matches the child
270  if (!flirt_node_shorten_and_insert(child, node)) {
271  return false;
272  }
274  } else if (node->length == i) {
275  // partial pattern match but matches the node
276  it->data = node;
278  if (!rz_list_append(node->child_list, child)) {
279  RZ_LOG_ERROR("FLIRT: cannot append child to optimized list.\n");
281  return false;
282  }
283  } else {
284  // partial pattern match, requires to check the middle node
285  middle_node = flirt_create_child(child->pattern_bytes, child->pattern_mask, i);
286  if (!middle_node) {
288  return false;
289  }
290  it->data = middle_node;
291  if (!rz_list_append(middle_node->child_list, child)) {
292  RZ_LOG_ERROR("FLIRT: cannot append child to optimized list.\n");
295  return false;
296  } else if (!rz_list_append(middle_node->child_list, node)) {
297  RZ_LOG_ERROR("FLIRT: cannot append child to optimized list.\n");
299  return false;
300  }
304  }
305  return true;
306  }
307 
308  if (!rz_list_append(root->child_list, node)) {
309  RZ_LOG_ERROR("FLIRT: cannot shorten node or append child to optimized list.\n");
311  return false;
312  }
313  return true;
314 }
315 
317  if (rz_list_length(root->child_list) < 1) {
318  return true;
319  }
320 
321  RzList *childs = root->child_list;
322 
324  if (!root->child_list) {
325  RZ_LOG_ERROR("FLIRT: cannot allocate child list.\n");
326  goto fail;
327  }
328 
330 
331  RzListIter *it;
332  RzFlirtNode *child;
333  rz_list_foreach (childs, it, child) {
334  it->data = NULL;
335  if (!flirt_node_shorten_and_insert(root, child)) {
336  goto fail;
337  }
338  }
339  rz_list_free(childs);
340 
341  return true;
342 
343 fail:
344  rz_list_free(childs);
345  return false;
346 }
347 
356  rz_return_val_if_fail(analysis && analysis->coreb.core, NULL);
357  if (optimization > RZ_FLIRT_NODE_OPTIMIZE_MAX) {
358  RZ_LOG_ERROR("FLIRT: optimization value is invalid (%u > RZ_FLIRT_NODE_OPTIMIZE_MAX).\n", optimization);
359  return NULL;
360  }
361 
362  if (rz_list_length(analysis->fcns) < 1) {
363  RZ_LOG_ERROR("FLIRT: There are no analyzed functions. Have you run 'aa'?\n");
364  return NULL;
365  }
366  bool tail_bytes = optimization != RZ_FLIRT_NODE_OPTIMIZE_MAX;
368  if (!root) {
369  RZ_LOG_ERROR("FLIRT: cannot allocate root node.\n");
370  return NULL;
371  }
373 
374  RzListIter *it;
375  RzAnalysisFunction *func;
376  rz_list_foreach (analysis->fcns, it, func) {
377  ut64 func_size = rz_analysis_function_linear_size(func);
378  if (!func->name) {
379  RZ_LOG_ERROR("FLIRT: function at 0x%" PFMT64x " has a null name. skipping function...\n", func->addr);
380  continue;
381  } else if ((func->type != RZ_ANALYSIS_FCN_TYPE_FCN &&
382  func->type != RZ_ANALYSIS_FCN_TYPE_LOC &&
383  func->type != RZ_ANALYSIS_FCN_TYPE_SYM) ||
384  func_size < 1 ||
385  starts_with_flag(func->name, "imp.") ||
386  starts_with_flag(func->name, "sym.imp.")) {
387  continue;
388  }
389 
390  if (func_size > ST32_MAX) {
391  RZ_LOG_ERROR("FLIRT: this function exceeds the max size allowed by iob->read_at.\n");
392  RZ_LOG_ERROR("FLIRT: this should never happen. please open a bug report.\n");
393  goto fail;
394  }
395 
396  ut8 *pattern = malloc(func_size);
397  if (!pattern) {
398  RZ_LOG_ERROR("FLIRT: cannot allocate function buffer.\n");
399  goto fail;
400  }
401 
402  if (!analysis->iob.read_at(analysis->iob.io, func->addr, pattern, (int)func_size)) {
403  RZ_LOG_WARN("FLIRT: couldn't read function %s at 0x%" PFMT64x ".\n", func->name, func->addr);
404  free(pattern);
405  continue;
406  }
407 
408  ut8 *mask = rz_analysis_mask(analysis, func_size, pattern, func->addr);
409  if (!mask) {
410  RZ_LOG_ERROR("FLIRT: cannot calculate pattern mask.\n");
411  free(pattern);
412  goto fail;
413  } else if (!is_valid_mask_prelude(mask, func_size)) {
414  free(pattern);
415  free(mask);
416  continue;
417  }
418 
419  for (ut32 i = func_size - 1; i > 1; --i) {
420  if (mask[i] != 0xFF) {
421  func_size--;
422  continue;
423  }
424  break;
425  }
426 
427  RzFlirtNode *child = flirt_create_child_from_analysis(analysis, func, pattern, mask, func_size, tail_bytes);
428  RZ_FREE(pattern);
429  free(mask);
430  if (!child || !rz_list_append(root->child_list, child)) {
431  RZ_LOG_ERROR("FLIRT: cannot append child to root list.\n");
433  goto fail;
434  }
435  }
436 
437  if (rz_list_length(root->child_list) < 1) {
438  RZ_LOG_ERROR("FLIRT: cannot create signature file when i do not have signatures.\n");
439  goto fail;
440  }
441 
442  if (optimization == RZ_FLIRT_NODE_OPTIMIZE_NONE) {
444  } else if (!flirt_node_optimize(root)) {
445  goto fail;
446  }
447 
448  return root;
449 
450 fail:
452  return NULL;
453 }
RZ_API ut64 rz_analysis_function_linear_size(RzAnalysisFunction *fcn)
Definition: function.c:318
RZ_API ut8 * rz_analysis_mask(RzAnalysis *analysis, ut32 size, const ut8 *data, ut64 at)
Definition: analysis.c:334
#define mask()
lzma_index ** i
Definition: index.h:629
#define RZ_API
RZ_API RZ_OWN RzFlirtNode * rz_sign_flirt_node_new(RZ_NONNULL RzAnalysis *analysis, ut32 optimization)
Generates the FLIRT signatures and returns an RzFlirtNode.
Definition: create.c:355
int flirt_compare_node(const RzFlirtNode *a, const RzFlirtNode *b)
Definition: create.c:225
static RzFlirtModule * flirt_module_new(RzAnalysis *analysis, RzAnalysisFunction *func, const ut8 *buffer, const ut8 *mask, ut64 b_size, bool tail_bytes)
Definition: create.c:63
void module_free(RzFlirtModule *module)
Definition: flirt.c:284
static bool flirt_node_shorten_and_insert(const RzFlirtNode *root, RzFlirtNode *node)
Definition: create.c:244
static RzFlirtNode * flirt_create_child_from_analysis(RzAnalysis *analysis, RzAnalysisFunction *func, const ut8 *buffer, const ut8 *mask, ut32 b_size, bool tail_bytes)
Definition: create.c:177
static RzFlirtFunction * flirt_function_new(const char *name, bool is_local, ut64 offset, ut64 address)
Definition: create.c:29
static void flirt_node_shorten_pattern(RzFlirtNode *node, ut32 from)
Definition: create.c:232
#define starts_with_flag(b, c)
Definition: create.c:12
static int flirt_compare_module(const RzFlirtModule *a, const RzFlirtModule *b)
Definition: create.c:216
bool flirt_node_optimize(RzFlirtNode *root)
Definition: create.c:316
static RzFlirtNode * flirt_create_child(const ut8 *buffer, const ut8 *mask, ut32 b_size)
Definition: create.c:126
static void flirt_function_sanitize_name(RzFlirtFunction *function)
Definition: create.c:17
ut16 flirt_crc16(const ut8 *data_p, size_t length)
Definition: flirt.c:204
static bool is_valid_mask_prelude(const ut8 *buffer, ut32 b_size)
Definition: create.c:207
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
uint16_t ut16
uint32_t ut32
int root
Definition: enough.c:226
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf uLong offset
Definition: ioapi.h:144
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
RZ_API bool rz_list_join(RZ_NONNULL RzList *list1, RZ_NONNULL RzList *list2)
Joins 2 list into one (list2 pointer needs to be freed by the user)
Definition: list.c:209
RZ_API RZ_BORROW void * rz_list_first(RZ_NONNULL const RzList *list)
Returns the first element of the list.
Definition: list.c:77
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
void * malloc(size_t size)
Definition: malloc.c:123
@ RZ_ANALYSIS_FCN_TYPE_SYM
Definition: rz_analysis.h:195
@ RZ_ANALYSIS_FCN_TYPE_LOC
Definition: rz_analysis.h:194
@ RZ_ANALYSIS_FCN_TYPE_FCN
Definition: rz_analysis.h:193
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API void rz_sign_flirt_node_free(RZ_NULLABLE RzFlirtNode *node)
Frees an RzFlirtNode struct.
Definition: flirt.c:299
#define RZ_FLIRT_MAX_PRELUDE_SIZE
Definition: rz_flirt.h:20
@ RZ_FLIRT_NODE_OPTIMIZE_NONE
keeps the structure flattened (keep the tail bytes)
Definition: rz_flirt.h:186
@ RZ_FLIRT_NODE_OPTIMIZE_MAX
optimize the tree structure and drops the tail bytes
Definition: rz_flirt.h:188
#define RZ_FLIRT_NAME_MAX
Definition: rz_flirt.h:17
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
#define rz_strf(buf,...)
Convenience macro for local temporary strings.
Definition: rz_str.h:59
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NONNULL
Definition: rz_types.h:64
#define RZ_FREE(x)
Definition: rz_types.h:369
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MIN(x, y)
#define ST32_MAX
Definition: rz_types_base.h:97
#define UT64_MAX
Definition: rz_types_base.h:86
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr from
Definition: sfsocketcall.h:123
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
Definition: buffer.h:15
Definition: sftypes.h:77
Definition: z80asm.h:102
char name[RZ_FLIRT_NAME_MAX]
Definition: rz_flirt.h:158
RzList * child_list
Definition: rz_flirt.h:177
RzList * module_list
Definition: rz_flirt.h:178
ut8 * pattern_mask
Definition: rz_flirt.h:182
ut8 * pattern_bytes
Definition: rz_flirt.h:181
ut64 variant_mask
Definition: rz_flirt.h:180
void * data
Definition: rz_list.h:14
#define fail(test)
Definition: tests.h:29
ut64(WINAPI *w32_GetEnabledXStateFeatures)()