Coverage Report

Created: 2023-06-07 07:19

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