Extracting Digital Signatures from Signed Malware with pf
September 3, 2015
Introduction
Lot of malware/PUP (Potential Unwanted Programs)/Adwares are now digitally signed. Those signatures can contain interesting properties that can be used as Indicators Of Compromise (IOC) by analysts or used to perform some large-scale analysis on a lot of samples. As an example, let’s use the recent signed dridex sample sample (5df62149bb91084eb677aecff7a8ca5fffeaaa23).
On Windows the Portable Executable file format uses IMAGE_DIRECTORY_ENTRY_SECURITY
to store the information which corresponds to the 5th IMAGE_DATA_DIRECTORY
. Let’s use radare2 to dump the certificate using pf
command.
Command construction
First we need to open our binary in a special mode using the -nn
flag (Only load the rbin structures) : r2 -nn binary.exe
.
By default you can notice that some structure are already parsed for certain filetype (PE, ELF, MachO, …), you can display those structures using pf.
(see also the article: parsing a fileformat with radare2.
-
pf.pe_nt_image_headers32
will parse a structure of the typepe_nt_image_headers32
at the current offset -
pf.pe_nt_image_headers32 @ pe_nt_image_headers32
will parse a structure of the typepe_nt_image_headers32
at the offset which should containpe_nt_image_headers32
, if we type this command we should get our array ofstruct<pe_image_data_directory>
displaying virtualAddress and size. -
Using
pfv
we are able to retrieve the actual value parsed:pfv.pe_nt_image_headers32.optionalHeader.dataDirectory[4].virtualAddress @ pe_nt_image_headers32
should return the virtualAdress andpfv.pe_nt_image_headers32.optionalHeader.dataDirectory[4].size @ pe_nt_image_headers32
the size of theIMAGE_DIRECTORY_ENTRY_SECURITY
. -
Now we need to dump
IMAGE_DIRECTORY_ENTRY_SECURITY
, usingpr
(print N raw bytes), we can pass the two command as argument ofpr
. Be careful to use the backticks `` that indicates we want to execute the sub-commands before, and also add +8 to the virtualAddress value.
pr `pfv.pe_nt_image_headers32.optionalHeader.dataDirectory[4].size @ pe_nt_image_headers32` @ `pfv.pe_nt_image_headers32.optionalHeader.dataDirectory[4].virtualAddress @ pe_nt_image_headers32`+8 > pe_certificate
- Ok now that the parsing has taken place, let’s try to decode the certificate using openssl:
openssl pkcs7 -inform DER -print_certs -text -in pe_certificate
[0x00000000]> pr ...
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
9f:ea:c8:11:b0:f1:62:47:a5:fc:20:d8:05:23:ac:e6
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Object
Validity
Not Before: May 5 00:00:00 2015 GMT
Not After : Dec 31 23:59:59 2015 GMT
Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Time Stamping Signer
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bc:35:a0:36:70:22:81:11:c3:b2:83:b9:d3:28:
c6:36:cd:25:6b:a9:7b:b2:1c:f6:9b:51:9c:ef:35:
f4:ed:08:8e:5e:38:08:f8:77:3c:0a:42:e0:f3:70:
....
...
- TADA! We can also use this one liner and add such command to a dedicated HUD for future use:
pr `pfv.pe_nt_image_headers32.optionalHeader.dataDirectory[4].size @ pe_nt_image_headers32` @ `pfv.pe_nt_image_headers32.optionalHeader.dataDirectory[4].virtualAddress @ pe_nt_image_headers32`+8 > pe_certificate ; !openssl pkcs7 -inform DER -print_certs -text -in pe_certificate