Rizin
unix-like reverse engineering framework and cli tools
pat.c File Reference
#include <rz_flirt.h>
#include <rz_util.h>

Go to the source code of this file.

Macros

#define pat_dbg(...)
 
#define PAT_LINE_BUFFER_SIZE   1024
 

Functions

void module_free (RzFlirtModule *module)
 
bool flirt_node_optimize (RzFlirtNode *root)
 
int flirt_compare_node (const RzFlirtNode *a, const RzFlirtNode *b)
 
static ut8 decode_byte (char b)
 
static ut8 parse_byte (char high, char low)
 
static bool flirt_pat_parse_pattern_mask (const char *in_pattern, RzFlirtNode *child)
 
static bool flirt_pat_parse_line (RzFlirtNode *root, RzStrBuf *sb, ut32 line_num, bool tail_bytes)
 
RZ_API RZ_OWN RzFlirtNoderz_sign_flirt_parse_string_pattern_from_buffer (RZ_NONNULL RzBuffer *flirt_buf, ut32 optimization, RZ_NULLABLE RzFlirtInfo *info)
 Parses the RzBuffer containing a FLIRT signature in string format and returns an RzFlirtNode. More...
 
static void flirt_pat_append_prelude (RzStrBuf *prelude, RZ_NONNULL const RzFlirtNode *child)
 
static bool flirt_pat_write_line (RZ_NONNULL const RzFlirtNode *node, RZ_NONNULL RzBuffer *buffer, RzStrBuf *prelude)
 
RZ_API bool rz_sign_flirt_write_string_pattern_to_buffer (RZ_NONNULL const RzFlirtNode *root, RZ_NONNULL RzBuffer *buffer)
 Writes in the the RzBuffer the FLIRT signatures in string format. More...
 

Detailed Description

FLIRT uncompressed file format.

An example of uncompressed format is shown below:

# some comment
4154554889FD534889F3C60700E8........C6441DFF004189C485C07515BE2E 07 FAEE 003B :0000@ Curl_gethostname ^0027 strchr ........4885C07403C600004489E05B5D415CC3
31C04885D2741F488D4417FF4839C77610EB1D0F1F4400004883E8014839C777 13 9867 0033 :0000 Curl_memrchr
---
#define B(x)
Definition: arc.h:166

The '—' is the pat file terminator Some files may contain comments using hashtag (#) as prefix but it is not the standard format.

4154554889FD534889F3C60700E8........C6441DFF004189C485C07515BE2E `--— Each line starts with a pattern mask (usually 32 bytes long)

07 FAEE | ---- CRC16 value ------— CRC16 length

003B ^----— Function size (min 2 bytes, but can be bigger)

:0000@ Curl_gethostname | || -------------- Symbol name | |-----------------— If set, then is local symbol | --------------------- Symbol offset and type (: -> public) ----------------------— Symbol type (: -> public, ^ -> reference)

This symbol, is a list and can be repeated N-times

........4885C07403C600004489E05B5D415CC3 `--— The line can end with another pattern mask

Definition in file pat.c.

Macro Definition Documentation

◆ pat_dbg

#define pat_dbg (   ...)

Definition at line 49 of file pat.c.

◆ PAT_LINE_BUFFER_SIZE

#define PAT_LINE_BUFFER_SIZE   1024

Definition at line 52 of file pat.c.

Function Documentation

◆ decode_byte()

static ut8 decode_byte ( char  b)
inlinestatic

Definition at line 58 of file pat.c.

58  {
59  if (b >= '0' && b <= '9') {
60  return b - '0';
61  } else if (b >= 'A' && b <= 'F') {
62  return (b - 'A') + 10;
63  }
64  return (b - 'a') + 10;
65 }
#define b(i)
Definition: sha256.c:42

References b.

Referenced by parse_byte().

◆ flirt_compare_node()

int flirt_compare_node ( const RzFlirtNode a,
const RzFlirtNode b 
)

Definition at line 225 of file create.c.

225  {
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 }
#define RZ_MIN(x, y)
#define a(i)
Definition: sha256.c:41

References a, b, and RZ_MIN.

Referenced by flirt_node_optimize(), flirt_node_shorten_and_insert(), rz_sign_flirt_node_new(), and rz_sign_flirt_parse_string_pattern_from_buffer().

◆ flirt_node_optimize()

bool flirt_node_optimize ( RzFlirtNode root)

Definition at line 316 of file create.c.

316  {
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 }
int flirt_compare_node(const RzFlirtNode *a, const RzFlirtNode *b)
Definition: create.c:225
static bool flirt_node_shorten_and_insert(const RzFlirtNode *root, RzFlirtNode *node)
Definition: create.c:244
#define NULL
Definition: cris-opc.c:27
int root
Definition: enough.c:226
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 ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
RZ_API void rz_sign_flirt_node_free(RZ_NULLABLE RzFlirtNode *node)
Frees an RzFlirtNode struct.
Definition: flirt.c:299
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_ERROR(fmtstr,...)
Definition: rz_log.h:58
void * data
Definition: rz_list.h:14
#define fail(test)
Definition: tests.h:29

References rz_list_iter_t::data, fail, flirt_compare_node(), flirt_node_shorten_and_insert(), NULL, root, rz_list_free(), rz_list_length(), rz_list_newf(), rz_list_sort(), RZ_LOG_ERROR, and rz_sign_flirt_node_free().

Referenced by rz_sign_flirt_node_new(), and rz_sign_flirt_parse_string_pattern_from_buffer().

◆ flirt_pat_append_prelude()

static void flirt_pat_append_prelude ( RzStrBuf prelude,
RZ_NONNULL const RzFlirtNode child 
)
static

Definition at line 443 of file pat.c.

443  {
444  for (ut32 i = 0; i < child->length; i++) {
445  if (child->pattern_mask[i]) {
446  rz_strbuf_appendf(prelude, "%02X", child->pattern_bytes[i]);
447  } else {
448  rz_strbuf_append(prelude, "..");
449  }
450  }
451 }
lzma_index ** i
Definition: index.h:629
uint32_t ut32
RZ_API bool rz_strbuf_append(RzStrBuf *sb, const char *s)
Definition: strbuf.c:222
RZ_API bool rz_strbuf_appendf(RzStrBuf *sb, const char *fmt,...) RZ_PRINTF_CHECK(2

References i, rz_strbuf_append(), and rz_strbuf_appendf().

Referenced by flirt_pat_write_line().

◆ flirt_pat_parse_line()

static bool flirt_pat_parse_line ( RzFlirtNode root,
RzStrBuf sb,
ut32  line_num,
bool  tail_bytes 
)
static

Expects one of these line formats and lines may end with '\r'

4154554889FD534889F3C60700E8........C6441DFF004189C485C07515BE2E 07 FAEE 003B :0000@ Curl_gethostname ^000E gethostname ^0027 strchr ........4885C07403C600004489E05B5D415CC3 31C04885D2741F488D4417FF4839C77610EB1D0F1F4400004883E8014839C777 13 9867 0033 :0000 Curl_memrchr

# some comment line

The '—' are the pat file terminator Some files may contain comments using hashtag (#) as prefix

Definition at line 140 of file pat.c.

140  {
141  RzFlirtNode *child = NULL;
143  char *tmp_tok = NULL;
144 
145  int line_len = rz_strbuf_length(sb);
146  char *line = rz_strbuf_get(sb);
147  if (!strncmp(line, "---", strlen("---"))) {
148  return false;
149  } else if (line[0] == '#') {
150  return true;
151  }
152 
153  if (line[line_len - 1] == '\r') {
154  line_len--;
155  line[line_len] = 0;
156  if (*line || line_len < 1) {
157  RZ_LOG_WARN("FLIRT: line %u is empty\n", line_num);
158  return true;
159  }
160  }
161 
162  RzList *tokens = rz_str_split_list(line, " ", 0);
163  if (rz_list_empty(tokens)) {
164  RZ_LOG_ERROR("FLIRT: cannot tokenize line %u\n", line_num);
165  goto err;
166  }
167 
168  child = RZ_NEW0(RzFlirtNode);
169  if (!child) {
170  RZ_LOG_ERROR("FLIRT: cannot allocate child node\n");
171  goto err;
172  }
173 
175  if (!child->module_list) {
176  RZ_LOG_ERROR("FLIRT: cannot allocate child module list\n");
177  goto err;
178  }
179 
181  if (!module || !rz_list_append(child->module_list, module)) {
182  free(module);
183  RZ_LOG_ERROR("FLIRT: cannot allocate or append child module\n");
184  goto err;
185  }
186 
187  module->public_functions = rz_list_newf((RzListFree)free);
188  if (!module->public_functions) {
189  RZ_LOG_ERROR("FLIRT: cannot allocate child module public function list\n");
190  goto err;
191  }
192 
193  module->referenced_functions = rz_list_newf((RzListFree)free);
194  if (!module->public_functions) {
195  RZ_LOG_ERROR("FLIRT: cannot allocate child module referenced function list\n");
196  goto err;
197  }
198 
199  // Pattern with mask
200  // 4154554889FD534889F3C60700E8........C6441DFF004189C485C07515BE2E
201  // 31C04885D2741F488D4417FF4839C77610EB1D0F1F4400004883E8014839C777
202  tmp_tok = (char *)rz_list_pop_head(tokens);
203  if (!flirt_pat_parse_pattern_mask(tmp_tok, child)) {
204  RZ_LOG_ERROR("FLIRT: invalid pattern with mask (%s) at line %u\n", tmp_tok, line_num);
205  goto err;
206  }
207  pat_dbg("pattern: %s\n", tmp_tok);
208 
209  // CRC16 length
210  // [...] 07
211  // [...] 13
212  tmp_tok = (char *)rz_list_pop_head(tokens);
213  if (tmp_tok && strlen(tmp_tok) == 2 && IS_HEXCHAR(tmp_tok[0]) && IS_HEXCHAR(tmp_tok[1])) {
214  module->crc_length = parse_byte(tmp_tok[0], tmp_tok[1]);
215  } else {
216  RZ_LOG_ERROR("FLIRT: invalid crc16 length (%s) at line %u\n", tmp_tok, line_num);
217  goto err;
218  }
219  pat_dbg("crc16 length: %s\n", tmp_tok);
220 
221  // CRC16 value
222  // [...] FAEE
223  // [...] 9867
224  tmp_tok = (char *)rz_list_pop_head(tokens);
225  if (tmp_tok && strlen(tmp_tok) == 4 &&
226  IS_HEXCHAR(tmp_tok[0]) && IS_HEXCHAR(tmp_tok[1]) &&
227  IS_HEXCHAR(tmp_tok[2]) && IS_HEXCHAR(tmp_tok[3])) {
228  module->crc16 = parse_byte(tmp_tok[0], tmp_tok[1]) << 8;
229  module->crc16 |= parse_byte(tmp_tok[2], tmp_tok[3]);
230  } else {
231  RZ_LOG_ERROR("FLIRT: invalid crc16 value (%s) at line %u\n", tmp_tok, line_num);
232  goto err;
233  }
234  pat_dbg("crc16: %s\n", tmp_tok);
235 
236  // function size (min 2 bytes, but can be bigger)
237  // [...] 003B
238  // [...] 0033
239  tmp_tok = (char *)rz_list_pop_head(tokens);
240  if (!tmp_tok || strlen(tmp_tok) < 4 || !(module->length = strtol(tmp_tok, NULL, 16))) {
241  RZ_LOG_ERROR("FLIRT: invalid function size (%s) at line %u\n", tmp_tok, line_num);
242  goto err;
243  }
244  pat_dbg("function size: %s\n", tmp_tok);
245 
246  // symbols
247  // :0000@ Curl_gethostname ^000E gethostname ^0027 strchr
248  // :0000 Curl_memrchr
249  while ((tmp_tok = (char *)rz_list_pop_head(tokens)) && RZ_STR_ISNOTEMPTY(tmp_tok)) {
250  RzList *to_append = NULL;
251  ut32 len_tok = strlen(tmp_tok);
252  ut32 offset = 0;
253  bool is_local = false;
254  if (len_tok > 0 && !(len_tok & 1) && (IS_HEXCHAR(tmp_tok[0]) || tmp_tok[0] == '.')) {
255  // it's trailer bytes
256  break;
257  }
258 
259  if (len_tok >= 6 && tmp_tok[0] == ':' && tmp_tok[len_tok - 1] == '@') {
260  // :0000@ -> local function (handling it as public)
261  tmp_tok[len_tok - 1] = 0;
262  offset = strtol(tmp_tok + 1, NULL, 16);
263  is_local = true;
264  to_append = module->public_functions;
265  tmp_tok[len_tok - 1] = '@';
266  } else if (len_tok >= 5 && tmp_tok[0] == ':') {
267  // :0000 -> public function
268  offset = strtol(tmp_tok + 1, NULL, 16);
269  to_append = module->public_functions;
270  } else if (len_tok == 5 && tmp_tok[0] == '^') {
271  // ^0000 -> reference function
272  offset = strtol(tmp_tok + 1, NULL, 16);
273  to_append = module->referenced_functions;
274  } else {
275  RZ_LOG_ERROR("FLIRT: invalid symbol offset (%.10s len %u) at line %u\n", tmp_tok, len_tok, line_num);
276  goto err;
277  }
278 
279  tmp_tok = (char *)rz_list_pop_head(tokens);
280  if (RZ_STR_ISEMPTY(tmp_tok)) {
281  RZ_LOG_ERROR("FLIRT: empty symbol name at line %u\n", line_num);
282  goto err;
283  }
284  len_tok = strlen(tmp_tok);
285 
287  if (!function || !rz_list_append(to_append, function)) {
288  free(function);
289  RZ_LOG_ERROR("FLIRT: cannot allocate or append RzFlirtFunction\n");
290  goto err;
291  }
292  function->is_local = is_local;
293  function->offset = offset;
294  strncpy(function->name, tmp_tok, RZ_MIN(len_tok, RZ_FLIRT_NAME_MAX - 1));
295  pat_dbg("%s function: %04x %s\n", to_append == module->referenced_functions ? "ref" : (function->is_local ? "loc" : "pub"), offset, tmp_tok);
296  }
297 
298  if (tail_bytes && RZ_STR_ISNOTEMPTY(tmp_tok) && (IS_HEXCHAR(tmp_tok[0]) || tmp_tok[0] == '.')) {
299  size_t len_tok = strlen(tmp_tok);
300 
301  module->tail_bytes = rz_list_newf((RzListFree)free);
302  if (!module->public_functions) {
303  RZ_LOG_ERROR("FLIRT: cannot allocate child module tail bytes list\n");
304  goto err;
305  }
306 
307  for (ut32 i = 0, o = 0; i < len_tok && rz_list_length(module->tail_bytes) < 0xFF; i += 2, o++) {
308  if (tmp_tok[i] == '.' && tmp_tok[i + 1] == '.') {
309  continue;
310  } else if (!IS_HEXCHAR(tmp_tok[i]) || !IS_HEXCHAR(tmp_tok[i + 1])) {
311  RZ_LOG_ERROR("FLIRT: expecting tail byte at line %u but got (%s)\n", line_num, tmp_tok + i);
312  goto err;
313  }
314  ut8 byte = parse_byte(tmp_tok[i], tmp_tok[i + 1]);
315 
317  if (!tail || !rz_list_append(module->tail_bytes, tail)) {
318  free(tail);
319  RZ_LOG_ERROR("FLIRT: cannot allocate or append RzFlirtTailByte\n");
320  goto err;
321  }
322 
323  tail->offset = o;
324  tail->value = byte;
325  }
326  pat_dbg("tail: %s\n", tmp_tok);
327  }
328 
329  if (rz_list_length(module->public_functions) < 1) {
330  RZ_LOG_ERROR("FLIRT: a node must have at least one public function\n");
331  goto err;
332  }
333 
334  if (!rz_list_append(root->child_list, child)) {
335  RZ_LOG_ERROR("FLIRT: cannot append child to root\n");
336  goto err;
337  }
338 
339  rz_list_free(tokens);
340  return true;
341 
342 err:
344  rz_list_free(tokens);
345  return false;
346 }
static bool err
Definition: armass.c:435
static SblHeader sb
Definition: bin_mbn.c:26
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
RZ_API RZ_OWN void * rz_list_pop_head(RZ_NONNULL RzList *list)
Removes and returns the first element of the list.
Definition: list.c:401
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
line
Definition: setup.py:34
void module_free(RzFlirtModule *module)
Definition: flirt.c:284
static bool flirt_pat_parse_pattern_mask(const char *in_pattern, RzFlirtNode *child)
Definition: pat.c:72
static ut8 parse_byte(char high, char low)
Definition: pat.c:67
#define pat_dbg(...)
Definition: pat.c:49
#define RZ_FLIRT_NAME_MAX
Definition: rz_flirt.h:17
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
#define RZ_STR_ISNOTEMPTY(x)
Definition: rz_str.h:68
#define RZ_STR_ISEMPTY(x)
Definition: rz_str.h:67
RZ_API RzList * rz_str_split_list(char *str, const char *c, int n)
Split the string str according to the substring c and returns a RzList with the result.
Definition: str.c:3429
#define IS_HEXCHAR(x)
Definition: rz_str_util.h:9
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
RZ_API int rz_strbuf_length(RzStrBuf *sb)
Definition: strbuf.c:28
#define RZ_NEW0(x)
Definition: rz_types.h:284
Definition: sftypes.h:77
RzList * module_list
Definition: rz_flirt.h:178

References err, flirt_pat_parse_pattern_mask(), free(), i, IS_HEXCHAR, setup::line, module_free(), rz_flirt_node_t::module_list, NULL, rz_flirt_tail_byte_t::offset, parse_byte(), pat_dbg, root, RZ_FLIRT_NAME_MAX, rz_list_append(), rz_list_free(), rz_list_length(), rz_list_newf(), rz_list_pop_head(), RZ_LOG_ERROR, RZ_LOG_WARN, RZ_MIN, RZ_NEW0, rz_sign_flirt_node_free(), RZ_STR_ISEMPTY, RZ_STR_ISNOTEMPTY, rz_str_split_list(), rz_strbuf_get(), rz_strbuf_length(), sb, and rz_flirt_tail_byte_t::value.

Referenced by rz_sign_flirt_parse_string_pattern_from_buffer().

◆ flirt_pat_parse_pattern_mask()

static bool flirt_pat_parse_pattern_mask ( const char *  in_pattern,
RzFlirtNode child 
)
static

Definition at line 72 of file pat.c.

72  {
73  size_t length = 0;
74  ut8 *bytes = NULL, *mask = NULL;
75 
76  if (RZ_STR_ISEMPTY(in_pattern)) {
77  return false;
78  }
79 
80  length = strlen(in_pattern);
81  if (length & 1) {
82  return false;
83  }
84 
85  ut32 n_bytes = length >> 1;
86 
87  bytes = RZ_NEWS(ut8, n_bytes);
88  if (!bytes) {
89  RZ_LOG_ERROR("FLIRT: cannot allocate child bytes\n");
90  return false;
91  }
92 
93  mask = RZ_NEWS(ut8, n_bytes);
94  if (!mask) {
95  RZ_LOG_ERROR("FLIRT: cannot allocate child mask\n");
96  goto err;
97  }
98 
99  child->variant_mask = 0;
100  for (ut32 i = 0; i < n_bytes; ++i) {
101  child->variant_mask <<= 1;
102  ut32 p = i << 1;
103  char high = in_pattern[p];
104  char low = in_pattern[p + 1];
105  if (IS_HEXCHAR(high) && IS_HEXCHAR(low)) {
106  bytes[i] = parse_byte(high, low);
107  mask[i] = 0xFF;
108  } else if (high == '.' && low == '.') {
109  bytes[i] = 0;
110  mask[i] = 0;
111  child->variant_mask |= 1;
112  } else {
113  goto err;
114  }
115  }
116 
117  child->pattern_bytes = bytes;
118  child->pattern_mask = mask;
119  child->length = n_bytes;
120  return true;
121 
122 err:
123  child->variant_mask = 0;
124  free(mask);
125  free(bytes);
126  return false;
127 }
#define mask()
static ut8 bytes[32]
Definition: asm_arc.c:23
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
void * p
Definition: libc.cpp:67
#define RZ_NEWS(x, y)
Definition: rz_types.h:283
ut8 * pattern_mask
Definition: rz_flirt.h:182
ut8 * pattern_bytes
Definition: rz_flirt.h:181
ut64 variant_mask
Definition: rz_flirt.h:180

References bytes, err, free(), i, IS_HEXCHAR, rz_flirt_node_t::length, length, mask, NULL, p, parse_byte(), rz_flirt_node_t::pattern_bytes, rz_flirt_node_t::pattern_mask, RZ_LOG_ERROR, RZ_NEWS, RZ_STR_ISEMPTY, and rz_flirt_node_t::variant_mask.

Referenced by flirt_pat_parse_line().

◆ flirt_pat_write_line()

static bool flirt_pat_write_line ( RZ_NONNULL const RzFlirtNode node,
RZ_NONNULL RzBuffer buffer,
RzStrBuf prelude 
)
static

Definition at line 453 of file pat.c.

453  {
454  flirt_pat_append_prelude(prelude, node);
455  int prelude_len = rz_strbuf_length(prelude);
456 
457  if (rz_list_length(node->child_list) > 0) {
458  RzListIter *it;
459  RzFlirtNode *child;
460  rz_list_foreach (node->child_list, it, child) {
461  rz_strbuf_slice(prelude, 0, prelude_len);
462  if (!flirt_pat_write_line(child, buffer, prelude)) {
463  return false;
464  }
465  }
466  return true;
467  }
468 
469  if (prelude_len < (RZ_FLIRT_MAX_PRELUDE_SIZE << 1)) {
470  const char *pad = rz_str_pad('.', (RZ_FLIRT_MAX_PRELUDE_SIZE << 1) - prelude_len);
471  rz_strbuf_append(prelude, pad);
472  }
473 
474  char tmp[32];
475  ut32 offset = 0;
476  RzListIter *it, *it2;
477  const RzFlirtModule *module;
478  const RzFlirtFunction *function;
479  const RzFlirtTailByte *byte;
480  rz_list_foreach (node->module_list, it, module) {
481  // prelude pattern mask
483 
484  // crc16 length + crc16 value
485  rz_strf(tmp, " %02X %04X ", module->crc_length, module->crc16);
487 
488  // function size
489  rz_strf(tmp, "%04X ", module->length);
491  // public functions
492  rz_list_foreach (module->public_functions, it2, function) {
493  rz_strf(tmp, ":%04X%s ", function->offset, function->is_local ? "@" : "");
495  rz_buf_append_string(buffer, function->name);
497  }
498  // referenced functions
499  rz_list_foreach (module->referenced_functions, it2, function) {
500  rz_strf(tmp, "^%04X ", function->offset);
502  rz_buf_append_string(buffer, function->name);
504  }
505 
506  // tail bytes (if any)
507  offset = 0;
508  rz_list_foreach (module->tail_bytes, it2, byte) {
509  while (offset < byte->offset) {
511  offset++;
512  }
513  rz_strf(tmp, "%02X", byte->value);
515  offset++;
516  }
518  }
519  return true;
520 }
static bool flirt_pat_write_line(RZ_NONNULL const RzFlirtNode *node, RZ_NONNULL RzBuffer *buffer, RzStrBuf *prelude)
Definition: pat.c:453
static void flirt_pat_append_prelude(RzStrBuf *prelude, RZ_NONNULL const RzFlirtNode *child)
Definition: pat.c:443
static void pad(RzStrBuf *sb, ut32 count)
Definition: protobuf.c:36
RZ_API st64 rz_buf_append_string(RZ_NONNULL RzBuffer *b, RZ_NONNULL const char *str)
Append a string to the buffer.
Definition: buf.c:962
#define RZ_FLIRT_MAX_PRELUDE_SIZE
Definition: rz_flirt.h:20
RZ_API const char * rz_str_pad(const char ch, int len)
Definition: str.c:3236
#define rz_strf(buf,...)
Convenience macro for local temporary strings.
Definition: rz_str.h:59
RZ_API bool rz_strbuf_slice(RZ_NONNULL RzStrBuf *sb, size_t from, size_t len)
Cuts the current string into a substring.
Definition: strbuf.c:122
Definition: buffer.h:15

References flirt_pat_append_prelude(), pad(), rz_buf_append_string(), RZ_FLIRT_MAX_PRELUDE_SIZE, rz_list_length(), rz_str_pad(), rz_strbuf_append(), rz_strbuf_get(), rz_strbuf_length(), rz_strbuf_slice(), rz_strf, autogen_x86imm::tmp, and rz_flirt_tail_byte_t::value.

Referenced by rz_sign_flirt_write_string_pattern_to_buffer().

◆ module_free()

void module_free ( RzFlirtModule module)

Definition at line 284 of file flirt.c.

284  {
285  if (!module) {
286  return;
287  }
288  rz_list_free(module->public_functions);
289  rz_list_free(module->tail_bytes);
290  rz_list_free(module->referenced_functions);
291  free(module);
292 }

Referenced by flirt_pat_parse_line(), and parse_leaf().

◆ parse_byte()

static ut8 parse_byte ( char  high,
char  low 
)
inlinestatic

Definition at line 67 of file pat.c.

67  {
68  ut8 value = decode_byte(high) << 4;
69  return value | decode_byte(low);
70 }
static int value
Definition: cmd_api.c:93
static ut8 decode_byte(char b)
Definition: pat.c:58

References decode_byte(), and value.

Referenced by flirt_pat_parse_line(), and flirt_pat_parse_pattern_mask().

◆ rz_sign_flirt_parse_string_pattern_from_buffer()

RZ_API RZ_OWN RzFlirtNode* rz_sign_flirt_parse_string_pattern_from_buffer ( RZ_NONNULL RzBuffer flirt_buf,
ut32  optimization,
RZ_NULLABLE RzFlirtInfo info 
)

Parses the RzBuffer containing a FLIRT signature in string format and returns an RzFlirtNode.

Parameters
flirt_bufThe buffer to read
optimizationOptimization to apply after creation of the flatten nodes.
infoPointer to a RzFlirtInfo that can be used to get info about the pat file
Returns
Parsed FLIRT node

Definition at line 356 of file pat.c.

356  {
357  rz_return_val_if_fail(flirt_buf, NULL);
358 
359  if (optimization > RZ_FLIRT_NODE_OPTIMIZE_MAX) {
360  RZ_LOG_ERROR("FLIRT: optimization value is invalid (%u > RZ_FLIRT_NODE_OPTIMIZE_MAX).\n", optimization);
361  return NULL;
362  }
363 
365  const char *buffer_end = buffer + sizeof(buffer);
366  ut32 line_num = 1;
367  char *newline = NULL;
368  st64 read = 0;
369  RzFlirtNode *root = NULL;
370  RzStrBuf *line = NULL;
371 
373  if (!root) {
374  RZ_LOG_ERROR("FLIRT: cannot allocate root node\n");
375  return NULL;
376  }
377 
379  if (!root->child_list) {
380  free(root);
381  RZ_LOG_ERROR("FLIRT: cannot allocate root node child list\n");
382  return NULL;
383  }
384 
385  line = rz_strbuf_new("");
386  if (!line) {
388  RZ_LOG_ERROR("FLIRT: cannot allocate line buffer\n");
389  return NULL;
390  }
391 
392  bool tail_bytes = optimization != RZ_FLIRT_NODE_OPTIMIZE_MAX;
393  do {
394  if (newline && rz_strbuf_length(line) > 0) {
395  char *p = newline + 1;
396  pat_dbg("%05u: %s\n", line_num, rz_strbuf_get(line));
397  bool parsed = flirt_pat_parse_line(root, line, line_num, tail_bytes);
400  if (!parsed) {
401  break;
402  }
403  line_num++;
404  if (p < buffer_end && *p) {
405  if ((newline = strchr(p, '\n'))) {
406  newline[0] = 0;
407  }
409  }
410  continue;
411  }
412  memset(buffer, 0, sizeof(buffer));
413  if ((read = rz_buf_read(flirt_buf, (ut8 *)buffer, sizeof(buffer) - 1)) < 1) {
414  break;
415  }
416  if ((newline = strchr(buffer, '\n'))) {
417  newline[0] = 0;
418  }
420  } while (true);
421 
422  if (rz_strbuf_length(line) > 0) {
423  flirt_pat_parse_line(root, line, line_num, tail_bytes);
424  }
425 
427 
428  if (optimization == RZ_FLIRT_NODE_OPTIMIZE_NONE) {
430  } else if (!flirt_node_optimize(root)) {
432  return NULL;
433  }
434 
435  if (info) {
437  info->u.pat.n_modules = rz_sign_flirt_node_count_nodes(root);
438  }
439 
440  return root;
441 }
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
struct buffer buffer
return memset(p, 0, total)
#define PAT_LINE_BUFFER_SIZE
Definition: pat.c:52
int flirt_compare_node(const RzFlirtNode *a, const RzFlirtNode *b)
Definition: create.c:225
static bool flirt_pat_parse_line(RzFlirtNode *root, RzStrBuf *sb, ut32 line_num, bool tail_bytes)
Definition: pat.c:140
bool flirt_node_optimize(RzFlirtNode *root)
Definition: create.c:316
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API st64 rz_buf_read(RZ_NONNULL RzBuffer *b, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
RZ_API ut32 rz_sign_flirt_node_count_nodes(RZ_NONNULL const RzFlirtNode *node)
Counts the number of FLIRT signatures in the node.
Definition: flirt.c:1334
@ 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
@ RZ_FLIRT_FILE_TYPE_PAT
.pat text format pattern file
Definition: rz_flirt.h:194
RZ_API void rz_strbuf_fini(RzStrBuf *sb)
Definition: strbuf.c:365
RZ_API RzStrBuf * rz_strbuf_new(const char *s)
Definition: strbuf.c:8
RZ_API void rz_strbuf_free(RzStrBuf *sb)
Definition: strbuf.c:358
RZ_API void rz_strbuf_init(RzStrBuf *sb)
Definition: strbuf.c:33
#define st64
Definition: rz_types_base.h:10
char * type
Definition: rz_bin.h:211
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115

References flirt_compare_node(), flirt_node_optimize(), flirt_pat_parse_line(), free(), info(), setup::line, memset(), NULL, p, pat_dbg, PAT_LINE_BUFFER_SIZE, read(), root, rz_buf_read(), RZ_FLIRT_FILE_TYPE_PAT, RZ_FLIRT_NODE_OPTIMIZE_MAX, RZ_FLIRT_NODE_OPTIMIZE_NONE, rz_list_newf(), rz_list_sort(), RZ_LOG_ERROR, RZ_NEW0, rz_return_val_if_fail, rz_sign_flirt_node_count_nodes(), rz_sign_flirt_node_free(), rz_strbuf_append(), rz_strbuf_fini(), rz_strbuf_free(), rz_strbuf_get(), rz_strbuf_init(), rz_strbuf_length(), rz_strbuf_new(), st64, and rz_bin_info_t::type.

Referenced by rz_core_flirt_convert_file(), rz_core_flirt_dump_file(), rz_sign_flirt_apply(), and sigdb_signature_resolve_details().

◆ rz_sign_flirt_write_string_pattern_to_buffer()

RZ_API bool rz_sign_flirt_write_string_pattern_to_buffer ( RZ_NONNULL const RzFlirtNode root,
RZ_NONNULL RzBuffer buffer 
)

Writes in the the RzBuffer the FLIRT signatures in string format.

Parameters
rootThe FLIRT root node to use as input
bufferThe buffer to write to
Returns
Parsed FLIRT node

Definition at line 529 of file pat.c.

529  {
530  rz_return_val_if_fail(root && buffer, false);
531  // 4154554889FD534889F3C60700E8........C6441DFF004189C485C07515BE2E 07 FAEE 003B :0000@ Curl_gethostname ^000E gethostname ^0027 strchr ........4885C07403C600004489E05B5D415CC3
532  RzStrBuf sb;
533 
534  RzListIter *it;
535  RzFlirtNode *child;
536  rz_list_foreach (root->child_list, it, child) {
537  rz_strbuf_init(&sb);
538  if (!flirt_pat_write_line(child, buffer, &sb)) {
539  return false;
540  }
541  rz_strbuf_fini(&sb);
542  }
543  rz_buf_append_string(buffer, "---\n");
544  return true;
545 }

References flirt_pat_write_line(), root, rz_buf_append_string(), rz_return_val_if_fail, rz_strbuf_fini(), rz_strbuf_init(), and sb.

Referenced by rz_core_flirt_convert_file(), and rz_core_flirt_create_file().