[Forensics-changes] [yara] 166/407: Implement overloaded not_before() and not_after().
Hilko Bengen
bengen at moszumanska.debian.org
Sat Jul 1 10:28:22 UTC 2017
This is an automated email from the git hooks/post-receive script.
bengen pushed a commit to annotated tag v3.3.0
in repository yara.
commit 92141933395fa236d2bbeccb125763a552100342
Author: Wesley Shields <wxs at atarininja.org>
Date: Thu Oct 30 00:36:24 2014 -0400
Implement overloaded not_before() and not_after().
not_before() and not_after() are now functions, instead of strings.
If given a string as a argument they will perform an exact match against all
certificates using ASN1_TIME_print() as before. If given an integer they will
call X509_cmp_time() to compare against all values.
When given an integer not_before() will return true if the timestamp in the
integer is equal to or later than the notBefore attribute of any of the
certificates.
When given an integer not_after() will return true if the timestamp is
"before" (not inclusive) the notAfter attribute of any of the certificates.
There is still a problem with functions in an array of structures if not
scanning a PE file. I still have to debug that.
---
libyara/modules/pe.c | 213 +++++++++++++++++++++++++++++++++++++++------------
1 file changed, 162 insertions(+), 51 deletions(-)
diff --git a/libyara/modules/pe.c b/libyara/modules/pe.c
index 49c06f4..4f0baa6 100644
--- a/libyara/modules/pe.c
+++ b/libyara/modules/pe.c
@@ -2369,7 +2369,7 @@ PX509_TIMESTAMPS pe_parse_certificates(
PWIN_CERTIFICATE win_cert;
PX509_TIMESTAMPS head = NULL;
PX509_TIMESTAMPS tail = NULL;
- BIO *date_bio, *cert_bio = NULL;
+ BIO *cert_bio = NULL;
PKCS7 *p7;
X509 *cert;
int i, j, counter = 0;
@@ -2377,7 +2377,6 @@ PX509_TIMESTAMPS pe_parse_certificates(
uint8_t *eod; // End of directory.
char *p;
const char *sig_alg;
- unsigned long date_length;
ASN1_INTEGER *serial;
ASN1_TIME *date_time;
STACK_OF(X509) *certs;
@@ -2472,63 +2471,22 @@ PX509_TIMESTAMPS pe_parse_certificates(
yr_free(p);
}
- //
- // Use a single BIO for notBefore and notAfter. Saves from having
- // to allocate multiple BIOs. Just have to track how much is written
- // each time.
- //
- date_bio = BIO_new(BIO_s_mem());
- if (!date_bio)
- break;
- date_time = X509_get_notBefore(cert);
- ASN1_TIME_print(date_bio, date_time);
- // Use num_write to get the number of bytes available for reading.
- p = (char *) yr_malloc(date_bio->num_write + 1);
- if (!p)
- {
- BIO_set_close(date_bio, BIO_CLOSE);
- BIO_free(date_bio);
- break;
- }
- BIO_read(date_bio, p, date_bio->num_write);
- p[date_bio->num_write] = '\x0';
- set_string(p, pe->object, "signatures[%i].not_before", counter);
- yr_free(p);
- // Store the ASN1_TIME structure in a list.
+ // Store the ASN1_TIME structures in a list.
PX509_TIMESTAMPS x509_timestamp = (PX509_TIMESTAMPS)
yr_calloc(1, sizeof(X509_TIMESTAMPS));
if (!x509_timestamp)
break;
- x509_timestamp->not_before = date_time;
if (head == NULL)
head = x509_timestamp;
if (tail != NULL)
tail->next = x509_timestamp;
tail = x509_timestamp;
- // Do the same for notAfter.
+ date_time = X509_get_notBefore(cert);
+ x509_timestamp->not_before = date_time;
date_time = X509_get_notAfter(cert);
- ASN1_TIME_print(date_bio, date_time);
- // How much is written the second time?
- date_length = date_bio->num_write - date_bio->num_read;
- if (date_length != 0)
- {
- p = (char *) yr_malloc(date_length + 1);
- if (!p)
- {
- BIO_set_close(date_bio, BIO_CLOSE);
- BIO_free(date_bio);
- break;
- }
- BIO_read(date_bio, p, date_length);
- p[date_length] = '\x0';
- set_string(p, pe->object, "signatures[%i].not_after", counter);
- yr_free(p);
- // Store the ASN1_TIME structure in a list.
- x509_timestamp->not_after = date_time;
- }
- BIO_set_close(date_bio, BIO_CLOSE);
- BIO_free(date_bio);
+ x509_timestamp->not_after = date_time;
+
counter++;
}
end = (uintptr_t) ((uint8_t *) win_cert) + win_cert->Length;
@@ -2665,6 +2623,157 @@ void pe_parse_header(
}
}
+// Given a string, see if any of the stored notBefore matches, exactly.
+define_function(not_before_string)
+{
+ char *p;
+ BIO* date_bio;
+ X509_TIMESTAMPS* x509_timestamp;
+ SIZED_STRING* not_before = string_argument(1);
+ YR_OBJECT* module = module();
+ PE* pe = (PE*) module->data;
+
+ x509_timestamp = pe->x509_timestamps;
+ while (x509_timestamp)
+ {
+ date_bio = BIO_new(BIO_s_mem());
+ if (!date_bio)
+ break;
+ ASN1_TIME_print(date_bio, x509_timestamp->not_before);
+ // Use num_write to get the number of bytes available for reading.
+ p = (char *) yr_malloc(date_bio->num_write + 1);
+ if (!p)
+ {
+ BIO_set_close(date_bio, BIO_CLOSE);
+ BIO_free(date_bio);
+ break;
+ }
+ BIO_read(date_bio, p, date_bio->num_write);
+ p[date_bio->num_write] = '\x0';
+ BIO_set_close(date_bio, BIO_CLOSE);
+ BIO_free(date_bio);
+ if (strcasecmp(p, not_before->c_string) == 0)
+ {
+ yr_free(p);
+ return_integer(1);
+ }
+ yr_free(p);
+
+ x509_timestamp = x509_timestamp->next;
+ }
+
+ return_integer(0);
+}
+
+
+//
+// Given an integer argument return 1 if any of the stored notBefore values
+// come "after" it. For example, to find a binary with a notBefore in 2014
+// or later you can use 1388534400, which is Wed Jan 1 00:00:00 UTC 2014.
+//
+// Note that the comparison is inclusive. So if it is an exact match this
+// function will return 1. This is due to how X509_cmp_time() works. :(
+//
+// Looks like X509_cmp_time returns:
+// 0 on failure
+// 1 if the second argument is "before" the first.
+// A negative number if the second argument is "after" the first.
+// If the timestamps are identical -1 is returned.
+//
+define_function(not_before_integer)
+{
+ X509_TIMESTAMPS* x509_timestamp;
+ time_t time = (time_t) integer_argument(1);
+ YR_OBJECT* module = module();
+ PE* pe = (PE*) module->data;
+ x509_timestamp = pe->x509_timestamps;
+
+ while (x509_timestamp)
+ {
+ if (X509_cmp_time(x509_timestamp->not_before, &time) < 0)
+ return_integer(1);
+ x509_timestamp = x509_timestamp->next;
+ }
+
+ return_integer(0);
+}
+
+
+// Given a string, see if any of the stored notAfter matches, exactly.
+define_function(not_after_string)
+{
+ char *p;
+ BIO* date_bio;
+ X509_TIMESTAMPS* x509_timestamp;
+ SIZED_STRING* not_after = string_argument(1);
+ YR_OBJECT* module = module();
+ PE* pe = (PE*) module->data;
+
+ x509_timestamp = pe->x509_timestamps;
+ while (x509_timestamp)
+ {
+ date_bio = BIO_new(BIO_s_mem());
+ if (!date_bio)
+ break;
+ ASN1_TIME_print(date_bio, x509_timestamp->not_after);
+ // Use num_write to get the number of bytes available for reading.
+ p = (char *) yr_malloc(date_bio->num_write + 1);
+ if (!p)
+ {
+ BIO_set_close(date_bio, BIO_CLOSE);
+ BIO_free(date_bio);
+ break;
+ }
+ BIO_read(date_bio, p, date_bio->num_write);
+ p[date_bio->num_write] = '\x0';
+ BIO_set_close(date_bio, BIO_CLOSE);
+ BIO_free(date_bio);
+ if (strcasecmp(p, not_after->c_string) == 0)
+ {
+ yr_free(p);
+ return_integer(1);
+ }
+ yr_free(p);
+
+ x509_timestamp = x509_timestamp->next;
+ }
+
+ return_integer(0);
+}
+
+
+//
+// Given an integer argument return 1 if any of the stored notAfter values
+// come "before" it. For example, to find a binary with a notAfter in 2014
+// or later you can use 1388534399, which is Tue, 31 Dec 2013 23:59:59 GMT.
+//
+// Note that the comparison is not inclusive. So if it is an exact match this
+// function will still return 0. This is due to how X509_cmp_time() works. :(
+//
+// Looks like X509_cmp_time returns:
+// 0 on failure
+// 1 if the second argument is "before" the first.
+// A negative number if the second argument is "after" the first.
+// If the timestamps are identical -1 is returned.
+//
+define_function(not_after_integer)
+{
+ X509_TIMESTAMPS* x509_timestamp;
+ time_t time = (time_t) integer_argument(1);
+ YR_OBJECT* module = module();
+ PE* pe = (PE*) module->data;
+ x509_timestamp = pe->x509_timestamps;
+
+ while (x509_timestamp)
+ {
+ if (X509_cmp_time(x509_timestamp->not_after, &time) == 1)
+ return_integer(1);
+ x509_timestamp = x509_timestamp->next;
+ }
+
+ return_integer(0);
+}
+
define_function(section_index)
{
@@ -3078,7 +3187,6 @@ begin_declarations;
declare_integer("raw_data_size");
end_struct_array("sections");
-
begin_struct("rich_signature");
declare_integer("start");
declare_integer("key");
@@ -3099,14 +3207,17 @@ begin_declarations;
declare_function("locale", "i", "i", locale);
declare_function("language", "i", "i", language);
+// XXX: Wrap in HAVE_LIBCRYPTO
begin_struct_array("signatures");
declare_string("issuer");
declare_string("subject");
declare_integer("version");
declare_string("algorithm");
declare_string("serial");
- declare_string("not_before");
- declare_string("not_after");
+ declare_function("not_before", "s", "i", not_before_string);
+ declare_function("not_before", "i", "i", not_before_integer);
+ declare_function("not_after", "s", "i", not_after_string);
+ declare_function("not_after", "i", "i", not_after_integer);
end_struct_array("signatures");
declare_integer("number_of_signatures");
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/forensics/yara.git
More information about the forensics-changes
mailing list