authenticode.js new computes the new checksum on sign/unsign.
Ylian Saint-Hilaire committed
Jun 8, 2022 at 00:27 UTC
f5f4305841a5cde548f25b0e2aadd524bbc2d28c
1 file changed
+90
-11
authenticode.js
+90
-11
@@ -244,9 +244,6 @@ function createAuthenticodeHandler(path) {
244
obj.header.siglen = obj.header.dataDirectories.certificateTable.size
245
obj.header.signed = ((obj.header.sigpos != 0) && (obj.header.siglen != 0));
246
247
- // Compute the checkSum value for this file
248
- obj.header.peWindows.checkSumActual = getChecksum(readFileSlice(0, obj.filesize));
249
-
247
// The section headers are located after the optional PE header
248
obj.header.SectionHeadersPtr = obj.header.peOptionalHeaderLocation + obj.header.coff.sizeOfOptionalHeader;
249
@@ -272,6 +269,9 @@ function createAuthenticodeHandler(path) {
269
obj.header.sections[sectionName] = section;
270
}
271
272
+ // Compute the checkSum value for this file
273
+ obj.header.peWindows.checkSumActual = runChecksum();
274
+
275
// If there is a .rsrc section, read the resource information and locations
276
if (obj.header.sections['.rsrc'] != null) {
277
obj.resources = readResourceTable(obj.header.sections['.rsrc'].rawAddr, 0); // Read all resources recursively
@@ -742,18 +742,85 @@ function createAuthenticodeHandler(path) {
742
while (ptr < end) { const buf = readFileSlice(ptr, Math.min(65536, end - ptr)); hash.update(buf); ptr += buf.length; }
743
}
744
745
+ // Checksum the file loading 64k chunks
746
+ function runChecksum() {
747
+ var ptr = 0, c = createChecksum();
748
+ while (ptr < obj.filesize) { const buf = readFileSlice(ptr, Math.min(65536, obj.filesize - ptr)); c.update(buf); ptr += buf.length; }
749
+ return c.digest();
750
+ }
751
+
752
+ // Checksum the open file loading 64k chunks
753
+ function runChecksumOnFile(fd, filesize) {
754
+ var ptr = 0, c = createChecksum(), buf = Buffer.alloc(65536);
755
+ while (ptr < filesize) { var len = fs.readSync(fd, buf, 0, Math.min(65536, filesize - ptr), ptr); c.update(buf, len); ptr += len; }
756
+ return c.digest();
757
+ }
758
+
759
+ // Steaming checksum methods
760
+ // TODO: Works only with files padded to 4 byte.
761
+ function createChecksum() {
762
+ const obj = { checksum: 0, length: 0 };
763
+ obj.update = function (data, len) {
764
+ if (!len) { len = data.length; }
765
+ for (var i = 0; i < (len / 4) ; i++) {
766
+ if (((obj.length / 4) + i) == 54) continue; // Skip PE checksum location
767
+ const dword = data.readUInt32LE(i * 4);
768
+ var checksumlo = (obj.checksum > 4294967296) ? (obj.checksum - 4294967296) : obj.checksum;
769
+ var checksumhi = (obj.checksum > 4294967296) ? 1 : 0;
770
+ obj.checksum = checksumlo + dword + checksumhi;
771
+ if (obj.checksum > 4294967296) {
772
+ checksumlo = (obj.checksum > 4294967296) ? (obj.checksum - 4294967296) : obj.checksum;
773
+ checksumhi = (obj.checksum > 4294967296) ? 1 : 0;
774
+ obj.checksum = checksumlo + checksumhi;
775
+ }
776
+ }
777
+ obj.length += len;
778
+ }
779
+ obj.digest = function () {
780
+ obj.checksum = (obj.checksum & 0xffff) + (obj.checksum >>> 16);
781
+ obj.checksum = (obj.checksum) + (obj.checksum >>> 16);
782
+ obj.checksum = obj.checksum & 0xffff;
783
+ obj.checksum += obj.length;
784
+ return obj.checksum;
785
+ }
786
+ return obj;
787
+ }
788
+
789
+ // Simple checksum method that works on a complete file at once
790
+ // TODO: Works only with files padded to 4 byte.
791
+ function updateChecksum(data) {
792
+ var checksum = 0;
793
+ for (var i = 0; i < (data.length / 4) ; i++) {
794
+ if (i == 54) continue; // Skip PE checksum location
795
+ var dword = data.readUInt32LE(i * 4);
796
+ var checksumlo = (checksum > 4294967296) ? (checksum - 4294967296) : checksum;
797
+ var checksumhi = (checksum > 4294967296) ? 1 : 0;
798
+ checksum = checksumlo + dword + checksumhi;
799
+ if (checksum > 4294967296) {
800
+ checksumlo = (checksum > 4294967296) ? (checksum - 4294967296) : checksum;
801
+ checksumhi = (checksum > 4294967296) ? 1 : 0;
802
+ checksum = checksumlo + checksumhi;
803
+ }
804
+ }
805
+ checksum = (checksum & 0xffff) + (checksum >>> 16);
806
+ checksum = (checksum) + (checksum >>> 16);
807
+ checksum = checksum & 0xffff;
808
+ checksum += data.length;
809
+ return checksum;
810
+ }
811
+
812
// Compute the PE checksum of an entire file
813
function getChecksum(data) {
747
- var checksum = 0, top = Math.pow(2, 32);
814
+ var checksum = 0;
815
for (var i = 0; i < (data.length / 4) ; i++) {
816
if (i == 54) continue; // Skip PE checksum location
817
var dword = data.readUInt32LE(i * 4);
751
- var checksumlo = (checksum > top) ? (checksum - top) : checksum;
752
- var checksumhi = (checksum > top) ? 1 : 0;
818
+ var checksumlo = (checksum > 4294967296) ? (checksum - 4294967296) : checksum;
819
+ var checksumhi = (checksum > 4294967296) ? 1 : 0;
820
checksum = checksumlo + dword + checksumhi;
754
- if (checksum > top) {
755
- checksumlo = (checksum > top) ? (checksum - top) : checksum;
756
- checksumhi = (checksum > top) ? 1 : 0;
821
+ if (checksum > 4294967296) {
822
+ checksumlo = (checksum > 4294967296) ? (checksum - 4294967296) : checksum;
823
+ checksumhi = (checksum > 4294967296) ? 1 : 0;
824
checksum = checksumlo + checksumhi;
825
}
826
}
@@ -816,7 +883,7 @@ function createAuthenticodeHandler(path) {
883
884
// Open the output file
885
var output = null;
819
- try { output = fs.openSync(args.out, 'w'); } catch (ex) { }
886
+ try { output = fs.openSync(args.out, 'w+'); } catch (ex) { }
887
if (output == null) return false;
888
var tmp, written = 0;
889
var executableSize = obj.header.sigpos ? obj.header.sigpos : this.filesize;
@@ -853,6 +920,12 @@ function createAuthenticodeHandler(path) {
920
fs.writeSync(output, win);
921
fs.writeSync(output, p7signature);
922
if (padding > 0) { fs.writeSync(output, Buffer.alloc(padding, 0)); }
923
+ written += p7signature.length + padding + 8;
924
+
925
+ // Compute the checksum and write it in the PE header at position (54 * 4)
926
+ var tmp = Buffer.alloc(4);
927
+ tmp.writeUInt32LE(runChecksumOnFile(output, written));
928
+ fs.writeSync(output, tmp, 0, 4, 54 * 4);
929
930
// Close the file
931
fs.closeSync(output);
@@ -862,7 +935,7 @@ function createAuthenticodeHandler(path) {
935
// Save an executable without the signature
936
obj.unsign = function (args) {
937
// Open the file
865
- var output = fs.openSync(args.out, 'w');
938
+ var output = fs.openSync(args.out, 'w+');
939
var written = 0, totalWrite = obj.header.sigpos;
940
941
// Compute pre-header length and copy that to the new file
@@ -881,6 +954,12 @@ function createAuthenticodeHandler(path) {
954
fs.writeSync(output, tmp);
955
written += tmp.length;
956
}
957
+
958
+ // Compute the checksum and write it in the PE header at position (54 * 4)
959
+ var tmp = Buffer.alloc(4);
960
+ tmp.writeUInt32LE(runChecksumOnFile(output, written));
961
+ fs.writeSync(output, tmp, 0, 4, 54 * 4);
962
+
963
fs.closeSync(output);
964
}
965