This is the expletive code (https://github.com/russolsen/expletive) ported to Crystal (http://crystal-lang.org).
Crystal Makefile
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
spec
src
.gitignore
.travis.yml
LICENSE
Makefile
Projectfile
README.md

README.md

crexpletive

© 2015 Russ Olsen

Expletive is a simple pair of utilities that allow you to dump a file -- presumably a binary file -- into a plain text format that you can edit. The trick is that as long as you follow the expletive conventions as you edit you can turn your plain text back into a binary file. So expletive has all the charm of your typical hex editor, without having to learn a new editor. Just use vim or emacs or lightTable or any other editor of your choice.

And the name... Well typically by the time I come to having to edit a binary file I'm usually muttering some bad words.

This version of expletive is a port to the Crystal programming language. Probably not a terriby idiomatic port though -- I'm working my way through learning Crystal by porting familiar Ruby code to it. See http://crystal-lang.org.

Lessons learned from this project:

  • The main changes that I needed to make were in the disconnects between the Ruby API and the Crystal API. For example, it's called getc in Ruby and read_char in Crystal. Not a big deal.

  • The other major porting issue was centered around Crystal's Char type. Again, not a big deal.

  • Love the fact that I can get two standalone executables from Crystal. The Crystal version seems eight or ten times faster than the Ruby version.

Installation

Running make will create the two executables: exdump and exundump.

Usage

Expletive is really just two commands, exdump and exundump. The exdump command will take your binary file and turn it into something you can edit with an ordinary text editor. For example, if I wanted to edit the ls command, I would do something like:

$ exdump < /bin/ls >ls.dump

What you will end up with in ls.dump will be plain text, albeit somewhat intimidating plain text:

\cf\fa\ed\fe\07\00\00\01\03\00\00\80\02\00\00\00\13\00\00\00\18
\07\00\00\85\00 \00\00\00\00\00\19\00\00\00H\00\00\00__PAGEZE
RO\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01\00
\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00
\00\00\00\00\00\00\00\00\00\00\00\00\00\19\00\00\00(\02\00\00
__TEXT\00\00\00\00\00\00\00\00\00\00\00\00\00\00\01\00\00\00\00

You can then edit the ls.dump file, making any changes you desire. Once you are done you can turn your modified text back into binary with exundump.

$ exundump < ls.dump > ls.new

The Dump File Format

The format of the dumped files is as simple as my small mind can make it:

  • Backslashes get converted to double backslashes, so \ becomes \\.

  • Newlines get converted to \n - that's a backslash character followed by an "n".

  • Any byte that looks like a simple, human readable single byte character is written as is.

  • Otherwise the byte is written as a backslash followed by a two digit hex number. Note that this number is zero filled: It's always \03, never \3.

  • The exdump command will periodically insert actual newlines into the output to make it more readable. Actual newlines are ignored by exundump.

That's it!

An Example

Have you ever noticed that when you do ls -l in your terminal, ls prints the total number of bytes at the top of the output?

~/projects/ruby/expletive: ls -l

total 304
-rw-r--r--  1 russolsen  staff    347 Jun 10 08:56 CHANGELOG.md
-rw-r--r--  1 russolsen  staff     55 Jun 10 09:20 Gemfile
-rw-r--r--  1 russolsen  staff    672 Jun 10 08:56 Gemfile.lock
-rw-r--r--  1 russolsen  staff   1067 Jun 10 08:56 LICENSE
...

Now imagine that for some obscure reason you wanted to make that total show up as YOOO!. Nothing to it. First dump the contents of the (very binary) ls command to some file:

exdump </bin/ls >ls.dump

Then edit the resulting dump file with the editor of your choice:

vi ls.dump

And look for the string total. Here is what I see when I do that:

llu\00%lu\00printscol\00/SourceCache/file_cmds/file_cmds-242/
ls/print.c\00dp\00total %qu\n\00%*llu \00%*qu \00%s%s %*u   \00
%s%s %*u %-*s  \00%s%s %*u %-*s  %-*s  \00%-*s \00%3d, 0x%08x
 \00%3d, %3d \00%*s%*qu \00, \00printcol\00dp->list\00base <·

Notice the total on the second line. Now all you need to do is change total to YOOO! or some other amusing string:

llu\00%lu\00printscol\00/SourceCache/file_cmds/file_cmds-242/
ls/print.c\00dp\00YOOO! %qu\n\00%*llu \00%*qu \00%s%s %*u   \00
%s%s %*u %-*s  \00%s%s %*u %-*s  %-*s  \00%-*s \00%3d, 0x%08x
 \00%3d, %3d \00%*s%*qu \00, \00printcol\00dp->list\00base <·

Note that you need to make sure that your new string is the same length as the old one (e.g. total) because executables contain counts and offsets that you don't want to mess up.

Having made your change, you just need to convert your dump file back to a binary. But don't overwrite your system's ls command!

exundump <ls.dump >ls.new

Make your new ls.new file executable:

chmod +x ls.new

And run your hacked binary:

./ls.new -l

YOOO! 312
-rw-r--r--  1 russolsen  staff    347 Jun 10 08:56 CHANGELOG.md
-rw-r--r--  1 russolsen  staff     55 Jun 10 09:20 Gemfile
-rw-r--r--  1 russolsen  staff    672 Jun 10 08:56 Gemfile.lock

## Contributing

1. Fork it ( https://github.com/russolsen/crexpletive/fork )
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create a new Pull Request

Contributors

  • russolsen Russ Olsen - creator, maintainer @russolsen