Coverage Report

Created: 2023-09-25 07:12

/src/yara/libyara/modules/dotnet/dotnet.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
Copyright (c) 2015. The YARA Authors. All Rights Reserved.
3
4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7
8
   http://www.apache.org/licenses/LICENSE-2.0
9
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16
17
#include <ctype.h>
18
#include <stdarg.h>
19
#include <stdbool.h>
20
#include <stdio.h>
21
#include <string.h>
22
#include <time.h>
23
#include <yara/dotnet.h>
24
#include <yara/mem.h>
25
#include <yara/modules.h>
26
#include <yara/pe.h>
27
#include <yara/pe_utils.h>
28
#include <yara/simple_str.h>
29
#include <yara/strutils.h>
30
#include <yara/unaligned.h>
31
32
#define MODULE_NAME dotnet
33
34
static uint32_t max_rows(int count, ...)
35
33.3M
{
36
33.3M
  va_list ap;
37
33.3M
  uint32_t biggest;
38
33.3M
  uint32_t x;
39
40
33.3M
  if (count == 0)
41
0
    return 0;
42
43
33.3M
  va_start(ap, count);
44
33.3M
  biggest = va_arg(ap, uint32_t);
45
46
69.6M
  for (int i = 1; i < count; i++)
47
36.3M
  {
48
36.3M
    x = va_arg(ap, uint32_t);
49
36.3M
    biggest = (x > biggest) ? x : biggest;
50
36.3M
  }
51
52
33.3M
  va_end(ap);
53
33.3M
  return biggest;
54
33.3M
}
55
56
static uint32_t read_u32(const uint8_t** data)
57
4.25M
{
58
4.25M
  uint32_t result = yr_le32toh(yr_unaligned_u32(*data));
59
4.25M
  *data += sizeof(uint32_t);
60
4.25M
  return result;
61
4.25M
}
62
63
static uint16_t read_u16(const uint8_t** data)
64
148M
{
65
148M
  uint16_t result = yr_le16toh(yr_unaligned_u16(*data));
66
148M
  *data += sizeof(uint16_t);
67
148M
  return result;
68
148M
}
69
70
static uint8_t read_u8(const uint8_t** data)
71
9.32M
{
72
9.32M
  uint8_t result = **data;
73
9.32M
  *data += sizeof(uint8_t);
74
9.32M
  return result;
75
9.32M
}
76
77
static uint32_t read_index(const uint8_t** data, uint8_t len)
78
87.3M
{
79
87.3M
  if (len == 2)
80
85.1M
    return read_u16(data);
81
2.17M
  else
82
2.17M
    return read_u32(data);
83
87.3M
}
84
85
// Returns valid offset within the table or NULL
86
const uint8_t* get_table_offset(const TABLE_INFO* tbl, uint32_t index)
87
252M
{
88
  // Indexes to .NET tables are based from 1
89
252M
  if (index < 1 || index > tbl->RowCount)
90
213k
    return NULL;
91
92
251M
  return tbl->Offset + tbl->RowSize * (index - 1);
93
252M
}
94
95
// Given an offset into a #US or #Blob stream, parse the entry at that position.
96
// The offset is relative to the start of the PE file.
97
// if size > 0 then it's valid and readable blob
98
BLOB_PARSE_RESULT dotnet_parse_blob_entry(PE* pe, const uint8_t* offset)
99
1.36M
{
100
1.36M
  BLOB_PARSE_RESULT result = {.size = 0, .length = 0};
101
102
  // Blob size is encoded in the first 1, 2 or 4 bytes of the blob.
103
  //
104
  // If the high bit is not set the length is encoded in one byte.
105
  //
106
  // If the high 2 bits are 10 (base 2) then the length is encoded in
107
  // the rest of the bits and the next byte.
108
  //
109
  // If the high 3 bits are 110 (base 2) then the length is encoded
110
  // in the rest of the bits and the next 3 bytes.
111
  //
112
  // See ECMA-335 II.24.2.4 for details.
113
114
  // Make sure we have at least one byte.
115
116
1.36M
  if (!fits_in_pe(pe, offset, 1))
117
46.7k
    return result;
118
119
1.32M
  if ((*offset & 0x80) == 0x00)
120
1.04M
  {
121
1.04M
    result.length = (uint32_t) (*offset);
122
1.04M
    result.size = 1;
123
1.04M
  }
124
273k
  else if ((*offset & 0xC0) == 0x80)
125
120k
  {
126
    // Make sure we have one more byte.
127
120k
    if (!fits_in_pe(pe, offset, 2))
128
1.90k
      return result;
129
130
    // Shift remaining 6 bits left by 8 and OR in the remaining byte.
131
118k
    result.length = ((*offset & 0x3F) << 8) | *(offset + 1);
132
118k
    result.size = 2;
133
118k
  }
134
153k
  else if (offset + 4 < pe->data + pe->data_size && (*offset & 0xE0) == 0xC0)
135
56.8k
  {
136
    // Make sure we have 3 more bytes.
137
56.8k
    if (!fits_in_pe(pe, offset, 4))
138
0
      return result;
139
140
56.8k
    result.length = ((*offset & 0x1F) << 24) | (*(offset + 1) << 16) |
141
56.8k
                    (*(offset + 2) << 8) | *(offset + 3);
142
56.8k
    result.size = 4;
143
56.8k
  }
144
96.3k
  else
145
96.3k
  {
146
    // Return a 0 size as an error.
147
96.3k
    return result;
148
96.3k
  }
149
150
  // Check if the length is actually readable
151
1.22M
  if (!fits_in_pe(pe, offset, result.size + result.length))
152
60.7k
  {
153
60.7k
    result.size = 0;
154
60.7k
    return result;
155
60.7k
  }
156
157
1.16M
  return result;
158
1.22M
}
159
160
char* pe_get_dotnet_string(
161
    PE* pe,
162
    const uint8_t* heap_offset,
163
    uint32_t heap_size,
164
    uint32_t string_index)
165
2.32M
{
166
2.32M
  size_t remaining;
167
168
2.32M
  char* start;
169
2.32M
  char* eos;
170
171
  // Start of string must be within boundary
172
2.32M
  if (!(heap_offset + string_index >= pe->data &&
173
2.32M
        heap_offset + string_index < pe->data + pe->data_size &&
174
2.32M
        string_index < heap_size))
175
291k
    return NULL;
176
177
  // Calculate how much until end of boundary, don't scan past that.
178
2.03M
  remaining = (pe->data + pe->data_size) - (heap_offset + string_index);
179
180
  // Search for a NULL terminator from start of string, up to remaining.
181
2.03M
  start = (char*) (heap_offset + string_index);
182
2.03M
  eos = (char*) memmem((void*) start, remaining, "\0", 1);
183
184
  // If no NULL terminator was found or the string is too large, return NULL.
185
2.03M
  if (eos == NULL || eos - start > 1024)
186
140k
    return NULL;
187
188
1.89M
  return start;
189
2.03M
}
190
191
static bool is_nested(uint32_t flags)
192
260k
{
193
  // ECMA 335 II.22.37
194
  // Whether a type is nested can be determined by the value of its
195
  // Flags.Visibility sub-field – it shall be one of the set
196
  // { NestedPublic, NestedPrivate, NestedFamily, NestedAssembly,
197
  // NestedFamANDAssem, NestedFamORAssem }
198
199
260k
  switch (flags & TYPE_ATTR_VISIBILITY_MASK)
200
260k
  {
201
49.4k
  case TYPE_ATTR_NESTED_PRIVATE:
202
63.4k
  case TYPE_ATTR_NESTED_PUBLIC:
203
88.0k
  case TYPE_ATTR_NESTED_FAMILY:
204
97.6k
  case TYPE_ATTR_NESTED_ASSEMBLY:
205
107k
  case TYPE_ATTR_NESTED_FAM_AND_ASSEM:
206
128k
  case TYPE_ATTR_NESTED_FAM_OR_ASSEM:
207
128k
    return true;
208
131k
  default:
209
131k
    return false;
210
260k
  }
211
260k
}
212
213
// ECMA 335 II.23.1.15 Flags for types [TypeAttribute]
214
static const char* get_type_visibility(uint32_t flags)
215
153k
{
216
153k
  switch (flags & TYPE_ATTR_VISIBILITY_MASK)
217
153k
  {
218
9.24k
  case TYPE_ATTR_NESTED_PRIVATE:
219
9.24k
    return "private";
220
10.5k
  case TYPE_ATTR_PUBLIC:
221
20.2k
  case TYPE_ATTR_NESTED_PUBLIC:
222
20.2k
    return "public";
223
9.98k
  case TYPE_ATTR_NESTED_FAMILY:
224
9.98k
    return "protected";
225
85.3k
  case TYPE_ATTR_NOT_PUBLIC:
226
93.0k
  case TYPE_ATTR_NESTED_ASSEMBLY:
227
93.0k
    return "internal";
228
8.69k
  case TYPE_ATTR_NESTED_FAM_AND_ASSEM:
229
8.69k
    return "private protected";
230
12.3k
  case TYPE_ATTR_NESTED_FAM_OR_ASSEM:
231
12.3k
    return "protected internal";
232
0
  default:
233
0
    return "private";
234
153k
  }
235
153k
}
236
237
// ECMA 335 II.23.1.10 Flags for methods [MethodAttributes]
238
static const char* get_method_visibility(uint32_t flags)
239
32.5k
{
240
32.5k
  switch (flags & METHOD_ATTR_ACCESS_MASK)
241
32.5k
  {
242
1.88k
  case METHOD_ATTR_PRIVATE:
243
1.88k
    return "private";
244
1.60k
  case METHOD_ATTR_FAM_AND_ASSEM:
245
1.60k
    return "private protected";
246
2.47k
  case METHOD_ATTR_ASSEM:
247
2.47k
    return "internal";
248
2.21k
  case METHOD_ATTR_FAMILY:
249
2.21k
    return "protected";
250
1.15k
  case METHOD_ATTR_FAM_OR_ASSEM:
251
1.15k
    return "protected internal";
252
941
  case METHOD_ATTR_PUBLIC:
253
941
    return "public";
254
22.2k
  default:
255
22.2k
    return "private";
256
32.5k
  }
257
32.5k
}
258
259
// ECMA 335 II.23.1.15 Flags for types [TypeAttribute]
260
static const char* get_typedef_type(uint32_t flags)
261
293k
{
262
293k
  switch (flags & TYPE_ATTR_CLASS_SEMANTIC_MASK)
263
293k
  {
264
161k
  case TYPE_ATTR_CLASS:
265
161k
    return "class";
266
131k
  case TYPE_ATTR_INTERFACE:
267
131k
    return "interface";
268
0
  default:
269
0
    return NULL;
270
293k
  }
271
293k
}
272
273
// returns allocated string <namespace>.<name>, must be freed
274
static char* create_full_name(const char* name, const char* namespace)
275
395k
{
276
395k
  if (!name || !strlen(name))
277
108k
    return namespace ? yr_strdup(namespace) : NULL;
278
279
  // No namespace -> return name only
280
287k
  if (!namespace || !strlen(namespace))
281
117k
  {
282
    // fix generic names
283
117k
    char* name_copy = yr_strdup(name);
284
117k
    char* end = strchr(name_copy, '`');
285
117k
    if (end)
286
22.8k
      *end = 0;
287
117k
    return name_copy;
288
117k
  }
289
290
170k
  size_t name_len = strlen(name);
291
170k
  size_t namespace_len = strlen(namespace);
292
293
  // <namespace>.<name>
294
170k
  char* full_name = yr_malloc(namespace_len + 1 + name_len + 1);
295
296
170k
  memcpy(full_name, namespace, namespace_len);
297
170k
  full_name[namespace_len] = '.';
298
170k
  memcpy(full_name + namespace_len + 1, name, name_len + 1);
299
300
  // fix generic names
301
170k
  char* end = strchr(full_name, '`');
302
170k
  if (end)
303
40.5k
    *end = 0;
304
305
170k
  return full_name;
306
287k
}
307
308
static bool read_typedef(
309
    const CLASS_CONTEXT* ctx,
310
    const uint8_t* data,
311
    TYPEDEF_ROW* result)
312
1.37M
{
313
1.37M
  uint32_t row_size = ctx->tables->typedef_.RowSize;
314
315
1.37M
  if (fits_in_pe(ctx->pe, data, row_size))
316
552k
  {
317
552k
    uint8_t ext_size = 2;
318
552k
    uint32_t row_count = max_rows(
319
552k
        3,
320
552k
        ctx->tables->typedef_.RowCount,
321
552k
        ctx->tables->typeref.RowCount,
322
552k
        ctx->tables->typespec.RowCount);
323
324
552k
    if (row_count > (0xFFFF >> 0x02))
325
0
      ext_size = 4;
326
327
552k
    result->Flags = read_u32(&data);
328
552k
    result->Name = read_index(&data, ctx->index_sizes->string);
329
552k
    result->Namespace = read_index(&data, ctx->index_sizes->string);
330
552k
    result->Extends = read_index(&data, ext_size);
331
552k
    result->Field = read_index(&data, ctx->index_sizes->field);
332
552k
    result->Method = read_index(&data, ctx->index_sizes->methoddef);
333
334
552k
    return true;
335
552k
  }
336
337
826k
  return false;
338
1.37M
}
339
340
static bool read_typeref(
341
    const CLASS_CONTEXT* ctx,
342
    const uint8_t* data,
343
    TYPEREF_ROW* result)
344
7.03k
{
345
7.03k
  uint32_t row_size = ctx->tables->typeref.RowSize;
346
347
7.03k
  if (fits_in_pe(ctx->pe, data, row_size))
348
7.03k
  {
349
7.03k
    uint8_t res_size = 2;
350
7.03k
    uint32_t row_count = max_rows(
351
7.03k
        4,
352
7.03k
        ctx->tables->module.RowCount,
353
7.03k
        ctx->tables->moduleref.RowCount,
354
7.03k
        ctx->tables->assemblyref.RowCount,
355
7.03k
        ctx->tables->typeref.RowCount);
356
357
7.03k
    if (row_count > (0xFFFF >> 0x02))
358
0
      res_size = 4;
359
360
7.03k
    result->ResolutionScope = read_index(&data, res_size);
361
7.03k
    result->Name = read_index(&data, ctx->index_sizes->string);
362
7.03k
    result->Namespace = read_index(&data, ctx->index_sizes->string);
363
364
7.03k
    return true;
365
7.03k
  }
366
367
0
  return false;
368
7.03k
}
369
370
static bool read_interfaceimpl(
371
    const CLASS_CONTEXT* ctx,
372
    const uint8_t* data,
373
    INTERFACEIMPL_ROW* result)
374
3.93M
{
375
3.93M
  uint32_t row_size = ctx->tables->intefaceimpl.RowSize;
376
377
3.93M
  if (fits_in_pe(ctx->pe, data, row_size))
378
2.38M
  {
379
2.38M
    uint32_t interface_size = 2;
380
2.38M
    uint32_t row_count = max_rows(
381
2.38M
        3,
382
2.38M
        ctx->tables->typedef_.RowCount,
383
2.38M
        ctx->tables->typeref.RowCount,
384
2.38M
        ctx->tables->typespec.RowCount);
385
386
2.38M
    if (row_count > (0xFFFF >> 0x02))
387
0
      interface_size = 4;
388
389
2.38M
    result->Class = read_index(&data, ctx->index_sizes->typedef_);
390
2.38M
    result->Interface = read_index(&data, interface_size);
391
392
2.38M
    return true;
393
2.38M
  }
394
395
1.54M
  return false;
396
3.93M
}
397
398
static bool read_methoddef(
399
    const CLASS_CONTEXT* ctx,
400
    const uint8_t* data,
401
    METHODDEF_ROW* result)
402
4.29M
{
403
4.29M
  uint32_t row_size = ctx->tables->methoddef.RowSize;
404
405
4.29M
  if (fits_in_pe(ctx->pe, data, row_size))
406
1.52M
  {
407
1.52M
    result->Rva = read_u32(&data);
408
1.52M
    result->ImplFlags = read_u16(&data);
409
1.52M
    result->Flags = read_u16(&data);
410
1.52M
    result->Name = read_index(&data, ctx->index_sizes->string);
411
1.52M
    result->Signature = read_index(&data, ctx->index_sizes->blob);
412
1.52M
    result->ParamList = read_index(&data, ctx->index_sizes->param);
413
1.52M
    return true;
414
1.52M
  }
415
416
2.77M
  return false;
417
4.29M
}
418
419
static bool read_param(
420
    const CLASS_CONTEXT* ctx,
421
    const uint8_t* data,
422
    PARAM_ROW* result)
423
11.7k
{
424
11.7k
  uint32_t row_size = ctx->tables->param.RowSize;
425
426
11.7k
  if (fits_in_pe(ctx->pe, data, row_size))
427
10.8k
  {
428
10.8k
    result->Flags = read_u16(&data);
429
10.8k
    result->Sequence = read_u16(&data);
430
10.8k
    result->Name = read_index(&data, ctx->index_sizes->string);
431
10.8k
    return true;
432
10.8k
  }
433
434
925
  return false;
435
11.7k
}
436
437
static bool read_genericparam(
438
    const CLASS_CONTEXT* ctx,
439
    const uint8_t* data,
440
    GENERICPARAM_ROW* result)
441
224M
{
442
224M
  uint32_t row_size = ctx->tables->genericparam.RowSize;
443
444
224M
  if (fits_in_pe(ctx->pe, data, row_size))
445
30.3M
  {
446
30.3M
    uint32_t owner_idx_size = 2;
447
30.3M
    uint32_t row_count = max_rows(
448
30.3M
        2, ctx->tables->typedef_.RowCount, ctx->tables->methoddef.RowCount);
449
450
30.3M
    if (row_count > (0xFFFF >> 0x01))
451
0
      owner_idx_size = 4;
452
453
30.3M
    result->Number = read_u16(&data);
454
30.3M
    result->Flags = read_u16(&data);
455
30.3M
    result->Owner = read_index(&data, owner_idx_size);
456
30.3M
    result->Name = read_index(&data, ctx->index_sizes->string);
457
30.3M
    return true;
458
30.3M
  }
459
460
194M
  return false;
461
224M
}
462
463
static bool read_typespec(
464
    const CLASS_CONTEXT* ctx,
465
    const uint8_t* data,
466
    TYPESPEC_ROW* result)
467
288k
{
468
288k
  uint32_t row_size = ctx->tables->typespec.RowSize;
469
470
288k
  if (fits_in_pe(ctx->pe, data, row_size))
471
285k
  {
472
285k
    result->Signature = read_index(&data, ctx->index_sizes->blob);
473
285k
    return true;
474
285k
  }
475
476
2.65k
  return false;
477
288k
}
478
479
static bool read_nestedclass(
480
    const CLASS_CONTEXT* ctx,
481
    const uint8_t* data,
482
    NESTEDCLASS_ROW* result)
483
17.0M
{
484
17.0M
  uint32_t row_size = ctx->tables->nestedclass.RowSize;
485
486
17.0M
  if (fits_in_pe(ctx->pe, data, row_size))
487
7.12M
  {
488
7.12M
    result->NestedClass = read_index(&data, ctx->index_sizes->typedef_);
489
7.12M
    result->EnclosingClass = read_index(&data, ctx->index_sizes->typedef_);
490
7.12M
    return true;
491
7.12M
  }
492
493
9.94M
  return false;
494
17.0M
}
495
496
// ECMA-335 II.23.2 blob heap uses variable length encoding of integers
497
static uint32_t read_blob_unsigned(const uint8_t** data, uint32_t* len)
498
1.87M
{
499
1.87M
  if (*len < 1)
500
32.2k
    return 0;
501
502
  // first byte is enough to decode the length
503
  // without worrying about endiannity
504
  // Compressed integers use big-endian order
505
1.84M
  uint8_t first_byte = *(*data);
506
507
  // If the value lies between 0 (0x00) and 127 (0x7F), inclusive, encode as a
508
  // one-byte integer (bit 7 is clear, value held in bits 6 through 0)
509
1.84M
  if (!(first_byte & 0x80))
510
1.51M
  {
511
1.51M
    *data += sizeof(uint8_t);
512
1.51M
    *len -= sizeof(uint8_t);
513
1.51M
    return first_byte;
514
1.51M
  }
515
516
327k
  if (*len < 2)
517
960
    return 0;
518
519
  // If the value lies between 2^8 (0x80) and 2^14 – 1 (0x3FFF), inclusive,
520
  // encode as a 2-byte integer with bit 15 set, bit 14 clear (value held in
521
  // bits 13 through 0)
522
326k
  if ((first_byte & 0xC0) == 0x80)
523
145k
  {
524
145k
    uint32_t result = yr_be16toh(yr_unaligned_u16(*data));
525
145k
    *data += sizeof(uint16_t);
526
145k
    *len -= sizeof(uint16_t);
527
    // value is in lower 14 bits
528
145k
    return result & 0x3FFF;
529
145k
  }
530
531
181k
  if (*len < 4)
532
6.72k
    return 0;
533
534
  // Otherwise, encode as a 4-byte integer, with bit 31 set, bit 30 set,
535
  // bit 29 clear (value held in bits 28 through 0)
536
174k
  if ((first_byte & 0xE0) == 0xC0)
537
88.5k
  {
538
88.5k
    uint32_t result = yr_be32toh(yr_unaligned_u32(*data));
539
88.5k
    *data += sizeof(uint32_t);
540
88.5k
    *len -= sizeof(uint32_t);
541
    // Uses last 29 bits for the result
542
88.5k
    return result & 0x1FFFFFFF;
543
88.5k
  }
544
545
86.1k
  return 0;
546
174k
}
547
548
// ECMA-335 II.23.2 blob heap uses variable length encoding of integers
549
// Probably wouldn't work on non 2's complement arches?
550
static int32_t read_blob_signed(const uint8_t** data, uint32_t* len)
551
68.9k
{
552
  // Compressed integers use big-endian order!
553
68.9k
  if (*len < 1)
554
4.57k
    return 0;
555
556
  // first byte is enough to decode the length
557
  // without worrying about endiannity
558
64.3k
  uint8_t first_byte = *(*data);
559
560
  // Encode as a one-byte integer, bit 7 clear, rotated value in bits 6
561
  // through 0, giving 0x01 (-2^6) to 0x7E (2^6-1).
562
64.3k
  if (!(first_byte & 0x80))
563
33.9k
  {
564
33.9k
    uint8_t tmp = first_byte >> 1;
565
    // sign extension in case of negative number
566
33.9k
    if (first_byte & 0x1)
567
10.4k
      tmp |= 0xC0;
568
569
33.9k
    *data += sizeof(uint8_t);
570
33.9k
    *len -= sizeof(uint8_t);
571
572
33.9k
    return (int32_t) tmp;
573
33.9k
  }
574
575
30.3k
  if (*len < 2)
576
891
    return 0;
577
578
  // Encode as a two-byte integer: bit 15 set, bit 14 clear, rotated value
579
  // in bits 13 through 0, giving 0x8001 (-2^13) to 0xBFFE (2^13-1).
580
29.4k
  if ((first_byte & 0xC0) == 0x80)
581
3.11k
  {
582
3.11k
    uint16_t tmp1 = yr_be16toh(yr_unaligned_u16(*data));
583
    // shift and leave top 2 bits clear
584
3.11k
    uint16_t tmp2 = (tmp1 >> 1) & 0x3FFF;
585
    // sign extension in case of negative number
586
3.11k
    if (tmp1 & 0x1)
587
1.31k
      tmp2 |= 0xC000;
588
589
3.11k
    *data += sizeof(uint16_t);
590
3.11k
    *len -= sizeof(uint16_t);
591
592
3.11k
    return (int32_t) tmp2;
593
3.11k
  }
594
595
26.3k
  if (*len < 4)
596
1.74k
    return 0;
597
598
  // Encode as a four-byte integer: bit 31 set, 30 set, bit 29 clear,
599
  // rotated value in bits 28 through 0, giving 0xC0000001 (-2^28) to
600
  // 0xDFFFFFFE (2^28-1).
601
24.6k
  if ((first_byte & 0xE0) == 0xC0)
602
4.98k
  {
603
4.98k
    uint32_t tmp1 = yr_be32toh(yr_unaligned_u32(*data));
604
    // shift and leave top 3 bits clear
605
4.98k
    uint32_t tmp2 = (tmp1 >> 1) & 0x1FFFFFFF;
606
    // sign extension in case of negative number
607
4.98k
    if (tmp1 & 0x1)
608
2.89k
      tmp2 |= 0xE0000000;
609
610
4.98k
    *data += sizeof(uint32_t);
611
4.98k
    *len -= sizeof(uint32_t);
612
613
4.98k
    return (int32_t) tmp2;
614
4.98k
  }
615
616
19.6k
  return 0;
617
24.6k
}
618
619
// Forward declarations
620
static char* parse_signature_type(
621
    const CLASS_CONTEXT* ctx,
622
    const uint8_t** data,
623
    uint32_t* len,
624
    GENERIC_PARAMETERS* class_gen_params,
625
    GENERIC_PARAMETERS* method_gen_params,
626
    uint32_t depth);
627
628
static char* parse_enclosing_types(
629
    const CLASS_CONTEXT* ctx,
630
    uint32_t nested_idx,
631
    uint32_t depth);
632
633
static char* get_type_def_or_ref_fullname(
634
    const CLASS_CONTEXT* ctx,
635
    uint32_t coded_index,
636
    GENERIC_PARAMETERS* class_gen_params,
637
    GENERIC_PARAMETERS* method_gen_params,
638
    uint32_t depth)  // against loops
639
522k
{
640
  // first 2 bits define table, index starts with third bit
641
522k
  uint32_t index = coded_index >> 2;
642
522k
  if (!index)
643
45.1k
    return NULL;
644
645
477k
  const uint8_t* str_heap = ctx->str_heap;
646
477k
  uint32_t str_size = ctx->str_size;
647
648
477k
  uint8_t table = coded_index & 0x3;
649
477k
  if (table == 0)  // TypeDef
650
121k
  {
651
121k
    const uint8_t* data = get_table_offset(&ctx->tables->typedef_, index);
652
121k
    if (!data)
653
19.6k
      return NULL;
654
655
101k
    TYPEDEF_ROW def_row;
656
101k
    bool result = read_typedef(ctx, data, &def_row);
657
101k
    if (result)
658
100k
    {
659
100k
      const char* name = pe_get_dotnet_string(
660
100k
          ctx->pe, str_heap, str_size, def_row.Name);
661
100k
      const char* namespace = pe_get_dotnet_string(
662
100k
          ctx->pe, str_heap, str_size, def_row.Namespace);
663
664
100k
      char* result = NULL;
665
      // Type might be nested, try to find correct namespace
666
100k
      if (is_nested(def_row.Flags))
667
65.2k
      {
668
65.2k
        char* nested_namespace = parse_enclosing_types(ctx, index, 1);
669
65.2k
        char* tmp = create_full_name(namespace, nested_namespace);
670
65.2k
        result = create_full_name(name, tmp);
671
65.2k
        yr_free(nested_namespace);
672
65.2k
        yr_free(tmp);
673
65.2k
      }
674
35.1k
      else
675
35.1k
        result = create_full_name(name, namespace);
676
677
100k
      return result;
678
100k
    }
679
101k
  }
680
356k
  else if (table == 1)  // TypeRef
681
24.0k
  {
682
24.0k
    const uint8_t* data = get_table_offset(&ctx->tables->typeref, index);
683
24.0k
    if (!data)
684
17.0k
      return NULL;
685
686
7.03k
    TYPEREF_ROW ref_row;
687
7.03k
    bool result = read_typeref(ctx, data, &ref_row);
688
7.03k
    if (result)
689
7.03k
    {
690
7.03k
      const char* name = pe_get_dotnet_string(
691
7.03k
          ctx->pe, str_heap, str_size, ref_row.Name);
692
7.03k
      const char* namespace = pe_get_dotnet_string(
693
7.03k
          ctx->pe, str_heap, str_size, ref_row.Namespace);
694
695
7.03k
      return create_full_name(name, namespace);
696
7.03k
    }
697
7.03k
  }
698
332k
  else if (table == 2)  // TypeSpec
699
304k
  {
700
304k
    const uint8_t* data = get_table_offset(&ctx->tables->typespec, index);
701
304k
    if (!data)
702
16.2k
      return NULL;
703
704
288k
    TYPESPEC_ROW spec_row;
705
288k
    bool result = read_typespec(ctx, data, &spec_row);
706
288k
    if (result)
707
285k
    {
708
285k
      const uint8_t* sig_data = ctx->blob_heap + spec_row.Signature;
709
710
      // Read the blob entry with the data
711
285k
      BLOB_PARSE_RESULT blob_res = dotnet_parse_blob_entry(ctx->pe, sig_data);
712
285k
      sig_data += blob_res.size;
713
285k
      uint32_t sig_len = blob_res.length;
714
715
      // Valid blob
716
285k
      if (blob_res.size)
717
271k
        return parse_signature_type(
718
271k
            ctx, &sig_data, &sig_len, class_gen_params, NULL, depth);
719
285k
    }
720
288k
  }
721
45.7k
  return NULL;
722
477k
}
723
724
static char* parse_signature_type(
725
    const CLASS_CONTEXT* ctx,
726
    const uint8_t** data,
727
    uint32_t* len,
728
    GENERIC_PARAMETERS* class_gen_params,
729
    GENERIC_PARAMETERS* method_gen_params,
730
    uint32_t depth  // against loops
731
)
732
14.4M
{
733
  // If at least first type fits and we are not too nested
734
14.4M
  if (*len < 1 || !fits_in_pe(ctx->pe, *data, 1) || depth > MAX_TYPE_DEPTH)
735
5.72M
    return NULL;
736
737
8.75M
  bool class = false;
738
8.75M
  uint32_t coded_index, index;
739
8.75M
  char* tmp = NULL;
740
8.75M
  char* ret_type = NULL;
741
742
8.75M
  uint8_t type = read_u8(data);
743
8.75M
  *len -= 1;
744
745
8.75M
  switch (type)
746
8.75M
  {
747
144k
  case TYPE_VOID:
748
144k
    ret_type = "void";
749
144k
    break;
750
751
72.9k
  case TYPE_BOOL:
752
72.9k
    ret_type = "bool";
753
72.9k
    break;
754
755
103k
  case TYPE_CHAR:
756
103k
    ret_type = "char";
757
103k
    break;
758
759
149k
  case TYPE_I1:
760
149k
    ret_type = "sbyte";
761
149k
    break;
762
763
100k
  case TYPE_U1:
764
100k
    ret_type = "byte";
765
100k
    break;
766
767
105k
  case TYPE_I2:
768
105k
    ret_type = "short";
769
105k
    break;
770
771
54.8k
  case TYPE_U2:
772
54.8k
    ret_type = "ushort";
773
54.8k
    break;
774
775
140k
  case TYPE_I4:
776
140k
    ret_type = "int";
777
140k
    break;
778
779
24.1k
  case TYPE_U4:
780
24.1k
    ret_type = "uint";
781
24.1k
    break;
782
783
21.6k
  case TYPE_I8:
784
21.6k
    ret_type = "long";
785
21.6k
    break;
786
787
13.5k
  case TYPE_U8:
788
13.5k
    ret_type = "ulong";
789
13.5k
    break;
790
791
66.8k
  case TYPE_R4:
792
66.8k
    ret_type = "float";
793
66.8k
    break;
794
795
40.1k
  case TYPE_R8:
796
40.1k
    ret_type = "double";
797
40.1k
    break;
798
799
28.1k
  case TYPE_STRING:
800
28.1k
    ret_type = "string";
801
28.1k
    break;
802
803
52.9k
  case TYPE_TYPEDREF:
804
52.9k
    ret_type = "TypedReference";
805
52.9k
    break;
806
807
78.3k
  case TYPE_I:
808
78.3k
    ret_type = "IntPtr";
809
78.3k
    break;
810
811
11.6k
  case TYPE_U:
812
11.6k
    ret_type = "UIntPtr";
813
11.6k
    break;
814
815
20.0k
  case TYPE_PTR:  // Ptr followed by type
816
20.0k
    tmp = parse_signature_type(
817
20.0k
        ctx, data, len, class_gen_params, method_gen_params, depth + 1);
818
20.0k
    if (tmp)
819
4.85k
    {
820
4.85k
      SIMPLE_STR* ss = sstr_new(NULL);
821
4.85k
      if (!ss)
822
0
      {
823
0
        yr_free(tmp);
824
0
        break;
825
0
      }
826
4.85k
      bool res = sstr_appendf(ss, "Ptr<%s>", tmp);
827
4.85k
      if (res)
828
4.85k
        ret_type = sstr_move(ss);
829
830
4.85k
      yr_free(tmp);
831
4.85k
      sstr_free(ss);
832
4.85k
      return ret_type;
833
4.85k
    }
834
15.1k
    break;
835
836
21.2k
  case TYPE_BYREF:
837
    // ByRef followed by type
838
21.2k
    tmp = parse_signature_type(
839
21.2k
        ctx, data, len, class_gen_params, method_gen_params, depth + 1);
840
21.2k
    if (tmp)
841
3.66k
    {
842
3.66k
      SIMPLE_STR* ss = sstr_new(NULL);
843
3.66k
      if (!ss)
844
0
      {
845
0
        yr_free(tmp);
846
0
        break;
847
0
      }
848
3.66k
      bool res = sstr_appendf(ss, "ref %s", tmp);
849
3.66k
      if (res)
850
3.66k
        ret_type = sstr_move(ss);
851
852
3.66k
      yr_free(tmp);
853
3.66k
      sstr_free(ss);
854
3.66k
      return ret_type;
855
3.66k
    }
856
17.5k
    break;
857
858
350k
  case TYPE_VALUETYPE:  // ValueType
859
366k
  case TYPE_CLASS:      // Class
860
    // followed by TypeDefOrRefOrSpecEncoded index
861
366k
    coded_index = read_blob_unsigned(data, len);
862
366k
    return get_type_def_or_ref_fullname(
863
366k
        ctx, coded_index, class_gen_params, method_gen_params, depth + 1);
864
0
    break;
865
866
43.6k
  case TYPE_VAR:   // Generic class var
867
87.8k
  case TYPE_MVAR:  // Generic method var
868
87.8k
    index = read_blob_unsigned(data, len);
869
87.8k
    class = type == TYPE_VAR;
870
    // return class generic var or method generic var
871
87.8k
    if (class && class_gen_params && index < class_gen_params->len)
872
288
      ret_type = class_gen_params->names[index];
873
87.5k
    else if (!class && method_gen_params && index < method_gen_params->len)
874
229
      ret_type = method_gen_params->names[index];
875
87.8k
    break;
876
877
82.0k
  case TYPE_ARRAY:
878
82.0k
  {
879
    // Array -> Type -> Rank -> NumSizes -> Size -> NumLobound -> LoBound
880
82.0k
    char* tmp = parse_signature_type(
881
82.0k
        ctx, data, len, class_gen_params, method_gen_params, depth + 1);
882
82.0k
    if (!tmp)
883
69.4k
      break;
884
885
12.5k
    uint32_t* sizes = NULL;
886
12.5k
    int32_t* lo_bounds = NULL;
887
888
    // Read number of dimensions
889
12.5k
    uint32_t rank = read_blob_unsigned(data, len);
890
12.5k
    if (!rank || rank > MAX_ARRAY_RANK)
891
2.89k
      goto cleanup;
892
893
    // Read number of specified sizes
894
9.68k
    uint32_t num_sizes = read_blob_unsigned(data, len);
895
9.68k
    sizes = yr_malloc(sizeof(uint32_t) * num_sizes);
896
9.68k
    if (!sizes || num_sizes > rank)
897
1.01k
      goto cleanup;
898
899
77.4k
    for (uint32_t i = 0; i < num_sizes; ++i)
900
68.7k
    {
901
68.7k
      sizes[i] = read_blob_unsigned(data, len);
902
68.7k
    }
903
904
    // Read number of specified lower bounds
905
8.67k
    uint32_t num_lowbounds = read_blob_unsigned(data, len);
906
8.67k
    lo_bounds = yr_malloc(sizeof(int32_t) * num_lowbounds);
907
8.67k
    if (!lo_bounds || num_lowbounds > rank)
908
843
      goto cleanup;
909
910
76.7k
    for (uint32_t i = 0; i < num_lowbounds; ++i)
911
68.9k
    {
912
68.9k
      lo_bounds[i] = read_blob_signed(data, len);
913
914
      // Adjust higher bound according to lower bound
915
68.9k
      if (num_sizes > i)
916
5.17k
        sizes[i] += lo_bounds[i];
917
68.9k
    }
918
919
    // Build the resulting array type
920
7.82k
    SIMPLE_STR* ss = sstr_new(NULL);
921
7.82k
    if (!ss)
922
0
      goto cleanup;
923
924
7.82k
    sstr_appendf(ss, "%s[", tmp);
925
926
307k
    for (uint32_t i = 0; i < rank; ++i)
927
299k
    {
928
299k
      if (num_sizes > i || num_lowbounds > i)
929
128k
      {
930
128k
        if (num_lowbounds > i && lo_bounds[i] != 0)
931
30.8k
          sstr_appendf(ss, "%lu...", lo_bounds[i]);
932
128k
        if (num_sizes > i && sizes[i] != 0)
933
29.8k
          sstr_appendf(ss, "%lu", sizes[i]);
934
128k
      }
935
299k
      if (i + 1 != rank)
936
291k
        sstr_appendf(ss, ",");
937
299k
    }
938
7.82k
    bool res = sstr_appendf(ss, "]");
939
7.82k
    if (res)
940
7.82k
      ret_type = sstr_move(ss);
941
942
7.82k
    yr_free(sizes);
943
7.82k
    yr_free(lo_bounds);
944
7.82k
    yr_free(tmp);
945
7.82k
    sstr_free(ss);
946
7.82k
    return ret_type;
947
948
4.75k
  cleanup:
949
4.75k
    yr_free(sizes);
950
4.75k
    yr_free(lo_bounds);
951
4.75k
    yr_free(tmp);
952
4.75k
  }
953
0
  break;
954
955
89.2k
  case TYPE_GENERICINST:
956
89.2k
  {
957
89.2k
    tmp = parse_signature_type(
958
89.2k
        ctx, data, len, class_gen_params, method_gen_params, depth + 1);
959
960
89.2k
    if (!tmp)
961
51.2k
      break;
962
963
37.9k
    uint32_t gen_count = read_blob_unsigned(data, len);
964
965
    // Sanity check for corrupted files
966
37.9k
    if (gen_count > MAX_GEN_PARAM_COUNT)
967
1.70k
    {
968
1.70k
      yr_free(tmp);
969
1.70k
      break;
970
1.70k
    }
971
972
36.2k
    SIMPLE_STR* ss = sstr_new(NULL);
973
36.2k
    if (!ss)
974
0
    {
975
0
      yr_free(tmp);
976
0
      break;
977
0
    }
978
36.2k
    sstr_appendf(ss, "%s<", tmp);
979
36.2k
    yr_free(tmp);
980
981
1.03M
    for (int i = 0; i < gen_count; i++)
982
998k
    {
983
998k
      char* param_type = parse_signature_type(
984
998k
          ctx, data, len, class_gen_params, method_gen_params, depth + 1);
985
986
998k
      if (param_type != NULL)
987
69.5k
      {
988
69.5k
        if (i > 0)
989
67.2k
          sstr_appendf(ss, ",");
990
991
69.5k
        sstr_appendf(ss, "%s", param_type);
992
69.5k
        yr_free(param_type);
993
69.5k
      }
994
998k
    }
995
36.2k
    bool res = sstr_appendf(ss, ">");
996
36.2k
    if (res)
997
36.2k
      ret_type = sstr_move(ss);
998
999
36.2k
    sstr_free(ss);
1000
36.2k
    return ret_type;
1001
36.2k
  }
1002
0
  break;
1003
1004
251k
  case TYPE_FNPTR:
1005
251k
    if (*len > 0)
1006
251k
    {  // Flags -> ParamCount -> RetType -> Param -> Sentinel ->Param
1007
      // Skip flags
1008
251k
      (*data)++;
1009
251k
      (*len)--;
1010
1011
251k
      uint32_t param_count = read_blob_unsigned(data, len);
1012
1013
      // Sanity check for corrupted files
1014
251k
      if (param_count > MAX_PARAM_COUNT)
1015
3.45k
      {
1016
3.45k
        yr_free(tmp);
1017
3.45k
        break;
1018
3.45k
      }
1019
1020
247k
      tmp = parse_signature_type(
1021
247k
          ctx, data, len, class_gen_params, method_gen_params, depth + 1);
1022
1023
247k
      if (!tmp)
1024
158k
        break;
1025
1026
89.1k
      SIMPLE_STR* ss = sstr_new(NULL);
1027
89.1k
      if (!ss)
1028
0
      {
1029
0
        yr_free(tmp);
1030
0
        break;
1031
0
      }
1032
1033
89.1k
      sstr_appendf(ss, "FnPtr<%s(", tmp);
1034
89.1k
      yr_free(tmp);
1035
1036
11.8M
      for (int i = 0; i < param_count; i++)
1037
11.7M
      {
1038
11.7M
        char* param_type = parse_signature_type(
1039
11.7M
            ctx, data, len, class_gen_params, method_gen_params, depth + 1);
1040
1041
11.7M
        if (param_type != NULL)
1042
1.02M
        {
1043
1.02M
          if (i > 0)
1044
984k
            sstr_appendf(ss, ", ");
1045
1046
1.02M
          sstr_appendf(ss, "%s", param_type);
1047
1.02M
          yr_free(param_type);
1048
1.02M
        }
1049
11.7M
      }
1050
1051
89.1k
      if (sstr_appendf(ss, ")>"))
1052
89.1k
        ret_type = sstr_move(ss);
1053
1054
89.1k
      sstr_free(ss);
1055
89.1k
      return ret_type;
1056
89.1k
    }
1057
624
    break;
1058
1059
50.4k
  case TYPE_OBJECT:
1060
50.4k
    ret_type = "object";
1061
50.4k
    break;
1062
1063
53.7k
  case TYPE_SZARRAY:
1064
    // Single dimensional array followed by type
1065
53.7k
    tmp = parse_signature_type(
1066
53.7k
        ctx, data, len, class_gen_params, method_gen_params, depth + 1);
1067
53.7k
    if (tmp)
1068
14.7k
    {
1069
14.7k
      SIMPLE_STR* ss = sstr_newf("%s[]", tmp);
1070
14.7k
      if (ss)
1071
14.7k
        ret_type = sstr_move(ss);
1072
1073
14.7k
      yr_free(tmp);
1074
14.7k
      sstr_free(ss);
1075
14.7k
      return ret_type;
1076
14.7k
    }
1077
39.0k
    break;
1078
1079
39.0k
  case TYPE_CMOD_REQD:  // Req modifier
1080
227k
  case TYPE_CMOD_OPT:   // Opt modifier
1081
227k
  {
1082
    // What is point of these
1083
    // Right now ignore them...
1084
227k
    read_blob_unsigned(data, len);
1085
227k
    return parse_signature_type(
1086
227k
        ctx, data, len, class_gen_params, method_gen_params, depth + 1);
1087
36.0k
  }
1088
0
  break;
1089
1090
6.29M
  default:
1091
6.29M
    break;
1092
8.75M
  }
1093
1094
8.00M
  if (ret_type)
1095
1.25M
    return yr_strdup(ret_type);
1096
6.74M
  else
1097
6.74M
    return NULL;
1098
8.00M
}
1099
1100
static void parse_type_parents(
1101
    const CLASS_CONTEXT* ctx,
1102
    uint32_t extends,
1103
    uint32_t type_idx,
1104
    uint32_t out_idx,  // Class idx in output array
1105
    GENERIC_PARAMETERS* class_gen_params)
1106
153k
{
1107
  // Find the parent class
1108
153k
  char* parent = get_type_def_or_ref_fullname(
1109
153k
      ctx, extends, class_gen_params, NULL, 0);
1110
1111
153k
  uint32_t base_type_idx = 0;
1112
153k
  if (parent)
1113
36.8k
  {
1114
36.8k
    yr_set_string(
1115
36.8k
        parent,
1116
36.8k
        ctx->pe->object,
1117
36.8k
        "classes[%i].base_types[%i]",
1118
36.8k
        out_idx,
1119
36.8k
        base_type_idx++);
1120
1121
36.8k
    yr_free(parent);
1122
36.8k
  }
1123
1124
  // linear search for every interface that the class implements
1125
4.08M
  for (uint32_t idx = 0; idx < ctx->tables->intefaceimpl.RowCount; ++idx)
1126
3.93M
  {
1127
3.93M
    const uint8_t* data = get_table_offset(&ctx->tables->intefaceimpl, idx + 1);
1128
3.93M
    if (!data)
1129
0
      break;
1130
1131
3.93M
    INTERFACEIMPL_ROW row = {0};
1132
3.93M
    bool result = read_interfaceimpl(ctx, data, &row);
1133
3.93M
    if (!result)
1134
1.54M
      continue;
1135
1136
    // We found the inherited interface
1137
2.38M
    if (row.Class == type_idx)
1138
2.93k
    {
1139
2.93k
      char* inteface = get_type_def_or_ref_fullname(
1140
2.93k
          ctx, row.Interface, class_gen_params, NULL, 0);
1141
2.93k
      if (inteface)
1142
1.31k
      {
1143
1.31k
        yr_set_string(
1144
1.31k
            inteface,
1145
1.31k
            ctx->pe->object,
1146
1.31k
            "classes[%i].base_types[%i]",
1147
1.31k
            out_idx,
1148
1.31k
            base_type_idx++);
1149
1150
1.31k
        yr_free(inteface);
1151
1.31k
      }
1152
2.93k
    }
1153
2.38M
  }
1154
153k
  yr_set_integer(
1155
153k
      base_type_idx,
1156
153k
      ctx->pe->object,
1157
153k
      "classes[%i].number_of_base_types",
1158
153k
      out_idx);
1159
153k
}
1160
1161
// Returns true if all parameters were correctly parsed
1162
static bool parse_method_params(
1163
    const CLASS_CONTEXT* ctx,
1164
    uint32_t param_list,
1165
    uint32_t method_idx,  // used for output
1166
    uint32_t class_idx,
1167
    uint32_t param_count,
1168
    const uint8_t* sig_data,
1169
    uint32_t sig_len,
1170
    GENERIC_PARAMETERS* class_gen_params,
1171
    GENERIC_PARAMETERS* method_gen_params)
1172
59.7k
{
1173
59.7k
  if (!param_list)  // NULL
1174
21.1k
    return true;
1175
1176
38.5k
  const uint8_t* str_heap = ctx->str_heap;
1177
38.5k
  uint32_t str_size = ctx->str_size;
1178
1179
  // Array to hold all the possible parameters
1180
38.5k
  PARAMETERS* params = yr_calloc(param_count, sizeof(PARAMETERS));
1181
1182
38.5k
  if (!params)
1183
0
    return false;
1184
1185
162k
  for (uint32_t idx = 0; idx < param_count; ++idx)
1186
151k
  {
1187
151k
    const uint8_t* data = get_table_offset(
1188
151k
        &ctx->tables->param, param_list + idx);
1189
1190
151k
    char* name = NULL;
1191
151k
    bool alloc = false;  // Flag if name needs freeing
1192
1193
151k
    if (data)            // We need param table mostly just for the param name
1194
11.7k
    {
1195
11.7k
      PARAM_ROW row = {0};
1196
11.7k
      bool result = read_param(ctx, data, &row);
1197
1198
11.7k
      if (!result)
1199
925
      {  // Cleanup and return
1200
2.47k
        for (uint32_t j = 0; j < idx; ++j)
1201
1.54k
        {
1202
1.54k
          if (params[j].alloc)
1203
0
            yr_free(params[j].name);
1204
1205
1.54k
          yr_free(params[j].type);
1206
1.54k
        }
1207
925
        yr_free(params);
1208
925
        return false;
1209
925
      }
1210
1211
10.8k
      name = pe_get_dotnet_string(ctx->pe, str_heap, str_size, row.Name);
1212
10.8k
    }
1213
139k
    else  // We can reconstruct their type from the signature
1214
          // and give them default name
1215
139k
    {
1216
139k
      alloc = true;
1217
139k
      SIMPLE_STR* ss = sstr_newf("P_%lu", idx);
1218
139k
      if (ss)
1219
139k
      {
1220
139k
        name = sstr_move(ss);
1221
139k
        sstr_free(ss);
1222
139k
      }
1223
139k
    }
1224
1225
150k
    char* type = parse_signature_type(
1226
150k
        ctx, &sig_data, &sig_len, class_gen_params, method_gen_params, 0);
1227
1228
150k
    params[idx].alloc = alloc;
1229
150k
    params[idx].name = name;
1230
150k
    params[idx].type = type;
1231
1232
150k
    if (!type)  // If any param fails, whole parsing is aborted
1233
26.2k
    {
1234
100k
      for (uint32_t j = 0; j <= idx; ++j)
1235
74.2k
      {
1236
74.2k
        if (params[j].alloc)
1237
65.3k
          yr_free(params[j].name);
1238
1239
74.2k
        yr_free(params[j].type);
1240
74.2k
      }
1241
26.2k
      yr_free(params);
1242
26.2k
      return false;
1243
26.2k
    }
1244
150k
  }
1245
1246
  // If we got all of them correctly, write to output and cleanup
1247
11.3k
  YR_OBJECT* out_obj = ctx->pe->object;
1248
11.3k
  yr_set_integer(
1249
11.3k
      param_count,
1250
11.3k
      out_obj,
1251
11.3k
      "classes[%i].methods[%i].number_of_parameters",
1252
11.3k
      class_idx,
1253
11.3k
      method_idx);
1254
1255
85.9k
  for (uint32_t i = 0; i < param_count; ++i)
1256
74.6k
  {
1257
74.6k
    yr_set_string(
1258
74.6k
        params[i].name,
1259
74.6k
        out_obj,
1260
74.6k
        "classes[%i].methods[%i].parameters[%i].name",
1261
74.6k
        class_idx,
1262
74.6k
        method_idx,
1263
74.6k
        i);
1264
74.6k
    yr_set_string(
1265
74.6k
        params[i].type,
1266
74.6k
        out_obj,
1267
74.6k
        "classes[%i].methods[%i].parameters[%i].type",
1268
74.6k
        class_idx,
1269
74.6k
        method_idx,
1270
74.6k
        i);
1271
74.6k
    if (params[i].alloc)
1272
74.3k
      yr_free(params[i].name);
1273
1274
74.6k
    yr_free(params[i].type);
1275
74.6k
  }
1276
1277
11.3k
  yr_free(params);
1278
11.3k
  return true;
1279
38.5k
}
1280
1281
// Walks GenericParam table, finds all generic params for the MethodDef or
1282
// TypeDef entry and allocates buffer with the Generic param names into result
1283
static void parse_generic_params(
1284
    const CLASS_CONTEXT* ctx,
1285
    bool method,  // true means MethodDef, false TypeDef index
1286
    uint32_t gen_idx,
1287
    GENERIC_PARAMETERS* result)
1288
1.16M
{
1289
1.16M
  const uint8_t* str_heap = ctx->str_heap;
1290
1.16M
  uint32_t str_size = ctx->str_size;
1291
1292
1.16M
  result->names = NULL;
1293
1.16M
  result->len = 0;
1294
1295
  // Walk the GenericParam table to find GenParameters of the class/method
1296
226M
  for (uint32_t idx = 0; idx < ctx->tables->genericparam.RowCount; ++idx)
1297
224M
  {
1298
224M
    const uint8_t* data = get_table_offset(&ctx->tables->genericparam, idx + 1);
1299
224M
    if (!data)
1300
0
      goto cleanup;
1301
1302
224M
    GENERICPARAM_ROW row = {0};
1303
224M
    bool read_result = read_genericparam(ctx, data, &row);
1304
224M
    if (!read_result)
1305
194M
      continue;
1306
1307
    // TypeOrMethodDef coded index
1308
30.3M
    uint8_t table = row.Owner & 0x1;
1309
    // 0 == TypeDef 1 == MethodDef
1310
    // Check if it's generic param of the type we want
1311
30.3M
    if (table == method && (row.Owner >> 1) == gen_idx)
1312
5.93k
    {
1313
5.93k
      char* name = pe_get_dotnet_string(ctx->pe, str_heap, str_size, row.Name);
1314
      // name must be valid string
1315
5.93k
      if (!name || !*name)  // ERROR
1316
2.26k
        goto cleanup;
1317
1318
3.67k
      result->len += 1;
1319
3.67k
      char** tmp = yr_realloc(result->names, result->len * sizeof(char*));
1320
3.67k
      if (!tmp)
1321
0
        goto cleanup;
1322
1323
      // Update the collection
1324
3.67k
      result->names = tmp;
1325
3.67k
      result->names[result->len - 1] = name;
1326
3.67k
    }
1327
30.3M
  }
1328
1.16M
  return;
1329
1330
1.16M
cleanup:
1331
2.26k
  yr_free(result->names);
1332
2.26k
  result->names = NULL;
1333
2.26k
  result->len = 0;
1334
2.26k
}
1335
1336
static void parse_methods(
1337
    const CLASS_CONTEXT* ctx,
1338
    uint32_t methodlist,
1339
    uint32_t method_count,
1340
    uint32_t class_idx,  // class index in the YARA output
1341
    GENERIC_PARAMETERS* class_gen_params)
1342
131k
{
1343
131k
  if (!methodlist)
1344
28.5k
    return;
1345
1346
102k
  const uint8_t* str_heap = ctx->str_heap;
1347
102k
  uint32_t str_size = ctx->str_size;
1348
1349
102k
  uint32_t out_idx = 0;
1350
4.40M
  for (uint32_t idx = 0; idx < method_count; ++idx)
1351
4.31M
  {
1352
4.31M
    const uint8_t* data = get_table_offset(
1353
4.31M
        &ctx->tables->methoddef, methodlist + idx);
1354
1355
4.31M
    if (!data)
1356
19.8k
      break;
1357
1358
4.29M
    METHODDEF_ROW row = {0};
1359
4.29M
    bool result = read_methoddef(ctx, data, &row);
1360
4.29M
    if (!result)
1361
2.77M
      continue;
1362
1363
1.52M
    const char* name = pe_get_dotnet_string(
1364
1.52M
        ctx->pe, str_heap, str_size, row.Name);
1365
1366
    // Ignore invalid/empty names
1367
1.52M
    if (!name || !*name)
1368
513k
      continue;
1369
1370
    // Try to find generic params for the method
1371
1.01M
    GENERIC_PARAMETERS method_gen_params = {0};
1372
1.01M
    parse_generic_params(ctx, true, methodlist + idx, &method_gen_params);
1373
1374
    // Read the blob entry with signature data
1375
1.01M
    const uint8_t* sig_data = ctx->blob_heap + row.Signature;
1376
1377
1.01M
    BLOB_PARSE_RESULT blob_res = dotnet_parse_blob_entry(ctx->pe, sig_data);
1378
1.01M
    sig_data += blob_res.size;
1379
1.01M
    uint32_t sig_len = blob_res.length;
1380
1.01M
    uint32_t param_count = 0;
1381
1382
1.01M
    char* return_type = NULL;
1383
    // If there is valid blob and at least minimum to parse
1384
    // (flags, paramCount, retType) parse these basic information
1385
1.01M
    if (blob_res.size && sig_len >= 3)
1386
562k
    {
1387
562k
      uint8_t flags = read_u8(&sig_data);
1388
562k
      sig_len -= 1;
1389
562k
      if (flags & SIG_FLAG_GENERIC)
1390
        // Generic param count, ignored as we get the
1391
        // information from generic param table
1392
246k
        (void) read_blob_unsigned(&sig_data, &sig_len);
1393
1394
      // Regular param count
1395
562k
      param_count = read_blob_unsigned(&sig_data, &sig_len);
1396
562k
      return_type = parse_signature_type(
1397
562k
          ctx, &sig_data, &sig_len, class_gen_params, &method_gen_params, 0);
1398
562k
    }
1399
450k
    else  // Error, skip
1400
450k
      goto clean_next;
1401
1402
    // Sanity check for corrupted files
1403
562k
    if (!return_type || param_count > MAX_PARAM_COUNT)
1404
502k
      goto clean_next;
1405
1406
59.7k
    result = parse_method_params(
1407
59.7k
        ctx,
1408
59.7k
        row.ParamList,
1409
59.7k
        out_idx,
1410
59.7k
        class_idx,
1411
59.7k
        param_count,
1412
59.7k
        sig_data,
1413
59.7k
        sig_len,
1414
59.7k
        class_gen_params,
1415
59.7k
        &method_gen_params);
1416
1417
59.7k
    if (!result)
1418
27.2k
      goto clean_next;
1419
1420
32.5k
    const char* visibility = get_method_visibility(row.Flags);
1421
32.5k
    uint32_t stat = (row.Flags & METHOD_ATTR_STATIC) != 0;
1422
32.5k
    uint32_t final = (row.Flags & METHOD_ATTR_FINAL) != 0;
1423
32.5k
    uint32_t virtual = (row.Flags & METHOD_ATTR_VIRTUAL) != 0;
1424
32.5k
    uint32_t abstract = (row.Flags & METHOD_ATTR_ABSTRACT) != 0;
1425
1426
32.5k
    YR_OBJECT* out_obj = ctx->pe->object;
1427
32.5k
    yr_set_string(
1428
32.5k
        name, out_obj, "classes[%i].methods[%i].name", class_idx, out_idx);
1429
32.5k
    yr_set_string(
1430
32.5k
        visibility,
1431
32.5k
        out_obj,
1432
32.5k
        "classes[%i].methods[%i].visibility",
1433
32.5k
        class_idx,
1434
32.5k
        out_idx);
1435
32.5k
    yr_set_integer(
1436
32.5k
        stat, out_obj, "classes[%i].methods[%i].static", class_idx, out_idx);
1437
32.5k
    yr_set_integer(
1438
32.5k
        virtual,
1439
32.5k
        out_obj,
1440
32.5k
        "classes[%i].methods[%i].virtual",
1441
32.5k
        class_idx,
1442
32.5k
        out_idx);
1443
32.5k
    yr_set_integer(
1444
32.5k
        final, out_obj, "classes[%i].methods[%i].final", class_idx, out_idx);
1445
32.5k
    yr_set_integer(
1446
32.5k
        abstract,
1447
32.5k
        out_obj,
1448
32.5k
        "classes[%i].methods[%i].abstract",
1449
32.5k
        class_idx,
1450
32.5k
        out_idx);
1451
32.5k
    yr_set_integer(
1452
32.5k
        method_gen_params.len,
1453
32.5k
        out_obj,
1454
32.5k
        "classes[%i].methods[%i].number_of_generic_parameters",
1455
32.5k
        class_idx,
1456
32.5k
        out_idx);
1457
1458
33.8k
    for (uint32_t i = 0; i < method_gen_params.len; ++i)
1459
1.39k
    {
1460
1.39k
      yr_set_string(
1461
1.39k
          method_gen_params.names[i],
1462
1.39k
          ctx->pe->object,
1463
1.39k
          "classes[%i].methods[%i].generic_parameters[%i]",
1464
1.39k
          class_idx,
1465
1.39k
          out_idx,
1466
1.39k
          i);
1467
1.39k
    }
1468
1469
    // Unset return type for constructors for FileInfo compatibility
1470
32.5k
    if (strcmp(name, ".ctor") != 0 && strcmp(name, ".cctor") != 0)
1471
31.4k
    {
1472
31.4k
      yr_set_string(
1473
31.4k
          return_type,
1474
31.4k
          out_obj,
1475
31.4k
          "classes[%i].methods[%i].return_type",
1476
31.4k
          class_idx,
1477
31.4k
          out_idx);
1478
31.4k
    }
1479
1480
32.5k
    out_idx++;
1481
1.01M
  clean_next:
1482
1.01M
    yr_free(return_type);
1483
1.01M
    yr_free(method_gen_params.names);
1484
1.01M
  }
1485
1486
102k
  yr_set_integer(
1487
102k
      out_idx, ctx->pe->object, "classes[%i].number_of_methods", class_idx);
1488
102k
}
1489
1490
// Walks NestedClass table, returns enclosing type fullname or NULL
1491
static char* parse_enclosing_types(
1492
    const CLASS_CONTEXT* ctx,
1493
    uint32_t nested_idx,
1494
    uint32_t depth)
1495
128k
{
1496
128k
  if (depth > MAX_NAMESPACE_DEPTH)
1497
494
    return NULL;
1498
1499
127k
  const uint8_t* str_heap = ctx->str_heap;
1500
127k
  uint32_t str_size = ctx->str_size;
1501
1502
17.1M
  for (uint32_t idx = 0; idx < ctx->tables->nestedclass.RowCount; ++idx)
1503
17.0M
  {
1504
17.0M
    const uint8_t* nested_data = get_table_offset(
1505
17.0M
        &ctx->tables->nestedclass, idx + 1);
1506
1507
17.0M
    NESTEDCLASS_ROW nested_row = {0};
1508
17.0M
    bool read_result = read_nestedclass(ctx, nested_data, &nested_row);
1509
17.0M
    if (!read_result)
1510
9.94M
      continue;
1511
1512
    // We found enclosing class, get the namespace
1513
7.12M
    if (nested_row.NestedClass == nested_idx)
1514
7.97k
    {
1515
7.97k
      const uint8_t* typedef_data = get_table_offset(
1516
7.97k
          &ctx->tables->typedef_, nested_row.EnclosingClass);
1517
1518
7.97k
      TYPEDEF_ROW typedef_row = {0};
1519
7.97k
      bool result = read_typedef(ctx, typedef_data, &typedef_row);
1520
7.97k
      if (!result)
1521
1.50k
        break;
1522
1523
6.47k
      const char* name = pe_get_dotnet_string(
1524
6.47k
          ctx->pe, str_heap, str_size, typedef_row.Name);
1525
1526
      // Skip the Module pseudo class
1527
6.47k
      if (name && strcmp(name, "<Module>") == 0)
1528
209
        break;
1529
1530
6.26k
      const char* namespace = pe_get_dotnet_string(
1531
6.26k
          ctx->pe, str_heap, str_size, typedef_row.Namespace);
1532
1533
      // Type might be further nested, try to find correct namespace,
1534
      // check for self-reference
1535
6.26k
      if (is_nested(typedef_row.Flags) &&
1536
6.26k
          nested_row.EnclosingClass != nested_row.NestedClass)
1537
5.59k
      {
1538
5.59k
        char* nested_namespace = parse_enclosing_types(
1539
5.59k
            ctx, nested_row.EnclosingClass, depth + 1);
1540
1541
5.59k
        char* tmp = create_full_name(namespace, nested_namespace);
1542
5.59k
        char* fullname = create_full_name(name, tmp);
1543
5.59k
        yr_free(nested_namespace);
1544
5.59k
        yr_free(tmp);
1545
5.59k
        return fullname;
1546
5.59k
      }
1547
1548
672
      return create_full_name(name, namespace);
1549
6.26k
    }
1550
7.12M
  }
1551
1552
121k
  return NULL;
1553
127k
}
1554
1555
// Parses and reconstructs user defined types with their methods and base types
1556
static void parse_user_types(const CLASS_CONTEXT* ctx)
1557
3.14k
{
1558
3.14k
  const uint8_t* str_heap = ctx->str_heap;
1559
3.14k
  uint32_t str_size = ctx->str_size;
1560
1561
  // Index for output tracking, we can't use
1562
  // offset as some classes can get skipped
1563
3.14k
  uint32_t out_idx = 0;
1564
  // skip first class as it's module pseudo class -> start at index 1
1565
1.12M
  for (uint32_t idx = 0; idx < ctx->tables->typedef_.RowCount; ++idx)
1566
1.11M
  {
1567
1.11M
    YR_OBJECT* out_obj = ctx->pe->object;
1568
    // Tables indexing starts at 1
1569
1.11M
    const uint8_t* data = get_table_offset(&ctx->tables->typedef_, idx + 1);
1570
1571
1.11M
    TYPEDEF_ROW row = {0};
1572
1.11M
    bool result = read_typedef(ctx, data, &row);
1573
1.11M
    if (!result)
1574
823k
      continue;
1575
1576
293k
    const char* name = pe_get_dotnet_string(
1577
293k
        ctx->pe, str_heap, str_size, row.Name);
1578
293k
    const char* type = get_typedef_type(row.Flags);
1579
1580
    // Ignore invalid types and invalid (empty) names
1581
293k
    if (!name || !*name || !type)
1582
139k
      continue;
1583
1584
    // If the type is generic, it will include ` at the end of a name
1585
    // with number of generic arguments, just use the part before that
1586
154k
    const char* end = strchr(name, '`');
1587
    // If the name will turn out empty, skip it and skip Module pseudo class
1588
154k
    if (end == name || strcmp(name, "<Module>") == 0)
1589
838
      continue;
1590
1591
153k
    if (end)
1592
27.5k
      yr_set_sized_string(
1593
153k
          name, end - name, out_obj, "classes[%i].name", out_idx);
1594
125k
    else
1595
153k
      yr_set_string(name, out_obj, "classes[%i].name", out_idx);
1596
1597
153k
    char* fullname = NULL;
1598
153k
    char* namespace = pe_get_dotnet_string(
1599
153k
        ctx->pe, str_heap, str_size, row.Namespace);
1600
1601
    // Type might be nested, if so -> find correct namespace
1602
153k
    if (is_nested(row.Flags))
1603
57.5k
    {
1604
57.5k
      char* nested_namespace = parse_enclosing_types(ctx, idx + 1, 1);
1605
57.5k
      namespace = create_full_name(namespace, nested_namespace);
1606
57.5k
      yr_set_string(namespace, out_obj, "classes[%i].namespace", out_idx);
1607
57.5k
      fullname = create_full_name(name, namespace);
1608
57.5k
      yr_free(nested_namespace);
1609
57.5k
      yr_free(namespace);
1610
57.5k
    }
1611
95.9k
    else
1612
95.9k
    {
1613
95.9k
      yr_set_string(namespace, out_obj, "classes[%i].namespace", out_idx);
1614
95.9k
      fullname = create_full_name(name, namespace);
1615
95.9k
    }
1616
1617
153k
    const char* visibility = get_type_visibility(row.Flags);
1618
153k
    uint32_t abstract = (row.Flags & TYPE_ATTR_ABSTRACT) != 0;
1619
153k
    uint32_t sealed = (row.Flags & TYPE_ATTR_SEALED) != 0;
1620
1621
153k
    yr_set_string(fullname, out_obj, "classes[%i].fullname", out_idx);
1622
153k
    yr_set_string(visibility, out_obj, "classes[%i].visibility", out_idx);
1623
153k
    yr_set_string(type, out_obj, "classes[%i].type", out_idx);
1624
153k
    yr_set_integer(abstract, out_obj, "classes[%i].abstract", out_idx);
1625
153k
    yr_set_integer(sealed, out_obj, "classes[%i].sealed", out_idx);
1626
1627
153k
    yr_free(fullname);
1628
1629
    // Find if type has any Generic parameters
1630
153k
    GENERIC_PARAMETERS gen_params = {0};
1631
153k
    parse_generic_params(ctx, false, idx + 1, &gen_params);
1632
1633
153k
    yr_set_integer(
1634
153k
        gen_params.len,
1635
153k
        out_obj,
1636
153k
        "classes[%i].number_of_generic_parameters",
1637
153k
        out_idx);
1638
1639
154k
    for (uint32_t i = 0; i < gen_params.len; ++i)
1640
1.00k
    {
1641
1.00k
      yr_set_string(
1642
1.00k
          gen_params.names[i],
1643
1.00k
          out_obj,
1644
1.00k
          "classes[%i].generic_parameters[%i]",
1645
1.00k
          out_idx,
1646
1.00k
          i);
1647
1.00k
    }
1648
    // Find type and interfaces the type inherits
1649
153k
    parse_type_parents(ctx, row.Extends, idx + 1, out_idx, &gen_params);
1650
1651
    // To get the number of methods, we must peek where the MethodList
1652
    // of the next type is, then there is next.MethodList - this.MethodList
1653
    // number of methods, or if there is no following type,
1654
    // the rest of the MethodDef table is used
1655
153k
    uint32_t method_count = 0;
1656
    // If there is next method
1657
153k
    if (idx + 1 < ctx->tables->typedef_.RowCount)
1658
151k
    {
1659
151k
      const uint8_t* data = get_table_offset(&ctx->tables->typedef_, idx + 2);
1660
1661
151k
      TYPEDEF_ROW next_row = {0};
1662
151k
      result = read_typedef(ctx, data, &next_row);
1663
1664
      // overflow check
1665
151k
      if (result && next_row.Method >= row.Method)
1666
99.3k
        method_count = next_row.Method - row.Method;
1667
151k
    }
1668
    // overflow check - use the rest of the methods in the table
1669
1.79k
    else if (ctx->tables->methoddef.RowCount >= row.Method)
1670
1.29k
    {
1671
1.29k
      method_count = ctx->tables->methoddef.RowCount + 1 - row.Method;
1672
1.29k
    }
1673
1674
    // Sanity check for corrupted files
1675
153k
    if (method_count <= MAX_METHOD_COUNT)
1676
131k
      parse_methods(ctx, row.Method, method_count, out_idx, &gen_params);
1677
1678
153k
    yr_free(gen_params.names);
1679
153k
    out_idx++;
1680
153k
  }
1681
1682
3.14k
  yr_set_integer(out_idx, ctx->pe->object, "number_of_classes");
1683
3.14k
}
1684
1685
void dotnet_parse_guid(
1686
    PE* pe,
1687
    int64_t metadata_root,
1688
    PSTREAM_HEADER guid_header)
1689
483
{
1690
  // GUIDs are 16 bytes each, converted to hex format plus separators and NULL.
1691
483
  char guid[37];
1692
483
  int i = 0;
1693
1694
483
  const uint8_t* guid_offset = pe->data + metadata_root +
1695
483
                               yr_le32toh(guid_header->Offset);
1696
1697
483
  DWORD guid_size = yr_le32toh(guid_header->Size);
1698
1699
  // Limit the number of GUIDs to 16.
1700
483
  guid_size = yr_min(guid_size, 256);
1701
1702
  // Parse GUIDs if we have them. GUIDs are 16 bytes each.
1703
1.92k
  while (guid_size >= 16 && fits_in_pe(pe, guid_offset, 16))
1704
1.44k
  {
1705
1.44k
    sprintf(
1706
1.44k
        guid,
1707
1.44k
        "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1708
1.44k
        yr_le32toh(*(uint32_t*) guid_offset),
1709
1.44k
        yr_le16toh(*(uint16_t*) (guid_offset + 4)),
1710
1.44k
        yr_le16toh(*(uint16_t*) (guid_offset + 6)),
1711
1.44k
        *(guid_offset + 8),
1712
1.44k
        *(guid_offset + 9),
1713
1.44k
        *(guid_offset + 10),
1714
1.44k
        *(guid_offset + 11),
1715
1.44k
        *(guid_offset + 12),
1716
1.44k
        *(guid_offset + 13),
1717
1.44k
        *(guid_offset + 14),
1718
1.44k
        *(guid_offset + 15));
1719
1720
1.44k
    guid[(16 * 2) + 4] = '\0';
1721
1722
1.44k
    yr_set_string(guid, pe->object, "guids[%i]", i);
1723
1724
1.44k
    i++;
1725
1.44k
    guid_size -= 16;
1726
1.44k
    guid_offset += 16;
1727
1.44k
  }
1728
1729
483
  yr_set_integer(i, pe->object, "number_of_guids");
1730
483
}
1731
1732
void dotnet_parse_us(PE* pe, int64_t metadata_root, PSTREAM_HEADER us_header)
1733
711
{
1734
711
  BLOB_PARSE_RESULT blob_result;
1735
711
  int i = 0;
1736
1737
711
  const uint32_t ush_sz = yr_le32toh(us_header->Size);
1738
1739
711
  const uint8_t* offset = pe->data + metadata_root +
1740
711
                          yr_le32toh(us_header->Offset);
1741
711
  const uint8_t* end_of_header = offset + ush_sz;
1742
1743
  // Make sure the header size is larger than 0 and its end is not past the
1744
  // end of PE.
1745
711
  if (ush_sz == 0 || !fits_in_pe(pe, offset, ush_sz))
1746
223
    return;
1747
1748
  // The first entry MUST be single NULL byte.
1749
488
  if (*offset != 0x00)
1750
178
    return;
1751
1752
310
  offset++;
1753
1754
6.98k
  while (offset < end_of_header)
1755
6.79k
  {
1756
6.79k
    blob_result = dotnet_parse_blob_entry(pe, offset);
1757
1758
6.79k
    if (blob_result.size == 0)
1759
121
      break;
1760
1761
6.67k
    offset += blob_result.size;
1762
    // There is an additional terminal byte which is 0x01 under certain
1763
    // conditions - when any top bit in utf16 top byte is set.
1764
    // The exact conditions are not relevant to our parsing but are
1765
    // documented in ECMA-335 II.24.2.4.
1766
6.67k
    if (blob_result.length > 0)
1767
2.27k
      blob_result.length--;
1768
1769
    // Avoid empty strings, which usually happen as padding at the end of the
1770
    // stream.
1771
6.67k
    if (blob_result.length > 0 && fits_in_pe(pe, offset, blob_result.length))
1772
1.82k
    {
1773
1.82k
      yr_set_sized_string(
1774
1.82k
          (char*) offset,
1775
1.82k
          blob_result.length,
1776
1.82k
          pe->object,
1777
1.82k
          "user_strings[%i]",
1778
1.82k
          i);
1779
1780
1.82k
      offset += blob_result.length;
1781
1.82k
      i++;
1782
1.82k
    }
1783
6.67k
  }
1784
1785
310
  yr_set_integer(i, pe->object, "number_of_user_strings");
1786
310
}
1787
1788
STREAMS dotnet_parse_stream_headers(
1789
    PE* pe,
1790
    int64_t offset,
1791
    int64_t metadata_root,
1792
    DWORD num_streams)
1793
5.46k
{
1794
5.46k
  PSTREAM_HEADER stream_header;
1795
5.46k
  STREAMS headers;
1796
1797
5.46k
  char* start;
1798
5.46k
  char* eos;
1799
5.46k
  char stream_name[DOTNET_STREAM_NAME_SIZE + 1];
1800
5.46k
  unsigned int i;
1801
1802
5.46k
  memset(&headers, '\0', sizeof(STREAMS));
1803
5.46k
  headers.metadata_root = metadata_root;
1804
1805
5.46k
  stream_header = (PSTREAM_HEADER) (pe->data + offset);
1806
1807
81.0k
  for (i = 0; i < num_streams; i++)
1808
80.4k
  {
1809
80.4k
    if (!struct_fits_in_pe(pe, stream_header, STREAM_HEADER))
1810
13
      break;
1811
1812
80.3k
    start = (char*) stream_header->Name;
1813
1814
80.3k
    if (!fits_in_pe(pe, start, DOTNET_STREAM_NAME_SIZE))
1815
3.84k
      break;
1816
1817
76.5k
    eos = (char*) memmem((void*) start, DOTNET_STREAM_NAME_SIZE, "\0", 1);
1818
1819
76.5k
    if (eos == NULL)
1820
1.01k
      break;
1821
1822
75.5k
    strncpy(stream_name, stream_header->Name, DOTNET_STREAM_NAME_SIZE);
1823
75.5k
    stream_name[DOTNET_STREAM_NAME_SIZE] = '\0';
1824
1825
75.5k
    yr_set_string(stream_name, pe->object, "streams[%i].name", i);
1826
1827
    // Offset is relative to metadata_root.
1828
75.5k
    yr_set_integer(
1829
75.5k
        metadata_root + yr_le32toh(stream_header->Offset),
1830
75.5k
        pe->object,
1831
75.5k
        "streams[%i].offset",
1832
75.5k
        i);
1833
1834
75.5k
    yr_set_integer(
1835
75.5k
        yr_le32toh(stream_header->Size), pe->object, "streams[%i].size", i);
1836
1837
    // Store necessary bits to parse these later. Not all tables will be
1838
    // parsed, but are referenced from others. For example, the #Strings
1839
    // stream is referenced from various tables in the #~ heap.
1840
    //
1841
    // #- is not documented but it represents unoptimized metadata stream. It
1842
    // may contain additional tables such as FieldPtr, ParamPtr, MethodPtr or
1843
    // PropertyPtr for indirect referencing. We already take into account these
1844
    // tables and they do not interfere with anything we parse in this module.
1845
1846
75.5k
    if ((strncmp(stream_name, "#~", 2) == 0 ||
1847
75.5k
         strncmp(stream_name, "#-", 2) == 0) &&
1848
75.5k
        headers.tilde == NULL)
1849
5.29k
      headers.tilde = stream_header;
1850
70.2k
    else if (strncmp(stream_name, "#GUID", 5) == 0)
1851
556
      headers.guid = stream_header;
1852
69.6k
    else if (strncmp(stream_name, "#Strings", 8) == 0 && headers.string == NULL)
1853
5.21k
      headers.string = stream_header;
1854
64.4k
    else if (strncmp(stream_name, "#Blob", 5) == 0 && headers.blob == NULL)
1855
5.22k
      headers.blob = stream_header;
1856
59.2k
    else if (strncmp(stream_name, "#US", 3) == 0 && headers.us == NULL)
1857
711
      headers.us = stream_header;
1858
1859
    // Stream name is padded to a multiple of 4.
1860
75.5k
    stream_header = (PSTREAM_HEADER) ((uint8_t*) stream_header +
1861
75.5k
                                      sizeof(STREAM_HEADER) +
1862
75.5k
                                      strlen(stream_name) + 4 -
1863
75.5k
                                      (strlen(stream_name) % 4));
1864
75.5k
  }
1865
1866
5.46k
  yr_set_integer(i, pe->object, "number_of_streams");
1867
1868
5.46k
  return headers;
1869
5.46k
}
1870
1871
// This is the second pass through the data for #~. The first pass collects
1872
// information on the number of rows for tables which have coded indexes.
1873
// This pass uses that information and the index_sizes to parse the tables
1874
// of interest.
1875
//
1876
// Because the indexes can vary in size depending upon the number of rows in
1877
// other tables it is impossible to use static sized structures. To deal with
1878
// this hardcode the sizes of each table based upon the documentation (for the
1879
// static sized portions) and use the variable sizes accordingly.
1880
1881
void dotnet_parse_tilde_2(
1882
    PE* pe,
1883
    PTILDE_HEADER tilde_header,
1884
    int64_t resource_base,
1885
    ROWS rows,
1886
    INDEX_SIZES index_sizes,
1887
    PSTREAMS streams)
1888
5.16k
{
1889
5.16k
  PMODULE_TABLE module_table;
1890
5.16k
  PASSEMBLY_TABLE assembly_table;
1891
5.16k
  PASSEMBLYREF_TABLE assemblyref_table;
1892
5.16k
  PFIELDRVA_TABLE fieldrva_table;
1893
5.16k
  PMANIFESTRESOURCE_TABLE manifestresource_table;
1894
5.16k
  PMODULEREF_TABLE moduleref_table;
1895
5.16k
  PCUSTOMATTRIBUTE_TABLE customattribute_table;
1896
5.16k
  PCONSTANT_TABLE constant_table;
1897
5.16k
  DWORD resource_size, implementation;
1898
1899
  // To save important data for future processing, initialize everything to 0
1900
5.16k
  TABLES tables = {0};
1901
1902
5.16k
  char* name;
1903
5.16k
  char typelib[MAX_TYPELIB_SIZE + 1];
1904
5.16k
  unsigned int i;
1905
5.16k
  int bit_check;
1906
5.16k
  int matched_bits = 0;
1907
1908
5.16k
  int64_t metadata_root = streams->metadata_root;
1909
5.16k
  int64_t resource_offset, field_offset;
1910
5.16k
  uint32_t row_size, row_count, counter, str_heap_size;
1911
1912
5.16k
  const uint8_t* string_offset;
1913
5.16k
  const uint8_t* blob_offset;
1914
1915
5.16k
  uint32_t num_rows = 0;
1916
5.16k
  uint32_t valid_rows = 0;
1917
5.16k
  uint32_t* row_offset = NULL;
1918
5.16k
  uint8_t* table_offset = NULL;
1919
5.16k
  uint8_t* row_ptr = NULL;
1920
1921
  // These are pointers and row sizes for tables of interest to us for special
1922
  // parsing. For example, we are interested in pulling out any CustomAttributes
1923
  // that are GUIDs so we need to be able to walk these tables. To find GUID
1924
  // CustomAttributes you need to walk the CustomAttribute table and look for
1925
  // any row with a Parent that indexes into the Assembly table and Type indexes
1926
  // into the MemberRef table. Then you follow the index into the MemberRef
1927
  // table and check the Class to make sure it indexes into TypeRef table. If it
1928
  // does you follow that index and make sure the Name is "GuidAttribute". If
1929
  // all that is valid then you can take the Value from the CustomAttribute
1930
  // table to find out the index into the Blob stream and parse that.
1931
  //
1932
  // Luckily we can abuse the fact that the order of the tables is guaranteed
1933
  // consistent (though some may not exist, but if they do exist they must exist
1934
  // in a certain order). The order is defined by their position in the Valid
1935
  // member of the tilde_header structure. By the time we are parsing the
1936
  // CustomAttribute table we have already recorded the location of the TypeRef
1937
  // and MemberRef tables, so we can follow the chain back up from
1938
  // CustomAttribute through MemberRef to TypeRef.
1939
1940
5.16k
  uint8_t* typeref_ptr = NULL;
1941
5.16k
  uint8_t* memberref_ptr = NULL;
1942
5.16k
  uint32_t typeref_row_size = 0;
1943
5.16k
  uint32_t memberref_row_size = 0;
1944
5.16k
  uint8_t* typeref_row = NULL;
1945
5.16k
  uint8_t* memberref_row = NULL;
1946
1947
5.16k
  DWORD type_index;
1948
5.16k
  DWORD class_index;
1949
5.16k
  BLOB_PARSE_RESULT blob_result;
1950
5.16k
  DWORD blob_index;
1951
5.16k
  DWORD blob_length;
1952
1953
  // These are used to determine the size of coded indexes, which are the
1954
  // dynamically sized columns for some tables. The coded indexes are
1955
  // documented in ECMA-335 Section II.24.2.6.
1956
5.16k
  uint8_t index_size, index_size2;
1957
1958
  // Number of rows is the number of bits set to 1 in Valid.
1959
  // Should use this technique:
1960
  // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
1961
  // Count number of Rows size entries in header to skip over them
1962
335k
  for (i = 0; i < 64; i++)
1963
330k
    valid_rows += ((yr_le64toh(tilde_header->Valid) >> i) & 0x01);
1964
1965
5.16k
  row_offset = (uint32_t*) (tilde_header + 1);
1966
5.16k
  table_offset = (uint8_t*) row_offset;
1967
5.16k
  table_offset += sizeof(uint32_t) * valid_rows;
1968
1969
  // Sometimes files have some sort of padding after, from DnSpy source
1970
  // it's denoted by EXTRA_DATA 0x40 flag in heapflags
1971
  // We then need to offset by 4 bytes, otherwise the analysis is wrong
1972
  // https://github.com/dnSpy/dnSpy/blob/2b6dcfaf602fb8ca6462b8b6237fdfc0c74ad994/dnSpy/dnSpy/Hex/Files/DotNet/TablesHeaderDataImpl.cs
1973
  // example: 1c2246af11000c3ce6b05ed6ba25060cbb00273c599428b98cf4013bdd82892f
1974
5.16k
  if (tilde_header->HeapSizes & HEAP_EXTRA_DATA)
1975
1.75k
    table_offset += 4;
1976
1977
5.16k
#define DOTNET_STRING_INDEX(Name)                       \
1978
65.7k
  index_sizes.string == 2 ? yr_le16toh(Name.Name_Short) \
1979
65.7k
                          : yr_le32toh(Name.Name_Long)
1980
1981
5.16k
  string_offset = pe->data + metadata_root +
1982
5.16k
                  yr_le32toh(streams->string->Offset);
1983
1984
5.16k
  str_heap_size = yr_le32toh(streams->string->Size);
1985
1986
  // Now walk again this time parsing out what we care about.
1987
244k
  for (bit_check = 0; bit_check < 64; bit_check++)
1988
241k
  {
1989
    // If the Valid bit is not set for this table, skip it...
1990
241k
    if (!((yr_le64toh(tilde_header->Valid) >> bit_check) & 0x01))
1991
219k
      continue;
1992
1993
21.7k
    if (!fits_in_pe(pe, row_offset + matched_bits, sizeof(uint32_t)))
1994
24
      return;
1995
1996
21.7k
    num_rows = yr_le32toh(*(row_offset + matched_bits));
1997
1998
    // Make sure that num_rows has a reasonable value. For example
1999
    // edc05e49dd3810be67942b983455fd43 sets a large value for number of
2000
    // rows for the BIT_MODULE section.
2001
21.7k
    if (num_rows > 10000)
2002
1.97k
      return;
2003
2004
    // Those tables which exist, but that we don't care about must be
2005
    // skipped.
2006
    //
2007
    // Sadly, given the dynamic sizes of some columns we can not have well
2008
    // defined structures for all tables and use them accordingly. To deal
2009
    // with this manually move the table_offset pointer by the appropriate
2010
    // number of bytes as described in the documentation for each table.
2011
    //
2012
    // The table structures are documented in ECMA-335 Section II.22.
2013
2014
19.7k
    switch (bit_check)
2015
19.7k
    {
2016
916
    case BIT_MODULE:
2017
916
      module_table = (PMODULE_TABLE) table_offset;
2018
2019
916
      if (!struct_fits_in_pe(pe, module_table, MODULE_TABLE))
2020
99
        break;
2021
2022
817
      name = pe_get_dotnet_string(
2023
817
          pe,
2024
817
          string_offset,
2025
817
          str_heap_size,
2026
817
          DOTNET_STRING_INDEX(module_table->Name));
2027
2028
817
      if (name != NULL)
2029
817
        yr_set_string(name, pe->object, "module_name");
2030
2031
817
      row_size = 2 + index_sizes.string + (index_sizes.guid * 3);
2032
2033
817
      tables.module.Offset = table_offset;
2034
817
      tables.module.RowCount = num_rows;
2035
817
      tables.module.RowSize = row_size;
2036
2037
817
      table_offset += row_size * num_rows;
2038
817
      break;
2039
2040
1.48k
    case BIT_TYPEREF:
2041
1.48k
      row_count = max_rows(
2042
1.48k
          4,
2043
1.48k
          yr_le32toh(rows.module),
2044
1.48k
          yr_le32toh(rows.moduleref),
2045
1.48k
          yr_le32toh(rows.assemblyref),
2046
1.48k
          yr_le32toh(rows.typeref));
2047
2048
1.48k
      if (row_count > (0xFFFF >> 0x02))
2049
218
        index_size = 4;
2050
1.27k
      else
2051
1.27k
        index_size = 2;
2052
2053
1.48k
      row_size = (index_size + (index_sizes.string * 2));
2054
1.48k
      typeref_row_size = row_size;
2055
1.48k
      typeref_ptr = table_offset;
2056
2057
1.48k
      tables.typeref.Offset = table_offset;
2058
1.48k
      tables.typeref.RowCount = num_rows;
2059
1.48k
      tables.typeref.RowSize = row_size;
2060
2061
1.48k
      table_offset += row_size * num_rows;
2062
1.48k
      break;
2063
2064
3.41k
    case BIT_TYPEDEF:
2065
3.41k
      row_count = max_rows(
2066
3.41k
          3,
2067
3.41k
          yr_le32toh(rows.typedef_),
2068
3.41k
          yr_le32toh(rows.typeref),
2069
3.41k
          yr_le32toh(rows.typespec));
2070
2071
3.41k
      if (row_count > (0xFFFF >> 0x02))
2072
87
        index_size = 4;
2073
3.33k
      else
2074
3.33k
        index_size = 2;
2075
2076
3.41k
      row_size = 4 + (index_sizes.string * 2) + index_size + index_sizes.field +
2077
3.41k
                 index_sizes.methoddef;
2078
2079
3.41k
      tables.typedef_.Offset = table_offset;
2080
3.41k
      tables.typedef_.RowCount = num_rows;
2081
3.41k
      tables.typedef_.RowSize = row_size;
2082
2083
3.41k
      table_offset += row_size * num_rows;
2084
3.41k
      break;
2085
2086
503
    case BIT_FIELDPTR:
2087
      // This one is not documented in ECMA-335.
2088
503
      table_offset += (index_sizes.field) * num_rows;
2089
503
      break;
2090
2091
786
    case BIT_FIELD:
2092
786
      table_offset += (2 + (index_sizes.string) + index_sizes.blob) * num_rows;
2093
786
      break;
2094
2095
308
    case BIT_METHODDEFPTR:
2096
      // This one is not documented in ECMA-335.
2097
308
      table_offset += (index_sizes.methoddef) * num_rows;
2098
308
      break;
2099
2100
2.16k
    case BIT_METHODDEF:
2101
2.16k
      row_size = 4 + 2 + 2 + index_sizes.string + index_sizes.blob +
2102
2.16k
                 index_sizes.param;
2103
2104
2.16k
      tables.methoddef.Offset = table_offset;
2105
2.16k
      tables.methoddef.RowCount = num_rows;
2106
2.16k
      tables.methoddef.RowSize = row_size;
2107
2.16k
      table_offset += row_size * num_rows;
2108
2.16k
      break;
2109
2110
945
    case BIT_PARAM:
2111
945
      row_size = 2 + 2 + index_sizes.string;
2112
2113
945
      tables.param.Offset = table_offset;
2114
945
      tables.param.RowCount = num_rows;
2115
945
      tables.param.RowSize = row_size;
2116
2117
945
      table_offset += row_size * num_rows;
2118
945
      break;
2119
2120
817
    case BIT_INTERFACEIMPL:
2121
817
      row_count = max_rows(
2122
817
          3,
2123
817
          yr_le32toh(rows.typedef_),
2124
817
          yr_le32toh(rows.typeref),
2125
817
          yr_le32toh(rows.typespec));
2126
2127
817
      if (row_count > (0xFFFF >> 0x02))
2128
59
        index_size = 4;
2129
758
      else
2130
758
        index_size = 2;
2131
2132
817
      row_size = index_sizes.typedef_ + index_size;
2133
2134
817
      tables.intefaceimpl.Offset = table_offset;
2135
817
      tables.intefaceimpl.RowCount = num_rows;
2136
817
      tables.intefaceimpl.RowSize = row_size;
2137
2138
817
      table_offset += row_size * num_rows;
2139
817
      break;
2140
2141
1.00k
    case BIT_MEMBERREF:
2142
1.00k
      row_count = max_rows(
2143
1.00k
          4,
2144
1.00k
          yr_le32toh(rows.methoddef),
2145
1.00k
          yr_le32toh(rows.moduleref),
2146
1.00k
          yr_le32toh(rows.typeref),
2147
1.00k
          yr_le32toh(rows.typespec));
2148
2149
1.00k
      if (row_count > (0xFFFF >> 0x03))
2150
154
        index_size = 4;
2151
848
      else
2152
848
        index_size = 2;
2153
2154
1.00k
      row_size = (index_size + index_sizes.string + index_sizes.blob);
2155
1.00k
      memberref_row_size = row_size;
2156
1.00k
      memberref_ptr = table_offset;
2157
1.00k
      table_offset += row_size * num_rows;
2158
1.00k
      break;
2159
2160
537
    case BIT_CONSTANT:
2161
537
      row_count = max_rows(
2162
537
          3,
2163
537
          yr_le32toh(rows.param),
2164
537
          yr_le32toh(rows.field),
2165
537
          yr_le32toh(rows.property));
2166
2167
537
      if (row_count > (0xFFFF >> 0x02))
2168
105
        index_size = 4;
2169
432
      else
2170
432
        index_size = 2;
2171
2172
      // Using 'i' is insufficent since we may skip certain constants and
2173
      // it would give an inaccurate count in that case.
2174
537
      counter = 0;
2175
537
      row_size = (1 + 1 + index_size + index_sizes.blob);
2176
537
      row_ptr = table_offset;
2177
2178
129k
      for (i = 0; i < num_rows; i++)
2179
128k
      {
2180
128k
        if (!fits_in_pe(pe, row_ptr, row_size))
2181
263
          break;
2182
2183
128k
        constant_table = (PCONSTANT_TABLE) row_ptr;
2184
2185
        // Only look for constants of type string.
2186
128k
        if (yr_le32toh(constant_table->Type) != TYPE_STRING)
2187
124k
        {
2188
124k
          row_ptr += row_size;
2189
124k
          continue;
2190
124k
        }
2191
2192
        // Get the blob offset and pull it out of the blob table.
2193
4.15k
        blob_offset = ((uint8_t*) constant_table) + 2 + index_size;
2194
2195
4.15k
        if (index_sizes.blob == 4)
2196
493
          blob_index = *(DWORD*) blob_offset;
2197
3.66k
        else
2198
          // Cast the value (index into blob table) to a 32bit value.
2199
3.66k
          blob_index = (DWORD) (*(WORD*) blob_offset);
2200
2201
        // Everything checks out. Make sure the index into the blob field
2202
        // is valid (non-null and within range).
2203
4.15k
        blob_offset = pe->data + metadata_root +
2204
4.15k
                      yr_le32toh(streams->blob->Offset) + blob_index;
2205
2206
4.15k
        blob_result = dotnet_parse_blob_entry(pe, blob_offset);
2207
2208
4.15k
        if (blob_result.size == 0)
2209
2.08k
        {
2210
2.08k
          row_ptr += row_size;
2211
2.08k
          continue;
2212
2.08k
        }
2213
2214
2.07k
        blob_length = blob_result.length;
2215
2.07k
        blob_offset += blob_result.size;
2216
2217
        // Quick sanity check to make sure the blob entry is within bounds.
2218
2.07k
        if (blob_offset + blob_length >= pe->data + pe->data_size)
2219
200
        {
2220
200
          row_ptr += row_size;
2221
200
          continue;
2222
200
        }
2223
2224
1.87k
        yr_set_sized_string(
2225
1.87k
            (char*) blob_offset,
2226
1.87k
            blob_result.length,
2227
1.87k
            pe->object,
2228
1.87k
            "constants[%i]",
2229
1.87k
            counter);
2230
2231
1.87k
        counter++;
2232
1.87k
        row_ptr += row_size;
2233
1.87k
      }
2234
2235
537
      yr_set_integer(counter, pe->object, "number_of_constants");
2236
537
      table_offset += row_size * num_rows;
2237
537
      break;
2238
2239
991
    case BIT_CUSTOMATTRIBUTE:
2240
      // index_size is size of the parent column.
2241
991
      row_count = max_rows(
2242
991
          21,
2243
991
          yr_le32toh(rows.methoddef),
2244
991
          yr_le32toh(rows.field),
2245
991
          yr_le32toh(rows.typeref),
2246
991
          yr_le32toh(rows.typedef_),
2247
991
          yr_le32toh(rows.param),
2248
991
          yr_le32toh(rows.interfaceimpl),
2249
991
          yr_le32toh(rows.memberref),
2250
991
          yr_le32toh(rows.module),
2251
991
          yr_le32toh(rows.property),
2252
991
          yr_le32toh(rows.event),
2253
991
          yr_le32toh(rows.standalonesig),
2254
991
          yr_le32toh(rows.moduleref),
2255
991
          yr_le32toh(rows.typespec),
2256
991
          yr_le32toh(rows.assembly),
2257
991
          yr_le32toh(rows.assemblyref),
2258
991
          yr_le32toh(rows.file),
2259
991
          yr_le32toh(rows.exportedtype),
2260
991
          yr_le32toh(rows.manifestresource),
2261
991
          yr_le32toh(rows.genericparam),
2262
991
          yr_le32toh(rows.genericparamconstraint),
2263
991
          yr_le32toh(rows.methodspec));
2264
2265
991
      if (row_count > (0xFFFF >> 0x05))
2266
490
        index_size = 4;
2267
501
      else
2268
501
        index_size = 2;
2269
2270
      // index_size2 is size of the type column.
2271
991
      row_count = max_rows(
2272
991
          2, yr_le32toh(rows.methoddef), yr_le32toh(rows.memberref));
2273
2274
991
      if (row_count > (0xFFFF >> 0x03))
2275
94
        index_size2 = 4;
2276
897
      else
2277
897
        index_size2 = 2;
2278
2279
991
      row_size = (index_size + index_size2 + index_sizes.blob);
2280
2281
991
      if (typeref_ptr != NULL && memberref_ptr != NULL)
2282
681
      {
2283
681
        row_ptr = table_offset;
2284
2285
288k
        for (i = 0; i < num_rows; i++)
2286
288k
        {
2287
288k
          if (!fits_in_pe(pe, row_ptr, row_size))
2288
465
            break;
2289
2290
          // Check the Parent field.
2291
288k
          customattribute_table = (PCUSTOMATTRIBUTE_TABLE) row_ptr;
2292
2293
288k
          if (index_size == 4)
2294
65.5k
          {
2295
            // Low 5 bits tell us what this is an index into. Remaining bits
2296
            // tell us the index value.
2297
            // Parent must be an index into the Assembly (0x0E) table.
2298
65.5k
            if ((*(DWORD*) customattribute_table & 0x1F) != 0x0E)
2299
60.9k
            {
2300
60.9k
              row_ptr += row_size;
2301
60.9k
              continue;
2302
60.9k
            }
2303
65.5k
          }
2304
222k
          else
2305
222k
          {
2306
            // Low 5 bits tell us what this is an index into. Remaining bits
2307
            // tell us the index value.
2308
            // Parent must be an index into the Assembly (0x0E) table.
2309
222k
            if ((*(WORD*) customattribute_table & 0x1F) != 0x0E)
2310
210k
            {
2311
210k
              row_ptr += row_size;
2312
210k
              continue;
2313
210k
            }
2314
222k
          }
2315
2316
          // Check the Type field.
2317
16.8k
          customattribute_table = (PCUSTOMATTRIBUTE_TABLE) (row_ptr +
2318
16.8k
                                                            index_size);
2319
2320
16.8k
          if (index_size2 == 4)
2321
553
          {
2322
            // Low 3 bits tell us what this is an index into. Remaining bits
2323
            // tell us the index value. Only values 2 and 3 are defined.
2324
            // Type must be an index into the MemberRef table.
2325
553
            if ((*(DWORD*) customattribute_table & 0x07) != 0x03)
2326
259
            {
2327
259
              row_ptr += row_size;
2328
259
              continue;
2329
259
            }
2330
2331
294
            type_index = *(DWORD*) customattribute_table >> 3;
2332
294
          }
2333
16.2k
          else
2334
16.2k
          {
2335
            // Low 3 bits tell us what this is an index into. Remaining bits
2336
            // tell us the index value. Only values 2 and 3 are defined.
2337
            // Type must be an index into the MemberRef table.
2338
16.2k
            if ((*(WORD*) customattribute_table & 0x07) != 0x03)
2339
8.61k
            {
2340
8.61k
              row_ptr += row_size;
2341
8.61k
              continue;
2342
8.61k
            }
2343
2344
            // Cast the index to a 32bit value.
2345
7.67k
            type_index = (DWORD) ((*(WORD*) customattribute_table >> 3));
2346
7.67k
          }
2347
2348
7.97k
          if (type_index > 0)
2349
7.11k
            type_index--;
2350
2351
          // Now follow the Type index into the MemberRef table.
2352
7.97k
          memberref_row = memberref_ptr + (memberref_row_size * type_index);
2353
2354
7.97k
          if (!fits_in_pe(pe, memberref_row, memberref_row_size))
2355
79
            break;
2356
2357
7.89k
          if (index_sizes.memberref == 4)
2358
0
          {
2359
            // Low 3 bits tell us what this is an index into. Remaining bits
2360
            // tell us the index value. Class must be an index into the
2361
            // TypeRef table.
2362
0
            if ((*(DWORD*) memberref_row & 0x07) != 0x01)
2363
0
            {
2364
0
              row_ptr += row_size;
2365
0
              continue;
2366
0
            }
2367
2368
0
            class_index = *(DWORD*) memberref_row >> 3;
2369
0
          }
2370
7.89k
          else
2371
7.89k
          {
2372
            // Low 3 bits tell us what this is an index into. Remaining bits
2373
            // tell us the index value. Class must be an index into the
2374
            // TypeRef table.
2375
7.89k
            if ((*(WORD*) memberref_row & 0x07) != 0x01)
2376
1.80k
            {
2377
1.80k
              row_ptr += row_size;
2378
1.80k
              continue;
2379
1.80k
            }
2380
2381
            // Cast the index to a 32bit value.
2382
6.08k
            class_index = (DWORD) (*(WORD*) memberref_row >> 3);
2383
6.08k
          }
2384
2385
6.08k
          if (class_index > 0)
2386
4.48k
            class_index--;
2387
2388
          // Now follow the Class index into the TypeRef table.
2389
6.08k
          typeref_row = typeref_ptr + (typeref_row_size * class_index);
2390
2391
6.08k
          if (!fits_in_pe(pe, typeref_row, typeref_row_size))
2392
8
            break;
2393
2394
          // Skip over the ResolutionScope and check the Name field,
2395
          // which is an index into the Strings heap.
2396
6.07k
          row_count = max_rows(
2397
6.07k
              4,
2398
6.07k
              yr_le32toh(rows.module),
2399
6.07k
              yr_le32toh(rows.moduleref),
2400
6.07k
              yr_le32toh(rows.assemblyref),
2401
6.07k
              yr_le32toh(rows.typeref));
2402
2403
6.07k
          if (row_count > (0xFFFF >> 0x02))
2404
434
            typeref_row += 4;
2405
5.64k
          else
2406
5.64k
            typeref_row += 2;
2407
2408
6.07k
          if (index_sizes.string == 4)
2409
1.53k
          {
2410
1.53k
            name = pe_get_dotnet_string(
2411
1.53k
                pe, string_offset, str_heap_size, *(DWORD*) typeref_row);
2412
1.53k
          }
2413
4.53k
          else
2414
4.53k
          {
2415
4.53k
            name = pe_get_dotnet_string(
2416
4.53k
                pe, string_offset, str_heap_size, *(WORD*) typeref_row);
2417
4.53k
          }
2418
2419
6.07k
          if (name != NULL && strncmp(name, "GuidAttribute", 13) != 0)
2420
667
          {
2421
667
            row_ptr += row_size;
2422
667
            continue;
2423
667
          }
2424
2425
          // Get the Value field.
2426
5.40k
          customattribute_table = (PCUSTOMATTRIBUTE_TABLE) (row_ptr +
2427
5.40k
                                                            index_size +
2428
5.40k
                                                            index_size2);
2429
2430
5.40k
          if (index_sizes.blob == 4)
2431
459
            blob_index = *(DWORD*) customattribute_table;
2432
4.95k
          else
2433
            // Cast the value (index into blob table) to a 32bit value.
2434
4.95k
            blob_index = (DWORD) (*(WORD*) customattribute_table);
2435
2436
          // Everything checks out. Make sure the index into the blob field
2437
          // is valid (non-null and within range).
2438
5.40k
          blob_offset = pe->data + metadata_root +
2439
5.40k
                        yr_le32toh(streams->blob->Offset) + blob_index;
2440
2441
          // If index into blob is 0 or past the end of the blob stream, skip
2442
          // it. We don't know the size of the blob entry yet because that is
2443
          // encoded in the start.
2444
5.40k
          if (blob_index == 0x00 || blob_offset >= pe->data + pe->data_size)
2445
1.58k
          {
2446
1.58k
            row_ptr += row_size;
2447
1.58k
            continue;
2448
1.58k
          }
2449
2450
3.82k
          blob_result = dotnet_parse_blob_entry(pe, blob_offset);
2451
2452
3.82k
          if (blob_result.size == 0)
2453
1.54k
          {
2454
1.54k
            row_ptr += row_size;
2455
1.54k
            continue;
2456
1.54k
          }
2457
2458
2.28k
          blob_length = blob_result.length;
2459
2.28k
          blob_offset += blob_result.size;
2460
2461
          // Quick sanity check to make sure the blob entry is within bounds
2462
          // and its length is at least 3 (2 bytes for the 16 bits prolog and
2463
          // 1 byte for the string length)
2464
2.28k
          if (blob_length < 3 ||
2465
2.28k
              blob_offset + blob_length >= pe->data + pe->data_size)
2466
846
          {
2467
846
            row_ptr += row_size;
2468
846
            continue;
2469
846
          }
2470
2471
          // Custom attributes MUST have a 16 bit prolog of 0x0001
2472
1.44k
          if (*(WORD*) blob_offset != 0x0001)
2473
588
          {
2474
588
            row_ptr += row_size;
2475
588
            continue;
2476
588
          }
2477
2478
          // The next byte after the 16 bit prolog is the length of the string.
2479
853
          blob_offset += 2;
2480
853
          uint8_t str_len = *blob_offset;
2481
2482
          // Increment blob_offset so that it points to the first byte of the
2483
          // string.
2484
853
          blob_offset += 1;
2485
2486
853
          if (blob_offset + str_len > pe->data + pe->data_size)
2487
239
          {
2488
239
            row_ptr += row_size;
2489
239
            continue;
2490
239
          }
2491
2492
614
          if (*blob_offset == 0xFF || *blob_offset == 0x00)
2493
411
          {
2494
411
            typelib[0] = '\0';
2495
411
          }
2496
203
          else
2497
203
          {
2498
203
            strncpy(typelib, (char*) blob_offset, str_len);
2499
203
            typelib[str_len] = '\0';
2500
203
          }
2501
2502
614
          yr_set_string(typelib, pe->object, "typelib");
2503
2504
614
          row_ptr += row_size;
2505
614
        }
2506
681
      }
2507
2508
991
      table_offset += row_size * num_rows;
2509
991
      break;
2510
2511
89
    case BIT_FIELDMARSHAL:
2512
89
      row_count = max_rows(2, yr_le32toh(rows.field), yr_le32toh(rows.param));
2513
2514
89
      if (row_count > (0xFFFF >> 0x01))
2515
0
        index_size = 4;
2516
89
      else
2517
89
        index_size = 2;
2518
2519
89
      table_offset += (index_size + index_sizes.blob) * num_rows;
2520
89
      break;
2521
2522
111
    case BIT_DECLSECURITY:
2523
111
      row_count = max_rows(
2524
111
          3,
2525
111
          yr_le32toh(rows.typedef_),
2526
111
          yr_le32toh(rows.methoddef),
2527
111
          yr_le32toh(rows.assembly));
2528
2529
111
      if (row_count > (0xFFFF >> 0x02))
2530
35
        index_size = 4;
2531
76
      else
2532
76
        index_size = 2;
2533
2534
111
      table_offset += (2 + index_size + index_sizes.blob) * num_rows;
2535
111
      break;
2536
2537
47
    case BIT_CLASSLAYOUT:
2538
47
      table_offset += (2 + 4 + index_sizes.typedef_) * num_rows;
2539
47
      break;
2540
2541
284
    case BIT_FIELDLAYOUT:
2542
284
      table_offset += (4 + index_sizes.field) * num_rows;
2543
284
      break;
2544
2545
38
    case BIT_STANDALONESIG:
2546
38
      table_offset += (index_sizes.blob) * num_rows;
2547
38
      break;
2548
2549
45
    case BIT_EVENTMAP:
2550
45
      table_offset += (index_sizes.typedef_ + index_sizes.event) * num_rows;
2551
45
      break;
2552
2553
22
    case BIT_EVENTPTR:
2554
      // This one is not documented in ECMA-335.
2555
22
      table_offset += (index_sizes.event) * num_rows;
2556
22
      break;
2557
2558
100
    case BIT_EVENT:
2559
100
      row_count = max_rows(
2560
100
          3,
2561
100
          yr_le32toh(rows.typedef_),
2562
100
          yr_le32toh(rows.typeref),
2563
100
          yr_le32toh(rows.typespec));
2564
2565
100
      if (row_count > (0xFFFF >> 0x02))
2566
45
        index_size = 4;
2567
55
      else
2568
55
        index_size = 2;
2569
2570
100
      table_offset += (2 + index_sizes.string + index_size) * num_rows;
2571
100
      break;
2572
2573
203
    case BIT_PROPERTYMAP:
2574
203
      table_offset += (index_sizes.typedef_ + index_sizes.property) * num_rows;
2575
203
      break;
2576
2577
31
    case BIT_PROPERTYPTR:
2578
      // This one is not documented in ECMA-335.
2579
31
      table_offset += (index_sizes.property) * num_rows;
2580
31
      break;
2581
2582
185
    case BIT_PROPERTY:
2583
185
      table_offset += (2 + index_sizes.string + index_sizes.blob) * num_rows;
2584
185
      break;
2585
2586
205
    case BIT_METHODSEMANTICS:
2587
205
      row_count = max_rows(
2588
205
          2, yr_le32toh(rows.event), yr_le32toh(rows.property));
2589
2590
205
      if (row_count > (0xFFFF >> 0x01))
2591
0
        index_size = 4;
2592
205
      else
2593
205
        index_size = 2;
2594
2595
205
      table_offset += (2 + index_sizes.methoddef + index_size) * num_rows;
2596
205
      break;
2597
2598
35
    case BIT_METHODIMPL:
2599
35
      row_count = max_rows(
2600
35
          2, yr_le32toh(rows.methoddef), yr_le32toh(rows.memberref));
2601
2602
35
      if (row_count > (0xFFFF >> 0x01))
2603
0
        index_size = 4;
2604
35
      else
2605
35
        index_size = 2;
2606
2607
35
      table_offset += (index_sizes.typedef_ + (index_size * 2)) * num_rows;
2608
35
      break;
2609
2610
195
    case BIT_MODULEREF:
2611
195
      row_ptr = table_offset;
2612
2613
      // Can't use 'i' here because we only set the string if it is not
2614
      // NULL. Instead use 'counter'.
2615
195
      counter = 0;
2616
2617
62.5k
      for (i = 0; i < num_rows; i++)
2618
62.5k
      {
2619
62.5k
        moduleref_table = (PMODULEREF_TABLE) row_ptr;
2620
2621
62.5k
        if (!struct_fits_in_pe(pe, moduleref_table, MODULEREF_TABLE))
2622
119
          break;
2623
2624
62.3k
        name = pe_get_dotnet_string(
2625
62.3k
            pe,
2626
62.3k
            string_offset,
2627
62.3k
            str_heap_size,
2628
62.3k
            DOTNET_STRING_INDEX(moduleref_table->Name));
2629
2630
62.3k
        if (name != NULL)
2631
48.1k
        {
2632
48.1k
          yr_set_string(name, pe->object, "modulerefs[%i]", counter);
2633
48.1k
          counter++;
2634
48.1k
        }
2635
2636
62.3k
        row_ptr += index_sizes.string;
2637
62.3k
      }
2638
2639
195
      yr_set_integer(counter, pe->object, "number_of_modulerefs");
2640
2641
195
      row_size = index_sizes.string;
2642
2643
195
      tables.moduleref.Offset = table_offset;
2644
195
      tables.moduleref.RowCount = num_rows;
2645
195
      tables.moduleref.RowSize = row_size;
2646
2647
195
      table_offset += row_size * num_rows;
2648
195
      break;
2649
2650
475
    case BIT_TYPESPEC:
2651
475
      row_size = index_sizes.blob;
2652
2653
475
      tables.typespec.Offset = table_offset;
2654
475
      tables.typespec.RowCount = num_rows;
2655
475
      tables.typespec.RowSize = row_size;
2656
2657
475
      table_offset += row_size * num_rows;
2658
475
      break;
2659
2660
97
    case BIT_IMPLMAP:
2661
97
      row_count = max_rows(
2662
97
          2, yr_le32toh(rows.field), yr_le32toh(rows.methoddef));
2663
2664
97
      if (row_count > (0xFFFF >> 0x01))
2665
0
        index_size = 4;
2666
97
      else
2667
97
        index_size = 2;
2668
2669
97
      table_offset += (2 + index_size + index_sizes.string +
2670
97
                       index_sizes.moduleref) *
2671
97
                      num_rows;
2672
97
      break;
2673
2674
368
    case BIT_FIELDRVA:
2675
368
      row_size = 4 + index_sizes.field;
2676
368
      row_ptr = table_offset;
2677
2678
      // Can't use 'i' here because we only set the field offset if it is
2679
      // valid. Instead use 'counter'.
2680
368
      counter = 0;
2681
2682
92.8k
      for (i = 0; i < num_rows; i++)
2683
92.6k
      {
2684
92.6k
        fieldrva_table = (PFIELDRVA_TABLE) row_ptr;
2685
2686
92.6k
        if (!struct_fits_in_pe(pe, fieldrva_table, FIELDRVA_TABLE))
2687
183
          break;
2688
2689
92.4k
        field_offset = pe_rva_to_offset(pe, fieldrva_table->RVA);
2690
2691
92.4k
        if (field_offset >= 0)
2692
11.7k
        {
2693
11.7k
          yr_set_integer(
2694
11.7k
              field_offset, pe->object, "field_offsets[%i]", counter);
2695
11.7k
          counter++;
2696
11.7k
        }
2697
2698
92.4k
        row_ptr += row_size;
2699
92.4k
      }
2700
2701
368
      yr_set_integer(counter, pe->object, "number_of_field_offsets");
2702
2703
368
      table_offset += row_size * num_rows;
2704
368
      break;
2705
2706
20
    case BIT_ENCLOG:
2707
20
      table_offset += (4 + 4) * num_rows;
2708
20
      break;
2709
2710
220
    case BIT_ENCMAP:
2711
220
      table_offset += (4) * num_rows;
2712
220
      break;
2713
2714
466
    case BIT_ASSEMBLY:
2715
466
      row_size =
2716
466
          (4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob + (index_sizes.string * 2));
2717
2718
466
      if (!fits_in_pe(pe, table_offset, row_size))
2719
185
        break;
2720
2721
281
      row_ptr = table_offset;
2722
281
      assembly_table = (PASSEMBLY_TABLE) table_offset;
2723
2724
281
      yr_set_integer(
2725
281
          yr_le16toh(assembly_table->MajorVersion),
2726
281
          pe->object,
2727
281
          "assembly.version.major");
2728
281
      yr_set_integer(
2729
281
          yr_le16toh(assembly_table->MinorVersion),
2730
281
          pe->object,
2731
281
          "assembly.version.minor");
2732
281
      yr_set_integer(
2733
281
          yr_le16toh(assembly_table->BuildNumber),
2734
281
          pe->object,
2735
281
          "assembly.version.build_number");
2736
281
      yr_set_integer(
2737
281
          yr_le16toh(assembly_table->RevisionNumber),
2738
281
          pe->object,
2739
281
          "assembly.version.revision_number");
2740
2741
      // Can't use assembly_table here because the PublicKey comes before
2742
      // Name and is a variable length field.
2743
2744
281
      if (index_sizes.string == 4)
2745
54
        name = pe_get_dotnet_string(
2746
54
            pe,
2747
54
            string_offset,
2748
54
            str_heap_size,
2749
54
            yr_le32toh(*(DWORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 +
2750
54
                                  index_sizes.blob)));
2751
227
      else
2752
227
        name = pe_get_dotnet_string(
2753
227
            pe,
2754
227
            string_offset,
2755
227
            str_heap_size,
2756
227
            yr_le16toh(
2757
227
                *(WORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob)));
2758
2759
281
      if (name != NULL)
2760
281
        yr_set_string(name, pe->object, "assembly.name");
2761
2762
      // Culture comes after Name.
2763
281
      if (index_sizes.string == 4)
2764
54
      {
2765
54
        name = pe_get_dotnet_string(
2766
54
            pe,
2767
54
            string_offset,
2768
54
            str_heap_size,
2769
54
            yr_le32toh(*(DWORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 +
2770
54
                                  index_sizes.blob + index_sizes.string)));
2771
54
      }
2772
227
      else
2773
227
      {
2774
227
        name = pe_get_dotnet_string(
2775
227
            pe,
2776
227
            string_offset,
2777
227
            str_heap_size,
2778
227
            yr_le16toh(*(WORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 +
2779
227
                                 index_sizes.blob + index_sizes.string)));
2780
227
      }
2781
2782
      // Sometimes it will be a zero length string. This is technically
2783
      // against the specification but happens from time to time.
2784
281
      if (name != NULL && strlen(name) > 0)
2785
281
        yr_set_string(name, pe->object, "assembly.culture");
2786
2787
281
      table_offset += row_size * num_rows;
2788
281
      break;
2789
2790
89
    case BIT_ASSEMBLYPROCESSOR:
2791
89
      table_offset += (4) * num_rows;
2792
89
      break;
2793
2794
23
    case BIT_ASSEMBLYOS:
2795
23
      table_offset += (4 + 4 + 4) * num_rows;
2796
23
      break;
2797
2798
690
    case BIT_ASSEMBLYREF:
2799
690
      row_size =
2800
690
          (2 + 2 + 2 + 2 + 4 + (index_sizes.blob * 2) +
2801
690
           (index_sizes.string * 2));
2802
2803
690
      row_ptr = table_offset;
2804
2805
56.8k
      for (i = 0; i < num_rows; i++)
2806
56.6k
      {
2807
56.6k
        if (!fits_in_pe(pe, row_ptr, row_size))
2808
456
          break;
2809
2810
56.1k
        assemblyref_table = (PASSEMBLYREF_TABLE) row_ptr;
2811
2812
56.1k
        yr_set_integer(
2813
56.1k
            yr_le16toh(assemblyref_table->MajorVersion),
2814
56.1k
            pe->object,
2815
56.1k
            "assembly_refs[%i].version.major",
2816
56.1k
            i);
2817
56.1k
        yr_set_integer(
2818
56.1k
            yr_le16toh(assemblyref_table->MinorVersion),
2819
56.1k
            pe->object,
2820
56.1k
            "assembly_refs[%i].version.minor",
2821
56.1k
            i);
2822
56.1k
        yr_set_integer(
2823
56.1k
            yr_le16toh(assemblyref_table->BuildNumber),
2824
56.1k
            pe->object,
2825
56.1k
            "assembly_refs[%i].version.build_number",
2826
56.1k
            i);
2827
56.1k
        yr_set_integer(
2828
56.1k
            yr_le16toh(assemblyref_table->RevisionNumber),
2829
56.1k
            pe->object,
2830
56.1k
            "assembly_refs[%i].version.revision_number",
2831
56.1k
            i);
2832
2833
56.1k
        blob_offset = pe->data + metadata_root +
2834
56.1k
                      yr_le32toh(streams->blob->Offset);
2835
2836
56.1k
        if (index_sizes.blob == 4)
2837
10.8k
          blob_offset += yr_le32toh(
2838
56.1k
              assemblyref_table->PublicKeyOrToken.PublicKeyOrToken_Long);
2839
45.3k
        else
2840
45.3k
          blob_offset += yr_le16toh(
2841
56.1k
              assemblyref_table->PublicKeyOrToken.PublicKeyOrToken_Short);
2842
2843
56.1k
        blob_result = dotnet_parse_blob_entry(pe, blob_offset);
2844
56.1k
        blob_offset += blob_result.size;
2845
2846
56.1k
        if (blob_result.size == 0 ||
2847
56.1k
            !fits_in_pe(pe, blob_offset, blob_result.length))
2848
19.5k
        {
2849
19.5k
          row_ptr += row_size;
2850
19.5k
          continue;
2851
19.5k
        }
2852
2853
        // Avoid empty strings.
2854
36.6k
        if (blob_result.length > 0)
2855
24.3k
        {
2856
24.3k
          yr_set_sized_string(
2857
24.3k
              (char*) blob_offset,
2858
24.3k
              blob_result.length,
2859
24.3k
              pe->object,
2860
24.3k
              "assembly_refs[%i].public_key_or_token",
2861
24.3k
              i);
2862
24.3k
        }
2863
2864
        // Can't use assemblyref_table here because the PublicKey comes before
2865
        // Name and is a variable length field.
2866
2867
36.6k
        if (index_sizes.string == 4)
2868
10.2k
          name = pe_get_dotnet_string(
2869
10.2k
              pe,
2870
10.2k
              string_offset,
2871
10.2k
              str_heap_size,
2872
10.2k
              yr_le32toh(
2873
10.2k
                  *(DWORD*) (row_ptr + 2 + 2 + 2 + 2 + 4 + index_sizes.blob)));
2874
26.3k
        else
2875
26.3k
          name = pe_get_dotnet_string(
2876
26.3k
              pe,
2877
26.3k
              string_offset,
2878
26.3k
              str_heap_size,
2879
26.3k
              yr_le16toh(
2880
26.3k
                  *(WORD*) (row_ptr + 2 + 2 + 2 + 2 + 4 + index_sizes.blob)));
2881
2882
36.6k
        if (name != NULL)
2883
36.6k
          yr_set_string(name, pe->object, "assembly_refs[%i].name", i);
2884
2885
36.6k
        row_ptr += row_size;
2886
36.6k
      }
2887
2888
690
      tables.assemblyref.Offset = table_offset;
2889
690
      tables.assemblyref.RowCount = num_rows;
2890
690
      tables.assemblyref.RowSize = row_size;
2891
2892
690
      yr_set_integer(i, pe->object, "number_of_assembly_refs");
2893
690
      table_offset += row_size * num_rows;
2894
690
      break;
2895
2896
17
    case BIT_ASSEMBLYREFPROCESSOR:
2897
17
      table_offset += (4 + index_sizes.assemblyrefprocessor) * num_rows;
2898
17
      break;
2899
2900
25
    case BIT_ASSEMBLYREFOS:
2901
25
      table_offset += (4 + 4 + 4 + index_sizes.assemblyref) * num_rows;
2902
25
      break;
2903
2904
26
    case BIT_FILE:
2905
26
      table_offset += (4 + index_sizes.string + index_sizes.blob) * num_rows;
2906
26
      break;
2907
2908
27
    case BIT_EXPORTEDTYPE:
2909
27
      row_count = max_rows(
2910
27
          3,
2911
27
          yr_le32toh(rows.file),
2912
27
          yr_le32toh(rows.assemblyref),
2913
27
          yr_le32toh(rows.exportedtype));
2914
2915
27
      if (row_count > (0xFFFF >> 0x02))
2916
0
        index_size = 4;
2917
27
      else
2918
27
        index_size = 2;
2919
2920
27
      table_offset += (4 + 4 + (index_sizes.string * 2) + index_size) *
2921
27
                      num_rows;
2922
27
      break;
2923
2924
605
    case BIT_MANIFESTRESOURCE:
2925
      // This is an Implementation coded index with no 3rd bit specified.
2926
605
      row_count = max_rows(
2927
605
          2, yr_le32toh(rows.file), yr_le32toh(rows.assemblyref));
2928
2929
605
      if (row_count > (0xFFFF >> 0x02))
2930
0
        index_size = 4;
2931
605
      else
2932
605
        index_size = 2;
2933
2934
605
      row_size = (4 + 4 + index_sizes.string + index_size);
2935
2936
      // Using 'i' is insufficent since we may skip certain resources and
2937
      // it would give an inaccurate count in that case.
2938
605
      counter = 0;
2939
605
      row_ptr = table_offset;
2940
2941
      // First DWORD is the offset.
2942
107k
      for (i = 0; i < num_rows; i++)
2943
107k
      {
2944
107k
        if (!fits_in_pe(pe, row_ptr, row_size))
2945
377
          break;
2946
2947
106k
        manifestresource_table = (PMANIFESTRESOURCE_TABLE) row_ptr;
2948
106k
        resource_offset = yr_le32toh(manifestresource_table->Offset);
2949
2950
        // Only set offset if it is in this file (implementation != 0).
2951
        // Can't use manifestresource_table here because the Name and
2952
        // Implementation fields are variable size.
2953
106k
        if (index_size == 4)
2954
0
          implementation = yr_le32toh(
2955
106k
              *(DWORD*) (row_ptr + 4 + 4 + index_sizes.string));
2956
106k
        else
2957
106k
          implementation = yr_le16toh(
2958
106k
              *(WORD*) (row_ptr + 4 + 4 + index_sizes.string));
2959
2960
106k
        if (implementation != 0)
2961
83.7k
        {
2962
83.7k
          row_ptr += row_size;
2963
83.7k
          continue;
2964
83.7k
        }
2965
2966
23.0k
        if (!fits_in_pe(
2967
23.0k
                pe, pe->data + resource_base + resource_offset, sizeof(DWORD)))
2968
15.5k
        {
2969
15.5k
          row_ptr += row_size;
2970
15.5k
          continue;
2971
15.5k
        }
2972
2973
7.44k
        resource_size = yr_le32toh(
2974
7.44k
            *(DWORD*) (pe->data + resource_base + resource_offset));
2975
2976
7.44k
        if (!fits_in_pe(
2977
7.44k
                pe, pe->data + resource_base + resource_offset, resource_size))
2978
4.91k
        {
2979
4.91k
          row_ptr += row_size;
2980
4.91k
          continue;
2981
4.91k
        }
2982
2983
        // Add 4 to skip the size.
2984
2.52k
        yr_set_integer(
2985
2.52k
            resource_base + resource_offset + 4,
2986
2.52k
            pe->object,
2987
2.52k
            "resources[%i].offset",
2988
2.52k
            counter);
2989
2990
2.52k
        yr_set_integer(
2991
2.52k
            resource_size, pe->object, "resources[%i].length", counter);
2992
2993
2.52k
        name = pe_get_dotnet_string(
2994
2.52k
            pe,
2995
2.52k
            string_offset,
2996
2.52k
            str_heap_size,
2997
2.52k
            DOTNET_STRING_INDEX(manifestresource_table->Name));
2998
2999
2.52k
        if (name != NULL)
3000
2.52k
          yr_set_string(name, pe->object, "resources[%i].name", counter);
3001
3002
2.52k
        row_ptr += row_size;
3003
2.52k
        counter++;
3004
2.52k
      }
3005
3006
605
      yr_set_integer(counter, pe->object, "number_of_resources");
3007
3008
605
      table_offset += row_size * num_rows;
3009
605
      break;
3010
3011
590
    case BIT_NESTEDCLASS:
3012
590
      row_size = index_sizes.typedef_ * 2;
3013
3014
590
      tables.nestedclass.Offset = table_offset;
3015
590
      tables.nestedclass.RowCount = num_rows;
3016
590
      tables.nestedclass.RowSize = row_size;
3017
3018
590
      table_offset += row_size * num_rows;
3019
590
      break;
3020
3021
430
    case BIT_GENERICPARAM:
3022
430
      row_count = max_rows(
3023
430
          2, yr_le32toh(rows.typedef_), yr_le32toh(rows.methoddef));
3024
3025
430
      if (row_count > (0xFFFF >> 0x01))
3026
0
        index_size = 4;
3027
430
      else
3028
430
        index_size = 2;
3029
3030
430
      row_size = (2 + 2 + index_size + index_sizes.string);
3031
3032
430
      tables.genericparam.Offset = table_offset;
3033
430
      tables.genericparam.RowCount = num_rows;
3034
430
      tables.genericparam.RowSize = row_size;
3035
3036
430
      table_offset += row_size * num_rows;
3037
430
      break;
3038
3039
66
    case BIT_METHODSPEC:
3040
66
      row_count = max_rows(
3041
66
          2, yr_le32toh(rows.methoddef), yr_le32toh(rows.memberref));
3042
3043
66
      if (row_count > (0xFFFF >> 0x01))
3044
0
        index_size = 4;
3045
66
      else
3046
66
        index_size = 2;
3047
3048
66
      table_offset += (index_size + index_sizes.blob) * num_rows;
3049
66
      break;
3050
3051
8
    case BIT_GENERICPARAMCONSTRAINT:
3052
8
      row_count = max_rows(
3053
8
          3,
3054
8
          yr_le32toh(rows.typedef_),
3055
8
          yr_le32toh(rows.typeref),
3056
8
          yr_le32toh(rows.typespec));
3057
3058
8
      if (row_count > (0xFFFF >> 0x02))
3059
0
        index_size = 4;
3060
8
      else
3061
8
        index_size = 2;
3062
3063
8
      table_offset += (index_sizes.genericparam + index_size) * num_rows;
3064
8
      break;
3065
3066
20
    default:
3067
      // printf("Unknown bit: %i\n", bit_check);
3068
20
      return;
3069
19.7k
    }
3070
3071
19.7k
    matched_bits++;
3072
19.7k
  }
3073
3074
3.14k
  CLASS_CONTEXT class_context = {
3075
3.14k
      .pe = pe,
3076
3.14k
      .tables = &tables,
3077
3.14k
      .index_sizes = &index_sizes,
3078
3.14k
      .str_heap = string_offset,
3079
3.14k
      .str_size = str_heap_size,
3080
3.14k
      .blob_heap = pe->data + streams->metadata_root +
3081
3.14k
                   yr_le32toh(streams->blob->Offset),
3082
3.14k
      .blob_size = yr_le32toh(streams->blob->Size)};
3083
3084
3.14k
  parse_user_types(&class_context);
3085
3.14k
}
3086
3087
// Parsing the #~ stream is done in two parts. The first part (this function)
3088
// parses enough of the Stream to provide context for the second pass. In
3089
// particular it is collecting the number of rows for each of the tables. The
3090
// second part parses the actual tables of interest.
3091
3092
void dotnet_parse_tilde(PE* pe, PCLI_HEADER cli_header, PSTREAMS streams)
3093
5.16k
{
3094
5.16k
  PTILDE_HEADER tilde_header;
3095
5.16k
  int64_t resource_base;
3096
5.16k
  int64_t metadata_root = streams->metadata_root;
3097
5.16k
  uint32_t* row_offset = NULL;
3098
3099
5.16k
  int bit_check;
3100
3101
  // This is used as an offset into the rows and tables. For every bit set in
3102
  // Valid this will be incremented. This is because the bit position doesn't
3103
  // matter, just the number of bits that are set, when determining how many
3104
  // rows and what the table structure is.
3105
5.16k
  int matched_bits = 0;
3106
3107
  // We need to know the number of rows for some tables, because they are
3108
  // indexed into. The index will be either 2 or 4 bytes, depending upon the
3109
  // number of rows being indexed into.
3110
5.16k
  ROWS rows;
3111
5.16k
  INDEX_SIZES index_sizes;
3112
5.16k
  uint32_t heap_sizes;
3113
3114
  // Default all rows to 0. They will be set to actual values later on, if
3115
  // they exist in the file.
3116
5.16k
  memset(&rows, '\0', sizeof(ROWS));
3117
3118
  // Default index sizes are 2. Will be bumped to 4 if necessary.
3119
5.16k
  memset(&index_sizes, 2, sizeof(index_sizes));
3120
3121
5.16k
  tilde_header = (PTILDE_HEADER) (pe->data + metadata_root +
3122
5.16k
                                  yr_le32toh(streams->tilde->Offset));
3123
3124
5.16k
  if (!struct_fits_in_pe(pe, tilde_header, TILDE_HEADER))
3125
2
    return;
3126
3127
5.16k
  heap_sizes = yr_le32toh(tilde_header->HeapSizes);
3128
3129
  // Set index sizes for various heaps.
3130
5.16k
  if (heap_sizes & 0x01)
3131
855
    index_sizes.string = 4;
3132
3133
5.16k
  if (heap_sizes & 0x02)
3134
1.04k
    index_sizes.guid = 4;
3135
3136
5.16k
  if (heap_sizes & 0x04)
3137
974
    index_sizes.blob = 4;
3138
3139
  // Immediately after the tilde header is an array of 32bit values which
3140
  // indicate how many rows are in each table. The tables are immediately
3141
  // after the rows array.
3142
  //
3143
  // Save the row offset.
3144
5.16k
  row_offset = (uint32_t*) (tilde_header + 1);
3145
3146
  // Walk all the bits first because we need to know the number of rows for
3147
  // some tables in order to parse others. In particular this applies to
3148
  // coded indexes, which are documented in ECMA-335 II.24.2.6.
3149
335k
  for (bit_check = 0; bit_check < 64; bit_check++)
3150
330k
  {
3151
330k
    if (!((yr_le64toh(tilde_header->Valid) >> bit_check) & 0x01))
3152
281k
      continue;
3153
3154
48.4k
#define ROW_CHECK(name)                                                  \
3155
48.4k
  if (fits_in_pe(pe, row_offset, (matched_bits + 1) * sizeof(uint32_t))) \
3156
25.7k
    rows.name = *(row_offset + matched_bits);
3157
3158
48.4k
#define ROW_CHECK_WITH_INDEX(name)    \
3159
48.4k
  ROW_CHECK(name);                    \
3160
22.3k
  if (yr_le32toh(rows.name) > 0xFFFF) \
3161
22.3k
    index_sizes.name = 4;
3162
3163
48.4k
    switch (bit_check)
3164
48.4k
    {
3165
1.11k
    case BIT_MODULE:
3166
1.11k
      ROW_CHECK_WITH_INDEX(module);
3167
1.11k
      break;
3168
933
    case BIT_MODULEREF:
3169
933
      ROW_CHECK_WITH_INDEX(moduleref);
3170
933
      break;
3171
1.31k
    case BIT_ASSEMBLYREF:
3172
1.31k
      ROW_CHECK_WITH_INDEX(assemblyref);
3173
1.31k
      break;
3174
443
    case BIT_ASSEMBLYREFPROCESSOR:
3175
443
      ROW_CHECK_WITH_INDEX(assemblyrefprocessor);
3176
443
      break;
3177
1.74k
    case BIT_TYPEREF:
3178
1.74k
      ROW_CHECK_WITH_INDEX(typeref);
3179
1.74k
      break;
3180
2.54k
    case BIT_METHODDEF:
3181
2.54k
      ROW_CHECK_WITH_INDEX(methoddef);
3182
2.54k
      break;
3183
1.41k
    case BIT_MEMBERREF:
3184
1.41k
      ROW_CHECK_WITH_INDEX(memberref);
3185
1.41k
      break;
3186
3.74k
    case BIT_TYPEDEF:
3187
3.74k
      ROW_CHECK_WITH_INDEX(typedef_);
3188
3.74k
      break;
3189
1.16k
    case BIT_TYPESPEC:
3190
1.16k
      ROW_CHECK_WITH_INDEX(typespec);
3191
1.16k
      break;
3192
1.13k
    case BIT_FIELD:
3193
1.13k
      ROW_CHECK_WITH_INDEX(field);
3194
1.13k
      break;
3195
1.33k
    case BIT_PARAM:
3196
1.33k
      ROW_CHECK_WITH_INDEX(param);
3197
1.33k
      break;
3198
765
    case BIT_PROPERTY:
3199
765
      ROW_CHECK_WITH_INDEX(property);
3200
765
      break;
3201
1.20k
    case BIT_INTERFACEIMPL:
3202
1.20k
      ROW_CHECK_WITH_INDEX(interfaceimpl);
3203
1.20k
      break;
3204
618
    case BIT_EVENT:
3205
618
      ROW_CHECK_WITH_INDEX(event);
3206
618
      break;
3207
543
    case BIT_STANDALONESIG:
3208
543
      ROW_CHECK(standalonesig);
3209
543
      break;
3210
1.09k
    case BIT_ASSEMBLY:
3211
1.09k
      ROW_CHECK_WITH_INDEX(assembly);
3212
1.09k
      break;
3213
814
    case BIT_FILE:
3214
814
      ROW_CHECK(file);
3215
814
      break;
3216
424
    case BIT_EXPORTEDTYPE:
3217
424
      ROW_CHECK(exportedtype);
3218
424
      break;
3219
1.17k
    case BIT_MANIFESTRESOURCE:
3220
1.17k
      ROW_CHECK(manifestresource);
3221
1.17k
      break;
3222
1.12k
    case BIT_GENERICPARAM:
3223
1.12k
      ROW_CHECK_WITH_INDEX(genericparam);
3224
1.12k
      break;
3225
482
    case BIT_GENERICPARAMCONSTRAINT:
3226
482
      ROW_CHECK(genericparamconstraint);
3227
482
      break;
3228
661
    case BIT_METHODSPEC:
3229
661
      ROW_CHECK_WITH_INDEX(methodspec);
3230
661
      break;
3231
22.6k
    default:
3232
22.6k
      break;
3233
48.4k
    }
3234
3235
48.4k
    matched_bits++;
3236
48.4k
  }
3237
3238
  // This is used when parsing the MANIFEST RESOURCE table.
3239
5.16k
  resource_base = pe_rva_to_offset(
3240
5.16k
      pe, yr_le32toh(cli_header->Resources.VirtualAddress));
3241
3242
5.16k
  dotnet_parse_tilde_2(
3243
5.16k
      pe, tilde_header, resource_base, rows, index_sizes, streams);
3244
5.16k
}
3245
3246
static bool dotnet_is_dotnet(PE* pe)
3247
5.95k
{
3248
5.95k
  PIMAGE_DATA_DIRECTORY directory = pe_get_directory_entry(
3249
5.95k
      pe, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR);
3250
3251
5.95k
  if (!directory)
3252
1
    return false;
3253
3254
5.95k
  int64_t offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress));
3255
3256
5.95k
  if (offset < 0 || !struct_fits_in_pe(pe, pe->data + offset, CLI_HEADER))
3257
302
    return false;
3258
3259
5.64k
  CLI_HEADER* cli_header = (CLI_HEADER*) (pe->data + offset);
3260
3261
5.64k
  if (yr_le32toh(cli_header->Size) != sizeof(CLI_HEADER))
3262
26
    return false;
3263
3264
5.62k
  int64_t metadata_root = pe_rva_to_offset(
3265
5.62k
      pe, yr_le32toh(cli_header->MetaData.VirtualAddress));
3266
5.62k
  offset = metadata_root;
3267
3268
5.62k
  if (!struct_fits_in_pe(pe, pe->data + metadata_root, NET_METADATA))
3269
15
    return false;
3270
3271
5.60k
  NET_METADATA* metadata = (NET_METADATA*) (pe->data + metadata_root);
3272
3273
5.60k
  if (yr_le32toh(metadata->Magic) != NET_METADATA_MAGIC)
3274
54
    return false;
3275
3276
  // Version length must be between 1 and 255, and be a multiple of 4.
3277
  // Also make sure it fits in pe.
3278
5.55k
  uint32_t md_len = yr_le32toh(metadata->Length);
3279
5.55k
  if (md_len == 0 || md_len > 255 || md_len % 4 != 0 ||
3280
5.55k
      !fits_in_pe(pe, pe->data + offset + sizeof(NET_METADATA), md_len))
3281
57
  {
3282
57
    return false;
3283
57
  }
3284
3285
5.49k
  if (IS_64BITS_PE(pe))
3286
1
  {
3287
1
    if (yr_le32toh(OptionalHeader(pe, NumberOfRvaAndSizes)) <
3288
1
        IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
3289
0
      return false;
3290
1
  }
3291
5.49k
  else if (!(pe->header->FileHeader.Characteristics & IMAGE_FILE_DLL))  // 32bit
3292
30
  {
3293
    // Check first 2 bytes of the Entry point are equal to 0xFF 0x25
3294
30
    int64_t entry_offset = pe_rva_to_offset(
3295
30
        pe, yr_le32toh(pe->header->OptionalHeader.AddressOfEntryPoint));
3296
3297
30
    if (entry_offset < 0 || !fits_in_pe(pe, pe->data + entry_offset, 2))
3298
2
      return false;
3299
3300
28
    const uint8_t* entry_data = pe->data + entry_offset;
3301
28
    if (!(entry_data[0] == 0xFF && entry_data[1] == 0x25))
3302
26
      return false;
3303
28
  }
3304
3305
5.46k
  return true;
3306
5.49k
}
3307
3308
void dotnet_parse_com(PE* pe)
3309
5.95k
{
3310
5.95k
  PIMAGE_DATA_DIRECTORY directory;
3311
5.95k
  PCLI_HEADER cli_header;
3312
5.95k
  PNET_METADATA metadata;
3313
5.95k
  int64_t metadata_root, offset;
3314
5.95k
  char* end;
3315
5.95k
  STREAMS headers;
3316
5.95k
  WORD num_streams;
3317
5.95k
  uint32_t md_len;
3318
3319
5.95k
  if (!dotnet_is_dotnet(pe))
3320
483
  {
3321
483
    yr_set_integer(0, pe->object, "is_dotnet");
3322
483
    return;
3323
483
  }
3324
3325
5.46k
  yr_set_integer(1, pe->object, "is_dotnet");
3326
3327
5.46k
  directory = pe_get_directory_entry(pe, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR);
3328
5.46k
  if (directory == NULL)
3329
0
    return;
3330
3331
5.46k
  offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress));
3332
3333
5.46k
  if (offset < 0 || !struct_fits_in_pe(pe, pe->data + offset, CLI_HEADER))
3334
0
    return;
3335
3336
5.46k
  cli_header = (PCLI_HEADER) (pe->data + offset);
3337
3338
5.46k
  offset = metadata_root = pe_rva_to_offset(
3339
5.46k
      pe, yr_le32toh(cli_header->MetaData.VirtualAddress));
3340
3341
5.46k
  if (!struct_fits_in_pe(pe, pe->data + offset, NET_METADATA))
3342
0
    return;
3343
3344
5.46k
  metadata = (PNET_METADATA) (pe->data + offset);
3345
3346
  // Version length must be between 1 and 255, and be a multiple of 4.
3347
  // Also make sure it fits in pe.
3348
5.46k
  md_len = yr_le32toh(metadata->Length);
3349
3350
5.46k
  if (md_len == 0 || md_len > 255 || md_len % 4 != 0 ||
3351
5.46k
      !fits_in_pe(pe, pe->data + offset + sizeof(NET_METADATA), md_len))
3352
0
  {
3353
0
    return;
3354
0
  }
3355
3356
  // The length includes the NULL terminator and is rounded up to a multiple of
3357
  // 4. We need to exclude the terminator and the padding, so search for the
3358
  // first NULL byte.
3359
5.46k
  end = (char*) memmem((void*) metadata->Version, md_len, "\0", 1);
3360
3361
5.46k
  if (end != NULL)
3362
2.56k
    yr_set_sized_string(
3363
5.46k
        metadata->Version, (end - metadata->Version), pe->object, "version");
3364
3365
  // The metadata structure has some variable length records after the version.
3366
  // We must manually parse things from here on out.
3367
  //
3368
  // Flags are 2 bytes (always 0).
3369
5.46k
  offset += sizeof(NET_METADATA) + md_len + 2;
3370
3371
  // 2 bytes for Streams.
3372
5.46k
  if (!fits_in_pe(pe, pe->data + offset, 2))
3373
8
    return;
3374
3375
5.46k
  num_streams = (WORD) * (pe->data + offset);
3376
5.46k
  offset += 2;
3377
3378
5.46k
  headers = dotnet_parse_stream_headers(pe, offset, metadata_root, num_streams);
3379
3380
5.46k
  if (headers.guid != NULL)
3381
483
    dotnet_parse_guid(pe, metadata_root, headers.guid);
3382
3383
  // Parse the #~ stream, which includes various tables of interest.
3384
  // These tables reference the blob and string streams, so we need to ensure
3385
  // those are not NULL also.
3386
5.46k
  if (headers.tilde != NULL && headers.string != NULL && headers.blob != NULL)
3387
5.16k
    dotnet_parse_tilde(pe, cli_header, &headers);
3388
3389
5.46k
  if (headers.us != NULL)
3390
711
    dotnet_parse_us(pe, metadata_root, headers.us);
3391
5.46k
}
3392
3393
7.34k
begin_declarations
3394
7.34k
  declare_integer("is_dotnet");
3395
7.34k
  declare_string("version");
3396
7.34k
  declare_string("module_name");
3397
3398
22.0k
  begin_struct_array("streams")
3399
7.34k
    declare_string("name");
3400
7.34k
    declare_integer("offset");
3401
7.34k
    declare_integer("size");
3402
14.6k
  end_struct_array("streams")
3403
3404
7.34k
  declare_integer("number_of_streams");
3405
3406
14.6k
  declare_string_array("guids");
3407
14.6k
  declare_integer("number_of_guids");
3408
3409
22.0k
  begin_struct_array("resources")
3410
7.34k
    declare_integer("offset");
3411
7.34k
    declare_integer("length");
3412
7.34k
    declare_string("name");
3413
14.6k
  end_struct_array("resources")
3414
3415
7.34k
  declare_integer("number_of_resources");
3416
3417
22.0k
  begin_struct_array("classes")
3418
7.34k
    declare_string("fullname");
3419
7.34k
    declare_string("name");
3420
7.34k
    declare_string("namespace");
3421
7.34k
    declare_string("visibility");
3422
7.34k
    declare_string("type");
3423
7.34k
    declare_integer("abstract");
3424
7.34k
    declare_integer("sealed");
3425
3426
7.34k
    declare_integer("number_of_generic_parameters");
3427
14.6k
    declare_string_array("generic_parameters");
3428
3429
14.6k
    declare_integer("number_of_base_types");
3430
14.6k
    declare_string_array("base_types");
3431
3432
14.6k
    declare_integer("number_of_methods");
3433
22.0k
    begin_struct_array("methods")
3434
14.6k
      declare_string_array("generic_parameters");
3435
3436
14.6k
      declare_integer("number_of_generic_parameters");
3437
3438
22.0k
      begin_struct_array("parameters")
3439
7.34k
        declare_string("name");
3440
7.34k
        declare_string("type");
3441
14.6k
      end_struct_array("parameters")
3442
3443
7.34k
      declare_integer("number_of_parameters");
3444
3445
7.34k
      declare_string("return_type");
3446
7.34k
      declare_integer("abstract");
3447
7.34k
      declare_integer("final");
3448
7.34k
      declare_integer("virtual");
3449
7.34k
      declare_integer("static");
3450
7.34k
      declare_string("visibility");
3451
7.34k
      declare_string("name");
3452
14.6k
    end_struct_array("methods")
3453
3454
14.6k
  end_struct_array("classes")
3455
3456
7.34k
  declare_integer("number_of_classes");
3457
3458
22.0k
  begin_struct_array("assembly_refs")
3459
14.6k
    begin_struct("version")
3460
7.34k
      declare_integer("major");
3461
7.34k
      declare_integer("minor");
3462
7.34k
      declare_integer("build_number");
3463
7.34k
      declare_integer("revision_number");
3464
14.6k
    end_struct("version")
3465
7.34k
    declare_string("public_key_or_token");
3466
7.34k
    declare_string("name");
3467
14.6k
  end_struct_array("assembly_refs")
3468
3469
7.34k
  declare_integer("number_of_assembly_refs");
3470
3471
14.6k
  begin_struct("assembly")
3472
14.6k
    begin_struct("version")
3473
7.34k
      declare_integer("major");
3474
7.34k
      declare_integer("minor");
3475
7.34k
      declare_integer("build_number");
3476
7.34k
      declare_integer("revision_number");
3477
14.6k
    end_struct("version")
3478
7.34k
    declare_string("name");
3479
7.34k
    declare_string("culture");
3480
14.6k
  end_struct("assembly")
3481
3482
14.6k
  declare_string_array("modulerefs");
3483
14.6k
  declare_integer("number_of_modulerefs");
3484
14.6k
  declare_string_array("user_strings");
3485
14.6k
  declare_integer("number_of_user_strings");
3486
7.34k
  declare_string("typelib");
3487
14.6k
  declare_string_array("constants");
3488
14.6k
  declare_integer("number_of_constants");
3489
3490
14.6k
  declare_integer_array("field_offsets");
3491
14.6k
  declare_integer("number_of_field_offsets");
3492
7.34k
end_declarations
3493
3494
int module_initialize(YR_MODULE* module)
3495
2
{
3496
2
  return ERROR_SUCCESS;
3497
2
}
3498
3499
int module_finalize(YR_MODULE* module)
3500
0
{
3501
0
  return ERROR_SUCCESS;
3502
0
}
3503
3504
int module_load(
3505
    YR_SCAN_CONTEXT* context,
3506
    YR_OBJECT* module_object,
3507
    void* module_data,
3508
    size_t module_data_size)
3509
7.33k
{
3510
7.33k
  YR_MEMORY_BLOCK* block;
3511
7.33k
  YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator;
3512
7.33k
  const uint8_t* block_data = NULL;
3513
3514
7.33k
  foreach_memory_block(iterator, block)
3515
7.33k
  {
3516
7.33k
    PIMAGE_NT_HEADERS32 pe_header;
3517
3518
7.33k
    block_data = block->fetch_data(block);
3519
3520
7.33k
    if (block_data == NULL)
3521
0
      continue;
3522
3523
7.33k
    pe_header = pe_get_header(block_data, block->size);
3524
3525
7.33k
    if (pe_header != NULL)
3526
5.95k
    {
3527
      // Ignore DLLs while scanning a process
3528
3529
5.95k
      if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) ||
3530
5.95k
          !(pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
3531
5.95k
      {
3532
5.95k
        PE* pe = (PE*) yr_malloc(sizeof(PE));
3533
3534
5.95k
        if (pe == NULL)
3535
0
          return ERROR_INSUFFICIENT_MEMORY;
3536
3537
5.95k
        pe->data = block_data;
3538
5.95k
        pe->data_size = block->size;
3539
5.95k
        pe->object = module_object;
3540
5.95k
        pe->header = pe_header;
3541
3542
5.95k
        module_object->data = pe;
3543
3544
5.95k
        dotnet_parse_com(pe);
3545
3546
5.95k
        break;
3547
5.95k
      }
3548
5.95k
    }
3549
7.33k
  }
3550
3551
7.33k
  return ERROR_SUCCESS;
3552
7.33k
}
3553
3554
int module_unload(YR_OBJECT* module_object)
3555
7.33k
{
3556
7.33k
  PE* pe = (PE*) module_object->data;
3557
3558
7.33k
  if (pe == NULL)
3559
1.38k
    return ERROR_SUCCESS;
3560
3561
5.95k
  yr_free(pe);
3562
3563
5.95k
  return ERROR_SUCCESS;
3564
7.33k
}