Coverage Report

Created: 2026-10-19 06:44

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