Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
# Copyright Carve Systems 2015
#
# LICENSE: If you use this code, and it helped you learn or accomplish a goal,
# please let us know. We would love to hear from you.
# Keep our numbers clean and such
def toint32(val):
return val & 0xffffffff
def toint16(val):
return val & 0xffff
"""
http://www.codepwn.com/posts/assembling-from-scratch-encoding-blx-instruction-in-arm-thumb/
Offset = 0xD8010
00 0D 80 10
Bits 31-24 23-16 15-8 7-0
0000 0000 0000 1101 1000 0000 0001 0000
Bits 31-25 24 23 22 21-12 11-2 10
0000000 0 0 0 0011011000 0000000100 00
S I1 I2 H L
J1 = ~I1 ^ S = 1
J2 = ~I2 ^ S = 1
https://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readings/ARMv7-M_ARM.pdf
A.6.7.18
"""
def bl_encode(pc, btarget):
"""
Provide the address shown in the disassembler for the instruction to
calculate for. When the code executes this will be PC.
Provide the address of the function (branch traget / btarget) the code
should branch to.
The return value will be an encode instruction ready to be an instruction
that can be patched into an ARM binary with a hex editor.
Why would you use this?
If you want to branch to a different function with the same (or at least
comptabile) signature, you can replace the branch instruction and
alter the code. This particular instruction is a little trickier than
direct branch instructions.
"""
pc = toint32(pc)
btarget = toint32(btarget)
pc = pc + 4 # Due to arm pipeline
pc = pc & 0xfffffffc # 4 byte alignment
offset = btarget - pc
print hex(offset)
s = get_bits(offset, 24, 24)
i1 = get_bits(offset, 23, 23)
i2 = get_bits(offset, 22, 22)
imm10h = get_bits(offset, 12, 21)
imm10l = get_bits(offset, 2, 11)
last2 = get_bits(offset, 0, 1)
# Mask all but the last bit
m = 0xfffffffe
j1 = (i1 ^ 0x1) # bitwise not
j2 = (i2 ^ 0x1) # bitwise not
j1 = j1 ^ s
j2 = j2 ^ s
# print 'pc:%x' % (pc)
# print 'btarget:%x' % (btarget)
# print 'offset:%x' % (offset)
# print 's:%x' % (s)
# print 'i1:%x' % (i1)
# print 'i2:%x' % (i2)
# print 'imm10h:%x' % (imm10h)
# print 'imm10l:%x' % (imm10l)
# print 'last2:%x' % (last2)
# print '---'
# print 'j1:%x' % (j1)
# print 'j2:%x' % (j2)
final_instr = 0
# bits 27-31 = 0b11110
final_instr = set_bits(final_instr, 27, 0x1e, 5)
# bit 26 = S
final_instr = set_bit(final_instr, 26, s)
# imm10h, bits 16-25
final_instr = set_bits(final_instr, 16, imm10h, 10)
# static
final_instr = set_bits(final_instr, 14, 0x3, 2)
# j1
final_instr = set_bit(final_instr, 13, j1)
# j2
final_instr = set_bit(final_instr, 12, 0x0)
# j2
final_instr = set_bit(final_instr, 11, j2)
# imm10l
final_instr = set_bits(final_instr, 1, imm10l, 10)
# last bit
final_instr = set_bit(final_instr, 0, 0x0)
top = 0xffff0000 & final_instr
bot = 0x0000ffff & final_instr
top = swap_bytes(top>>16)
bot = swap_bytes(bot)
final_instr = top << 16 | bot
return final_instr
print 'FINAL_INSTR'
print hex(final_instr)
def bl_decode(raw_instr):
raw_instr = toint32(raw_instr)
top = 0xffff0000 & raw_instr
bot = 0x0000ffff & raw_instr
top = swap_bytes(top>>16)
bot = swap_bytes(bot)
print 'raw_instr:%x' % (raw_instr)
print 'top: %x' % (top)
print 'bot: %x' % (bot)
print 'top+bot: %x' % (top<<16 | bot)
instr = top << 16 | bot
static = get_bits(instr, 27, 31)
S = get_bits(instr, 26, 26)
imm10h = get_bits(instr, 16, 25)
static = get_bits(instr, 14, 15)
j1 = get_bits(instr, 13, 13)
static = get_bits(instr, 12, 12)
j2 = get_bits(instr, 11, 11)
imm10l = get_bits(instr, 1, 10)
static = get_bits(instr, 0, 0)
ret = {
'S':S,
'imm10h':imm10h,
'j1':j1,
'j2':j2,
'imm10l':imm10l
}
return ret
# Swap the bytes in a word
def swap_bytes(word):
word = toint16(word)
b0 = word & 0x00ff
b1 = word & 0xff00
return b0 << 8 | b1 >> 8
def get_bit(byteval,idx):
x = byteval & (1 << idx)
return int(x != 0)
def set_bit(val, index, x):
"""Set the index:th bit of val to x, and return the new value."""
"""
some times its easier to just google...
http://stackoverflow.com/questions/12173774/modify-bits-in-an-integer-in-python
"""
mask = 1 << index
val &= ~mask
if x:
val |= mask
return val
def set_bits(val, offset, bits, nbits):
val = toint32(val)
for i in range(nbits):
bit = get_bit(bits, i)
val = set_bit(val, i+offset, bit)
return val
# print 'nbits: %d' % (nbits)
# print 'bits: 0x%x' % (bits)
# for i in range(nbits):
# print i
# print 'bit[%d]:%x' % (i, get_bit(bits, i))
# return val
def get_bits(val, start, end):
# [start,end)
val = toint32(val)
assert(end < 32)
assert(start >= 0)
# Make a mask the size of the range
mask_bits = end - start + 1
mask = 0
for i in range(mask_bits):
mask = mask + (1 << i)
# Chop off using right shift, then mask to get the range desired
result = (val >> start) & mask
print 'mask: %s:%x' % (mask, mask)
return result
def test_get_bits(val, start, end):
x = val
y = get_bits(x, start, end)
print hex(y)
print bin(y)
print '---'
def test_set_bits(val, offset, bits, nbits):
x = val
print 'before: %x' % (x)
y = set_bits(x, offset, bits, nbits)
print hex(y)
print bin(y)
print '---'
def test_swap_bytes(val):
print 'val: %x, swapped:%x' % (val, swap_bytes(val))
def test_bl_decode(val):
x = bl_decode(val)
print 'S:%x, imm10h:%x, j1:%x, j2: %x, imm10l:%x' % (
x['S'], x['imm10h'], x['j1'], x['j2'], x['imm10l'])
if __name__ == '__main__':
# print '--- 0xC7F3D2E8 decode'
# test_bl_decode(0xC7F3D2E8) # Hex right from hoppah
# # PC 0000c44e
# # Close v2: 003d35f4
# print '--- 0xC7F3D2E8 encode.'
# test_bl_encode(0x0000c44e, 0x003d35f4)
#test_set_bits(0xFFF00FFF, 12, 0x99, 8)
print '______EXAMPLE_____ from codepwn'
bl_encode(0x2EA6, 0xDAEB8)
print '_____v2 close, 0x0000c44e______'
bl_encode(0x0000c44e, 0x003d35f4)
print '_____close, 0x0000c44e______'
bl_encode(0x0000c44e, 0x003d35e4)
print '_____v2 close, 0x000fb5f6_______'
bl_encode(0x000fb5f6, 0x003d35f4)
print '_____close, 0x000fb5f6_______'
bl_encode(0x000fb5f6, 0x003d35e4)
# print '--- 0xD7F2FEEF'
# test_bl_decode(0xD7F2FEEF) # Hex right from hoppah
# test_get_bits(0x000000, 27, 31)
# print 'static'
# test_get_bits(0xF3C7E8D2, 27, 31)
# print 'S=1'
# test_get_bits(0xF7C7E8D2, 26, 26) # (flipped 26 to 1)
# print 'S=0'
# test_get_bits(0xF3C7E8D2, 26, 26)
# print 'imm10h'
# test_get_bits(0xF3C7E8D2, 16, 25)
# print 'static'
# test_get_bits(0xF3C7E8D2, 14, 15)
# print 'j1'
# test_get_bits(0xF3C7E8D2, 13, 13)
# print 's'
# test_get_bits(0xF3C7E8D2, 12, 12)
# print 'j2'
# test_get_bits(0xF3C7E8D2, 11, 11)
# print 'imm10l'
# test_get_bits(0xF3C7E8D2, 1, 10)
# print 's'
# test_get_bits(0xF3C7E8D2, 0, 0)
# get_bits(0xF3C7E8D2, 27, 31)
# get_bits(0xF3C7E8D2, 26, 26)
# get_bits(0xF3C7E8D2, 16, 25)
# get_bits(0xF3C7E8D2, 14, 15)
# get_bits(0xF3C7E8D2, 13, 13)
# get_bits(0xF3C7E8D2, 12, 12)
# get_bits(0xF3C7E8D2, 11, 11)
# get_bits(0xF3C7E8D2, 1, 10)
# get_bits(0xF3C7E8D2, 0, 0)
# bl_decode(0xd7f2feef)
# print '--'
# bl_decode(0xc7f3d2e8)
# test_swap_bytes(0xff00)
# test_swap_bytes(0x00ff)
# test_swap_bytes(0x1100)
# test_swap_bytes(0x2200)
# test_swap_bytes(0x00c1)
# test_swap_bytes(0x0011)
# test_swap_bytes(0x0022)
# test_swap_bytes(0xc100)
# test_swap_bytes(0x00ff)
# test_swap_bytes(0x0010)
# test_swap_bytes(0x1122)
# test_swap_bytes(0x3344)
# test_swap_bytes(0x5566)
# test_swap_bytes(0xaabb)
# test_swap_bytes(0xdead)
# test_swap_bytes(0xbeef)
# test_get_bits(0xffffddff, 8, 15)
# test_get_bits(0xffffffff, 0, 31)
# test_get_bits(0xdfffffff, 28, 31)
@pgaskin

This comment has been minimized.

@bitexploder

This comment has been minimized.

Copy link

@bitexploder bitexploder commented Jul 18, 2019

I just found this. Really cool! Thanks for the credit. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment