Rizin
unix-like reverse engineering framework and cli tools
sigdb.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 
5 #include <rz_flirt.h>
6 
13  if (!entry) {
14  return;
15  }
16  // base_name points to file_path, so there is no need to call free
17  // short_path points to file_path, so there is no need to call free
18  free(entry->bin_name);
19  free(entry->arch_name);
20  free(entry->file_path);
21  free(entry);
22 }
23 
24 static int sigdb_signature_cmp(const RzSigDBEntry *a, const RzSigDBEntry *b) {
25  return strcmp(a->short_path, b->short_path);
26 }
27 
28 static bool sigdb_signature_resolve_details(RzSigDBEntry *entry, size_t path_len, bool with_details) {
29  char *bin_end = NULL;
30  char *arch_end = NULL;
31  char *bits_end = NULL;
32  char copy_path[1024] = { 0 };
33  RzFlirtNode *node = NULL;
34  RzFlirtInfo info = { 0 };
35  RzBuffer *buffer = NULL;
36 
37 #if __WINDOWS__
38  rz_str_replace_char(entry->file_path, '/', '\\');
39 #endif
40  // expected path elf/x86/64/signature.sig/.pat
41  strncpy(copy_path, entry->file_path + path_len, sizeof(copy_path) - 1);
42  entry->base_name = rz_file_basename(entry->file_path);
43  entry->short_path = entry->file_path + path_len;
44 
45  if (!(bin_end = strstr(copy_path, RZ_SYS_DIR))) {
46  RZ_LOG_WARN("sigdb: folder structure is invalid (missing bin name).\n");
47  return false;
48  } else if (!(arch_end = strstr(bin_end + strlen(RZ_SYS_DIR), RZ_SYS_DIR))) {
49  RZ_LOG_WARN("sigdb: folder structure is invalid (missing arch name).\n");
50  return false;
51  } else if (!(bits_end = strstr(arch_end + strlen(RZ_SYS_DIR), RZ_SYS_DIR))) {
52  RZ_LOG_WARN("sigdb: folder structure is invalid (missing arch bits).\n");
53  return false;
54  }
55 
56  if (!with_details) {
57  goto skip_details;
58  }
59 
60  buffer = rz_buf_new_file(entry->file_path, O_RDONLY, 0);
61  if (!buffer) {
62  RZ_LOG_WARN("sigdb: cannot open signature file '%s'.\n", entry->file_path);
63  return false;
64  }
65 
66  if (rz_str_endswith(entry->base_name, ".sig")) {
69  if (!success) {
70  return false;
71  }
72 
73  entry->details = RZ_STR_DUP(info.u.sig.name);
74  entry->n_modules = info.u.sig.n_modules;
75  } else {
78  if (!node) {
79  return false;
80  }
81 
82  entry->n_modules = info.u.pat.n_modules;
83  }
86 
87 skip_details:
88  bin_end[0] = 0;
89  entry->bin_name = strdup(copy_path);
90  arch_end[0] = 0;
91  entry->arch_name = strdup(bin_end + strlen(RZ_SYS_DIR));
92  bits_end[0] = 0;
93  entry->arch_bits = rz_get_input_num_value(NULL, arch_end + strlen(RZ_SYS_DIR));
94 
95  return true;
96 }
97 
105 RZ_API RZ_OWN RzSigDb *rz_sign_sigdb_load_database(RZ_NONNULL const char *sigdb_path, bool with_details) {
107  char glob[1024];
108  if (!rz_file_is_directory(sigdb_path)) {
109  RZ_LOG_ERROR("sigdb path is unknown or invalid (path: %s)\n", sigdb_path);
110  return NULL;
111  }
112  size_t path_len = strlen(sigdb_path) + 1; // ignoring also the filesystem separator
113  RzSigDb *sigs = rz_sign_sigdb_new();
114  if (!sigs) {
115  RZ_LOG_ERROR("cannot allocate signature database\n");
116  return NULL;
117  }
118 
119  rz_strf(glob, RZ_JOIN_2_PATHS("%s", "**"), sigdb_path);
120  RzList *files = rz_file_globsearch(glob, 10);
121  char *file = NULL;
122  RzListIter *iter = NULL;
123  RzSigDBEntry *sig = NULL;
124 
125  rz_list_foreach (files, iter, file) {
126  if (!rz_str_endswith(file, ".pat") && !rz_str_endswith(file, ".sig")) {
127  continue;
128  }
129 
130  sig = RZ_NEW0(RzSigDBEntry);
131  if (!sig) {
132  goto fail;
133  }
134 
135  sig->file_path = strdup(file);
136  if (!sig->file_path || !sigdb_signature_resolve_details(sig, path_len, with_details)) {
138  goto fail;
139  }
140  rz_sign_sigdb_add_entry(sigs, sig);
141  }
143  return sigs;
144 
145 fail:
147  rz_sign_sigdb_free(sigs);
148  return NULL;
149 }
150 
160  return ht_pu_insert(db->entries, entry, 1);
161 }
162 
166 };
167 
168 static bool sigdb_move_entry(void *user, const void *k, const ut64 v) {
169  struct sigdb_move_data_t *move_data = (struct sigdb_move_data_t *)user;
170  rz_sign_sigdb_add_entry(move_data->dst, k);
171  ht_pu_delete(move_data->src->entries, k);
172  return true;
173 }
174 
185  rz_return_val_if_fail(db && db2, NULL);
186  struct sigdb_move_data_t opt = {
187  .src = db2,
188  .dst = db,
189  };
190  db2->entries->opt.freefn = NULL;
191  ht_pu_foreach(db2->entries, sigdb_move_entry, &opt);
192  return true;
193 }
194 
195 static int ut32cmp(int a, int b) {
196  if (a < b) {
197  return -1;
198  }
199  if (a > b) {
200  return 1;
201  }
202  return 0;
203 }
204 
205 static int strcmp_null(const char *a, const char *b) {
206  if (!a && !b) {
207  return 0;
208  }
209  if (!a && b) {
210  return -1;
211  }
212  if (a && !b) {
213  return 1;
214  }
215  return strcmp(a, b);
216 }
217 
218 static int sigdb_entry_cmp(const void *a, const void *b) {
219 #define field_cmp(fname, cmpfunction) \
220  do { \
221  int r = cmpfunction(sa->fname, sb->fname); \
222  if (r != 0) { \
223  return r; \
224  } \
225  } while (0)
226 
227  const RzSigDBEntry *sa = (const RzSigDBEntry *)a;
228  const RzSigDBEntry *sb = (const RzSigDBEntry *)b;
229  field_cmp(bin_name, strcmp_null);
230  field_cmp(arch_name, strcmp_null);
231  field_cmp(arch_bits, ut32cmp);
232  field_cmp(base_name, strcmp_null);
233  field_cmp(short_path, strcmp_null);
234  field_cmp(file_path, strcmp_null);
235  field_cmp(details, strcmp_null);
236  field_cmp(n_modules, ut32cmp);
237  return 0;
238 #undef field_cmp
239 }
240 
241 static ut32 sigdb_entry_hash(const void *k) {
242  const RzSigDBEntry *s = (const RzSigDBEntry *)k;
243  ut32 r = sdb_hash(s->bin_name);
244  r ^= sdb_hash(s->arch_name);
245  r ^= s->arch_bits;
246  r ^= sdb_hash(s->short_path);
247  return r;
248 }
249 
250 static void ht_pu_sigdb_freekv(HtPUKv *kv) {
251  if (!kv) {
252  return;
253  }
255 }
256 
261  RzSigDb *db = RZ_NEW0(RzSigDb);
262  if (!db) {
263  return NULL;
264  }
265  HtPUOptions opt = { 0 };
266  opt.cmp = sigdb_entry_cmp,
267  opt.hashfn = sigdb_entry_hash,
268  opt.freefn = ht_pu_sigdb_freekv;
269  db->entries = ht_pu_new_opt(&opt);
270  if (!db->entries) {
271  free(db);
272  return NULL;
273  }
274  return db;
275 }
276 
278  if (!db) {
279  return;
280  }
281  ht_pu_free(db->entries);
282  free(db);
283 }
284 
285 static bool sigdb_to_list(void *user, const void *k, const ut64 v) {
286  RzList *l = (RzList *)user;
287  rz_list_append(l, (void *)k);
288  return true;
289 }
290 
294 RZ_API RZ_OWN RzList /*<RzSigDBEntry *>*/ *rz_sign_sigdb_list(RZ_NONNULL const RzSigDb *db) {
296 
297  RzList *res = rz_list_new();
298  if (!res) {
299  return NULL;
300  }
301  ht_pu_foreach(db->entries, sigdb_to_list, res);
303  return res;
304 }
static SblHeader sb
Definition: bin_mbn.c:26
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
uint32_t ut32
const char * k
Definition: dsignal.c:11
const char * v
Definition: dsignal.c:12
checking print the parsed form of the magic use in n conjunction with m to debug a new magic file n before installing it n output MIME type special files
Definition: file_opts.h:46
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
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 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
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static RzSocket * s
Definition: rtr.c:28
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
RZ_API RZ_OWN RzBuffer * rz_buf_new_file(const char *file, int perm, int mode)
Creates a new buffer from a file.
Definition: buf.c:317
RZ_API const char * rz_file_basename(const char *path)
Definition: file.c:83
RZ_API bool rz_file_is_directory(const char *str)
Definition: file.c:167
RZ_API RzList * rz_file_globsearch(const char *globbed_path, int maxdepth)
Definition: file.c:1263
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.
Definition: pat.c:356
RZ_API void rz_sign_flirt_node_free(RZ_NULLABLE RzFlirtNode *node)
Frees an RzFlirtNode struct.
Definition: flirt.c:299
RZ_API RZ_OWN bool rz_sign_flirt_parse_header_compressed_pattern_from_buffer(RZ_NONNULL RzBuffer *flirt_buf, RZ_NONNULL RzFlirtInfo *info)
Parses the RzBuffer containing a FLIRT structure and returns an RzFlirtInfo.
Definition: flirt.c:1062
RZ_API void rz_sign_flirt_info_fini(RZ_NULLABLE RzFlirtInfo *info)
Frees an RzFlirtInfo struct elements without freeing the pointer.
Definition: flirt.c:315
@ RZ_FLIRT_NODE_OPTIMIZE_NONE
keeps the structure flattened (keep the tail bytes)
Definition: rz_flirt.h:186
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
RZ_API ut64 rz_get_input_num_value(RzNum *num, const char *input_value)
Definition: unum.c:743
#define RZ_STR_ISNOTEMPTY(x)
Definition: rz_str.h:68
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
#define RZ_STR_DUP(x)
Definition: rz_str.h:69
RZ_API bool rz_str_endswith(RZ_NONNULL const char *str, RZ_NONNULL const char *needle)
Checks if a string ends with a specifc sequence of characters (case sensitive)
Definition: str.c:3329
#define rz_strf(buf,...)
Convenience macro for local temporary strings.
Definition: rz_str.h:59
#define RZ_SYS_DIR
Definition: rz_types.h:218
#define RZ_NULLABLE
Definition: rz_types.h:65
#define RZ_OWN
Definition: rz_types.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_JOIN_2_PATHS(p1, p2)
Definition: rz_types.h:224
#define RZ_NONNULL
Definition: rz_types.h:64
RZ_API ut32 sdb_hash(const char *key)
Definition: util.c:22
#define O_RDONLY
Definition: sftypes.h:486
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
static int ut32cmp(int a, int b)
Definition: sigdb.c:195
static int sigdb_signature_cmp(const RzSigDBEntry *a, const RzSigDBEntry *b)
Definition: sigdb.c:24
RZ_API bool rz_sign_sigdb_merge(RZ_NONNULL RzSigDb *db, RZ_NONNULL RzSigDb *db2)
Merge the signatures from db2 into db.
Definition: sigdb.c:184
static int strcmp_null(const char *a, const char *b)
Definition: sigdb.c:205
static void ht_pu_sigdb_freekv(HtPUKv *kv)
Definition: sigdb.c:250
RZ_API RZ_OWN RzSigDb * rz_sign_sigdb_new(void)
Create a new empty RzSigDb instance.
Definition: sigdb.c:260
#define field_cmp(fname, cmpfunction)
RZ_API void rz_sign_sigdb_free(RzSigDb *db)
Definition: sigdb.c:277
static bool sigdb_move_entry(void *user, const void *k, const ut64 v)
Definition: sigdb.c:168
RZ_API RZ_OWN RzList * rz_sign_sigdb_list(RZ_NONNULL const RzSigDb *db)
Return the signature database as a list of entries.
Definition: sigdb.c:294
static bool sigdb_signature_resolve_details(RzSigDBEntry *entry, size_t path_len, bool with_details)
Definition: sigdb.c:28
RZ_API RZ_OWN RzSigDb * rz_sign_sigdb_load_database(RZ_NONNULL const char *sigdb_path, bool with_details)
Returns a database of signatures loaded from the signature database path.
Definition: sigdb.c:105
static int sigdb_entry_cmp(const void *a, const void *b)
Definition: sigdb.c:218
static bool sigdb_to_list(void *user, const void *k, const ut64 v)
Definition: sigdb.c:285
RZ_API bool rz_sign_sigdb_add_entry(RZ_NONNULL RzSigDb *db, RZ_NONNULL const RzSigDBEntry *entry)
Add a new signature entry to a database.
Definition: sigdb.c:158
static ut32 sigdb_entry_hash(const void *k)
Definition: sigdb.c:241
RZ_API void rz_sign_sigdb_signature_free(RZ_NULLABLE RzSigDBEntry *entry)
Frees a RzSigDBEntry structure.
Definition: sigdb.c:12
Definition: buffer.h:15
Definition: zipcmp.c:77
Definition: gzappend.c:170
Definition: rz_flirt.h:240
char * file_path
full path to the signature file
Definition: rz_flirt.h:246
RzSigDb * dst
Definition: sigdb.c:165
RzSigDb * src
Definition: sigdb.c:164
#define fail(test)
Definition: tests.h:29
ut64(WINAPI *w32_GetEnabledXStateFeatures)()