Documentation
¶
Overview ¶
Package gho implements Norton Ghost GHO image format parsing.
GHO files contain disk/partition images created by Symantec Ghost (versions 11.x-12.x). The format supports Fast LZ (Z1), High/zlib (Z2-Z9), and no compression modes, with optional CRC-16 stream cipher encryption.
File structure:
[512B File Header (FE EF 01 02)] [Record type 6: Track 0 / MBR data] [Record type 0x0603: Partition descriptor (20B body)] [512B FEEF Partition Header (FE EF 02 02)] [Compressed blocks: 2B stored_len + block_data] [Record type 0x0703: Continuation (20B body)] [512B FEEF Header] [More compressed blocks...] [Record type 0x23: End record (24B body)]
Compressed block format:
stored_len = LE uint16 (includes the 2-byte length field itself) comp_len = stored_len - 2 block_data[0] == 1: uncompressed, output = block_data[4:comp_len] block_data[0] != 1: Fast LZ compressed
Record format:
[4B type (LE uint32, low 16 = type code, high 16 = flags)] [4B magic (0x012F18D8)] [2B body_len (LE uint16)] [body_len bytes body]
Index ¶
- Constants
- Variables
- func FastLZCompress(src []byte) []byte
- func FastLZDecompress(data []byte, compLen int, dst []byte) (int, error)
- func IsEncrypted(header []byte) bool
- func ModifyHeader(path string, mode string) error
- func ZlibCompress(src []byte, level int) []byte
- func ZlibDecompress(data []byte, compLen int, dst []byte) (int, error)
- type CRC16Cipher
- type FileHeader
- type Image
- func (img *Image) Close() error
- func (img *Image) DecompressPartition(partIdx int, w io.Writer) error
- func (img *Image) IsEncrypted() bool
- func (img *Image) MBRPartitions() []MBRPartitionEntry
- func (img *Image) SetPassword(password string)
- func (img *Image) Summary() string
- func (img *Image) Verify(partIdx int) error
- type MBRPartitionEntry
- type PartitionHeader
- type PartitionInfo
- type Record
- type Span
- type Track0Header
- type Writer
Constants ¶
const ( // FileMagic is the first 2 bytes of GHO file header and FEEF partition header. FileMagic = 0xEFFE // RecordMagic appears at offset 4 in every record header. RecordMagic = 0x012F18D8 // HeaderSize is the size of file header and FEEF partition header. HeaderSize = 512 // RecordHeaderSize is the fixed size of a record header. RecordHeaderSize = 10 // BlockSize is the default decompressed block size. BlockSize = 32768 // MaxStoredLen is the maximum valid stored length for a block. MaxStoredLen = 33002 // BlockSize + 4 (uncompressed header) + 2 (stored_len) // FastLZHashSize is the hash table size for Fast LZ. FastLZHashSize = 4096 )
const ( RecordTypeTrack0 = 0x0006 // Track 0 / MBR data RecordTypePartition = 0x0603 // Partition descriptor RecordTypeContinuation = 0x0703 // Partition data continuation RecordTypeEnd = 0x0023 // End of image )
Record types (low 16 bits of the type field).
const ( CompressionNone = 0 CompressionOld = 1 // Not supported CompressionFast = 2 // Fast LZ (Z1) CompressionHigh3 = 3 // High compression (Z3, zlib) CompressionHigh4 = 4 CompressionHigh5 = 5 CompressionHigh6 = 6 CompressionHigh7 = 7 CompressionHigh8 = 8 CompressionHigh9 = 9 )
Compression types (byte 3 of file header).
const ( FixupCD = "cd" // Set spanned bit at file offset 584 FixupCDOff = "cd-" // Clear spanned bit at file offset 584 FixupSpan = "span" // Toggle CD flag at header offset 55 )
Fixup mode constants for ModifyHeader.
Variables ¶
var ( ErrInvalidMagic = errors.New("gho: invalid file magic") ErrInvalidRecordMagic = errors.New("gho: invalid record magic") ErrUnsupportedCompression = errors.New("gho: unsupported compression type") ErrCorruptBlock = errors.New("gho: corrupt compressed block") ErrTruncated = errors.New("gho: unexpected end of data") )
Errors
var ErrBadPassword = errors.New("gho: invalid password")
ErrBadPassword is returned when the password is empty or decryption fails.
Functions ¶
func FastLZCompress ¶ added in v1.1.0
FastLZCompress compresses src using the Ghost Fast LZ (Z1) algorithm.
The compressor maintains exact hash table synchronization with the decompressor (FastLZDecompress). Every hash table update in the compressor mirrors what the decompressor would do when processing the compressed stream.
Returns the compressed block data including the 4-byte header.
func FastLZDecompress ¶
FastLZDecompress decompresses a Ghost Fast LZ (Z1) compressed block.
The algorithm is a custom LZ77 variant with a 4096-entry hash table. Each hash entry stores a pointer to a previous position in the output buffer.
Block format:
- byte[0] == 1: uncompressed, output = data[4:compLen]
- byte[0] != 1: compressed with 16-bit control words
Compressed format uses 16-bit control words where:
- bit 0 = literal byte (copy from input)
- bit 1 = match reference (2-byte token: hash_idx + extra_len)
Hash function: h = ((-24993 * (b2 ^ (16 * (b1 ^ (16 * b0))))) >> 4) & 0xFFF
Reversed from Norton Ghost 11.5.1 sub_4DDD70 via IDA.
func IsEncrypted ¶ added in v1.2.0
IsEncrypted checks if a GHO file header indicates encryption is enabled. Ghost sets a specific flag pattern when encryption is used. The encryption indicator is at header byte 12 (after ID field), bit 0.
func ModifyHeader ¶ added in v1.1.0
ModifyHeader modifies a GHO file's header flags, replicating the functionality of Norton Ghost's ghofixup.exe utility.
Modes:
- "cd": Set the spanned/CD bit at file offset 584
- "cd-": Clear the spanned/CD bit at file offset 584
- "span": Toggle the CD flag byte at header offset 55
The header is decrypted, modified, and re-encrypted using the Ghost PRNG cipher. Only the necessary portion of the file is read and written back.
Reversed from ghofixup.exe (PDB: c:\depot\ghost\gsstrunk\ghost\utilityapps\ghofixup\).
func ZlibCompress ¶ added in v1.2.0
ZlibCompress compresses src using zlib at the given level (3-9).
The output includes the 4-byte header expected by the GHO block format. If compression doesn't reduce size, an uncompressed block is returned.
func ZlibDecompress ¶ added in v1.2.0
ZlibDecompress decompresses a Ghost High/zlib (Z3-Z9) compressed block.
Block format is identical to Fast LZ: byte[0] == 1 means uncompressed. Otherwise the data (starting at offset 4) is zlib-compressed.
Types ¶
type CRC16Cipher ¶ added in v1.2.0
type CRC16Cipher struct {
// contains filtered or unexported fields
}
CRC16Cipher implements the Ghost CRC-16 stream cipher used for GHO encryption.
Ghost uses a CRC-16 based stream cipher where each byte of plaintext is XORed with the low byte of a running CRC-16 state. The CRC state is updated with each plaintext byte, creating a password-dependent keystream.
The password is used to initialize the CRC-16 state by feeding each password byte through the CRC update function.
Reversed from Norton Ghost 11.5.1 encryption routines.
func NewCRC16Cipher ¶ added in v1.2.0
func NewCRC16Cipher(password string) (*CRC16Cipher, error)
NewCRC16Cipher creates a new CRC-16 stream cipher initialized with the given password.
func (*CRC16Cipher) Decrypt ¶ added in v1.2.0
func (c *CRC16Cipher) Decrypt(data []byte)
Decrypt decrypts data in-place using the CRC-16 stream cipher. Each byte is XORed with the low byte of the CRC state, then the CRC state is updated with the decrypted (plaintext) byte.
func (*CRC16Cipher) Encrypt ¶ added in v1.2.0
func (c *CRC16Cipher) Encrypt(data []byte)
Encrypt encrypts data in-place using the CRC-16 stream cipher. Each plaintext byte updates the CRC state, then is XORed with the low byte of the previous CRC state.
func (*CRC16Cipher) Reset ¶ added in v1.2.0
func (c *CRC16Cipher) Reset(password string)
Reset reinitializes the cipher with a new password.
type FileHeader ¶
type FileHeader struct {
Magic uint16 // 0xEFFE
FileType byte // 0x01=first file, 0x09=span file
Compression byte // Compression type (0-9)
ID uint32 // CRC/timestamp identifier
Flags [3]byte // bytes 8-10
Raw [512]byte // Full raw header
}
FileHeader represents the 512-byte GHO file header.
func ParseFileHeader ¶
func ParseFileHeader(data []byte) (*FileHeader, error)
ParseFileHeader parses a 512-byte file header.
type Image ¶
type Image struct {
Header *FileHeader
Track0 []byte // Raw Track 0 data (MBR at offset 6)
Track0Hdr Track0Header // 6-byte mini-header
Partitions []PartitionInfo // Partition descriptors
EndRecord *Record
// contains filtered or unexported fields
}
Image represents a parsed GHO image file.
func OpenSpanned ¶ added in v1.2.0
OpenSpanned opens a multi-file GHO image (primary .gho + span .ghs files).
Norton Ghost splits large images into multiple files:
- image.gho (FileType=0x01) — primary file with headers and initial data
- image.ghs (FileType=0x09) — span continuation files
The span files are auto-discovered in the same directory as the primary file, sorted by filename (which Ghost names sequentially).
OpenSpanned uses a zero-copy multi-file reader — no temporary files are created and the span files are not loaded into memory.
func (*Image) DecompressPartition ¶
DecompressPartition decompresses all blocks of a partition and writes to w. If the image is encrypted, SetPassword must be called first.
func (*Image) IsEncrypted ¶ added in v1.2.0
IsEncrypted returns true if the image header indicates encryption.
func (*Image) MBRPartitions ¶
func (img *Image) MBRPartitions() []MBRPartitionEntry
MBRPartitions returns parsed MBR partition entries from Track 0.
func (*Image) SetPassword ¶ added in v1.2.0
SetPassword sets the decryption password for encrypted GHO images. Must be called before DecompressPartition on encrypted images.
type MBRPartitionEntry ¶
type MBRPartitionEntry struct {
Status byte
CHSStart [3]byte
Type byte
CHSEnd [3]byte
LBAStart uint32
LBASize uint32
}
MBRPartitionEntry represents a single MBR partition table entry.
func ParseMBRPartitions ¶
func ParseMBRPartitions(mbr []byte) []MBRPartitionEntry
ParseMBRPartitions extracts partition table entries from a 512-byte MBR.
type PartitionHeader ¶
type PartitionHeader struct {
Magic uint16
SubType byte
Compression byte
ID uint32
Flags [3]byte
Raw [512]byte
}
PartitionHeader represents the 512-byte FEEF partition header.
func ParsePartitionHeader ¶
func ParsePartitionHeader(data []byte) (*PartitionHeader, error)
ParsePartitionHeader parses a 512-byte FEEF partition header.
type PartitionInfo ¶
type PartitionInfo struct {
Descriptor *Record // Type 0x0603 record
Header *PartitionHeader // FEEF partition header
Spans []Span // Data spans (may span multiple continuation records)
DescBody [20]byte // Raw descriptor body
}
PartitionInfo holds information about a single partition in the image.
func (*PartitionInfo) TotalCompressedSize ¶ added in v1.4.0
func (p *PartitionInfo) TotalCompressedSize() int64
TotalCompressedSize returns the total compressed data size across all spans.
type Record ¶
type Record struct {
Type uint32 // Full type (low 16 = type code, high 16 = flags)
Magic uint32 // Should be RecordMagic
BodyLen uint16
Offset int64 // File offset of this record
}
Record represents a GHO record header.
func ParseRecord ¶
ParseRecord reads a record header from data.
type Span ¶
type Span struct {
DataStart int64 // File offset where compressed blocks begin
DataEnd int64 // File offset where this span ends (next record)
}
Span represents a contiguous range of compressed blocks in the file.
type Track0Header ¶
type Track0Header struct {
Unknown1 byte // Usually 0x06
Sectors byte // Sectors per track (e.g., 126)
Unknown2 uint32 // Usually 0
}
Track0Header is the 6-byte mini-header before the actual MBR in Track 0 data.
type Writer ¶ added in v1.1.0
type Writer struct {
// contains filtered or unexported fields
}
Writer creates a new GHO image file.
Usage:
w, _ := Create("output.gho", CompressionFast)
w.WriteTrack0(mbrData, 63)
w.WritePartition(partitionImageReader)
w.Close()
func NewWriter ¶ added in v1.1.0
func NewWriter(w io.WriteSeeker, compression byte) (*Writer, error)
NewWriter wraps an io.WriteSeeker as a GHO writer.
func (*Writer) Close ¶ added in v1.1.0
Close writes the end record and closes the underlying writer (if it's a file).
func (*Writer) SetID ¶ added in v1.1.0
SetID sets the image ID and rewrites it in the file header. Can be called at any point before Close.
func (*Writer) SetPassword ¶ added in v1.4.0
SetPassword enables CRC-16 encryption for all subsequent blocks.
func (*Writer) WritePartition ¶ added in v1.1.0
WritePartition reads partition data from r and writes it as compressed GHO blocks.
func (*Writer) WriteTrack0 ¶ added in v1.1.0
WriteTrack0 writes the MBR / Track 0 data as a type-6 record. track0Data should be the raw MBR + boot sectors (typically 512 * sectors bytes). sectors is the sector count field in the Track 0 mini-header (e.g. 63 or 126).