Rizin
unix-like reverse engineering framework and cli tools
dotnet.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2022. The YARA Authors. All Rights Reserved.
2 // SPDX-FileCopyrightText: 2022 wingdeans <wingdeans@protonmail.com>
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "pe.h"
6 #include "dotnet.h"
7 #include <rz_util/rz_alloc.h>
8 
9 #define MAX_METADATA_STRING_LENGTH 256
10 
11 static int bin_pe_read_metadata_string(char *to, RzBuffer *frombuf, ut64 fromoff) {
12  int covered = 0;
13  while (covered < MAX_METADATA_STRING_LENGTH) {
14  ut8 covch;
15  if (!rz_buf_read8_at(frombuf, fromoff + covered, &covch)) {
16  return 0;
17  }
18 
19  to[covered] = covch;
20  if (covch == '\0') {
21  covered += 1;
22  break;
23  }
24  covered++;
25  }
26  while (covered % 4 != 0) {
27  covered++;
28  }
29  return covered;
30 }
31 
33  if (!stream) {
34  return;
35  }
36  free(stream->Name);
37  free(stream);
38 }
39 
40 static ut32 clr_max_rows(int count, ...) {
41  va_list ap;
42  int i;
43  ut32 biggest;
44  ut32 x;
45 
46  if (count == 0) {
47  return 0;
48  }
49 
50  va_start(ap, count);
51  biggest = va_arg(ap, uint32_t);
52 
53  for (i = 1; i < count; i++) {
54  x = va_arg(ap, uint32_t);
55  biggest = (x > biggest) ? x : biggest;
56  }
57 
58  va_end(ap);
59  return biggest;
60 }
61 
64 
65  st64 o_addr = rz_buf_seek(b, 0, RZ_BUF_CUR);
66  if (rz_buf_seek(b, addr, RZ_BUF_SET) < 0) {
67  return -1;
68  }
69 
70  // Header structure
71  ut8 buf[(32 + (8 * 4) + 64 + 64) / 8];
72  if (!rz_buf_read(b, buf, sizeof(buf))) {
73  return -1;
74  }
82 
83  // Row counts
84  ut8 rowcountbuf[sizeof(ut32)];
86  if (!rowcounts) {
87  return -1;
88  }
89 
91  memset(&index_sizes, 2, sizeof(index_sizes));
92 
93  // Default index sizes are 2. Will be bumped to 4 if necessary.
94  if (tilde->HeapSizes & 0x01) {
95  index_sizes.string = 4;
96  }
97  if (tilde->HeapSizes & 0x02) {
98  index_sizes.guid = 4;
99  }
100  if (tilde->HeapSizes & 0x04) {
101  index_sizes.blob = 4;
102  }
103 
104  // This is used as an offset into the rows and tables. For every bit set in
105  // Valid this will be incremented. This is because the bit position doesn't
106  // matter, just the number of bits that are set, when determining how many
107  // rows and what the table structure is.
108  int matched_bits = 0;
109 
110  for (int bit_check = 0; bit_check < 64; ++bit_check) {
111  if (!((tilde->Valid >> bit_check) & 0x1)) {
112  continue;
113  }
114 
115  if (!rz_buf_read(b, rowcountbuf, sizeof(rowcountbuf))) { // Read row count
116  goto error;
117  }
118 
119 #define ROW_READ(name) \
120  rowcounts->name = rz_read_le32(rowcountbuf);
121 
122 #define ROW_READ_WITH_INDEX(name) \
123  ROW_READ(name); \
124  if (rowcounts->name > 0xFFFF) { \
125  index_sizes.name = 4; \
126  }
127 
128  switch (bit_check) {
129  case BIT_MODULE:
131  break;
132  case BIT_TYPEREF:
133  ROW_READ(typeref);
134  break;
135  case BIT_TYPEDEF:
136  ROW_READ_WITH_INDEX(typedef_);
137  break;
138  case BIT_FIELDPTR:
139  ROW_READ(fieldptr);
140  break;
141  case BIT_FIELD:
142  ROW_READ_WITH_INDEX(field);
143  break;
144  case BIT_METHODDEFPTR:
145  ROW_READ(methoddef);
146  break;
147  case BIT_METHODDEF:
148  ROW_READ_WITH_INDEX(methoddef);
149  break;
150  case BIT_PARAM:
151  ROW_READ_WITH_INDEX(param);
152  break;
153  case BIT_INTERFACEIMPL:
154  ROW_READ(interfaceimpl);
155  break;
156  case BIT_MEMBERREF:
157  ROW_READ_WITH_INDEX(memberref);
158  break;
159  case BIT_CONSTANT:
160  ROW_READ(constant);
161  break;
162  case BIT_CUSTOMATTRIBUTE:
163  ROW_READ(customattribute);
164  break;
165  case BIT_FIELDMARSHAL:
166  ROW_READ(fieldmarshal);
167  break;
168  case BIT_DECLSECURITY:
169  ROW_READ(declsecurity);
170  break;
171  case BIT_CLASSLAYOUT:
172  ROW_READ(classlayout);
173  break;
174  case BIT_FIELDLAYOUT:
175  ROW_READ(fieldlayout);
176  break;
177  case BIT_STANDALONESIG:
178  ROW_READ(standalonesig);
179  break;
180  case BIT_EVENTMAP:
181  ROW_READ(eventmap);
182  break;
183  case BIT_EVENTPTR:
184  ROW_READ(eventptr);
185  break;
186  case BIT_EVENT:
187  ROW_READ_WITH_INDEX(event);
188  break;
189  case BIT_PROPERTYMAP:
190  ROW_READ(propertymap);
191  break;
192  case BIT_PROPERTYPTR:
193  ROW_READ(propertyptr);
194  break;
195  case BIT_PROPERTY:
196  ROW_READ_WITH_INDEX(property);
197  break;
198  case BIT_METHODSEMANTICS:
199  ROW_READ(methodsemantics);
200  break;
201  case BIT_METHODIMPL:
202  ROW_READ(methodimpl);
203  break;
204  case BIT_MODULEREF:
205  ROW_READ_WITH_INDEX(moduleref);
206  break;
207  case BIT_TYPESPEC:
208  ROW_READ(typespec);
209  break;
210  case BIT_IMPLMAP:
211  ROW_READ(implmap);
212  break;
213  case BIT_FIELDRVA:
214  ROW_READ(fieldrva);
215  break;
216  case BIT_ENCLOG:
217  ROW_READ(enclog);
218  break;
219  case BIT_ENCMAP:
220  ROW_READ(encmap);
221  break;
222  case BIT_ASSEMBLY:
223  ROW_READ(assembly);
224  break;
226  ROW_READ(assemblyprocessor);
227  break;
228  case BIT_ASSEMBLYOS:
229  ROW_READ(assemblyos);
230  break;
231  case BIT_ASSEMBLYREF:
232  ROW_READ_WITH_INDEX(assemblyref);
233  break;
235  ROW_READ_WITH_INDEX(assemblyrefprocessor);
236  break;
237  case BIT_ASSEMBLYREFOS:
238  ROW_READ(assemblyrefos);
239  break;
240  case BIT_FILE:
241  ROW_READ(file);
242  break;
243  case BIT_EXPORTEDTYPE:
244  ROW_READ(exportedtype);
245  break;
247  ROW_READ(manifestresource);
248  break;
249  case BIT_NESTEDCLASS:
250  ROW_READ(nestedclass);
251  break;
252  case BIT_GENERICPARAM:
253  ROW_READ_WITH_INDEX(genericparam);
254  break;
255  case BIT_METHODSPEC:
256  ROW_READ(methodspec);
257  break;
259  ROW_READ(genericparamconstraint);
260  break;
261  default:
262  break;
263  }
264 
265  matched_bits++;
266  }
267 
268  // Now walk again this time parsing out what we care about
269  for (int bit_check = 0; bit_check < 64; ++bit_check) {
270  if (!((tilde->Valid >> bit_check) & 0x1)) {
271  continue;
272  }
273 
274 #define TRY_SEEK(rowsize, rowcountname) \
275  if (rz_buf_seek(b, (rowsize) * (st64)rowcounts->rowcountname, RZ_BUF_CUR) < 0) { \
276  RZ_LOG_WARN("seeking #rowcountname (size %d)", rowsize); \
277  goto error; \
278  }
279 
280 #define READ_BUF_INDEX_SIZE(var, index_size) \
281  var = (index_size == 2) ? rz_read_le16(buf) : rz_read_le32(buf); \
282  buf += index_size;
283 
284 #define INDEX_SIZE_FROM_TAG(name, tag_size) \
285  ut32 name = (index_count > (0xFFFF >> tag_size)) ? 4 : 2;
286 
287  // Those tables which exist, but that we don't care about must be
288  // skipped.
289  //
290  // Sadly, given the dynamic sizes of some columns we can not have well
291  // defined structures for all tables and use them accordingly. To deal
292  // with this manually move the table_offset pointer by the appropriate
293  // number of bytes as described in the documentation for each table.
294  //
295  // The table structures are documented in ECMA-335 Section II.22.
296 
297  switch (bit_check) {
298  case BIT_MODULE:
299  TRY_SEEK(2 + index_sizes.string +
300  (index_sizes.guid * 3),
301  module)
302 
303  break;
304 
305  case BIT_TYPEREF: {
306  ut32 index_count = clr_max_rows(4,
307  rowcounts->module,
308  rowcounts->moduleref,
309  rowcounts->assemblyref,
310  rowcounts->typeref);
312 
313  TRY_SEEK(index_size + (index_sizes.string * 2), typeref);
314  break;
315  }
316 
317  case BIT_TYPEDEF: {
318  ut32 index_count = clr_max_rows(3,
319  rowcounts->typedef_,
320  rowcounts->typeref,
321  rowcounts->typespec);
323 
324  ut32 rowsize = 4 + (index_sizes.string * 2) +
325  index_size + index_sizes.field +
326  index_sizes.methoddef;
327  ut32 rowcount = rowcounts->typedef_;
328 
329  ut8 *rows = rz_calloc(rowcount, rowsize);
330  if (!rz_buf_read(b, rows, (st64)rowsize * rowcount)) {
331  free(rows);
332  goto error;
333  }
334 
335  ut8 *buf = rows;
336  for (int i = 0; i < rowcount; ++i) {
338 
340  buf += 4;
341 
342  READ_BUF_INDEX_SIZE(typedef_->name, index_sizes.string);
343  READ_BUF_INDEX_SIZE(typedef_->namespace, index_sizes.string);
344 
346  READ_BUF_INDEX_SIZE(typedef_->fieldlist, index_sizes.field)
347  READ_BUF_INDEX_SIZE(typedef_->methodlist, index_sizes.methoddef)
348 
349  rz_list_append(clr->typedefs, typedef_);
350  }
351  free(rows);
352  break;
353  }
354 
355  case BIT_FIELDPTR:
356  // This one is not documented in ECMA-335.
357  TRY_SEEK(index_sizes.field, fieldptr)
358  break;
359 
360  case BIT_FIELD:
361  TRY_SEEK(2 + (index_sizes.string) +
362  index_sizes.blob,
363  field)
364  break;
365 
366  case BIT_METHODDEFPTR:
367  // This one is not documented in ECMA-335.
368  TRY_SEEK(index_sizes.methoddef, methoddefptr)
369  break;
370 
371  case BIT_METHODDEF: {
372  ut32 rowsize = 4 + 2 + 2 + index_sizes.string +
373  index_sizes.blob + index_sizes.param;
374  ut32 rowcount = rowcounts->methoddef;
375 
376  ut8 *rows = rz_calloc(rowcount, rowsize);
377  if (!rz_buf_read(b, rows, (st64)rowsize * rowcount)) {
378  free(rows);
379  goto error;
380  }
381 
382  ut8 *buf = rows;
383  for (int i = 0; i < rowcount; ++i) {
385 
387  PE_READ_STRUCT_FIELD(methoddef, Pe_image_metadata_methoddef, implflags, 16);
389  buf += 4 + 2 + 2;
390 
391  READ_BUF_INDEX_SIZE(methoddef->name, index_sizes.string)
392  READ_BUF_INDEX_SIZE(methoddef->signature, index_sizes.blob)
393  READ_BUF_INDEX_SIZE(methoddef->paramlist, index_sizes.param)
394 
395  rz_pvector_push(clr->methoddefs, methoddef);
396  }
397  free(rows);
398  break;
399  }
400 
401  case BIT_PARAM:
402  TRY_SEEK(2 + 2 + index_sizes.string, param)
403  break;
404 
405  case BIT_INTERFACEIMPL: {
406  ut32 index_count = clr_max_rows(3,
407  rowcounts->typedef_,
408  rowcounts->typeref,
409  rowcounts->typespec);
411 
412  TRY_SEEK(index_sizes.typedef_ + index_size, interfaceimpl)
413  break;
414  }
415 
416  case BIT_MEMBERREF: {
417  ut32 index_count = clr_max_rows(4,
418  rowcounts->methoddef,
419  rowcounts->moduleref,
420  rowcounts->typeref,
421  rowcounts->typespec);
423 
424  TRY_SEEK(index_size + index_sizes.string +
425  index_sizes.blob,
426  memberref)
427  break;
428  }
429 
430  case BIT_CONSTANT: {
431  ut32 index_count = clr_max_rows(3,
432  rowcounts->param,
433  rowcounts->field,
434  rowcounts->property);
436 
437  ut32 row_size = 1 + 1 + index_size + index_sizes.blob;
438 
439  TRY_SEEK(row_size, constant)
440  break;
441  }
442 
443  case BIT_CUSTOMATTRIBUTE: {
444  // index_size is size of the parent column.
445  ut32 index_count = clr_max_rows(21,
446  rowcounts->methoddef,
447  rowcounts->field,
448  rowcounts->typeref,
449  rowcounts->typedef_,
450  rowcounts->param,
451  rowcounts->interfaceimpl,
452  rowcounts->memberref,
453  rowcounts->module,
454  rowcounts->property,
455  rowcounts->event,
456  rowcounts->standalonesig,
457  rowcounts->moduleref,
458  rowcounts->typespec,
459  rowcounts->assembly,
460  rowcounts->assemblyref,
461  rowcounts->file,
462  rowcounts->exportedtype,
463  rowcounts->manifestresource,
464  rowcounts->genericparam,
465  rowcounts->genericparamconstraint,
466  rowcounts->methodspec);
468 
469  // index_size2 is size of the type column.
470  index_count = clr_max_rows(2,
471  rowcounts->methoddef,
472  rowcounts->memberref);
473  ut32 index_size2 = (index_count > (0xFFFF >> 0x03)) ? 4 : 2;
474 
475  ut32 row_size = (index_size + index_size2 + index_sizes.blob);
476 
477  TRY_SEEK(row_size, customattribute)
478  break;
479  }
480 
481  case BIT_FIELDMARSHAL: {
482  ut32 index_count = clr_max_rows(2,
483  rowcounts->field,
484  rowcounts->param);
486 
487  TRY_SEEK(index_size + index_sizes.blob, fieldmarshal)
488  break;
489  }
490 
491  case BIT_DECLSECURITY: {
492  ut32 index_count = clr_max_rows(3,
493  rowcounts->typedef_,
494  rowcounts->methoddef,
495  rowcounts->assembly);
497 
498  TRY_SEEK(2 + index_size + index_sizes.blob, declsecurity)
499  break;
500  }
501 
502  case BIT_CLASSLAYOUT:
503  TRY_SEEK(2 + 4 + index_sizes.typedef_, classlayout)
504  break;
505 
506  case BIT_FIELDLAYOUT:
507  TRY_SEEK(4 + index_sizes.field, fieldlayout)
508  break;
509 
510  case BIT_STANDALONESIG:
511  TRY_SEEK(index_sizes.blob, fieldlayout)
512  break;
513 
514  case BIT_EVENTMAP:
515  TRY_SEEK(index_sizes.typedef_ + index_sizes.event, eventmap)
516  break;
517 
518  case BIT_EVENTPTR:
519  // This one is not documented in ECMA-335.
520  TRY_SEEK(index_sizes.event, eventptr)
521  break;
522 
523  case BIT_EVENT: {
524  ut32 index_count = clr_max_rows(3,
525  rowcounts->typedef_,
526  rowcounts->typeref,
527  rowcounts->typespec);
529 
530  TRY_SEEK(2 + index_sizes.string + index_size, event)
531  break;
532  }
533 
534  case BIT_PROPERTYMAP:
535  TRY_SEEK(index_sizes.typedef_ + index_sizes.property, propertymap)
536  break;
537 
538  case BIT_PROPERTYPTR:
539  // This one is not documented in ECMA-335.
540  TRY_SEEK(index_sizes.property, propertyptr)
541  break;
542 
543  case BIT_PROPERTY:
544  TRY_SEEK(2 + index_sizes.string + index_sizes.blob, property)
545  break;
546 
547  case BIT_METHODSEMANTICS: {
548  ut32 index_count = clr_max_rows(2,
549  rowcounts->event,
550  rowcounts->property);
552 
553  TRY_SEEK(2 + index_sizes.methoddef + index_size, methodsemantics)
554  break;
555  }
556 
557  case BIT_METHODIMPL: {
558  ut32 index_count = clr_max_rows(2,
559  rowcounts->methoddef,
560  rowcounts->memberref);
562 
563  TRY_SEEK(index_sizes.typedef_ + (index_size * 2), methodimpl)
564  break;
565  }
566 
567  case BIT_MODULEREF: {
568  TRY_SEEK(index_sizes.string, moduleref)
569  break;
570  }
571 
572  case BIT_TYPESPEC:
573  TRY_SEEK(index_sizes.blob, typespec)
574  break;
575 
576  case BIT_IMPLMAP: {
577  ut32 index_count = clr_max_rows(2,
578  rowcounts->field,
579  rowcounts->methoddef);
581 
582  TRY_SEEK(2 + index_size + index_sizes.string +
583  index_sizes.moduleref,
584  implmap)
585  break;
586  }
587 
588  case BIT_FIELDRVA: {
589  ut32 row_size = 4 + index_sizes.field;
590 
591  TRY_SEEK(row_size, fieldrva)
592  break;
593  }
594 
595  case BIT_ENCLOG:
596  TRY_SEEK(4 + 4, enclog)
597  break;
598 
599  case BIT_ENCMAP:
600  TRY_SEEK(4, encmap)
601  break;
602 
603  case BIT_ASSEMBLY: {
604  ut32 row_size = (4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob +
605  (index_sizes.string * 2));
606 
607  TRY_SEEK(row_size, assembly)
608  break;
609  }
610 
612  TRY_SEEK(4, assemblyprocessor)
613  break;
614 
615  case BIT_ASSEMBLYOS:
616  TRY_SEEK(4 + 4 + 4, assemblyos)
617  break;
618 
619  case BIT_ASSEMBLYREF: {
620  ut32 row_size = (2 + 2 + 2 + 2 + 4 +
621  (index_sizes.blob * 2) +
622  (index_sizes.string * 2));
623 
624  TRY_SEEK(row_size, assemblyref)
625  break;
626  }
627 
629  TRY_SEEK(4 + index_sizes.assemblyrefprocessor, assemblyrefprocessor)
630  break;
631 
632  case BIT_ASSEMBLYREFOS:
633  TRY_SEEK(4 + 4 + 4 + index_sizes.assemblyref, assemblyrefos)
634  break;
635 
636  case BIT_FILE:
637  TRY_SEEK(4 + index_sizes.string + index_sizes.blob, file)
638  break;
639 
640  case BIT_EXPORTEDTYPE: {
641  ut32 index_count = clr_max_rows(3,
642  rowcounts->file,
643  rowcounts->assemblyref,
644  rowcounts->exportedtype);
646 
647  TRY_SEEK(4 + 4 + (index_sizes.string * 2) + index_size, exportedtype)
648  break;
649  }
650 
651  case BIT_MANIFESTRESOURCE: {
652  // This is an Implementation coded index with no 3rd bit specified.
653  ut32 index_count = clr_max_rows(2,
654  rowcounts->file,
655  rowcounts->assemblyref);
657 
658  ut32 row_size = (4 + 4 + index_sizes.string + index_size);
659 
660  TRY_SEEK(row_size, manifestresource)
661  break;
662  }
663 
664  case BIT_NESTEDCLASS:
665  TRY_SEEK(index_sizes.typedef_ * 2, nestedclass)
666  break;
667 
668  case BIT_GENERICPARAM: {
669  ut32 index_count = clr_max_rows(2,
670  rowcounts->typedef_,
671  rowcounts->methoddef);
673 
674  TRY_SEEK(2 + 2 + index_size + index_sizes.string, genericparam)
675  break;
676  }
677 
678  case BIT_METHODSPEC: {
679  ut32 index_count = clr_max_rows(2,
680  rowcounts->methoddef,
681  rowcounts->memberref);
683 
684  TRY_SEEK(index_size + index_sizes.blob, methodspec)
685  break;
686  }
687 
689  ut32 index_count = clr_max_rows(3,
690  rowcounts->typedef_,
691  rowcounts->typeref,
692  rowcounts->typespec);
694 
695  TRY_SEEK(index_sizes.genericparam + index_size, genericparamconstraint)
696  break;
697  }
698 
699  default:
700  RZ_LOG_WARN("Unknown bit in metatable: %i\n", bit_check);
701  goto error;
702  }
703  }
704 
705  free(rowcounts);
706  rz_buf_seek(b, o_addr, RZ_BUF_SET);
707  return 0;
708 
709 error:
710  free(rowcounts);
711  rz_buf_seek(b, o_addr, RZ_BUF_SET);
712  return -1;
713 }
714 
716  st64 o_addr = rz_buf_seek(b, 0, RZ_BUF_CUR);
717  if (rz_buf_seek(b, addr, RZ_BUF_SET) < 0) {
718  return -1;
719  }
720  ut8 buf[sizeof(Pe_image_clr_header)];
721  rz_buf_read(b, buf, sizeof(buf));
723  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, MajorRuntimeVersion, 16);
724  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, MinorRuntimeVersion, 16);
725  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, MetaDataDirectoryAddress, 32);
726  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, MetaDataDirectorySize, 32);
728  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, EntryPointToken, 32);
729  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, ResourcesDirectoryAddress, 32);
730  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, ResourcesDirectorySize, 32);
731  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, StrongNameSignatureAddress, 32);
732  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, StrongNameSignatureSize, 32);
733  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, CodeManagerTableAddress, 32);
734  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, CodeManagerTableSize, 32);
735  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, VTableFixupsAddress, 32);
736  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, VTableFixupsSize, 32);
737  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, ExportAddressTableJumpsAddress, 32);
738  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, ExportAddressTableJumpsSize, 32);
739  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, ManagedNativeHeaderAddress, 32);
740  PE_READ_STRUCT_FIELD(header, Pe_image_clr_header, ManagedNativeHeaderSize, 32);
741  rz_buf_seek(b, o_addr, RZ_BUF_SET);
742  return sizeof(Pe_image_clr_header);
743 }
744 
746  st64 o_addr = rz_buf_seek(b, 0, RZ_BUF_CUR);
747  if (rz_buf_seek(b, sym->paddr, RZ_BUF_SET) < 0) {
748  return -1;
749  }
750 
752  if (!rz_buf_read8(b, buf)) {
753  return -1;
754  }
755 
756  if ((buf[0] & 0x03) == 0x02) { // Tiny
757  sym->paddr += 1;
758  sym->vaddr += 1;
759  sym->size = buf[0] >> 2;
760  } else if ((buf[0] & 0x03) == 0x03) { // Fat
761  rz_buf_read(b, buf + 1, sizeof(Pe_image_clr_methodheader) - 1);
762  Pe_image_clr_methodheader methodheader;
764  PE_READ_STRUCT_FIELD((&methodheader), Pe_image_clr_methodheader, maxstack, 16);
765  PE_READ_STRUCT_FIELD((&methodheader), Pe_image_clr_methodheader, size, 32);
766  PE_READ_STRUCT_FIELD((&methodheader), Pe_image_clr_methodheader, tok, 32);
767 
768  rz_warn_if_fail(methodheader.flags >> 12 == 3); // top 4 bits indicate size
769  sym->paddr += 12;
770  sym->vaddr += 12;
771  sym->size = methodheader.size;
772 
773  // TODO: exception sections
774  } else {
776  }
777 
778  rz_buf_seek(b, o_addr, RZ_BUF_SET);
779  return 0;
780 }
781 
782 // Entrypoint
783 int bin_pe_dotnet_init_metadata(Pe_image_clr *clr, bool big_endian, RzBuffer *b, ut64 metadata_directory) {
785  if (!metadata) {
786  return -1;
787  }
788  if (!metadata_directory) {
789  free(metadata);
790  return -1;
791  }
792 
793  int rr = rz_buf_fread_at(b, metadata_directory,
794  (ut8 *)metadata, big_endian ? "1I2S" : "1i2s", 1);
795  if (rr < 1) {
796  goto fail;
797  }
798 
799  rr = rz_buf_fread_at(b, metadata_directory + 8,
800  (ut8 *)(&metadata->Reserved), big_endian ? "1I" : "1i", 1);
801  if (rr < 1) {
802  goto fail;
803  }
804 
805  rr = rz_buf_fread_at(b, metadata_directory + 12,
806  (ut8 *)(&metadata->VersionStringLength), big_endian ? "1I" : "1i", 1);
807  if (rr < 1) {
808  goto fail;
809  }
810 
811  // read the version string
812  int len = metadata->VersionStringLength; // XXX: dont trust this length
813  if (len > 0) {
814  metadata->VersionString = calloc(1, len + 1);
815  if (!metadata->VersionString) {
816  goto fail;
817  }
818 
819  rr = rz_buf_read_at(b, metadata_directory + 16, (ut8 *)(metadata->VersionString), len);
820  if (rr != len) {
821  RZ_LOG_WARN("read (metadata header) - cannot parse version string\n");
822  free(metadata->VersionString);
823  free(metadata);
824  return -1;
825  }
826  }
827 
828  // read the header after the string
829  rr = rz_buf_fread_at(b, metadata_directory + 16 + metadata->VersionStringLength,
830  (ut8 *)(&metadata->Flags), big_endian ? "2S" : "2s", 1);
831 
832  if (rr < 1) {
833  goto fail;
834  }
835 
836  clr->metadata_header = metadata;
837 
838  // read metadata streams
839  int start_of_stream = metadata_directory + 20 + metadata->VersionStringLength;
842  if (!streams) {
843  goto fail;
844  }
845  int count = 0;
846 
847  while (count < metadata->NumberOfStreams) {
849  if (!stream) {
851  goto fail;
852  }
853 
854  if (rz_buf_fread_at(b, start_of_stream, (ut8 *)stream, big_endian ? "2I" : "2i", 1) < 1) {
855  free(stream);
857  goto fail;
858  }
859  char *stream_name = calloc(1, MAX_METADATA_STRING_LENGTH + 1);
860 
861  if (!stream_name) {
862  free(stream);
864  goto fail;
865  }
866 
867  if (rz_buf_size(b) < (start_of_stream + 8 + MAX_METADATA_STRING_LENGTH)) {
868  free(stream_name);
869  free(stream);
871  goto fail;
872  }
873  int c = bin_pe_read_metadata_string(stream_name, b, start_of_stream + 8);
874  if (c == 0) {
875  free(stream_name);
876  free(stream);
878  goto fail;
879  }
880 
881  stream->Name = stream_name;
883  start_of_stream += 8 + c;
884  count += 1;
885 
886  // save special streams
887  if (strncmp(stream_name, "#Strings", 8) == 0 && clr->strings_stream == NULL) {
888  clr->strings_stream = stream;
889  } else if (strncmp(stream_name, "#~", 2) == 0 && clr->tilde_stream == NULL) {
890  clr->tilde_stream = stream;
891  } else if (strncmp(stream_name, "#Blob", 5) == 0) {
892  clr->blob_stream = stream;
893  }
894  }
895  clr->streams = streams;
896 
897  if (clr->strings_stream) {
898  RzBuffer *strings = rz_buf_new_slice(b, metadata_directory + clr->strings_stream->Offset, clr->strings_stream->Size);
899  if (!strings) {
900  return -1;
901  }
902  clr->strings = strings;
903  }
904 
905  if (clr->tilde_stream && clr->blob_stream && clr->strings) {
907  clr->typedefs = rz_list_newf(free);
908  if (!clr->methoddefs || !clr->typedefs) {
909  goto fail;
910  }
911 
913  if (!tilde) {
914  goto fail;
915  }
916 
917  clr->tilde = tilde;
918  if (read_image_metadata_tilde_header(b, metadata_directory + clr->tilde_stream->Offset, clr)) {
919  RZ_LOG_WARN("read (metadata tilde header)\n");
920  goto fail;
921  }
922  }
923 
924  return -1;
925 fail:
926  RZ_LOG_WARN("read (metadata header)\n");
927  free(metadata);
928  clr->metadata_header = NULL;
929  return 0;
930 }
931 
932 int bin_pe_dotnet_init_clr(Pe_image_clr *clr, RzBuffer *b, ut64 image_clr_hdr_paddr) {
934  if (!header) {
935  goto error;
936  }
937  clr->header = header;
938 
939  int rr, len = sizeof(Pe_image_clr_header);
940 
941  rr = read_image_clr_header(b, image_clr_hdr_paddr, header);
942 
943  // probably not a .NET binary
944  // 64bit?
945  if (header->HeaderSize != 0x48) {
946  goto error;
947  }
948  if (rr != len) {
949  goto error;
950  }
951  return 0;
952 
953 error:
954  free(header);
955  free(clr);
956  return -1;
957 }
958 
959 // Cleanup
961  if (!metadata) {
962  return;
963  }
964  free(metadata->VersionString);
965  free(metadata);
966 }
967 
969  if (!clr) {
970  return;
971  }
972  free(clr->header);
973  free(clr->tilde);
975  rz_list_free(clr->streams);
976  rz_buf_free(clr->strings);
977 
979  rz_list_free(clr->typedefs);
980 
981  free(clr);
982 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static ut64 rva(RzBinObject *o, ut64 paddr, ut64 vaddr, int va)
Definition: cbin.c:77
static lzma_vli index_size(lzma_vli count, lzma_vli index_list_size)
Calculate the size of the Index field including Index Padding.
Definition: index.h:57
#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 count
Definition: sflib.h:98
uint32_t ut32
int bin_pe_dotnet_read_method_header(Pe_image_clr *clr, RzBuffer *b, RzBinSymbol *sym)
Definition: dotnet.c:745
static void _free_stream(Pe_image_metadata_stream *stream)
Definition: dotnet.c:32
static int read_image_clr_header(RzBuffer *b, ut64 addr, Pe_image_clr_header *header)
Definition: dotnet.c:715
#define READ_BUF_INDEX_SIZE(var, index_size)
#define INDEX_SIZE_FROM_TAG(name, tag_size)
static int read_image_metadata_tilde_header(RzBuffer *b, ut64 addr, Pe_image_clr *clr)
Definition: dotnet.c:62
static ut32 clr_max_rows(int count,...)
Definition: dotnet.c:40
static int bin_pe_read_metadata_string(char *to, RzBuffer *frombuf, ut64 fromoff)
Definition: dotnet.c:11
#define MAX_METADATA_STRING_LENGTH
Definition: dotnet.c:9
#define ROW_READ(name)
#define TRY_SEEK(rowsize, rowcountname)
int bin_pe_dotnet_init_clr(Pe_image_clr *clr, RzBuffer *b, ut64 image_clr_hdr_paddr)
Definition: dotnet.c:932
int bin_pe_dotnet_init_metadata(Pe_image_clr *clr, bool big_endian, RzBuffer *b, ut64 metadata_directory)
Definition: dotnet.c:783
static void free_metadata_header(Pe_image_metadata_header *metadata)
Definition: dotnet.c:960
#define ROW_READ_WITH_INDEX(name)
void bin_pe_dotnet_destroy_clr(Pe_image_clr *clr)
Definition: dotnet.c:968
#define BIT_MODULE
Definition: dotnet.h:174
#define BIT_EXPORTEDTYPE
Definition: dotnet.h:213
#define BIT_CLASSLAYOUT
Definition: dotnet.h:189
#define BIT_PROPERTYPTR
Definition: dotnet.h:196
#define BIT_METHODDEF
Definition: dotnet.h:180
#define BIT_GENERICPARAM
Definition: dotnet.h:216
#define BIT_STANDALONESIG
Definition: dotnet.h:191
#define BIT_DECLSECURITY
Definition: dotnet.h:188
#define BIT_EVENTMAP
Definition: dotnet.h:192
#define BIT_GENERICPARAMCONSTRAINT
Definition: dotnet.h:218
#define BIT_METHODDEFPTR
Definition: dotnet.h:179
#define BIT_ENCMAP
Definition: dotnet.h:205
#define BIT_INTERFACEIMPL
Definition: dotnet.h:183
#define BIT_FIELD
Definition: dotnet.h:178
#define BIT_NESTEDCLASS
Definition: dotnet.h:215
#define BIT_TYPEDEF
Definition: dotnet.h:176
#define BIT_FIELDMARSHAL
Definition: dotnet.h:187
#define BIT_ASSEMBLYREF
Definition: dotnet.h:209
#define BIT_ASSEMBLYREFOS
Definition: dotnet.h:211
#define BIT_IMPLMAP
Definition: dotnet.h:202
#define BIT_METHODSPEC
Definition: dotnet.h:217
#define BIT_EVENTPTR
Definition: dotnet.h:193
#define BIT_PROPERTYMAP
Definition: dotnet.h:195
#define BIT_CUSTOMATTRIBUTE
Definition: dotnet.h:186
#define BIT_PROPERTY
Definition: dotnet.h:197
#define BIT_FIELDPTR
Definition: dotnet.h:177
#define BIT_CONSTANT
Definition: dotnet.h:185
#define BIT_METHODIMPL
Definition: dotnet.h:199
#define BIT_ASSEMBLYOS
Definition: dotnet.h:208
#define BIT_MANIFESTRESOURCE
Definition: dotnet.h:214
#define BIT_PARAM
Definition: dotnet.h:182
#define BIT_MODULEREF
Definition: dotnet.h:200
#define BIT_EVENT
Definition: dotnet.h:194
#define BIT_ASSEMBLYREFPROCESSOR
Definition: dotnet.h:210
#define BIT_MEMBERREF
Definition: dotnet.h:184
#define BIT_TYPESPEC
Definition: dotnet.h:201
#define BIT_ASSEMBLY
Definition: dotnet.h:206
#define BIT_METHODSEMANTICS
Definition: dotnet.h:198
#define BIT_ASSEMBLYPROCESSOR
Definition: dotnet.h:207
#define BIT_FIELDLAYOUT
Definition: dotnet.h:190
#define BIT_FILE
Definition: dotnet.h:212
#define BIT_FIELDRVA
Definition: dotnet.h:203
#define BIT_ENCLOG
Definition: dotnet.h:204
#define BIT_TYPEREF
Definition: dotnet.h:175
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 strings(--mime-type and\n" " --mime-encoding)\n") OPT('s'
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf stream
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
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 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 * calloc(size_t number, size_t size)
Definition: malloc.c:102
#define header(is_bt, len_min, ret_op)
int x
Definition: mipsasm.c:20
#define PE_READ_STRUCT_FIELD(var, struct_type, field, size)
Definition: pe.h:177
#define rz_calloc(x, y)
Definition: rz_alloc.h:42
#define rz_warn_if_reached()
Definition: rz_assert.h:29
#define rz_warn_if_fail(expr)
Definition: rz_assert.h:35
RZ_API st64 rz_buf_seek(RZ_NONNULL RzBuffer *b, st64 addr, int whence)
Modify the current cursor position in the buffer.
Definition: buf.c:1166
#define RZ_BUF_CUR
Definition: rz_buf.h:15
RZ_API bool rz_buf_read8_at(RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *result)
Read a byte at the specified address in the buffer.
Definition: buf.c:876
RZ_API st64 rz_buf_read_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
Read len bytes of the buffer at the specified address.
Definition: buf.c:1136
RZ_API bool rz_buf_read8(RZ_NONNULL RzBuffer *b, RZ_NONNULL RZ_OUT ut8 *result)
Read a byte at the cursor in the buffer.
Definition: buf.c:860
RZ_API st64 rz_buf_fread_at(RZ_NONNULL RzBuffer *b, ut64 addr, RZ_NONNULL ut8 *buf, RZ_NONNULL const char *fmt, int n)
...
Definition: buf.c:1001
#define RZ_BUF_SET
Definition: rz_buf.h:14
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_slice(RzBuffer *b, ut64 offset, ut64 size)
Creates a new buffer from a slice of another buffer.
Definition: buf.c:364
RZ_API st64 rz_buf_read(RZ_NONNULL RzBuffer *b, RZ_NONNULL RZ_OUT ut8 *buf, ut64 len)
RZ_API ut64 rz_buf_size(RZ_NONNULL RzBuffer *b)
Return the size of the buffer.
Definition: buf.c:1225
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_WARN(fmtstr,...)
Definition: rz_log.h:56
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define st64
Definition: rz_types_base.h:10
RZ_API RzPVector * rz_pvector_new(RzPVectorFree free)
Definition: vector.c:302
static void ** rz_pvector_push(RzPVector *vec, void *x)
Definition: rz_vector.h:300
RZ_API void rz_pvector_free(RzPVector *vec)
Definition: vector.c:336
static struct sockaddr static addrlen static backlog const void static flags void struct sockaddr socklen_t static fromlen const void const struct sockaddr to
Definition: sfsocketcall.h:125
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
unsigned int uint32_t
Definition: sftypes.h:29
#define b(i)
Definition: sha256.c:42
#define c(i)
Definition: sha256.c:43
Pe_image_metadata_stream * tilde_stream
Definition: dotnet.h:156
RzList * typedefs
Definition: dotnet.h:164
RzPVector * methoddefs
Definition: dotnet.h:163
Pe_image_metadata_header * metadata_header
Definition: dotnet.h:152
RzList * streams
Definition: dotnet.h:153
Pe_image_clr_header * header
Definition: dotnet.h:151
Pe_image_metadata_stream * strings_stream
Definition: dotnet.h:157
Pe_image_metadata_stream * blob_stream
Definition: dotnet.h:158
Pe_image_metadata_tilde_header * tilde
Definition: dotnet.h:161
RzBuffer * strings
Definition: dotnet.h:162
Definition: gzappend.c:170
Definition: sftypes.h:77
uint64_t streams
Definition: list.c:103
#define fail(test)
Definition: tests.h:29
void error(const char *msg)
Definition: untgz.c:593
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58