Didier Stevens

Thursday 22 January 2015

Converting PEiD Signatures To YARA Rules

Filed under: Forensics,Malware,My Software — Didier Stevens @ 0:56

I converted Jim Clausing’s PEiD rules to YARA rules so that I can use them to detect executable code in suspect Microsoft Office Documents with my oledump tool.

Of course, I wrote a program to do this automatically: peid-userdb-to-yara-rules.py

This program converts PEiD signatures to YARA rules. These signatures are typically found in file userdb.txt. Since PEiD signature names don’t need to be unique, and can contain characters that are not allowed in YARA rules, the name of the YARA rule is prefixed with PEiD_ and a running counter, and non-alphanumeric characters are converted to underscores (_).
Signatures that can not be parsed are ignored.

Here is an example:
PEiD signature:

 [!EP (ExE Pack) V1.0 -> Elite Coding Group]
 signature = 60 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? FF 10
 ep_only = true

Generated YARA rule:

 rule PEiD_00001__EP__ExE_Pack__V1_0____Elite_Coding_Group_
         description = "[!EP (ExE Pack) V1.0 -> Elite Coding Group]"
         ep_only = "true"
         $a = {60 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? FF 10}

PEiD signatures have an ep_only property that can be true or false. This property specifies if the signature has to be found at the PE file’s entry point (true) or can be found anywhere (false).
This program will convert all signatures, regardless of the value of the ep_only property. Use option -e to convert only rules with ep_only property equal to true or false.

Option -p generates rules that use YARA’s pe module. If a signature has ep_only property equal to true, then the YARA rule’s condition becomes $a at pe.entry_point instead of just $a.


 import "pe"

 rule PEiD_00001__EP__ExE_Pack__V1_0____Elite_Coding_Group_
         description = "[!EP (ExE Pack) V1.0 -> Elite Coding Group]"
         ep_only = "true"
         $a = {60 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? FF 10}
         $a at pe.entry_point

Specific signatures can be excluded with option -x. This option takes a file that contains signatures to ignore (signatures like 60 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? FF 10, not names like [!EP (ExE Pack) V1.0 -> Elite Coding Group]).

Download my YARA Rules.

peid-userdb-to-yara-rules_V0_0_1.zip (https)
MD5: D5B9B6FA7EC50A107A70419D30FEC9ED

Tuesday 20 January 2015

YARA Rule: Detecting JPEG Exif With eval()

Filed under: Forensics,Malware — Didier Stevens @ 20:39

My first release of 2015 was a new YARA rule to detect JPEG images with an eval() function inside their Exif data.

Such images are not new, but I needed an example to develop a complex YARA rule:

rule JPEG_EXIF_Contains_eval
        author = "Didier Stevens (https://DidierStevens.com)"
        description = "Detect eval function inside JPG EXIF header (http://blog.sucuri.net/2013/07/malware-hidden-inside-jpg-exif-headers.html)"
        method = "Detect JPEG file and EXIF header ($a) and eval function ($b) inside EXIF data"
        $a = {FF E1 ?? ?? 45 78 69 66 00}
        $b = /\Weval\s*\(/
        uint16be(0x00) == 0xFFD8 and $a and $b in (@a + 0x12 .. @a + 0x02 + uint16be(@a + 0x02) - 0x06)

Here is an example of such an image:


The YARA rule has 3 conditions that must be satisfied:

  1. JPEG magic header FFD8, tested with: uint16be(0x00) == 0xFFD8
  2. Exif structure: FF E1 ?? ?? 45 78 69 66 00
  3. eval function inside Exif data, tested with a regular expression: \Weval\s*\(

Condition 1 is straightforward: the file must start with FFD8. I’m using test uint16be(0x00) == 0xFFD8 instead of searching for {FF D8} at 0x00. FF D8 is a short string, searching for {FF D8} can cause performance problems (you’ll get a warning from YARA when it compiles rules with such short strings).

Condition 2 checks for the presence of the Exif data header. Bytes 3 and 4 (?? ??) encode the length of the Exif Data.

Condition 3 checks for the presence of the eval function. To reduce the number of false positives that would occur when searching for string eval, we use a regular expression that matches string eval, possibly followed by whitespace characters (\s*), and an opening parenthesis: \(. And we don’t want letters or numbers before the string eval (we don’t want to match a string like deval), eval must be the start of a word. To achieve this with regular expressions, you use a word boundary: \b. So our regular expression would be \beval\s*\(. Unfortunately, YARA’s regular expression engine does not support word boundaries, so I had to come up with something else. I match any character that is not alphanumeric: \W. Be warned that there is a small difference between \W and \b. \b also matches the beginning of a string (like $), while \W has to match a character. So the regular expression I use is \Weval\s*\(.

The eval function must also be found inside the Exif data. We don’t want to trigger on the eval function if it is found somewhere else in the image. That’s where YARA’s in ( .. ) syntax comes in.

The first 18 bytes of the Exif structure are various headers which we ignore, so our eval function $b must start at @a + 0x12 or further.

The total size of the Exif structure is given by expression 0x02 + uint16be(@a + 0x02). We add this to the start of the Exif header (@a): @a + 0x02 + uint16be(@a + 0x02). And finally, we have to subtract the size of the string matched by the regular expression. Unfortunately, YARA has no function to calculate this length. So we will use the minimum length our regular expression can match: 6 characters. So our eval function $b must start no further than @a + 0x02 + uint16be(@a + 0x02) – 0x06. Putting all this together gives: $b in (@a + 0x12 .. @a + 0x02 + uint16be(@a + 0x02) – 0x06)

FYI: Victor told me that he plans to add a string length function to YARA, so our condition will then become: $b in (@a + 0x12 .. @a + 0x02 + uint16be(@a + 0x02) – &b)

You can find all my YARA rules here: YARA Rules.

Friday 16 January 2015

Update: oledump.py Version 0.0.6

Filed under: Malware,My Software,Update — Didier Stevens @ 16:11

My last software release for 2014 was oledump.py V0.0.6 with support for the “ZIP/XML” Microsoft Office fileformat and YARA.

In this post I will highlight support for the “new” Microsoft Office fileformat (.docx, .docm, .xlsx, .xlsm, …), which is mainly composed of XML files stored inside a ZIP container. Except macros which are still stored with OLE files (inside the ZIP container).

When oledump.py detects that the file is actually a ZIP file, it searches through all the files stored inside the ZIP container for OLE files, and analyses these.

Here is an example of a simple spreadsheet with macros. The xlsm file contains one OLE file: xl/vbaProject.bin. oledump gives it the identifier A. All the streams inside the OLE file are reported, and their index is prefixed with the identifier (A in this example).


If you want to select the stream with the macros, you use A6, like this: oledump.py -s A1

oledump also supports the analysis of an OLE file stored in a password protected ZIP file (typically, malware samples are stored inside ZIP files with password infected). When oledump.py analyses a ZIP file with extension .zip, it assumes that the file is NOT using the “new” Microsoft Office fileformat. Only when the file is a ZIP file but the extension is not .zip does oledump assume that the file is using the “new” Microsoft Office fileformat.

I have another example in my Internet Storm Center Guest Diary Entry.

oledump_V0_0_6.zip (https)
MD5: E32069589FEB7B53707D00D7E0256F79
SHA256: 8FCEFAEF5E6A2779FC8755ED96FB1A8DACDBE037B98EE419DBB974B5F18E578B

Thursday 8 January 2015

Didier Stevens Suite

Filed under: My Software — Didier Stevens @ 20:14

I bundled most of my software in a ZIP file. In all modesty, I call it Didier Stevens Suite.

Blog at WordPress.com.