...

Source file src/github.com/sassoftware/relic/lib/authenticode/checksum.go

Documentation: github.com/sassoftware/relic/lib/authenticode

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package authenticode
    18  
    19  import (
    20  	"encoding/binary"
    21  	"errors"
    22  	"hash"
    23  	"io"
    24  	"os"
    25  )
    26  
    27  // An undocumented, non-CRC checksum used in PE images
    28  // https://www.codeproject.com/Articles/19326/An-Analysis-of-the-Windows-PE-Checksum-Algorithm
    29  
    30  func FixPEChecksum(f *os.File) error {
    31  	if _, err := f.Seek(0, 0); err != nil {
    32  		return err
    33  	}
    34  	peStart, err := readDosHeader(f, nil)
    35  	if err != nil {
    36  		return err
    37  	}
    38  	ck := NewPEChecksum(int(peStart))
    39  	if _, err := f.Seek(0, 0); err != nil {
    40  		return err
    41  	}
    42  	if _, err := io.Copy(ck, f); err != nil {
    43  		return err
    44  	}
    45  	if _, err := f.WriteAt(ck.Sum(nil), peStart+88); err != nil {
    46  		return err
    47  	}
    48  	return nil
    49  }
    50  
    51  type peChecksum struct {
    52  	cksumPos  int
    53  	sum, size uint32
    54  	odd       bool
    55  }
    56  
    57  // Hasher that calculates the undocumented, non-CRC checksum used in PE images.
    58  // peStart is the offset found at 0x3c in the DOS header.
    59  func NewPEChecksum(peStart int) hash.Hash {
    60  	var cksumPos int
    61  	if peStart <= 0 {
    62  		cksumPos = -1
    63  	} else {
    64  		cksumPos = peStart + 88
    65  	}
    66  	return &peChecksum{cksumPos: cksumPos}
    67  }
    68  
    69  func (peChecksum) Size() int {
    70  	return 4
    71  }
    72  
    73  func (peChecksum) BlockSize() int {
    74  	return 2
    75  }
    76  
    77  func (h *peChecksum) Reset() {
    78  	h.cksumPos = -1
    79  	h.sum = 0
    80  	h.size = 0
    81  }
    82  
    83  func (h *peChecksum) Write(d []byte) (int, error) {
    84  	// tolerate odd-sized files by adding a final zero byte, but odd writes anywhere but the end are an error
    85  	n := len(d)
    86  	if h.odd {
    87  		return 0, errors.New("odd write")
    88  	} else if n%2 != 0 {
    89  		h.odd = true
    90  		d2 := make([]byte, n+1)
    91  		copy(d2, d)
    92  		d = d2
    93  	}
    94  	ckpos := -1
    95  	if h.cksumPos > n {
    96  		h.cksumPos -= n
    97  	} else if h.cksumPos >= 0 {
    98  		ckpos = h.cksumPos
    99  		h.cksumPos = -1
   100  	}
   101  	sum := h.sum
   102  	for i := 0; i < n; i += 2 {
   103  		val := uint32(d[i+1])<<8 | uint32(d[i])
   104  		if i == ckpos || i == ckpos+2 {
   105  			val = 0
   106  		}
   107  		sum += val
   108  		sum = 0xffff & (sum + (sum >> 16))
   109  	}
   110  	h.sum = sum
   111  	h.size += uint32(n)
   112  	return n, nil
   113  }
   114  
   115  func (h *peChecksum) Sum(buf []byte) []byte {
   116  	sum := h.sum
   117  	sum = 0xffff & (sum + (sum >> 16))
   118  	sum += h.size
   119  	d := make([]byte, 4)
   120  	binary.LittleEndian.PutUint32(d, sum)
   121  	return append(buf, d...)
   122  }
   123  

View as plain text