mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-28 15:41:38 +00:00
af0a865d9f
- Adds endian aware functions - Removes references to host endian - Uses binary detected endianness else tries LE and restricts by RAsmPlugin - Fixes gdb debugger endianness when debugging BE qemu gdbserver Signed-off-by: Damien Zammit <damien@zamaudio.com>
69 lines
2.2 KiB
Plaintext
69 lines
2.2 KiB
Plaintext
Endian issues
|
|
=============
|
|
|
|
As hackers, we need to be aware of endianness.
|
|
|
|
Endianness can become a problem when you try to process buffers or streams
|
|
of bytes and store intermediate values as integers with width larger than
|
|
a single byte.
|
|
|
|
It can seem very easy to write the following code:
|
|
|
|
ut8 opcode[4] = {0x10, 0x20, 0x30, 0x40};
|
|
ut32 value = *(ut32*)opcode;
|
|
|
|
... and then continue to use "value" in the code to represent the opcode.
|
|
|
|
This needs to be avoided!
|
|
|
|
Why? What is actually happening?
|
|
|
|
When you cast the opcode stream to a unsigned int, the compiler uses the endianness
|
|
of the host to interpret the bytes and stores it in host endianness. This leads to
|
|
very unportable code, because if you compile on a different endian machine, the
|
|
value stored in "value" might be 0x40302010 instead of 0x10203040.
|
|
|
|
In the past, radare devs were not as strict about this issue, and as a result,
|
|
needed to swap the endian of values regularly in the code.
|
|
|
|
Solution
|
|
========
|
|
|
|
Use bitshifts and OR instructions to interpret bytes in a known endian.
|
|
Instead of casting streams of bytes to larger width integers, do the following:
|
|
|
|
ut8 opcode[4] = {0x10, 0x20, 0x30, 0x40};
|
|
ut32 value = opcode[0] | opcode[1] << 8 | opcode[2] << 16 | opcode[3] << 24;
|
|
|
|
or if you prefer the other endian:
|
|
|
|
ut32 value = opcode[3] | opcode[2] << 8 | opcode[1] << 16 | opcode[0] << 24;
|
|
|
|
This is much better because you actually know which endian your bytes are stored in
|
|
within the integer value, REGARDLESS of the host endian of the machine.
|
|
|
|
|
|
Endian helper functions
|
|
=======================
|
|
|
|
Radare2 now uses helper functions to interpret all byte streams in a known endian.
|
|
|
|
Please use these at all times, eg:
|
|
|
|
val32 = r_read_be32(buffer) // reads 4 bytes from a stream in BE
|
|
val32 = r_read_le32(buffer) // reads 4 bytes from a stream in LE
|
|
val32 = r_read_ble32(buffer, isbig) // reads 4 bytes from a stream:
|
|
// if isbig is true, reads in BE
|
|
// otherwise reads in LE
|
|
|
|
There are a number of helper functions for 64, 32, 16, and 8 bit reads and writes.
|
|
|
|
(Note that 8 bit reads are equivalent to casting a single byte of the buffer
|
|
to a ut8 value, ie endian is irrelevant).
|
|
|
|
Happy hacking!
|
|
|
|
- damo22
|
|
|
|
|