Add files via upload

This commit is contained in:
vxunderground
2020-10-11 00:40:44 -05:00
committed by GitHub
parent e1d25298f4
commit ad3ed5a13f
20 changed files with 5942 additions and 0 deletions
@@ -0,0 +1,251 @@
package manifest
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"math"
"path/filepath"
"strings"
"unicode/utf16"
"unicode/utf8"
)
const (
stringFlagSorted = 0x00000001
stringFlagUtf8 = 0x00000100
)
var StringCnt uint32
var ManifestStringsDmp, _ = filepath.Abs("manifest_strings.dmp")
var StringTableEndPos int
type stringTable struct {
isUtf8 bool
stringOffsets []byte
data []byte
cache map[uint32]string
}
func parseStringTableWithChunk(r io.Reader) (res stringTable, err error) {
id, _, totalLen, err := parseChunkHeader(r)
if err != nil {
return
}
if id != chunkStringTable {
err = fmt.Errorf("Invalid chunk id 0x%08x, expected 0x%08x", id, chunkStringTable)
return
}
return parseStringTable(&io.LimitedReader{R: r, N: int64(totalLen - chunkHeaderSize)})
}
func check(e error) {
if e != nil {
panic(e)
}
}
func dumpStrings(data []byte) {
err := ioutil.WriteFile(ManifestStringsDmp, data, 0644)
check(err)
}
func parseStringTable(r *io.LimitedReader) (stringTable, error) {
var err error
var stringOffset, flags uint32
var res stringTable
// stringCnt - STRING COUNT
if err := binary.Read(r, binary.LittleEndian, &StringCnt); err != nil {
return res, fmt.Errorf("error reading stringCnt: %s", err.Error())
}
// skip styles count
if _, err = io.CopyN(ioutil.Discard, r, 4); err != nil {
return res, fmt.Errorf("error reading styleCnt: %s", err.Error())
}
if err := binary.Read(r, binary.LittleEndian, &flags); err != nil {
return res, fmt.Errorf("error reading flags: %s", err.Error())
}
res.isUtf8 = (flags & stringFlagUtf8) != 0
if res.isUtf8 {
flags &^= stringFlagUtf8
}
flags &^= stringFlagSorted // just ignore
if flags != 0 {
return res, fmt.Errorf("Unknown string flag: 0x%08x", flags)
}
if err := binary.Read(r, binary.LittleEndian, &stringOffset); err != nil {
return res, fmt.Errorf("error reading stringOffset: %s", err.Error())
}
// skip styles offset
if _, err = io.CopyN(ioutil.Discard, r, 4); err != nil {
return res, fmt.Errorf("error reading styleOffset: %s", err.Error())
}
// Read lengths
if StringCnt >= 2*1024*1024 {
return res, fmt.Errorf("Too many strings in this file (%d).", StringCnt)
}
// allocate memory for each offset. 1 offset for 1 string. 1 offset = 4 bytes
res.stringOffsets = make([]byte, 4*StringCnt)
// fill stringOffssets array with offsets. Read from manifest
if _, err := io.ReadFull(r, res.stringOffsets); err != nil {
return res, fmt.Errorf("Failed to read string offsets data: %s", err.Error())
}
remainder := int64(stringOffset) - 7*4 - 4*int64(StringCnt)
if remainder < 0 {
return res, fmt.Errorf("Wrong string offset (got remainder %d)", remainder)
} else if remainder > 0 {
if _, err = io.CopyN(ioutil.Discard, r, remainder); err != nil {
return res, fmt.Errorf("error reading styleArray: %s", err.Error())
}
}
// read STRINGS
// TODO Здесь в r.N попал resourceID, а это не должно быть
res.data = make([]byte, r.N)
if _, err := io.ReadFull(r, res.data); err != nil {
return res, fmt.Errorf("Failed to read string table data: %s", err.Error())
}
// write res.data to stdout. res.data contains = resource strings and manifest in plaintext
if mr, ok := r.R.(myRead); ok {
StringTableEndPos = mr.GetRead()
}
dumpStrings(res.data)
res.cache = make(map[uint32]string)
return res, nil
}
func (t *stringTable) parseString16(r io.Reader) (string, error) {
var strCharacters uint32
var strCharactersLow, strCharactersHigh uint16
if err := binary.Read(r, binary.LittleEndian, &strCharactersHigh); err != nil {
return "", fmt.Errorf("error reading string char count: %s", err.Error())
}
if (strCharactersHigh & 0x8000) != 0 {
if err := binary.Read(r, binary.LittleEndian, &strCharactersLow); err != nil {
return "", fmt.Errorf("error reading string char count: %s", err.Error())
}
strCharacters = (uint32(strCharactersHigh&0x7FFF) << 16) | uint32(strCharactersLow)
} else {
strCharacters = uint32(strCharactersHigh)
}
buf := make([]uint16, int64(strCharacters))
if err := binary.Read(r, binary.LittleEndian, &buf); err != nil {
return "", fmt.Errorf("error reading string : %s", err.Error())
}
decoded := utf16.Decode(buf)
for len(decoded) != 0 && decoded[len(decoded)-1] == 0 {
decoded = decoded[:len(decoded)-1]
}
return string(decoded), nil
}
func (t *stringTable) parseString8Len(r io.Reader) (int64, error) {
var strCharacters int64
var strCharactersLow, strCharactersHigh uint8
if err := binary.Read(r, binary.LittleEndian, &strCharactersHigh); err != nil {
return 0, fmt.Errorf("error reading string char count: %s", err.Error())
}
if (strCharactersHigh & 0x80) != 0 {
if err := binary.Read(r, binary.LittleEndian, &strCharactersLow); err != nil {
return 0, fmt.Errorf("error reading string char count: %s", err.Error())
}
strCharacters = (int64(strCharactersHigh&0x7F) << 8) | int64(strCharactersLow)
} else {
strCharacters = int64(strCharactersHigh)
}
return strCharacters, nil
}
func (t *stringTable) parseString8(r io.Reader) (string, error) {
// Length of the string in UTF16
_, err := t.parseString8Len(r)
if err != nil {
return "", err
}
len8, err := t.parseString8Len(r)
if err != nil {
return "", err
}
buf := make([]uint8, len8)
if err := binary.Read(r, binary.LittleEndian, &buf); err != nil {
return "", fmt.Errorf("error reading string : %s", err.Error())
}
for len(buf) != 0 && buf[len(buf)-1] == 0 {
buf = buf[:len(buf)-1]
}
return string(buf), nil
}
func (t *stringTable) get(idx uint32) (string, error) {
if idx == math.MaxUint32 {
return "", nil
} else if idx >= uint32(len(t.stringOffsets)/4) {
return "", fmt.Errorf("String with idx %d not found!", idx)
}
if str, prs := t.cache[idx]; prs {
return str, nil
}
offset := binary.LittleEndian.Uint32(t.stringOffsets[4*idx : 4*idx+4])
if offset >= uint32(len(t.data)) {
return "", fmt.Errorf("String offset for idx %d is out of bounds (%d >= %d).", idx, offset, len(t.data))
}
r := bytes.NewReader(t.data[offset:])
var err error
var res string
if t.isUtf8 {
res, err = t.parseString8(r)
} else {
res, err = t.parseString16(r)
}
if err != nil {
return "", err
}
if !utf8.ValidString(res) || strings.ContainsRune(res, 0) {
res = strings.Map(func(r rune) rune {
switch r {
case 0, utf8.RuneError:
return '\uFFFE'
default:
return r
}
}, res)
}
t.cache[idx] = res
return res, nil
}
func (t *stringTable) isEmpty() bool {
return t.cache == nil
}