Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 24th, 2012  |  syntax: None  |  size: 2.79 KB  |  hits: 14  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. import ctypes, mmap, struct
  2. try:
  3.     _VirtualAlloc = ctypes.windll.kernel32.VirtualAlloc
  4.     def valloc(size):
  5.         addr = _VirtualAlloc(0, size, 0x1000, 0x40)
  6.         if not addr:
  7.             raise RuntimeError("Cannot allocate RWX memory")
  8.         return addr
  9. except:
  10.     libc = ctypes.CDLL("libc.so.6")
  11.     def valloc(size):
  12.         addr = libc.valloc(size)
  13.         if not addr or libc.mprotect(addr, size, 0x07):
  14.             raise RuntimeError("Cannot allocate RWX memory")
  15.         return addr
  16.    
  17. class RPN_jit:
  18.     def __init__(self):
  19.         self.size = mmap.PAGESIZE
  20.         self.exepage = valloc(self.size) # a single page for execution at the very minimum
  21.     def emit(self, code):
  22.         # we will use cdecl function declarations, assume small endianness
  23.         buffer = "\x55" + "\x8b\xec" + "\x81\xec\xcc\0\0\0" + "\x53" + "\x56" + "\x57" + "\x8d\xbd\x34\xff\xff\xff"
  24.         def _num(o):
  25.             try: return int(o)
  26.             except: return int(o, 16)
  27.         sp = 0 # stack count, used to clean up stack space
  28.         for o in code.split():
  29.             # valid tokens: integers, +, -, *, /, %; all operators are assumed binary
  30.             try:
  31.                 o = _num(o)
  32.                 # eax, ecx serves as our registers for most current values, the stack comes later
  33.                 # every time we load in an integer, effectively, we push the content of ecx, bump eax's data into ecx, and then load into eax
  34.                 buffer += "\x51"+"\x91"+"\xb8"+struct.pack("i",o&(0xffffffff)) # don't want to overflow the mov instruction
  35.                 sp+=1
  36.             except (ValueError):
  37.                 # eax is first param, ecx is second param, eax is storage, and then we pop into ecx
  38.                 # at the end of the run, eax is the most recently "pushed" item, perfect for /xc3
  39.                 if sp<2: raise RuntimeError("Stack will underflow.")
  40.                 buffer += "\x03\xc1" if o in ("+", "add", "plus") else "\x2b\xc1" if o in ("-", "sub", "minus") \
  41.                     else "\x0f\xaf\xc1" if o in ("*", "mul", "mult") else "\x99\xf7\xf9" if o in ("/", "div") \
  42.                     else "\x99\xf7\xf9\x92" if o in ("%", "mod", "rem") else "\x55" # mod is actually just idiv and xchg edx, eax
  43.                 buffer += "\x59" # pop ecx
  44.                 sp-=1
  45.         if not sp: raise RuntimeError("Nothing to compile.")
  46.         for _ in range(sp): buffer += "\x59" # pop ecx to clear the stack
  47.         buffer += "\x5f\x5e\x5b\x8b\xe5\x5d\xc3" # pops all register, rebases ebp&esp, and return eax, which contains the last push
  48.         if not ctypes.memmove(self.exepage, buffer, min(len(buffer), self.size)):
  49.             raise RuntimeError("Input cannot not fit into memory.")
  50.         return ctypes.CFUNCTYPE(ctypes.c_int32)(self.exepage)
  51.        
  52. a = RPN_jit()
  53. print a.emit("3 10 mod 10 + 0x100 * 100 * 50 -")()