Skip to content

Instantly share code, notes, and snippets.

@NyaMisty
Last active August 23, 2018 10:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NyaMisty/2a6b7d6a82c9724a92c29dddd41f15de to your computer and use it in GitHub Desktop.
Save NyaMisty/2a6b7d6a82c9724a92c29dddd41f15de to your computer and use it in GitHub Desktop.
Python APIHook
MAX_INSN_LEN = 15 # maximum length of x86 instruction
JMP_OPCODE = 0xE9
PUSH_OPCODE = 0x68
MOV_OPCODE = 0xC7
RET_OPCODE = 0xC3
MOV_MODRM_BYTE = 0x44 # write to address + 1 byte displacement
MOV_SIB_BYTE = 0x24 # write to [rsp]
MOV_OFFSET = 0x04
# struct jmp64 {
# uint8_t push_opcode
# uint32_t push_addr /* lower 32-bits of the address to jump to */
# uint8_t mov_opcode
# uint8_t mov_modrm
# uint8_t mov_sib
# uint8_t mov_offset
# uint32_t mov_addr /* upper 32-bits of the address to jump to */
# uint8_t ret_opcode
# }
class Jmp64Struct(Structure):
_pack_ = 1
_fields_ = [
("push_opcode", c_byte),
("push_addr", c_int),
("mov_opcode", c_byte),
("mov_modrm", c_byte),
("mov_sib", c_byte),
("mov_offset", c_byte),
("mov_addr", c_int),
("ret_opcode", c_byte),
]
def make_jmp(src, dst):
jmp = cast(src, POINTER(Jmp64Struct)).contents
jmp.push_opcode = (PUSH_OPCODE)
jmp.push_addr = dst & 0xffffffff # truncate
jmp.mov_opcode = (MOV_OPCODE)
jmp.mov_modrm = (MOV_MODRM_BYTE)
jmp.mov_sib = (MOV_SIB_BYTE)
jmp.mov_offset = (MOV_OFFSET)
jmp.mov_addr = c_int((dst >> 32) & 0xffffffff)
jmp.ret_opcode = (RET_OPCODE)
return True
def get_jmp_size():
return sizeof(Jmp64Struct)
def make_trampoline(trampoline,
src,
jmp_size,
trampoline_len_ret):
orig_size = 0
trampoline_addr = trampoline
src_addr = src
assert (trampoline_len_ret is not None)
# Determine how many bytes of original code needs to be copied over
# to the trampoline.
while (orig_size < jmp_size):
reloc_op_offset = [0]
insn_len = disasm((src_addr + orig_size), reloc_op_offset)
if (insn_len == 0):
return False
# Copy this instruction to the trampoline.
memmove((trampoline_addr + orig_size),
(src_addr + orig_size),
insn_len)
# If the operand is a relative address, such as found in calls or
# jumps, it needs to be relocated because the original code and the
# trampoline reside at different locations in memory.
if (reloc_op_offset[0] > 0):
# Calculate how far our trampoline is from the source and change
# the address accordingly.
# print "Reloc: off:" + str(hex(trampoline_addr - src_addr))
offset = c_int((trampoline_addr - src_addr) & 0xffffffff)
op_pointer = cast((trampoline_addr + orig_size + reloc_op_offset[0]), POINTER(c_int))
op_pointer.contents.value -= offset.value
orig_size += insn_len
# print "orig_size: " + str(orig_size)
trampoline_len_ret[0] = orig_size + jmp_size
# Insert the final jump. It goes back to the original code at
# src + orig_size.
# print "make_jmp: %x %x" % ((trampoline_addr + orig_size), (src_addr + orig_size))
return make_jmp((trampoline_addr + orig_size),
(src_addr + orig_size))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment