We are often looking at ARM binaries in our favorite disassembler as we work on mobile applications and "Internet of Things" devices. As we worked on this binary we discovered a particular branch instruction that we wanted to modify. If you are familiar with the X86 jmp instruction, the ARM bx and bl instructions are similar.
Below is some ARM assembly. To the right side of the image is the raw encoding for the BLX instruction:
This particular instruction uses PC relative addressing. The BL instruction permits a branch of up to -16777216 to 16777214 bytes. It suited our purposes for modifying this binary to jump to a routine with the same signature, but resulting in a very different outcome in the execution of the binary.
It would be nice if the bits for the address were neatly packed in order, but they are not. It takes a little math and bit mangling to massage a new address into an ARM instruction that did what we wanted. So, of course, we googled for the results and found the ARMv7 reference manual: ARM v7 Reference See section A 6.7.18 for the details of the ARM BLX instruction. This is all that is really needed to decode and encode an instruction as it gives the layout for the opcode and the logic required to encode the address.
However, the following URLs are useful examples of encoding and decoding:
We needed to modify a lot of instructions, so we opted to automate this using a Python program we created. This is just a quick and dirty script we hacked up in an hour, which pleased us greatly:
You find the PC relative BLX/BL instruction you want to replace, and then find the new instruction you want it to link to. These are the two inputs into the file. Next, open up your favorite hex editor and replace the raw machine code bytes with your new instruction. When the program executes it will jump to your desired sub-routine.