Kaitai Struct — Парсер бинарных форматов

Kaitai Struct

A new way to develop parsers for binary structures.

Поддерживает генерацию кода на языках:

  • C++/STL
  • C#
  • Java
  • JavaScript
  • Perl
  • PHP
  • Python
  • Ruby

Пример генерации кода

Описание формата

meta:
  id: dos_mz
  file-extension: exe
  endian: le
seq:
  - id: mz_header
    type: mz_header
  - id: mz_header2
    size: mz_header.relocations_ofs - 0x1c
  - id: relocations
    type: relocation
    repeat: expr
    repeat-expr: mz_header.qty_relocations
  - id: body
    size-eos: true
types:
  mz_header:
    seq:
      - id: magic
        size: 2
      - id: last_page_extra_bytes
        type: u2
      - id: qty_pages
        type: u2
      - id: qty_relocations
        type: u2
      - id: header_size
        type: u2
      - id: min_allocation
        type: u2
      - id: max_allocation
        type: u2
      - id: initial_ss
        type: u2
      - id: initial_sp
        type: u2
      - id: checksum
        type: u2
      - id: initial_ip
        type: u2
      - id: initial_cs
        type: u2
      - id: relocations_ofs
        type: u2
      - id: overlay_id
        type: u2
  relocation:
    seq:
      - id: ofs
        type: u2
      - id: seg
        type: u2

Сгененерированный код на Perl

# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

use strict;
use warnings;
use Kaitai::Struct;
use Kaitai::Stream;
use Compress::Zlib;

########################################################################
package DosMz;

our @ISA = 'Kaitai::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, Kaitai::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = Kaitai::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;

    $self->{mz_header} = DosMz::MzHeader->new($self->{_io}, $self, $self->{_root});
    $self->{mz_header2} = $self->{_io}->read_bytes(($self->mz_header()->relocations_ofs() - 28));
    $self->{relocations} = ();
    my $n_relocations = $self->mz_header()->qty_relocations();
    for (my $i = 0; $i < $n_relocations; $i++) {
        $self->{relocations}[$i] = DosMz::Relocation->new($self->{_io}, $self, $self->{_root});
    }
    $self->{body} = $self->{_io}->read_bytes_full();

    return $self;
}

sub mz_header {
    my ($self) = @_;
    return $self->{mz_header};
}

sub mz_header2 {
    my ($self) = @_;
    return $self->{mz_header2};
}

sub relocations {
    my ($self) = @_;
    return $self->{relocations};
}

sub body {
    my ($self) = @_;
    return $self->{body};
}

########################################################################
package DosMz::MzHeader;

our @ISA = 'Kaitai::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, Kaitai::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = Kaitai::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;

    $self->{magic} = $self->{_io}->read_bytes(2);
    $self->{last_page_extra_bytes} = $self->{_io}->read_u2le();
    $self->{qty_pages} = $self->{_io}->read_u2le();
    $self->{qty_relocations} = $self->{_io}->read_u2le();
    $self->{header_size} = $self->{_io}->read_u2le();
    $self->{min_allocation} = $self->{_io}->read_u2le();
    $self->{max_allocation} = $self->{_io}->read_u2le();
    $self->{initial_ss} = $self->{_io}->read_u2le();
    $self->{initial_sp} = $self->{_io}->read_u2le();
    $self->{checksum} = $self->{_io}->read_u2le();
    $self->{initial_ip} = $self->{_io}->read_u2le();
    $self->{initial_cs} = $self->{_io}->read_u2le();
    $self->{relocations_ofs} = $self->{_io}->read_u2le();
    $self->{overlay_id} = $self->{_io}->read_u2le();

    return $self;
}

sub magic {
    my ($self) = @_;
    return $self->{magic};
}

sub last_page_extra_bytes {
    my ($self) = @_;
    return $self->{last_page_extra_bytes};
}

sub qty_pages {
    my ($self) = @_;
    return $self->{qty_pages};
}

sub qty_relocations {
    my ($self) = @_;
    return $self->{qty_relocations};
}

sub header_size {
    my ($self) = @_;
    return $self->{header_size};
}

sub min_allocation {
    my ($self) = @_;
    return $self->{min_allocation};
}

sub max_allocation {
    my ($self) = @_;
    return $self->{max_allocation};
}

sub initial_ss {
    my ($self) = @_;
    return $self->{initial_ss};
}

sub initial_sp {
    my ($self) = @_;
    return $self->{initial_sp};
}

sub checksum {
    my ($self) = @_;
    return $self->{checksum};
}

sub initial_ip {
    my ($self) = @_;
    return $self->{initial_ip};
}

sub initial_cs {
    my ($self) = @_;
    return $self->{initial_cs};
}

sub relocations_ofs {
    my ($self) = @_;
    return $self->{relocations_ofs};
}

sub overlay_id {
    my ($self) = @_;
    return $self->{overlay_id};
}

########################################################################
package DosMz::Relocation;

our @ISA = 'Kaitai::Struct';

sub from_file {
    my ($class, $filename) = @_;
    my $fd;

    open($fd, '<', $filename) or return undef;
    binmode($fd);
    return new($class, Kaitai::Stream->new($fd));
}

sub new {
    my ($class, $_io, $_parent, $_root) = @_;
    my $self = Kaitai::Struct->new($_io);

    bless $self, $class;
    $self->{_parent} = $_parent;
    $self->{_root} = $_root || $self;

    $self->{ofs} = $self->{_io}->read_u2le();
    $self->{seg} = $self->{_io}->read_u2le();

    return $self;
}

sub ofs {
    my ($self) = @_;
    return $self->{ofs};
}

sub seg {
    my ($self) = @_;
    return $self->{seg};
}

1;

Leave a Reply