Browse code

Ignore section information when computing Authenticode sig A more reliable way to calculate the authenticode hash appears to be to hash the header (minus the checksum and security table) and then just hash everything between the end of the header and the start of the security section.

Andrew authored on 2018/09/05 12:54:32
Showing 1 changed files
... ...
@@ -5607,7 +5607,7 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1, stats_section_t *hashes, uin
5607 5607
     }
5608 5608
     nregions = 0;
5609 5609
 
5610
-#define hash_chunk(where, _size, isStatAble, section) \
5610
+#define hash_chunk(where, _size) \
5611 5611
     do { \
5612 5612
         const uint8_t *hptr; \
5613 5613
         if(!(_size)) break; \
... ...
@@ -5621,21 +5621,13 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1, stats_section_t *hashes, uin
5621 5621
             regions[nregions].size = _size; \
5622 5622
             nregions++; \
5623 5623
         } \
5624
-        if (isStatAble && flags & CL_CHECKFP_PE_FLAG_STATS) { \
5625
-            void *md5ctx; \
5626
-            md5ctx = cl_hash_init("md5"); \
5627
-            if (md5ctx) { \
5628
-                cl_update_hash(md5ctx, (void *)hptr, _size); \
5629
-                cl_finish_hash(md5ctx, hashes->sections[section].md5); \
5630
-            } \
5631
-        } \
5632 5624
     } while(0)
5633 5625
 
5634 5626
     while (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE) {
5635 5627
         /* MZ to checksum */
5636 5628
         at = 0;
5637 5629
         hlen = e_lfanew + sizeof(struct pe_image_file_hdr) + (pe_plus ? offsetof(struct pe_image_optional_hdr64, CheckSum) : offsetof(struct pe_image_optional_hdr32, CheckSum));
5638
-        hash_chunk(0, hlen, 0, 0);
5630
+        hash_chunk(0, hlen);
5639 5631
         at = hlen + 4;
5640 5632
 
5641 5633
         /* Checksum to security */
... ...
@@ -5643,7 +5635,7 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1, stats_section_t *hashes, uin
5643 5643
             hlen = offsetof(struct pe_image_optional_hdr64, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr64, CheckSum) - 4;
5644 5644
         else
5645 5645
             hlen = offsetof(struct pe_image_optional_hdr32, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4;
5646
-        hash_chunk(at, hlen, 0, 0);
5646
+        hash_chunk(at, hlen);
5647 5647
         at += hlen + 8;
5648 5648
 
5649 5649
         if(at > hdr_size) {
... ...
@@ -5659,53 +5651,44 @@ int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1, stats_section_t *hashes, uin
5659 5659
 
5660 5660
         /* Security to End of header */
5661 5661
         hlen = hdr_size - at;
5662
-        hash_chunk(at, hlen, 0, 0);
5662
+        hash_chunk(at, hlen);
5663 5663
         at += hlen;
5664 5664
         break;
5665 5665
     }
5666 5666
 
5667 5667
     /* Hash the sections */
5668
-    for(i = 0; i < nsections; i++) {
5669
-        if(!exe_sections[i].rsz)
5670
-            continue;
5671
-
5672
-        hash_chunk(exe_sections[i].raw, exe_sections[i].rsz, 1, i);
5673
-
5674
-        /* If the section overlaps with the header (the case for UPX binaries)
5675
-         * adjust the entry in the authenticode hash regions list to account
5676
-         * for the fact that we've already accounted for computing the hash
5677
-         * over the header */
5678
-        if (exe_sections[i].raw < at)
5679
-        {
5680
-            uint32_t overlap_size = (at - exe_sections[i].raw);
5681
-            if (overlap_size >= exe_sections[i].rsz) {
5682
-                /* The section completely overlaps the header.  Setting the
5683
-                 * size to zero should prevent this section from affecting
5684
-                 * the actual Authenticode hash computation. */
5685
-                regions[nregions-1].size = 0;
5686
-            } else {
5687
-                regions[nregions-1].size -= overlap_size;
5688
-                regions[nregions-1].ptr += overlap_size;
5668
+    if (flags & CL_CHECKFP_PE_FLAG_STATS) {
5669
+
5670
+        for(i = 0; i < nsections; i++) {
5671
+            const uint8_t *hptr;
5672
+            void *md5ctx;
5673
+
5674
+            if(!exe_sections[i].rsz)
5675
+                continue;
5676
+
5677
+            if(!(hptr = fmap_need_off_once(map, exe_sections[i].raw, exe_sections[i].rsz))){
5678
+                free(exe_sections);
5679
+                free(regions);
5680
+                return CL_EFORMAT;
5681
+            }
5682
+            md5ctx = cl_hash_init("md5");
5683
+            if (md5ctx) {
5684
+                cl_update_hash(md5ctx, (void *)hptr, exe_sections[i].rsz);
5685
+                cl_finish_hash(md5ctx, hashes->sections[i].md5);
5689 5686
             }
5690 5687
         }
5691 5688
     }
5692 5689
 
5693
-    /* Finally, if there is data after the section with the highest
5694
-     * PointerToRawData, hash that too.  This is a variation of what
5695
-     * the 2008 spec doc says to do (add up all the SizeOfRawData's and
5696
-     * start hashing at that point after the PE header), but should also
5697
-     * work in the case where a binary has overlapping sections or a section
5698
-     * overlaps the PE header (barring some edge cases like a section
5699
-     * fully containing another section with a higher starting addr.)
5690
+    free(exe_sections);
5691
+
5692
+    /* Finally, hash everything from the end of the header to the start of
5693
+     * the security section, which must be the last thing in a file
5700 5694
      */
5701
-    at = exe_sections[nsections-1].raw + exe_sections[nsections-1].rsz;
5702 5695
     if (at < EC32(dirs[4].VirtualAddress)) {
5703 5696
         hlen = EC32(dirs[4].VirtualAddress)-at;
5704
-        hash_chunk(at, hlen, 0, 0);
5697
+        hash_chunk(at, hlen);
5705 5698
     }
5706 5699
 
5707
-    free(exe_sections);
5708
-
5709 5700
     if (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE) {
5710 5701
 
5711 5702
         hlen = EC32(dirs[4].Size);