boxxx: Add update API
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"debug/pe"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
const (
|
||||
peSecurityDirectoryIndex = 4
|
||||
nsisFirstHeaderSize = 28
|
||||
nsisSignature = 0xDEADBEEF
|
||||
nsisIdentity = "NullsoftInst"
|
||||
nsisMaximumAlignmentTail = 8
|
||||
)
|
||||
|
||||
func validateNSISExecutable(path string) error {
|
||||
executable, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer executable.Close()
|
||||
information, err := executable.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
peFile, err := pe.NewFile(executable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer peFile.Close()
|
||||
var overlayOffset uint64
|
||||
for _, section := range peFile.Sections {
|
||||
sectionEnd := uint64(section.Offset) + uint64(section.Size)
|
||||
if sectionEnd > overlayOffset {
|
||||
overlayOffset = sectionEnd
|
||||
}
|
||||
}
|
||||
contentEnd := uint64(information.Size())
|
||||
var securityOffset uint64
|
||||
switch optionalHeader := peFile.OptionalHeader.(type) {
|
||||
case *pe.OptionalHeader32:
|
||||
securityOffset = uint64(optionalHeader.DataDirectory[peSecurityDirectoryIndex].VirtualAddress)
|
||||
case *pe.OptionalHeader64:
|
||||
securityOffset = uint64(optionalHeader.DataDirectory[peSecurityDirectoryIndex].VirtualAddress)
|
||||
}
|
||||
if securityOffset != 0 {
|
||||
if securityOffset > contentEnd {
|
||||
return E.New("invalid Authenticode directory offset")
|
||||
}
|
||||
contentEnd = securityOffset
|
||||
}
|
||||
if overlayOffset+nsisFirstHeaderSize > contentEnd {
|
||||
return E.New("missing NSIS first header")
|
||||
}
|
||||
firstHeader := make([]byte, nsisFirstHeaderSize)
|
||||
_, err = executable.ReadAt(firstHeader, int64(overlayOffset))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if binary.LittleEndian.Uint32(firstHeader[4:8]) != nsisSignature || string(firstHeader[8:20]) != nsisIdentity {
|
||||
return E.New("invalid NSIS first header signature")
|
||||
}
|
||||
headerSize := uint64(binary.LittleEndian.Uint32(firstHeader[20:24]))
|
||||
archiveSize := uint64(binary.LittleEndian.Uint32(firstHeader[24:28]))
|
||||
if headerSize < nsisFirstHeaderSize || archiveSize < headerSize || overlayOffset+archiveSize > contentEnd {
|
||||
return E.New("invalid NSIS archive size")
|
||||
}
|
||||
if contentEnd-(overlayOffset+archiveSize) > nsisMaximumAlignmentTail {
|
||||
return E.New("unexpected data after NSIS archive")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user