pax-replace/extract/list

master
cheetah 1 month ago
parent e71cd8a105
commit 01af8d2a7a

@ -3,16 +3,30 @@ package commands
type BaseCommand struct {
Help HelpCommand `command:"help" description:"Print this help message"`
//PrepareBin PrepareBinCommand `command:"prepare" alias:"p" description:"Prepare a Binary file and attach the propietary header to it"`
DecryptDBF DecryptDBFCommand `command:"decrypt-dbf" description:"decrypt dbf-data"`
DecryptDES DecryptDESCommand `command:"decrypt-des" description:"decrypt des-data"`
MparUnpack MparUnpackCommand `command:"mpar-unpack" description:"extracts the raw bin from an mpar file"`
MparPack MparPackCommand `command:"mpar-pack" description:"creates an mpar file from the binary file and header info"`
//CodePlugModify
//CodePlugUnify
//CodePlugToJSON
//CodePlugFromJSON
S19Tree S19TreeCommand `command:"s19-tree" description:"dump s19 tree"`
S19IsolatePart S19IsolatePartitionCommand `command:"s19-isolate-part" description:"isolate a segment from an s19"`
S19FromMpar S19FromMparCommand `command:"s19-from-mpar" description:"creates an s19 from an mpar"`
//CodePlugFlash
//CodePlugDump
//KernelModifyFile
//KernelRepack
MparUnpack MparUnpackCommand `command:"mpar-unpack" description:"Extracts the Raw Binary Data from an Partition-File"`
MparPack MparPackCommand `command:"mpar-pack" description:"Creates a new Partition-File from Raw Binary-Data"`
S19Tree S19TreeCommand `command:"s19-tree" description:"Dump the S19 Record Tree and seperate Memory Regions"`
S19IsolatePart S19IsolatePartitionCommand `command:"s19-isolate-part" description:"Isolate a Partition from an S19-File"`
S19FromMpar S19FromMparCommand `command:"s19-from-mpar" description:"Creates a new S19-File from a Partition-File"`
MparPaxList MparPaxListCommand `command:"mpar-pax-list" description:"prints the contents of an pax archive within an mpar"`
MparPaxExtract MparPaxExtractCommand `command:"mpar-pax-extract" description:"extracts a single file from an pax'd mpar file"`
MparPaxReplace MparPaxReplaceCommand `command:"mpar-pax-replace" description:"replaces a single file in a pax'd mpar file"`
}
var MotoCLI BaseCommand

@ -43,7 +43,7 @@ func (command *MparPackCommand) Execute(args []string) error {
}
originalHeader, err := hex.DecodeString(command.OriginalFullHeader)
if len(originalHeader) != 32 {
if err != nil {
return errors.New("header invalid")
}

@ -0,0 +1,98 @@
package commands
import (
"archive/tar"
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"strings"
"git.cheetah.cat/cheetah/moto-flash-data/flashpart"
"github.com/rs/zerolog/log"
)
type MparPaxExtractCommand struct {
InputFilename string `long:"mpar" short:"m" required:"true" description:"input-filename"`
TargetFileName string `long:"file" short:"f" required:"true" description:"output-filename"`
}
func (command *MparPaxExtractCommand) Execute(args []string) error {
inputFile, err := os.Open(command.InputFilename)
if err != nil {
return err
}
defer inputFile.Close()
inputFileStat, err := inputFile.Stat()
if err != nil {
return err
}
log.Info().Int64("fileSize", inputFileStat.Size()).Msg("Reading raw file...")
pdata := make([]byte, inputFileStat.Size())
_, err = io.ReadFull(inputFile, pdata)
if err != nil {
return err
}
fpHeader := flashpart.ParseFlashPartHeader(pdata[:32])
log.Info().Msg(
fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s",
fpHeader.MediaID,
fpHeader.TotalSize,
fpHeader.TotalSize,
fpHeader.VersionText,
),
)
log.Info().Msg(
fmt.Sprintf("Original-Full-Header-Hex: %s", hex.EncodeToString(pdata[:32])),
)
if len(pdata[32:]) != len(pdata)-32 {
return errors.New("something doesnt add up")
}
if len(pdata[32:]) != int(fpHeader.TotalSize)-32 {
log.Error().Uint32("header ts", fpHeader.TotalSize).Uint32("len pdata", uint32(len(pdata))).Msg("size mismatch")
return nil
}
breader := bytes.NewReader(pdata[32:])
tarReader := tar.NewReader(breader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
log.Error().Err(err)
}
if header.Typeflag == tar.TypeReg && !strings.Contains(header.Name, "._") && header.Name == command.TargetFileName {
content, err := io.ReadAll(tarReader)
if err != nil {
log.Error().Err(err)
}
outputFile, err := os.Create(command.TargetFileName)
if err != nil {
return err
}
defer outputFile.Close()
_, err = outputFile.Write(content)
if err != nil {
return err
}
log.Info().Str("fileName", header.Name).Int64("fileSize", header.Size).Msg("extracted file")
return nil
}
}
log.Error().Msg("no file extracted")
return nil
}

@ -0,0 +1,85 @@
package commands
import (
"archive/tar"
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"git.cheetah.cat/cheetah/moto-flash-data/flashpart"
"github.com/rs/zerolog/log"
)
type MparPaxListCommand struct {
SourceFileName string `long:"file" short:"f" required:"true" description:"input-filename"`
}
func (command *MparPaxListCommand) Execute(args []string) error {
inputFile, err := os.Open(command.SourceFileName)
if err != nil {
return err
}
defer inputFile.Close()
inputFileStat, err := inputFile.Stat()
if err != nil {
return err
}
log.Info().Int64("fileSize", inputFileStat.Size()).Msg("Reading raw file...")
pdata := make([]byte, inputFileStat.Size())
_, err = io.ReadFull(inputFile, pdata)
if err != nil {
return err
}
fpHeader := flashpart.ParseFlashPartHeader(pdata[:32])
log.Info().Msg(
fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s",
fpHeader.MediaID,
fpHeader.TotalSize,
fpHeader.TotalSize,
fpHeader.VersionText,
),
)
log.Info().Msg(
fmt.Sprintf("Original-Full-Header-Hex: %s", hex.EncodeToString(pdata[:32])),
)
if len(pdata[32:]) != len(pdata)-32 {
return errors.New("something doesnt add up")
}
if len(pdata[32:]) != int(fpHeader.TotalSize)-32 {
log.Error().Uint32("header ts", fpHeader.TotalSize).Uint32("len pdata", uint32(len(pdata))).Msg("size mismatch")
return nil
}
breader := bytes.NewReader(pdata[32:])
tarReader := tar.NewReader(breader)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
log.Error().Err(err)
}
fmt.Println(header)
// if header.Typeflag == tar.TypeReg && !strings.Contains(header.Name, "._") {
// // content, err := io.ReadAll(tarReader)
// // if err != nil {
// // log.Error().Err(err)
// // }
// fmt.Println("FILE_NAME: ", header.Name)
// ///fmt.Println(string(content))
// }
}
return nil
}

@ -0,0 +1,157 @@
package commands
import (
"archive/tar"
"bytes"
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"strings"
"git.cheetah.cat/cheetah/moto-flash-data/flashpart"
"github.com/rs/zerolog/log"
)
type MparPaxReplaceCommand struct {
InputFilename string `long:"mpar" short:"m" required:"true" description:"Source Partition File"`
OutputFilename string `long:"output" short:"o" required:"true" description:"Target Partition File"`
FindFileName string `long:"file" short:"f" required:"true" description:"Name of the File to Find"`
ReplaceWithFilename string `long:"replacewith" short:"r" required:"true" description:"Source Bytes for Replace-Action"`
}
func (command *MparPaxReplaceCommand) Execute(args []string) error {
inputFile, err := os.Open(command.InputFilename)
if err != nil {
return err
}
defer inputFile.Close()
replaceWithFile, err := os.Open(command.ReplaceWithFilename)
if err != nil {
return err
}
defer replaceWithFile.Close()
inputFileStat, err := inputFile.Stat()
if err != nil {
return err
}
log.Info().Int64("fileSize", inputFileStat.Size()).Msg("Reading raw file...")
pdata := make([]byte, inputFileStat.Size())
_, err = io.ReadFull(inputFile, pdata)
if err != nil {
return err
}
fpHeader := flashpart.ParseFlashPartHeader(pdata[:32])
log.Info().Msg(
fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s",
fpHeader.MediaID,
fpHeader.TotalSize,
fpHeader.TotalSize,
fpHeader.VersionText,
),
)
log.Info().Msg(
fmt.Sprintf("Original-Full-Header-Hex: %s", hex.EncodeToString(pdata[:32])),
)
if len(pdata[32:]) != len(pdata)-32 {
return errors.New("something doesnt add up")
}
if len(pdata[32:]) != int(fpHeader.TotalSize)-32 {
log.Error().Uint32("header ts", fpHeader.TotalSize).Uint32("len pdata", uint32(len(pdata))).Msg("size mismatch")
return nil
}
breader := bytes.NewReader(pdata[32:])
tarReader := tar.NewReader(breader)
temporaryPaxFile, _ := os.CreateTemp("", "pax-replace.tar")
defer temporaryPaxFile.Close()
tarWriter := tar.NewWriter(temporaryPaxFile)
defer tarWriter.Close()
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
if err != nil {
log.Error().Err(err)
return err
}
if header.Typeflag == tar.TypeReg && !strings.Contains(header.Name, "._") && header.Name == command.FindFileName {
log.Info().Str("fileName", header.Name).Int64("fileSize", header.Size).Msg("found file to modify")
replaceWithFileStat, err := replaceWithFile.Stat()
if err != nil {
return err
}
header.Size = replaceWithFileStat.Size()
header.ModTime = replaceWithFileStat.ModTime()
tarWriter.WriteHeader(header)
content, err := io.ReadAll(replaceWithFile)
if err != nil {
log.Error().Err(err)
}
tarWriter.Write(content)
} else {
tarWriter.WriteHeader(header)
content, err := io.ReadAll(tarReader)
if err != nil {
log.Error().Err(err)
}
tarWriter.Write(content)
}
}
//log.Error().Msg("no file replaced")
// create new mpar with same header base
_, err = temporaryPaxFile.Seek(0, 0)
if err != nil {
return err
}
temporaryPaxFileStat, err := temporaryPaxFile.Stat()
if err != nil {
return err
}
rawData := make([]byte, temporaryPaxFileStat.Size())
_, err = io.ReadFull(temporaryPaxFile, rawData)
if err != nil {
return err
}
outputFile, err := os.Create(command.OutputFilename)
if err != nil {
return err
}
defer outputFile.Close()
fpHeader.AdjustRawSize(uint32(len(rawData)))
log.Info().Msg(
fmt.Sprintf("New-Full-Header-Hex: %s", hex.EncodeToString(fpHeader.GetBytes())),
)
fpHeaderNew := flashpart.ParseFlashPartHeader(fpHeader.GetBytes())
log.Info().Msg(
fmt.Sprintf("Media-ID: 0x%02X, Partition Size: 0x%08X / %d bytes, Partition Tag: %s",
fpHeaderNew.MediaID,
fpHeaderNew.TotalSize,
fpHeaderNew.TotalSize,
fpHeaderNew.VersionText,
),
)
_, err = outputFile.Write(fpHeaderNew.GetBytes())
if err != nil {
return err
}
_, err = outputFile.Write(rawData)
if err != nil {
return err
}
return nil
}
Loading…
Cancel
Save