Skip to content

Commit 59dd2b8

Browse files
committed
Fix bug with multiple signatures.
1 parent 72fd000 commit 59dd2b8

File tree

2 files changed

+196
-149
lines changed

2 files changed

+196
-149
lines changed

libyara/include/yara/pe.h

+2
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,8 @@ typedef struct _WIN_CERTIFICATE {
481481
BYTE Certificate[0];
482482
} WIN_CERTIFICATE, *PWIN_CERTIFICATE;
483483

484+
#define SPC_NESTED_SIGNATURE_OBJID "1.3.6.1.4.1.311.2.4.1"
485+
484486

485487
//
486488
// Rich signature.

libyara/modules/pe.c

+194-149
Original file line numberDiff line numberDiff line change
@@ -1100,10 +1100,196 @@ EXPORT_FUNCTIONS* pe_parse_exports(
11001100

11011101
#if defined(HAVE_LIBCRYPTO)
11021102

1103+
//
1104+
// Parse a PKCS7 blob, looking for certs and nested PKCS7 blobs.
1105+
//
1106+
1107+
void _parse_pkcs7(
1108+
PE* pe,
1109+
PKCS7* pkcs7,
1110+
int* counter)
1111+
{
1112+
int i;
1113+
STACK_OF(X509)* certs;
1114+
certs = PKCS7_get0_signers(pkcs7, NULL, 0);
1115+
1116+
if (!certs)
1117+
{
1118+
return;
1119+
}
1120+
1121+
for (i = 0; i < sk_X509_num(certs); i++)
1122+
{
1123+
time_t date_time;
1124+
const char* sig_alg;
1125+
char buffer[256];
1126+
int bytes;
1127+
const EVP_MD* sha1_digest = EVP_sha1();
1128+
const unsigned char* p;
1129+
unsigned char thumbprint[YR_SHA1_LEN];
1130+
char thumbprint_ascii[YR_SHA1_LEN * 2 + 1];
1131+
1132+
PKCS7_SIGNER_INFO* signer_info;
1133+
ASN1_INTEGER* serial;
1134+
ASN1_TYPE* nested;
1135+
ASN1_STRING* value;
1136+
PKCS7* nested_pkcs7;
1137+
1138+
X509* cert = sk_X509_value(certs, i);
1139+
1140+
X509_digest(cert, sha1_digest, thumbprint, NULL);
1141+
1142+
for (i = 0; i < YR_SHA1_LEN; i++)
1143+
sprintf(thumbprint_ascii + (i * 2), "%02x", thumbprint[i]);
1144+
1145+
set_string(
1146+
(char*) thumbprint_ascii,
1147+
pe->object,
1148+
"signatures[%i].thumbprint",
1149+
*counter);
1150+
1151+
X509_NAME_oneline(
1152+
X509_get_issuer_name(cert), buffer, sizeof(buffer));
1153+
1154+
set_string(buffer, pe->object, "signatures[%i].issuer", *counter);
1155+
1156+
X509_NAME_oneline(
1157+
X509_get_subject_name(cert), buffer, sizeof(buffer));
1158+
1159+
set_string(buffer, pe->object, "signatures[%i].subject", *counter);
1160+
1161+
set_integer(
1162+
X509_get_version(cert) + 1, // Versions are zero based, so add one.
1163+
pe->object,
1164+
"signatures[%i].version", *counter);
1165+
1166+
sig_alg = OBJ_nid2ln(X509_get_signature_nid(cert));
1167+
1168+
set_string(sig_alg, pe->object, "signatures[%i].algorithm", *counter);
1169+
1170+
serial = X509_get_serialNumber(cert);
1171+
1172+
if (serial)
1173+
{
1174+
// ASN1_INTEGER can be negative (serial->type & V_ASN1_NEG_INTEGER),
1175+
// in which case the serial number will be stored in 2's complement.
1176+
//
1177+
// Handle negative serial numbers, which are technically not allowed
1178+
// by RFC5280, but do exist. An example binary which has a negative
1179+
// serial number is: 4bfe05f182aa273e113db6ed7dae4bb8.
1180+
//
1181+
// Negative serial numbers are handled by calling i2d_ASN1_INTEGER()
1182+
// with a NULL second parameter. This will return the size of the
1183+
// buffer necessary to store the proper serial number.
1184+
//
1185+
// Do this even for positive serial numbers because it makes the code
1186+
// cleaner and easier to read.
1187+
1188+
bytes = i2d_ASN1_INTEGER(serial, NULL);
1189+
1190+
// According to X.509 specification the maximum length for the
1191+
// serial number is 20 octets. Add two bytes to account for
1192+
// DER type and length information.
1193+
1194+
if (bytes > 2 && bytes <= 22)
1195+
{
1196+
// Now that we know the size of the serial number allocate enough
1197+
// space to hold it, and use i2d_ASN1_INTEGER() one last time to
1198+
// hold it in the allocated buffer.
1199+
1200+
unsigned char* serial_der = (unsigned char*) yr_malloc(bytes);
1201+
1202+
if (serial_der != NULL)
1203+
{
1204+
unsigned char* serial_bytes;
1205+
char *serial_ascii;
1206+
1207+
bytes = i2d_ASN1_INTEGER(serial, &serial_der);
1208+
1209+
// i2d_ASN1_INTEGER() moves the pointer as it writes into
1210+
// serial_bytes. Move it back.
1211+
1212+
serial_der -= bytes;
1213+
1214+
// Skip over DER type, length information
1215+
serial_bytes = serial_der + 2;
1216+
bytes -= 2;
1217+
1218+
// Also allocate space to hold the "common" string format:
1219+
// 00:01:02:03:04...
1220+
//
1221+
// For each byte in the serial to convert to hexlified format we
1222+
// need three bytes, two for the byte itself and one for colon.
1223+
// The last one doesn't have the colon, but the extra byte is used
1224+
// for the NULL terminator.
1225+
1226+
serial_ascii = (char*) yr_malloc(bytes * 3);
1227+
1228+
if (serial_ascii)
1229+
{
1230+
int j;
1231+
1232+
for (j = 0; j < bytes; j++)
1233+
{
1234+
// Don't put the colon on the last one.
1235+
if (j < bytes - 1)
1236+
snprintf(
1237+
serial_ascii + 3 * j, 4, "%02x:", serial_bytes[j]);
1238+
else
1239+
snprintf(
1240+
serial_ascii + 3 * j, 3, "%02x", serial_bytes[j]);
1241+
}
1242+
1243+
set_string(
1244+
serial_ascii,
1245+
pe->object,
1246+
"signatures[%i].serial",
1247+
*counter);
1248+
1249+
yr_free(serial_ascii);
1250+
}
1251+
1252+
yr_free(serial_der);
1253+
}
1254+
}
1255+
}
1256+
1257+
date_time = ASN1_get_time_t(X509_get_notBefore(cert));
1258+
set_integer(date_time, pe->object, "signatures[%i].not_before", *counter);
1259+
1260+
date_time = ASN1_get_time_t(X509_get_notAfter(cert));
1261+
set_integer(date_time, pe->object, "signatures[%i].not_after", *counter);
1262+
1263+
(*counter)++;
1264+
1265+
// See if there is a nested signature, which is apparently an authenticode
1266+
// specific feature. See https://github.com/VirusTotal/yara/issues/515.
1267+
signer_info = sk_PKCS7_SIGNER_INFO_value(pkcs7->d.sign->signer_info, 0);
1268+
if (signer_info == NULL)
1269+
continue;
1270+
nested = PKCS7_get_attribute(
1271+
signer_info, OBJ_txt2nid(SPC_NESTED_SIGNATURE_OBJID));
1272+
if (nested != NULL)
1273+
{
1274+
value = nested->value.sequence;
1275+
p = value->data;
1276+
nested_pkcs7 = d2i_PKCS7(NULL, &p, value->length);
1277+
if (nested_pkcs7 != NULL)
1278+
{
1279+
_parse_pkcs7(pe, nested_pkcs7, counter);
1280+
PKCS7_free(nested_pkcs7);
1281+
}
1282+
}
1283+
}
1284+
1285+
sk_X509_free(certs);
1286+
}
1287+
1288+
11031289
void pe_parse_certificates(
11041290
PE* pe)
11051291
{
1106-
int i, counter = 0;
1292+
int counter = 0;
11071293

11081294
const uint8_t* eod;
11091295
uintptr_t end;
@@ -1155,7 +1341,6 @@ void pe_parse_certificates(
11551341
{
11561342
BIO* cert_bio;
11571343
PKCS7* pkcs7;
1158-
STACK_OF(X509)* certs;
11591344

11601345
// Some sanity checks
11611346

@@ -1186,161 +1371,16 @@ void pe_parse_certificates(
11861371
break;
11871372

11881373
pkcs7 = d2i_PKCS7_bio(cert_bio, NULL);
1189-
certs = PKCS7_get0_signers(pkcs7, NULL, 0);
1190-
1191-
if (!certs)
1374+
if (pkcs7 != NULL)
11921375
{
1193-
BIO_free(cert_bio);
1376+
_parse_pkcs7(pe, pkcs7, &counter);
11941377
PKCS7_free(pkcs7);
1195-
break;
1196-
}
1197-
1198-
for (i = 0; i < sk_X509_num(certs); i++)
1199-
{
1200-
time_t date_time;
1201-
const char* sig_alg;
1202-
char buffer[256];
1203-
int bytes;
1204-
const EVP_MD* sha1_digest = EVP_sha1();
1205-
unsigned char thumbprint[YR_SHA1_LEN];
1206-
char thumbprint_ascii[YR_SHA1_LEN * 2 + 1];
1207-
1208-
ASN1_INTEGER* serial;
1209-
1210-
X509* cert = sk_X509_value(certs, i);
1211-
1212-
X509_digest(cert, sha1_digest, thumbprint, NULL);
1213-
1214-
for (i = 0; i < YR_SHA1_LEN; i++)
1215-
sprintf(thumbprint_ascii + (i * 2), "%02x", thumbprint[i]);
1216-
1217-
set_string(
1218-
(char*) thumbprint_ascii,
1219-
pe->object,
1220-
"signatures[%i].thumbprint",
1221-
counter);
1222-
1223-
X509_NAME_oneline(
1224-
X509_get_issuer_name(cert), buffer, sizeof(buffer));
1225-
1226-
set_string(buffer, pe->object, "signatures[%i].issuer", counter);
1227-
1228-
X509_NAME_oneline(
1229-
X509_get_subject_name(cert), buffer, sizeof(buffer));
1230-
1231-
set_string(buffer, pe->object, "signatures[%i].subject", counter);
1232-
1233-
set_integer(
1234-
X509_get_version(cert) + 1, // Versions are zero based, so add one.
1235-
pe->object,
1236-
"signatures[%i].version", counter);
1237-
1238-
sig_alg = OBJ_nid2ln(X509_get_signature_nid(cert));
1239-
1240-
set_string(sig_alg, pe->object, "signatures[%i].algorithm", counter);
1241-
1242-
serial = X509_get_serialNumber(cert);
1243-
1244-
if (serial)
1245-
{
1246-
// ASN1_INTEGER can be negative (serial->type & V_ASN1_NEG_INTEGER),
1247-
// in which case the serial number will be stored in 2's complement.
1248-
//
1249-
// Handle negative serial numbers, which are technically not allowed
1250-
// by RFC5280, but do exist. An example binary which has a negative
1251-
// serial number is: 4bfe05f182aa273e113db6ed7dae4bb8.
1252-
//
1253-
// Negative serial numbers are handled by calling i2d_ASN1_INTEGER()
1254-
// with a NULL second parameter. This will return the size of the
1255-
// buffer necessary to store the proper serial number.
1256-
//
1257-
// Do this even for positive serial numbers because it makes the code
1258-
// cleaner and easier to read.
1259-
1260-
bytes = i2d_ASN1_INTEGER(serial, NULL);
1261-
1262-
// According to X.509 specification the maximum length for the
1263-
// serial number is 20 octets. Add two bytes to account for
1264-
// DER type and length information.
1265-
1266-
if (bytes > 2 && bytes <= 22)
1267-
{
1268-
// Now that we know the size of the serial number allocate enough
1269-
// space to hold it, and use i2d_ASN1_INTEGER() one last time to
1270-
// hold it in the allocated buffer.
1271-
1272-
unsigned char* serial_der = (unsigned char*) yr_malloc(bytes);
1273-
1274-
if (serial_der != NULL)
1275-
{
1276-
unsigned char* serial_bytes;
1277-
char *serial_ascii;
1278-
1279-
bytes = i2d_ASN1_INTEGER(serial, &serial_der);
1280-
1281-
// i2d_ASN1_INTEGER() moves the pointer as it writes into
1282-
// serial_bytes. Move it back.
1283-
1284-
serial_der -= bytes;
1285-
1286-
// Skip over DER type, length information
1287-
serial_bytes = serial_der + 2;
1288-
bytes -= 2;
1289-
1290-
// Also allocate space to hold the "common" string format:
1291-
// 00:01:02:03:04...
1292-
//
1293-
// For each byte in the serial to convert to hexlified format we
1294-
// need three bytes, two for the byte itself and one for colon.
1295-
// The last one doesn't have the colon, but the extra byte is used
1296-
// for the NULL terminator.
1297-
1298-
serial_ascii = (char*) yr_malloc(bytes * 3);
1299-
1300-
if (serial_ascii)
1301-
{
1302-
int j;
1303-
1304-
for (j = 0; j < bytes; j++)
1305-
{
1306-
// Don't put the colon on the last one.
1307-
if (j < bytes - 1)
1308-
snprintf(
1309-
serial_ascii + 3 * j, 4, "%02x:", serial_bytes[j]);
1310-
else
1311-
snprintf(
1312-
serial_ascii + 3 * j, 3, "%02x", serial_bytes[j]);
1313-
}
1314-
1315-
set_string(
1316-
serial_ascii,
1317-
pe->object,
1318-
"signatures[%i].serial",
1319-
counter);
1320-
1321-
yr_free(serial_ascii);
1322-
}
1323-
1324-
yr_free(serial_der);
1325-
}
1326-
}
1327-
}
1328-
1329-
date_time = ASN1_get_time_t(X509_get_notBefore(cert));
1330-
set_integer(date_time, pe->object, "signatures[%i].not_before", counter);
1331-
1332-
date_time = ASN1_get_time_t(X509_get_notAfter(cert));
1333-
set_integer(date_time, pe->object, "signatures[%i].not_after", counter);
1334-
1335-
counter++;
13361378
}
13371379

13381380
end = (uintptr_t)((uint8_t *) win_cert) + yr_le32toh(win_cert->Length);
13391381
win_cert = (PWIN_CERTIFICATE)(end + (end % 8));
13401382

13411383
BIO_free(cert_bio);
1342-
PKCS7_free(pkcs7);
1343-
sk_X509_free(certs);
13441384
}
13451385

13461386
set_integer(counter, pe->object, "number_of_signatures");
@@ -2597,6 +2637,11 @@ end_declarations;
25972637
int module_initialize(
25982638
YR_MODULE* module)
25992639
{
2640+
#if defined(HAVE_LIBCRYPTO)
2641+
// Not checking return value here because if it fails we will not parse the
2642+
// nested signature silently.
2643+
OBJ_create(SPC_NESTED_SIGNATURE_OBJID, NULL, NULL);
2644+
#endif
26002645
return ERROR_SUCCESS;
26012646
}
26022647

0 commit comments

Comments
 (0)