diff --git a/bindings/dotnet/Unicorn/Unicorn.fs b/bindings/dotnet/Unicorn/Unicorn.fs index 79108c1d..5c881e57 100644 --- a/bindings/dotnet/Unicorn/Unicorn.fs +++ b/bindings/dotnet/Unicorn/Unicorn.fs @@ -51,6 +51,7 @@ and Unicorn(arch: Int32, mode: Int32) = let _inHooks = new Dictionary<IntPtr, (InHook * Object)>() let _outHooks = new Dictionary<IntPtr, (OutHook * Object)>() let _syscallHooks = new Dictionary<IntPtr, (SyscallHook * Object)>() + let _disposablePointers = new List<nativeint>() let mutable _eng = [|UIntPtr.Zero|] @@ -66,10 +67,14 @@ and Unicorn(arch: Int32, mode: Int32) = callbacks.Keys |> Seq.tryFind(fun k -> match callbacks.[k] with | (c, _) -> c = callback) |> (fun k -> if k.IsSome then callbacks.Remove(k.Value) |> ignore) + + let allocate(size: Int32) = + let mem = Marshal.AllocHGlobal(size) + _disposablePointers.Add(mem) + mem.ToPointer() - do - let mem = Marshal.AllocHGlobal(IntPtr.Size) - _eng <- [|new UIntPtr(mem.ToPointer())|] + do + _eng <- [|new UIntPtr(allocate(IntPtr.Size))|] let err = NativeUnicornEngine.uc_open(uint32 arch, uint32 mode, _eng) checkResult(err, "Unable to open the Unicorn Engine") @@ -130,8 +135,8 @@ and Unicorn(arch: Int32, mode: Int32) = let id = getId() _codeHooks.Add(id, (callback, userData)) - let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline)) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr) |> this.CheckResult with | Some e -> raise e | None -> () @@ -147,7 +152,7 @@ and Unicorn(arch: Int32, mode: Int32) = _blockHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new BlockHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr) |> this.CheckResult with | Some e -> raise e | None -> () @@ -163,7 +168,7 @@ and Unicorn(arch: Int32, mode: Int32) = _interruptHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new InterruptHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_noarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), id) |> this.CheckResult with | Some e -> raise e | None -> () @@ -179,7 +184,7 @@ and Unicorn(arch: Int32, mode: Int32) = _memReadHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemReadHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr) |> this.CheckResult with | Some e -> raise e | None -> () @@ -195,7 +200,7 @@ and Unicorn(arch: Int32, mode: Int32) = _memWriteHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemWriteHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr) |> this.CheckResult with | Some e -> raise e | None -> () @@ -212,7 +217,7 @@ and Unicorn(arch: Int32, mode: Int32) = _memEventHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new EventMemHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_noarg(_eng.[0], hh, check, new UIntPtr(funcPointer.ToPointer()), id) |> this.CheckResult with | Some e -> raise e | None -> () @@ -241,7 +246,7 @@ and Unicorn(arch: Int32, mode: Int32) = _inHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new InHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_arg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), id, new IntPtr(X86.UC_X86_INS_IN)) |> this.CheckResult with | Some e -> raise e | None -> () @@ -254,7 +259,7 @@ and Unicorn(arch: Int32, mode: Int32) = _outHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new OutHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_arg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), id, new IntPtr(X86.UC_X86_INS_OUT)) |> this.CheckResult with | Some e -> raise e | None -> () @@ -267,7 +272,7 @@ and Unicorn(arch: Int32, mode: Int32) = _syscallHooks.Add(id, (callback, userData)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new SyscallHookInternal(trampoline)) - let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) + let hh = new UIntPtr(allocate(IntPtr.Size)) match NativeUnicornEngine.hook_add_arg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), id, new IntPtr(X86.UC_X86_INS_SYSCALL)) |> this.CheckResult with | Some e -> raise e | None -> () @@ -275,3 +280,24 @@ and Unicorn(arch: Int32, mode: Int32) = let (major, minor) = (new UIntPtr(), new UIntPtr()) let combined = NativeUnicornEngine.version(major, minor) (major.ToUInt32(), minor.ToUInt32(), combined) + + abstract Dispose : Boolean -> unit + default this.Dispose(disposing: Boolean) = + if (disposing) then + // free managed resources, this is the default dispose implementation pattern + () + + _disposablePointers + |> Seq.filter(fun pointer -> pointer <> IntPtr.Zero) + |> Seq.iter Marshal.FreeHGlobal + + member this.Dispose() = + this.Dispose(true) + GC.SuppressFinalize(this) + + override this.Finalize() = + this.Dispose(false) + + interface IDisposable with + member this.Dispose() = + this.Dispose() diff --git a/bindings/dotnet/Unicorn/Unicorn.fsproj b/bindings/dotnet/Unicorn/Unicorn.fsproj index 8f6ee136..1bb52e8c 100644 --- a/bindings/dotnet/Unicorn/Unicorn.fsproj +++ b/bindings/dotnet/Unicorn/Unicorn.fsproj @@ -8,9 +8,9 @@ <ProjectGuid>6f0e55fa-a056-45ff-bb24-641457b430a8</ProjectGuid> <OutputType>Library</OutputType> <RootNamespace>UnicornSln</RootNamespace> - <AssemblyName>UnicornSln</AssemblyName> - <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> - <TargetFSharpCoreVersion>4.3.0.0</TargetFSharpCoreVersion> + <AssemblyName>UnicornManaged</AssemblyName> + <TargetFrameworkVersion>v4.6</TargetFrameworkVersion> + <TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion> <Name>Unicorn</Name> <TargetFrameworkProfile /> </PropertyGroup> @@ -22,8 +22,11 @@ <OutputPath>bin\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <WarningLevel>3</WarningLevel> - <DocumentationFile>bin\Debug\UnicornSln.XML</DocumentationFile> + <DocumentationFile>bin\Debug\UnicornManaged.XML</DocumentationFile> <PlatformTarget>x86</PlatformTarget> + <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <WarningsAsErrors /> + <EnableUnmanagedDebugging>true</EnableUnmanagedDebugging> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> diff --git a/bindings/dotnet/UnicornTests/App.config b/bindings/dotnet/UnicornTests/App.config index 9c05822f..2d2a12d8 100644 --- a/bindings/dotnet/UnicornTests/App.config +++ b/bindings/dotnet/UnicornTests/App.config @@ -1,6 +1,6 @@ -<?xml version="1.0" encoding="utf-8" ?> +<?xml version="1.0" encoding="utf-8"?> <configuration> <startup> - <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" /> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/> </startup> -</configuration> \ No newline at end of file +</configuration> diff --git a/bindings/dotnet/UnicornTests/Program.cs b/bindings/dotnet/UnicornTests/Program.cs index dde8d1e8..9cdd5cd2 100644 --- a/bindings/dotnet/UnicornTests/Program.cs +++ b/bindings/dotnet/UnicornTests/Program.cs @@ -34,6 +34,9 @@ namespace UnicornTests // Run all shellcode tests ShellcodeTest.TestX86Code32Self(); ShellcodeTest.TestX86Code32(); + + Console.Write("Tests completed"); + Console.ReadLine(); } } } diff --git a/bindings/dotnet/UnicornTests/ShellcodeTest.cs b/bindings/dotnet/UnicornTests/ShellcodeTest.cs index e254fb4a..af1481f3 100644 --- a/bindings/dotnet/UnicornTests/ShellcodeTest.cs +++ b/bindings/dotnet/UnicornTests/ShellcodeTest.cs @@ -72,33 +72,35 @@ namespace UnicornTests { try { - var u = new Unicorn(Common.UC_ARCH_X86, Common.UC_MODE_32); - Console.WriteLine("Unicorn version: {0}", u.Version()); + using (var u = new Unicorn(Common.UC_ARCH_X86, Common.UC_MODE_32)) + { + Console.WriteLine("Unicorn version: {0}", u.Version()); - // map 2MB of memory for this emulation - u.MemMap(address, new UIntPtr(2 * 1024 * 1024), Common.UC_PROT_ALL); + // map 2MB of memory for this emulation + u.MemMap(address, new UIntPtr(2 * 1024 * 1024), Common.UC_PROT_ALL); - // write machine code to be emulated to memory - u.MemWrite(address, code); + // write machine code to be emulated to memory + u.MemWrite(address, code); - // initialize machine registers - u.RegWrite(X86.UC_X86_REG_ESP, Utils.Int64ToBytes(address + 0x200000)); + // initialize machine registers + u.RegWrite(X86.UC_X86_REG_ESP, Utils.Int64ToBytes(address + 0x200000)); - // tracing all instructions by having @begin > @end - u.AddCodeHook(CodeHookCallback, null, 1, 0); + // tracing all instructions by having @begin > @end + u.AddCodeHook(CodeHookCallback, null, 1, 0); - // handle interrupt ourself - u.AddInterruptHook(InterruptHookCallback, null); + // handle interrupt ourself + u.AddInterruptHook(InterruptHookCallback, null); - // handle SYSCALL - u.AddSyscallHook(SyscallHookCallback, null); + // handle SYSCALL + u.AddSyscallHook(SyscallHookCallback, null); - Console.WriteLine(">>> Start tracing linux code"); + Console.WriteLine(">>> Start tracing linux code"); - // emulate machine code in infinite time - u.EmuStart(address, address + (UInt64)code.Length, 0u, new UIntPtr(0)); + // emulate machine code in infinite time + u.EmuStart(address, address + (UInt64)code.Length, 0u, new UIntPtr(0)); - Console.WriteLine(">>> Emulation Done!"); + Console.WriteLine(">>> Emulation Done!"); + } } catch (UnicornEngineException ex) { diff --git a/bindings/dotnet/UnicornTests/UnicornTests.csproj b/bindings/dotnet/UnicornTests/UnicornTests.csproj index dfb6bdf1..1c8a9278 100644 --- a/bindings/dotnet/UnicornTests/UnicornTests.csproj +++ b/bindings/dotnet/UnicornTests/UnicornTests.csproj @@ -9,9 +9,10 @@ <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>UnicornTests</RootNamespace> <AssemblyName>UnicornTests</AssemblyName> - <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion> + <TargetFrameworkVersion>v4.6</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> + <TargetFrameworkProfile /> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>x86</PlatformTarget> @@ -22,6 +23,7 @@ <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget>