Wednesday, January 25, 2023

mkbin: make binary data

We've all been there. We want a set of bytes containing some specific binary data to feed into some program. In my case, it's often a network socket that I want to push the bytes into, but it could be a data file, an RS-232 port, etc.

I've written this program at least twice before in my career, but that was long before there was a GitHub, so who knows where that code is? Yesterday I wanted to push a specific byte sequence to a network socket, and I just didn't feel like using a hex editor to poke the bytes into a file.

So I wrote it once again:

It's a "little language" (oh boy) that lets you specify the binary data in hex or decimal, as 8, 16, 32, or 64-bit integers, big or little endian (or a mix of the two), or ASCII. 


For example, let's say I want to get the home page from yahoo using interactively from a shell prompt:

./ | nc 80
"GET / HTTP/1.1" 0x0d0a
"Host:" 0x0d0a0d0a

HTTP/1.1 301 Moved Permanently

(I typed the yellow, yahoo server returned the ... blue? Cyan? I'm not good with colors.) Naturally, yahoo wants me to use https, so it is redirecting me. But this is just an example.

Here's a shell script that does the same thing with some comments added:

./ <<__EOF__ | nc 80
"GET / HTTP/1.1" 0x0d0a       # Get request
"Host:" 0x0d0a0d0a  # double cr/lf ends HTTP request

Sometimes it's just easier to echo the commands into mkbin to create a one-liner:

echo '"GET / HTTP/1.1" 0x0d0a "Host:" 0x0d0a0d0a' |
  ./ | nc 80

(Note the use of single quotes to ensure that the double quotes aren't stripped by the shell; the program needs the double quotes.)


So far, we've seen commands for inputting ASCII and arbitrary hex bytes. Here are two 16-bit integers with the value 13, first specified in decimal, then in hex:

$ echo '16d13 16xd' | ./ | od -tx1
0000000 00 0d 00 0d

As you can see, it defaults to big endian.

Here are two 32-bit integer value 13, first in little endian, then in big endian:

$ echo '!endian=0 32d13 !endian=1 32xd' | ./ | od -tx1
0000000 0d 00 00 00 00 00 00 0d

You can also do 64-bit integers (64d13 64xd) and even 8-bit integers (8d13 8xd).


The construct I used earlier with 0x0d0a encodes an arbitrary series of bytes of any desired length. Note that it must have an even number of hex digits. I.e. 0xd is not valid, even though 8xd is.


Finally, be aware that the string construct does not have fancy C-like escapes, like "\x0d". The backslash only escapes the next character for inclusion and is only useful for including a double quote or a backslash into the string. For example:

$ echo '"I say, \"Hi\\hello.\"" 0x0a' | ./ | od -tx1
0000000 49 20 73 61 79 2c 20 22 48 69 5c 68 65 6c 6c 6f
0000020 2e 22 0a
$ echo '"I say, \"Hi\\hello.\"" 0x0a' | ./
I say, "Hi\hello."

No comments: