Skip to content

Commit 4793b49

Browse files
committed
Fix issue while parsing PE rich header.
YARA was making the assumption that the 12 bytes following the `DanS` header contained 3 copies of the 32-bits XOR key, but these bytes are actually padding. As these bytes were usually filled with zeroes before applying the XOR key, they appear to contain the key itself after the XOR operation. However, files like `043066108b68b30fc2c475eae8edfafc080be7d451600eaa283d2c750bddbceb` don't contain zeroes in those bytes, and therefore were not satisfying YARA's assumption. YARA-X was right: https://github.com/VirusTotal/yara-x/blob/6ada059b9e4b328e2341b42304765c5614fc89af/lib/src/modules/pe/parser.rs#L687-L693
1 parent f51b9d7 commit 4793b49

File tree

2 files changed

+18
-32
lines changed

2 files changed

+18
-32
lines changed

libyara/include/yara/pe.h

+15-14
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,12 @@ typedef struct _IMAGE_NT_HEADERS64
365365
// IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is
366366
// the same either way.
367367

368-
#define IMAGE_FIRST_SECTION(ntheader) \
369-
((PIMAGE_SECTION_HEADER)( \
370-
(BYTE*) ntheader + offsetof(IMAGE_NT_HEADERS32, OptionalHeader) + \
371-
yr_le16toh(((PIMAGE_NT_HEADERS32)(ntheader)) \
372-
->FileHeader.SizeOfOptionalHeader)))
368+
#define IMAGE_FIRST_SECTION(ntheader) \
369+
((PIMAGE_SECTION_HEADER) ((BYTE*) ntheader + \
370+
offsetof(IMAGE_NT_HEADERS32, OptionalHeader) + \
371+
yr_le16toh( \
372+
((PIMAGE_NT_HEADERS32) (ntheader)) \
373+
->FileHeader.SizeOfOptionalHeader)))
373374

374375
// Subsystem Values
375376

@@ -727,22 +728,22 @@ typedef struct _IMAGE_SYMBOL_EX
727728
// MACROS
728729

729730
// Basic Type of x
730-
#define BTYPE(x) ((x) &N_BTMASK)
731+
#define BTYPE(x) ((x) & N_BTMASK)
731732

732733
// Is x a pointer?
733734
#ifndef ISPTR
734-
#define ISPTR(x) (((x) &N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT))
735+
#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT))
735736
#endif
736737

737738
// Is x a function?
738739
#ifndef ISFCN
739-
#define ISFCN(x) (((x) &N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT))
740+
#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT))
740741
#endif
741742

742743
// Is x an array?
743744

744745
#ifndef ISARY
745-
#define ISARY(x) (((x) &N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT))
746+
#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT))
746747
#endif
747748

748749
// Is x a structure, union, or enumeration TAG?
@@ -755,10 +756,10 @@ typedef struct _IMAGE_SYMBOL_EX
755756
#ifndef INCREF
756757
#define INCREF(x) \
757758
((((x) & ~N_BTMASK) << N_TSHIFT) | (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT) | \
758-
((x) &N_BTMASK))
759+
((x) & N_BTMASK))
759760
#endif
760761
#ifndef DECREF
761-
#define DECREF(x) ((((x) >> N_TSHIFT) & ~N_BTMASK) | ((x) &N_BTMASK))
762+
#define DECREF(x) ((((x) >> N_TSHIFT) & ~N_BTMASK) | ((x) & N_BTMASK))
762763
#endif
763764

764765
#pragma pack(pop)
@@ -865,9 +866,9 @@ typedef struct _RICH_VERSION_INFO
865866
typedef struct _RICH_SIGNATURE
866867
{
867868
DWORD dans;
868-
DWORD key1;
869-
DWORD key2;
870-
DWORD key3;
869+
DWORD padding_1;
870+
DWORD padding_2;
871+
DWORD padding_3;
871872
RICH_VERSION_INFO versions[0];
872873
} RICH_SIGNATURE, *PRICH_SIGNATURE;
873874

libyara/modules/pe/pe.c

+3-18
Original file line numberDiff line numberDiff line change
@@ -204,19 +204,6 @@ static void pe_parse_rich_signature(PE* pe, uint64_t base_address)
204204
if (rich_signature == NULL)
205205
return;
206206

207-
// The three key values must all be equal and the first dword
208-
// XORs to "DanS". Then walk the buffer looking for "Rich" which marks the
209-
// end. Technically the XOR key should be right after "Rich" but it's not
210-
// important.
211-
212-
if (yr_le32toh(rich_signature->key1) != yr_le32toh(rich_signature->key2) ||
213-
yr_le32toh(rich_signature->key2) != yr_le32toh(rich_signature->key3) ||
214-
(yr_le32toh(rich_signature->dans) ^ yr_le32toh(rich_signature->key1)) !=
215-
RICH_DANS)
216-
{
217-
return;
218-
}
219-
220207
// Multiply by 4 because we are counting in DWORDs.
221208
rich_len = (rich_ptr - (DWORD*) rich_signature) * 4;
222209
raw_data = (BYTE*) yr_malloc(rich_len);
@@ -232,9 +219,7 @@ static void pe_parse_rich_signature(PE* pe, uint64_t base_address)
232219
"rich_signature.offset");
233220

234221
yr_set_integer(rich_len, pe->object, "rich_signature.length");
235-
236-
yr_set_integer(
237-
yr_le32toh(rich_signature->key1), pe->object, "rich_signature.key");
222+
yr_set_integer(yr_le32toh(key), pe->object, "rich_signature.key");
238223

239224
clear_data = (BYTE*) yr_malloc(rich_len);
240225

@@ -251,7 +236,7 @@ static void pe_parse_rich_signature(PE* pe, uint64_t base_address)
251236
rich_ptr < (DWORD*) (clear_data + rich_len);
252237
rich_ptr++)
253238
{
254-
*rich_ptr ^= rich_signature->key1;
239+
*rich_ptr ^= key;
255240
}
256241

257242
yr_set_sized_string(
@@ -383,7 +368,7 @@ static void pe_parse_debug_directory(PE* pe)
383368
pdb_path_len = strnlen(
384369
pdb_path, yr_min(available_space(pe, pdb_path), MAX_PATH));
385370

386-
if (pdb_path_len > 0 && pdb_path_len < MAX_PATH)
371+
if (pdb_path_len >= 0 && pdb_path_len < MAX_PATH)
387372
{
388373
yr_set_sized_string(pdb_path, pdb_path_len, pe->object, "pdb_path");
389374
break;

0 commit comments

Comments
 (0)