Last active
May 25, 2021 21:14
-
-
Save jeremy-allen-cs/c93bd333b5b585c2b840 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I just found this. Really cool! Thanks for the credit. :)