diff --git a/bindings/dotnet/UnicornEngine/Unicorn.fs b/bindings/dotnet/UnicornEngine/Unicorn.fs index e353bf0c..56a683b0 100644 --- a/bindings/dotnet/UnicornEngine/Unicorn.fs +++ b/bindings/dotnet/UnicornEngine/Unicorn.fs @@ -22,17 +22,16 @@ and SyscallHook = delegate of Unicorn * Object -> unit and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = // hook callback list - let _codeHooks = new List<(CodeHook * Object)>() - let _blockHooks = new List<(BlockHook * Object)>() - let _interruptHooks = new List<(InterruptHook * Object)>() - let _memReadHooks = new List<(MemReadHook * Object)>() - let _memWriteHooks = new List<(MemWriteHook * Object)>() - let _memEventHooks = new Dictionary>() - let _inHooks = new List<(InHook * Object)>() - let _outHooks = new List<(OutHook * Object)>() - let _syscallHooks = new List<(SyscallHook * Object)>() + let _codeHooks = new List<(CodeHook * (UIntPtr * Object * Object))>() + let _blockHooks = new List<(BlockHook * (UIntPtr * Object * Object))>() + let _interruptHooks = new List<(InterruptHook * (UIntPtr * Object * Object))>() + let _memReadHooks = new List<(MemReadHook * (UIntPtr * Object * Object))>() + let _memWriteHooks = new List<(MemWriteHook * (UIntPtr * Object * Object))>() + let _memEventHooks = new Dictionary>() + let _inHooks = new List<(InHook * (UIntPtr * Object * Object))>() + let _outHooks = new List<(OutHook * (UIntPtr * Object * Object))>() + let _syscallHooks = new List<(SyscallHook * (UIntPtr * Object * Object))>() let _disposablePointers = new List() - let _hookInternals = new List(); let _eventMemMap = [ @@ -46,14 +45,25 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = let mutable _eng = [|UIntPtr.Zero|] - let checkResult(errCode: Int32, errMsg: String) = - if errCode <> Common.UC_ERR_OK then raise(ApplicationException(String.Format("{0}. Error: {1}", errMsg, errCode))) + let strError(errorNo: Int32) = + let errorStringPointer = binding.Strerror(errorNo) + Marshal.PtrToStringAnsi(errorStringPointer) - let hookDel(callbacks: List<'a * Object>) (callback: 'a)= - // TODO: invoke the native function in order to not call the trampoline anymore - callbacks - |> Seq.tryFind(fun item -> match item with | (c, _) -> c = callback) - |> (fun k -> if k.IsSome then callbacks.Remove(k.Value) |> ignore) + let checkResult(errorCode: Int32) = + // return the exception instead of raising it in order to have a more meaningful stack trace + if errorCode <> Common.UC_ERR_OK then + let errorMessage = strError(errorCode) + Some <| UnicornEngineException(errorCode, errorMessage) + else None + + let hookDel(callbacks: List<'a * (UIntPtr * Object * Object)>) (callback: 'a)= + match callbacks |> Seq.tryFind(fun item -> match item with | (c, _) -> c = callback) with + | Some(item) -> + let (hh, _, _) = snd item + match binding.HookDel(_eng.[0], hh) |> checkResult with + | Some e -> raise e + | None -> callbacks.Remove(item) |> ignore + | None -> () let allocate(size: Int32) = let mem = Marshal.AllocHGlobal(size) @@ -64,61 +74,55 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = // initialize event list _eventMemMap |> Seq.map(fun kv -> kv.Key) - |> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List())) + |> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List())) // init engine _eng <- [|new UIntPtr(allocate(IntPtr.Size))|] let err = binding.UcOpen(uint32 arch, uint32 mode, _eng) - checkResult(err, "Unable to open the Unicorn Engine") + if err <> Common.UC_ERR_OK then + raise(ApplicationException(String.Format("Unable to open the Unicorn Engine. Error: {0}", err))) new(arch, mode) = new Unicorn(arch, mode, BindingFactory.getDefault()) - member private this.CheckResult(errorCode: Int32) = - // return the exception instead of raising it in order to have a more meaningful stack trace - if errorCode <> Common.UC_ERR_OK then - let errorMessage = this.StrError(errorCode) - Some <| UnicornEngineException(errorCode, errorMessage) - else None - member this.MemMap(address: Int64, size: Int64, perm: Int32) = let size = new UIntPtr(uint64 size) - match binding.MemMap(_eng.[0], uint64 address, size, uint32 perm) |> this.CheckResult with + match binding.MemMap(_eng.[0], uint64 address, size, uint32 perm) |> checkResult with | Some e -> raise e | None -> () member this.MemMapPtr(address: Int64, size: Int64, perm: Int32, ptr: IntPtr) = let size = new UIntPtr(uint64 size) let ptr = new UIntPtr(ptr.ToPointer()) - match binding.MemMapPtr(_eng.[0], uint64 address, size, uint32 perm, ptr) |> this.CheckResult with + match binding.MemMapPtr(_eng.[0], uint64 address, size, uint32 perm, ptr) |> checkResult with | Some e -> raise e | None -> () member this.MemUnmap(address: Int64, size: Int64) = let size = new UIntPtr(uint64 size) - match binding.MemUnmap(_eng.[0], uint64 address, size) |> this.CheckResult with + match binding.MemUnmap(_eng.[0], uint64 address, size) |> checkResult with | Some e -> raise e | None -> () member this.MemProtect(address: Int64, size: Int64, ?perm: Int32) = let size = new UIntPtr(uint64 size) let perm = defaultArg perm Common.UC_PROT_ALL - match binding.MemProtect(_eng.[0], uint64 address, size, uint32 perm) |> this.CheckResult with + match binding.MemProtect(_eng.[0], uint64 address, size, uint32 perm) |> checkResult with | Some e -> raise e | None -> () member this.MemWrite(address: Int64, value: Byte array) = - match binding.MemWrite(_eng.[0], uint64 address, value, new UIntPtr(uint32 value.Length)) |> this.CheckResult with + match binding.MemWrite(_eng.[0], uint64 address, value, new UIntPtr(uint32 value.Length)) |> checkResult with | Some e -> raise e | None -> () member this.MemRead(address: Int64, memValue: Byte array) = - match binding.MemRead(_eng.[0], uint64 address, memValue, new UIntPtr(uint32 memValue.Length)) |> this.CheckResult with + match binding.MemRead(_eng.[0], uint64 address, memValue, new UIntPtr(uint32 memValue.Length)) |> checkResult with | Some e -> raise e | None -> () member this.RegWrite(regId: Int32, value: Byte array) = - match binding.RegWrite(_eng.[0], regId, value) |> this.CheckResult with + match binding.RegWrite(_eng.[0], regId, value) |> checkResult with | Some e -> raise e | None -> () member this.RegWrite(regId: Int32, value: Int64) = this.RegWrite(regId, int64ToBytes value) member this.RegRead(regId: Int32, regValue: Byte array) = - match binding.RegRead(_eng.[0], regId, regValue) |> this.CheckResult with + match binding.RegRead(_eng.[0], regId, regValue) |> checkResult with | Some e -> raise e | None -> () member this.RegRead(regId: Int32) = @@ -127,15 +131,15 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = bytesToInt64 buffer member this.EmuStart(beginAddr: Int64, untilAddr: Int64, timeout: Int64, count: Int64) = - match binding.EmuStart(_eng.[0], uint64 beginAddr, uint64 untilAddr, uint64 timeout, uint64 count) |> this.CheckResult with + match binding.EmuStart(_eng.[0], uint64 beginAddr, uint64 untilAddr, uint64 timeout, uint64 count) |> checkResult with | Some e -> raise e | None -> () member this.EmuStop() = - match binding.EmuStop(_eng.[0]) |> this.CheckResult with + match binding.EmuStop(_eng.[0]) |> checkResult with | Some e -> raise e | None -> () member this.Close() = - match binding.Close(_eng.[0]) |> this.CheckResult with + match binding.Close(_eng.[0]) |> checkResult with | Some e -> raise e | None -> () member this.ArchSupported(arch: Int32) = @@ -144,24 +148,18 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = member this.ErrNo() = binding.Errono(_eng.[0]) - member this.StrError(errorNo: Int32) = - let errorStringPointer = binding.Strerror(errorNo) - Marshal.PtrToStringAnsi(errorStringPointer) - member this.AddCodeHook(callback: CodeHook, userData: Object, beginAddr: Int64, endAddr: Int64) = let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) = - _codeHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData)) + callback.Invoke(this, addr, size, userData) - if _codeHooks |> Seq.isEmpty then - let codeHookInternal = new CodeHookInternal(trampoline) - _hookInternals.Add(codeHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(codeHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () + let codeHookInternal = new CodeHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(codeHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () - _codeHooks.Add(callback, userData) + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _codeHooks.Add(callback, (hh, userData, codeHookInternal)) member this.AddCodeHook(callback: CodeHook, beginAddr: Int64, endAddr: Int64) = this.AddCodeHook(callback, null, beginAddr, endAddr) @@ -171,36 +169,32 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = member this.AddBlockHook(callback: BlockHook, userData: Object, beginAddr: Int64, endAddr: Int64) = let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) = - _blockHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData)) + callback.Invoke(this, addr, size, userData) - if _blockHooks |> Seq.isEmpty then - let blockHookInternal = new BlockHookInternal(trampoline) - _hookInternals.Add(blockHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(blockHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () + let blockHookInternal = new BlockHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(blockHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () - _blockHooks.Add(callback, userData) + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _blockHooks.Add(callback, (hh, userData, blockHookInternal)) member this.HookDel(callback: BlockHook) = hookDel _blockHooks callback member this.AddInterruptHook(callback: InterruptHook, userData: Object, hookBegin: UInt64, hookEnd : UInt64) = let trampoline(u: IntPtr) (intNumber: Int32) (user: IntPtr) = - _interruptHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, intNumber, userData)) + callback.Invoke(this, intNumber, userData) - if _interruptHooks |> Seq.isEmpty then - let interruptHookInternal = new InterruptHookInternal(trampoline) - _hookInternals.Add(interruptHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(interruptHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, hookBegin, hookEnd) |> this.CheckResult with - | Some e -> raise e | None -> () + let interruptHookInternal = new InterruptHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(interruptHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, hookBegin, hookEnd) |> checkResult with + | Some e -> raise e | None -> () - _interruptHooks.Add(callback, userData) + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _interruptHooks.Add(callback, (hh, userData, interruptHookInternal)) member this.AddInterruptHook(callback: InterruptHook) = this.AddInterruptHook(callback, null, uint64 1, uint64 0) @@ -210,129 +204,130 @@ and Unicorn(arch: Int32, mode: Int32, binding: IBinding) = member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) = let trampoline(u: IntPtr) (_eventType: Int32) (addr: Int64) (size: Int32) (user: IntPtr) = - _memReadHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData)) + callback.Invoke(this, addr, size, userData) - if _memReadHooks |> Seq.isEmpty then - let memReadHookInternal = new MemReadHookInternal(trampoline) - _hookInternals.Add(memReadHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(memReadHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () + let memReadHookInternal = new MemReadHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(memReadHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () - _memReadHooks.Add(callback, userData) + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _memReadHooks.Add(callback, (hh, userData, memReadHookInternal)) member this.HookDel(callback: MemReadHook) = hookDel _memReadHooks callback member this.AddMemWriteHook(callback: MemWriteHook, userData: Object, beginAddr: Int64, endAddr: Int64) = let trampoline(u: IntPtr) (_eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) = - _memWriteHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, value, userData)) + callback.Invoke(this, addr, size, value, userData) - if _memWriteHooks |> Seq.isEmpty then - let memWriteHookInternal = new MemWriteHookInternal(trampoline) - _hookInternals.Add(memWriteHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(memWriteHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> this.CheckResult with - | Some e -> raise e | None -> () + let memWriteHookInternal = new MemWriteHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(memWriteHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddNoarg(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with + | Some e -> raise e | None -> () - _memWriteHooks.Add(callback, userData) + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _memWriteHooks.Add(callback, (hh, userData, memWriteHookInternal)) member this.HookDel(callback: MemWriteHook) = hookDel _memWriteHooks callback - member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object) = + member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object, beginAddr: Int64, endAddr: Int64) = let trampoline(u: IntPtr) (eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) = - _memEventHooks.Keys - |> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0) - |> Seq.map(fun eventflag -> _memEventHooks.[eventflag]) - |> Seq.concat - |> Seq.map(fun (callback, userData) -> callback.Invoke(this, eventType, addr, size, value, userData)) - |> Seq.forall id + callback.Invoke(this, eventType, addr, size, value, userData) // register the event if not already done _memEventHooks.Keys |> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0) - |> Seq.filter(fun eventFlag -> _memEventHooks.[eventFlag] |> Seq.isEmpty) |> Seq.iter(fun eventFlag -> let memEventHookInternal = new EventMemHookInternal(trampoline) - _hookInternals.Add(memEventHookInternal) let funcPointer = Marshal.GetFunctionPointerForDelegate(memEventHookInternal) let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddNoarg(_eng.[0], hh, eventFlag, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 1, uint64 0) |> this.CheckResult with + match binding.HookAddNoarg(_eng.[0], hh, eventFlag, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr) |> checkResult with | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _memEventHooks.[eventFlag].Add((callback, (hh, userData, memEventHookInternal))) ) - // register the callbacks - _memEventHooks.Keys - |> Seq.filter(fun eventFlag -> (eventType &&& eventFlag) <> 0) - |> Seq.iter(fun eventFlag -> _memEventHooks.[eventFlag].Add((callback, userData))) + member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object) = + this.AddEventMemHook(callback, eventType, userData, 1, 0) member this.AddEventMemHook(callback: EventMemHook, eventType: Int32) = this.AddEventMemHook(callback, eventType, null) member this.HookDel(callback: EventMemHook) = - let callbacks = (_memEventHooks.Values |> Seq.concat).ToList() - hookDel callbacks callback + _memEventHooks.Keys + |> Seq.iter(fun eventFlag -> hookDel _memEventHooks.[eventFlag] callback) + + member this.AddInHook(callback: InHook, userData: Object, beginAddr: Int64, endAddr: Int64) = + let trampoline(u: IntPtr) (port: Int32) (size: Int32) (user: IntPtr) = + callback.Invoke(this, port, size, userData) + + let inHookInternal = new InHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(inHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_IN) |> checkResult with + | Some e -> raise e | None -> () + + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _inHooks.Add(callback, (hh, userData, inHookInternal)) member this.AddInHook(callback: InHook, userData: Object) = - let trampoline(u: IntPtr) (port: Int32) (size: Int32) (user: IntPtr) = - _inHooks - |> Seq.map(fun (callback, userData) -> callback.Invoke(this, port, size, userData)) - |> Seq.last - - if _inHooks |> Seq.isEmpty then - let inHookInternal = new InHookInternal(trampoline) - _hookInternals.Add(inHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(inHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 1, uint64 0, X86.UC_X86_INS_IN) |> this.CheckResult with - | Some e -> raise e | None -> () - - _inHooks.Add(callback, userData) + this.AddInHook(callback, userData, 1, 0) member this.AddInHook(callback: InHook) = this.AddInHook(callback, null) - member this.AddOutHook(callback: OutHook, userData: Object) = + member this.HookDel(callback: InHook) = + hookDel _inHooks callback + + member this.AddOutHook(callback: OutHook, userData: Object, beginAddr: Int64, endAddr: Int64) = let trampoline(u: IntPtr) (port: Int32) (size: Int32) (value: Int32) (user: IntPtr) = - _outHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, port, size, value, userData)) + callback.Invoke(this, port, size, value, userData) - if _outHooks |> Seq.isEmpty then - let outHookInternal = new OutHookInternal(trampoline) - _hookInternals.Add(outHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(outHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 1, uint64 0, X86.UC_X86_INS_OUT) |> this.CheckResult with - | Some e -> raise e | None -> () + let outHookInternal = new OutHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(outHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_OUT) |> checkResult with + | Some e -> raise e | None -> () - _outHooks.Add(callback, userData) + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _outHooks.Add(callback, (hh, userData, outHookInternal)) + + member this.AddOutHook(callback: OutHook, userData: Object) = + this.AddOutHook(callback, userData, 1, 0) member this.AddOutHook(callback: OutHook) = this.AddOutHook(callback, null) - member this.AddSyscallHook(callback: SyscallHook, userData: Object) = + member this.HookDel(callback: OutHook) = + hookDel _outHooks callback + + member this.AddSyscallHook(callback: SyscallHook, userData: Object, beginAddr: Int64, endAddr: Int64) = let trampoline(u: IntPtr) (user: IntPtr) = - _syscallHooks - |> Seq.iter(fun (callback, userData) -> callback.Invoke(this, userData)) + callback.Invoke(this, userData) - if _syscallHooks |> Seq.isEmpty then - let syscallHookInternal = new SyscallHookInternal(trampoline) - _hookInternals.Add(syscallHookInternal) - let funcPointer = Marshal.GetFunctionPointerForDelegate(syscallHookInternal) - let hh = new UIntPtr(allocate(IntPtr.Size)) - match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 1, uint64 0, X86.UC_X86_INS_SYSCALL) |> this.CheckResult with - | Some e -> raise e | None -> () + let syscallHookInternal = new SyscallHookInternal(trampoline) + let funcPointer = Marshal.GetFunctionPointerForDelegate(syscallHookInternal) + let hh = new UIntPtr(allocate(IntPtr.Size)) + match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 beginAddr, uint64 endAddr, X86.UC_X86_INS_SYSCALL) |> checkResult with + | Some e -> raise e | None -> () - _syscallHooks.Add(callback, userData) + let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh)) + _syscallHooks.Add(callback, (hh, userData, syscallHookInternal)) + + member this.AddSyscallHook(callback: SyscallHook, userData: Object) = + this.AddSyscallHook(callback, userData, 1, 0) member this.AddSyscallHook(callback: SyscallHook) = this.AddSyscallHook(callback, null) + member this.HookDel(callback: SyscallHook) = + hookDel _syscallHooks callback + member this.Version() = let (major, minor) = (new UIntPtr(), new UIntPtr()) let combined = binding.Version(major, minor)