| 82 | var primeUpdateNeedle = []byte("P\x00r\x00i\x00m\x00e\x00U\x00p\x00d\x00a\x00t\x00e\x00") |
| 83 | |
| 84 | func scanFeatureSet(f *pe.File, data []byte) (string, error) { |
| 85 | var rdataSect *pe.Section |
| 86 | for i := range f.Sections { |
| 87 | if strings.HasPrefix(f.Sections[i].String(), ".rdata") { |
| 88 | rdataSect = &f.Sections[i] |
| 89 | break |
| 90 | } |
| 91 | } |
| 92 | if rdataSect == nil { |
| 93 | return "", fmt.Errorf("no .rdata section") |
| 94 | } |
| 95 | start := int(rdataSect.Header.PointerToRawData) |
| 96 | rdata := data[start : start+int(rdataSect.Header.SizeOfRawData)] |
| 97 | |
| 98 | type update struct { |
| 99 | major uint64 |
| 100 | suffix string |
| 101 | full string |
| 102 | } |
| 103 | seen := make(map[[2]string]bool) |
| 104 | var updates []update |
| 105 | |
| 106 | for offset := 0; offset+len(primeUpdateNeedle) <= len(rdata); { |
| 107 | pos := bytes.Index(rdata[offset:], primeUpdateNeedle) |
| 108 | if pos < 0 { |
| 109 | break |
| 110 | } |
| 111 | absPos := offset + pos |
| 112 | offset = absPos + 1 |
| 113 | if absPos%2 != 0 { |
| 114 | continue |
| 115 | } |
| 116 | |
| 117 | rest := rdata[absPos+len(primeUpdateNeedle):] |
| 118 | var chars []uint16 |
| 119 | for i := 0; i+1 < len(rest); i += 2 { |
| 120 | c := binary.LittleEndian.Uint16(rest[i:]) |
| 121 | if c <= 0x20 { |
| 122 | break |
| 123 | } |
| 124 | chars = append(chars, c) |
| 125 | } |
| 126 | if len(chars) == 0 { |
| 127 | continue |
| 128 | } |
| 129 | tail := string(utf16.Decode(chars)) |
| 130 | |
| 131 | digitEnd := 0 |
| 132 | for digitEnd < len(tail) && tail[digitEnd] >= '0' && tail[digitEnd] <= '9' { |
| 133 | digitEnd++ |
| 134 | } |
| 135 | if digitEnd == 0 { |
| 136 | continue |
| 137 | } |
| 138 | var major uint64 |
| 139 | for _, ch := range tail[:digitEnd] { |
| 140 | major = major*10 + uint64(ch-'0') |
| 141 | } |