Skip to content

Instantly share code, notes, and snippets.

@nlitsme
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nlitsme/32e38faefd48a368a5bc to your computer and use it in GitHub Desktop.
Save nlitsme/32e38faefd48a368a5bc to your computer and use it in GitHub Desktop.
easily modify binary files
#!/usr/bin/perl -w
# (C) 2003-2007 Willem Jan Hengeveld <itsme@xs4all.nl>
# Web: http://www.xs4all.nl/~itsme/
# http://wiki.xda-developers.com/
#
# $Id$
#
use strict;
use IO::File;
use Getopt::Long qw(:config no_ignore_case);
my $filebaseofs= 0;
my $g_test= 0;
my @patches;
my %datasize= (
V=>4,
N=>4,
v=>2,
n=>2,
C=>1,
);
sub usage {
return <<__EOF__
Usage: hexedit [patches] file
-pd ofs:dword,dword
-pN ofs:netdword,netdword
-pw ofs:word,word
-pn ofs:netword,netword
-pb ofs:byte,byte OR ofs:bytebytebytebyte
-ps ofs:string
-pu ofs:string stored as unicode
-pf ofs-ofs:byte fill inclusive range.
-pl ofs:file:seek:len
-t test only
all numbers hexdigits
__EOF__
}
GetOptions(
"b=s"=> sub { $filebaseofs= eval($_[1]); },
"pd=s"=> sub { push @patches, ParseData($_[1], "V"); },
"pN=s"=> sub { push @patches, ParseData($_[1], "N"); },
"pw=s"=> sub { push @patches, ParseData($_[1], "v"); },
"pn=s"=> sub { push @patches, ParseData($_[1], "n"); },
"pb=s"=> sub { push @patches, ParseData($_[1], "C"); },
"ps=s"=> sub { push @patches, ParseStringData($_[1]); },
"pu=s"=> sub { push @patches, ParseWStringData($_[1]); },
"pf=s"=> sub { push @patches, ParseFill($_[1]); },
"pl=s"=> sub { push @patches, ParseFileData($_[1]); },
"t" => \$g_test,
) or die usage();
sub ParseData {
my ($ext, $datatype)= @_;
if ($ext =~ /^(\w+):(.*)/) {
my $ofs= hex($1);
my $ascdata= $2;
if ($datatype eq "C" && $ascdata =~ /^\w+$/ && length($ascdata)>2) {
# right align odd length data
$ascdata="0$ascdata" if length($ascdata)&1;
return {
offset=>$ofs,
data=>pack("H*", $ascdata)
};
}
my @data= map { hex($_) } split /,/, $ascdata;
return {
offset=>$ofs,
data=>pack($datatype."*", @data),
};
}
die "Invalid data edit format $ext\n";
}
sub ParseFill {
my ($ext)= @_;
if ($ext =~ /^(\w+)-(\w+):(\w+)/) {
my ($sofs, $eofs, $val, $valsize)= (hex($1), hex($2), hex($3), length($3)/2);
my $fmt= $valsize==1?"C":$valsize==2?"v":$valsize==4?"V":undef;
if (!$fmt) {
die "-pf: invalid data format, must be 2,4 or 8 hex chars";
}
return {
offset=>$sofs,
data => pack($fmt, $val) x (($eofs-$sofs+1)/$valsize),
};
}
die "invalid data fill spec: $ext\n";
}
sub ParseStringData {
my ($ext)= @_;
if ($ext =~ /^(\w+):(.*)/) {
my $ofs= hex($1);
my $data= eval("\"$2\"");
return {
offset=>$ofs,
data=>$data,
};
}
die "Invalid stringdata edit format $ext\n";
}
# todo: this does not convert utf8 from the commandline properly
sub ParseWStringData {
my ($ext)= @_;
if ($ext =~ /^(\w+):(.*)/) {
my $ofs= hex($1);
my $data= pack("v*", unpack("C*", eval("\"$2\"")));
return {
offset=>$ofs,
data=>$data,
};
}
die "Invalid wstringdata edit format $ext\n";
}
sub ParseFileData {
my ($ext)= @_;
if ($ext =~ /^(\w+):(.+?)(?::(\w+)(?::(\w+))?)?$/) {
my $romofs= hex($1);
my $filename= $2;
my $fileofs= defined $3 ? hex($3) : 0;
my $filelen= defined $4 ? hex($4) : (-s $filename)-$fileofs;
my $fh=IO::File->new($filename, "r") or die "$filename: $!\n";
binmode $fh;
$fh->seek($fileofs, SEEK_SET);
my $data;
$fh->read($data, $filelen);
$fh->close();
if (length($data) != $filelen) {
die "error reading $filelen bytes from $filename\n";
}
return {
offset=>$romofs,
data=>$data,
};
}
die "Invalid filedata edit format $ext\n";
}
my $filename = shift || die usage();
my $fh=IO::File->new($filename, "r+") or die "$filename: $!\n";
binmode $fh;
for (sort { $a->{offset} <=> $b->{offset} } @patches) {
$fh->seek($_->{offset}-$filebaseofs, SEEK_SET) or warn "$!";
if ($g_test) {
my $data;
$fh->read($data, length($_->{data})) or warn "$!";
print unpack("H*", $data), "\n";
}
else {
$fh->write($_->{data}) or warn "$!";
}
}
$fh->seek(0, SEEK_END) or warn "$!";
$fh->close();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment