Next: , Previous: , Up: Basic Editing   [Contents][Index]


3.4 Poking Bytes

Let’s look again at the first bytes of the file foo.o:

(poke) dump :size 64#B
76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0100 f700 0102 0000 0000 0000 0000 0000  ................
00000020: 0102 0000 0000 0000 9801 0000 0000 0000  ................
00000030: 0000 0000 4000 0000 0000 4000 0800 0700  ..............

At this point we know how to use the ruler to localize specific bytes just by looking at the displayed data. If we wanted to operate on the values of some given bytes, we could look at the dump and type the values in the REPL. For example, if we wanted to add the values of the bytes at offsets 0x2 and 0x4, we could look at the dump and then type:

(poke) 0x4c + 0x02
0x4e

GNU poke supports many operators that take integers as arguments, to perform arithmetic, relational, logical and bit-wise operations on them (see Integers). Since bytes are no more (and no less) than little unsigned integers, we can use these operators to perform calculations on bytes.

For example, this is how we would calculate whether the highest bit in the second byte in foo.o is set:

(poke) 0x45 & 0x80
0

Note how booleans are encoded in Poke as integers, 0 meaning false, any other value meaning true.

Looking at the output of dump and writing the desired byte value in the prompt is cumbersome. Fortunately, there is a much more convenient way to access the value of a byte, given its offset in the file: it is called mapping a byte value. This operation is implemented by a binary operator, called the map operator.

This is how it works. Assuming we were interested in the byte at 64 bytes from the beginning of the file, this is how we would refer to it (or “map” it):

(poke) byte @ 64#B
37UB

This application of the map operator tells poke to map a byte at the offset 64 bytes. It can be read as “byte at 64 bytes”. Note how poke replies with the value 37UB. The suffix UB means “unsigned byte”, and is an indication for the user about the nature of the preceding number: it is unsigned, and it occupies a byte when stored.

As we can see in this example, poke uses decimal by default when showing values in the REPL. We already noted how it is usually better to work in hexadecimal when dealing with byte values. Fortunately, we can change the numeration base used by poke when printing numbers, using the .set obase (“set output base”) dot-command as this:

(poke) .set obase 16

After this, we can map the byte again, this time getting the result expressed in hexadecimal:

(poke) byte @ 64#B
0x25UB

Again, you may find it useful to add the .set obase 16 command to your .pokerc file, if you want the customization to be persistent between poke invocations.

Going back to the example of calculating whether the highest bit in the second byte in foo.o is set, this is how we would do it with a map:

(poke) (byte @ 2#B) & 0x80
0

Turns out the answer is no.

The map operator can also be used at the left side of an assignment operator:

(poke) byte @ 0x28#B = 0xff

Which reads “assign 0xff to the byte at offset 0x4a bytes”. Dumping again, we can verify that the byte actually changed:

76543210  0011 2233 4455 6677 8899 aabb ccdd eeff  0123456789ABCDEF
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0100 f700 0102 0000 0000 0000 0000 0000  ................
00000020: 0102 0000 0000 0000 ff01 0000 0000 0000  ................
00000030: 0000 0000 4000 0000 0000 4000 0800 0700  ..............

Does this mean that foo.o changed accordingly, in disk? The answer is yes. poke always commits changes immediately to the file being edited. This, that is an useful feature, can also be a bit tricky if you forget about it, leading to data corruption, so please be careful.

Incidentally, altering the byte at offset 0x28 most probably have caused foo.o to stop being a valid ELF file, but since we are just editing bytes (and not ELF structures) we actually don’t care much.


Next: Values and Variables, Previous: Dumping File Contents, Up: Basic Editing   [Contents][Index]