Soo, uuhhh, I was just bored on a train. And "I have no idea what I'm doing" 
applies rather heavily.

But... I just ported: <https://nullprogram.com/blog/2016/03/31/> to Nim to try 
it out for this. To my utter surprise it actually works. I'm pretty sure it's 
_not_ a good idea to use this for testing, but it's fun, haha.
    
    
    import posix
    
    proc foo(s: string, x: int) =
      echo "Hello ", s, " id ", x
    
    proc bar(s: string, x: int) =
      echo "Hax0r you! ", s, " id ", x * 123
    type
      Instr {.union.} = object
        bytes: array[8, byte]
        value: uint64
    
    proc hotpatchImpl*(target, replacement: pointer) =
      # YOLO who needs alignment
      #doAssert (cast[ByteAddress](target) and ByteAddress(0x07)) == 0
      var page = cast[pointer](cast[ByteAddress](target) and (not 0xfff))
      doAssert mprotect(page, 4096, PROT_WRITE or PROT_EXEC) == 0
      let rel = cast[ByteAddress](replacement) - cast[ByteAddress](target) - 5
      var instr = Instr(bytes: [0xe9.byte,
                                (rel shr 0).byte,
                                (rel shr 8).byte,
                                (rel shr 16).byte,
                                (rel shr 24).byte,
                                0, 0, 0])
      cast[ptr uint64](target)[] = instr.value
      doAssert mprotect(page, 4096, PROT_EXEC) == 0
    
    template hotpatch*(target, replacement: untyped): untyped =
      hotpatchImpl(cast[pointer](target), cast[pointer](replacement))
    
    foo("world", 1)
    hotpatch(foo, bar)
    foo("world", 1)
    
    import strutils
    proc myParse(s: string): int = 1337
    hotpatch(parseInt, myParse)
    echo "12".parseInt()
    
    
    Run

(or see here that it actually works:

<https://play.nim-lang.org/#ix=40DX>

Reply via email to