Merge branch 'dev' into zig-bindgen

This commit is contained in:
Matheus C. França
2023-03-23 16:17:55 -03:00
committed by GitHub
69 changed files with 1199 additions and 1221 deletions

View File

@@ -90,10 +90,10 @@ template = {
'comment_close': '',
},
'dotnet': {
'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nnamespace UnicornManaged.Const\n\nopen System\n\n[<AutoOpen>]\nmodule %s =\n",
'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nnamespace UnicornEngine.Const\n\nopen System\n\n[<AutoOpen>]\nmodule %s =\n",
'footer': "\n",
'line_format': ' let UC_%s = %s\n',
'out_file': os.path.join('dotnet', 'UnicornManaged', 'Const', '%s.fs'),
'out_file': os.path.join('dotnet', 'UnicornEngine', 'Const', '%s.fs'),
# prefixes for constant filenames of all archs - case sensitive
'arm.h': 'Arm',
'arm64.h': 'Arm64',

View File

@@ -5,7 +5,7 @@ VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicornSamples", "UnicornSamples\UnicornSamples.csproj", "{B80B5987-1E24-4309-8BF9-C4F91270F21C}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UnicornManaged", "UnicornManaged\UnicornManaged.fsproj", "{0C21F1C1-2725-4A46-9022-1905F85822A5}"
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "UnicornEngine", "UnicornEngine\UnicornEngine.fsproj", "{0C21F1C1-2725-4A46-9022-1905F85822A5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@@ -1,4 +1,4 @@
namespace UnicornManaged.Binding
namespace UnicornEngine.Binding
module BindingFactory =

View File

@@ -1,4 +1,4 @@
namespace UnicornManaged.Binding
namespace UnicornEngine.Binding
open System

View File

@@ -1,4 +1,4 @@
namespace UnicornManaged.Binding
namespace UnicornEngine.Binding
open System

View File

@@ -1,4 +1,4 @@
namespace UnicornManaged.Binding
namespace UnicornEngine.Binding
open System
open System.Runtime.InteropServices

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System
@@ -9,13 +9,13 @@ module Common =
let UC_API_MAJOR = 2
let UC_API_MINOR = 0
let UC_API_PATCH = 1
let UC_API_EXTRA = 255
let UC_API_PATCH = 2
let UC_API_EXTRA = 1
let UC_VERSION_MAJOR = 2
let UC_VERSION_MINOR = 0
let UC_VERSION_PATCH = 1
let UC_VERSION_EXTRA = 255
let UC_VERSION_PATCH = 2
let UC_VERSION_EXTRA = 1
let UC_SECOND_SCALE = 1000000
let UC_MILISECOND_SCALE = 1000
let UC_ARCH_ARM = 1

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,6 +1,6 @@
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
namespace UnicornManaged.Const
namespace UnicornEngine.Const
open System

View File

@@ -1,4 +1,4 @@
namespace UnicornManaged
namespace UnicornEngine
open System

View File

@@ -1,4 +1,4 @@
namespace UnicornManaged
namespace UnicornEngine
open System
open System.Runtime.InteropServices
@@ -14,10 +14,10 @@ type internal BlockHookInternal = delegate of IntPtr * Int64 * Int32 * IntPtr ->
type internal InterruptHookInternal = delegate of IntPtr * Int32 * IntPtr -> unit
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type internal MemReadHookInternal = delegate of IntPtr * Int64 * Int32 * IntPtr -> unit
type internal MemReadHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * IntPtr -> unit
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type internal MemWriteHookInternal = delegate of IntPtr * Int64 * Int32 * Int64 * IntPtr -> unit
type internal MemWriteHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * Int64 * IntPtr -> unit
[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type internal EventMemHookInternal = delegate of IntPtr * Int32 * Int64 * Int32 * Int64 * IntPtr-> Boolean

View File

@@ -0,0 +1,356 @@
namespace UnicornEngine
open System
open System.Collections.Generic
open System.Runtime.InteropServices
open System.Linq
open UnicornEngine.Const
open UnicornEngine.Binding
// exported hooks
type CodeHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
and BlockHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
and InterruptHook = delegate of Unicorn * Int32 * Object -> unit
and MemReadHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
and MemWriteHook = delegate of Unicorn * Int64 * Int32 * Int64 * Object -> unit
and EventMemHook = delegate of Unicorn * Int32 * Int64 * Int32 * Int64 * Object -> Boolean
and InHook = delegate of Unicorn * Int32 * Int32 * Object -> Int32
and OutHook = delegate of Unicorn * Int32 * Int32 * Int32 * Object -> unit
and SyscallHook = delegate of Unicorn * Object -> unit
// the managed unicorn engine
and Unicorn(arch: Int32, mode: Int32, binding: IBinding) =
// hook callback list
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<Int32, List<(EventMemHook * (UIntPtr * Object * Object))>>()
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<nativeint>()
let _eventMemMap =
[
(UC_HOOK_MEM_READ_UNMAPPED, UC_MEM_READ_UNMAPPED)
(UC_HOOK_MEM_WRITE_UNMAPPED, UC_MEM_WRITE_UNMAPPED)
(UC_HOOK_MEM_FETCH_UNMAPPED, UC_MEM_FETCH_UNMAPPED)
(UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT)
(UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT)
(UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT)
] |> dict
let mutable _eng = [|UIntPtr.Zero|]
let strError(errorNo: Int32) =
let errorStringPointer = binding.Strerror(errorNo)
Marshal.PtrToStringAnsi(errorStringPointer)
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)
_disposablePointers.Add(mem)
mem.ToPointer()
do
// initialize event list
_eventMemMap
|> Seq.map(fun kv -> kv.Key)
|> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List<EventMemHook * (UIntPtr * Object * Object)>()))
// init engine
_eng <- [|new UIntPtr(allocate(IntPtr.Size))|]
let err = binding.UcOpen(uint32 arch, uint32 mode, _eng)
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 this.MemMap(address: Int64, size: Int64, perm: Int32) =
let size = new UIntPtr(uint64 size)
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) |> 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) |> 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) |> 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)) |> 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)) |> checkResult with
| Some e -> raise e | None -> ()
member this.RegWrite(regId: Int32, value: Byte array) =
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) |> checkResult with
| Some e -> raise e | None -> ()
member this.RegRead(regId: Int32) =
let buffer = Array.zeroCreate<Byte> 8
this.RegRead(regId, buffer)
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) |> checkResult with
| Some e -> raise e | None -> ()
member this.EmuStop() =
match binding.EmuStop(_eng.[0]) |> checkResult with
| Some e -> raise e | None -> ()
member this.Close() =
match binding.Close(_eng.[0]) |> checkResult with
| Some e -> raise e | None -> ()
member this.ArchSupported(arch: Int32) =
binding.ArchSupported(arch)
member this.ErrNo() =
binding.Errono(_eng.[0])
member this.AddCodeHook(callback: CodeHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
callback.Invoke(this, addr, size, userData)
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 -> ()
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)
member this.HookDel(callback: CodeHook) =
hookDel _codeHooks callback
member this.AddBlockHook(callback: BlockHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
callback.Invoke(this, addr, size, userData)
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 -> ()
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) =
callback.Invoke(this, intNumber, userData)
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 -> ()
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)
member this.HookDel(callback: InterruptHook) =
hookDel _interruptHooks callback
member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
let trampoline(u: IntPtr) (_eventType: Int32) (addr: Int64) (size: Int32) (user: IntPtr) =
callback.Invoke(this, addr, size, userData)
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 -> ()
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) =
callback.Invoke(this, addr, size, value, userData)
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 -> ()
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, beginAddr: Int64, endAddr: Int64) =
let trampoline(u: IntPtr) (eventType: Int32) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) =
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.iter(fun eventFlag ->
let memEventHookInternal = new EventMemHookInternal(trampoline)
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 beginAddr, uint64 endAddr) |> checkResult with
| Some e -> raise e | None -> ()
let hh = (unativeint)(Marshal.ReadIntPtr((nativeint)hh))
_memEventHooks.[eventFlag].Add((callback, (hh, userData, memEventHookInternal)))
)
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) =
_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) =
this.AddInHook(callback, userData, 1, 0)
member this.AddInHook(callback: InHook) =
this.AddInHook(callback, null)
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) =
callback.Invoke(this, port, size, value, userData)
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 -> ()
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.HookDel(callback: OutHook) =
hookDel _outHooks callback
member this.AddSyscallHook(callback: SyscallHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
let trampoline(u: IntPtr) (user: IntPtr) =
callback.Invoke(this, userData)
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 -> ()
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)
(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
_disposablePointers.Clear()
member this.Dispose() =
this.Dispose(true)
GC.SuppressFinalize(this)
override this.Finalize() =
this.Dispose(false)
interface IDisposable with
member this.Dispose() =
this.Dispose()

View File

@@ -1,11 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>UnicornManaged</RootNamespace>
<AssemblyName>UnicornManaged</AssemblyName>
<PackageId>UnicornEngine.Unicorn</PackageId>
<Authors>UnicornEngine</Authors>
<Copyright>Copyright © Antonio Parata 2016</Copyright>
<RepositoryUrl>https://github.com/unicorn-engine/unicorn</RepositoryUrl>
<Version>2.0.0</Version>
<PackageDescription>.NET bindings for unicorn</PackageDescription>
<VersionPrefix>2.0.2-rc1</VersionPrefix>
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
<ProjectGuid>0c21f1c1-2725-4a46-9022-1905f85822a5</ProjectGuid>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -15,6 +17,10 @@
<WarningLevel>3</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>
<Compile Include="Const\Arm.fs" />
<Compile Include="Const\Arm64.fs" />
@@ -36,4 +42,8 @@
<Compile Include="ConvertUtility.fs" />
<Compile Include="Unicorn.fs" />
</ItemGroup>
<ItemGroup>
<Content Include="runtimes\**" PackagePath="runtimes" Visible="false" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
namespace UnicornManaged
namespace UnicornEngine
open System

View File

@@ -1,342 +0,0 @@
namespace UnicornManaged
open System
open System.Collections.Generic
open System.Runtime.InteropServices
open System.Linq
open UnicornManaged.Const
open UnicornManaged.Binding
// exported hooks
type CodeHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
and BlockHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
and InterruptHook = delegate of Unicorn * Int32 * Object -> unit
and MemReadHook = delegate of Unicorn * Int64 * Int32 * Object -> unit
and MemWriteHook = delegate of Unicorn * Int64 * Int32 * Int64 * Object -> unit
and EventMemHook = delegate of Unicorn * Int32 * Int64 * Int32 * Int64 * Object -> Boolean
and InHook = delegate of Unicorn * Int32 * Int32 * Object -> Int32
and OutHook = delegate of Unicorn * Int32 * Int32 * Int32 * Object -> unit
and SyscallHook = delegate of Unicorn * Object -> unit
// the managed unicorn engine
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<Int32, List<(EventMemHook * Object)>>()
let _inHooks = new List<(InHook * Object)>()
let _outHooks = new List<(OutHook * Object)>()
let _syscallHooks = new List<(SyscallHook * Object)>()
let _disposablePointers = new List<nativeint>()
let _eventMemMap =
[
(UC_HOOK_MEM_READ_UNMAPPED, UC_MEM_READ_UNMAPPED)
(UC_HOOK_MEM_WRITE_UNMAPPED, UC_MEM_WRITE_UNMAPPED)
(UC_HOOK_MEM_FETCH_UNMAPPED, UC_MEM_FETCH_UNMAPPED)
(UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT)
(UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT)
(UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT)
] |> dict
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 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 allocate(size: Int32) =
let mem = Marshal.AllocHGlobal(size)
_disposablePointers.Add(mem)
mem.ToPointer()
do
// initialize event list
_eventMemMap
|> Seq.map(fun kv -> kv.Key)
|> Seq.iter (fun eventType -> _memEventHooks.Add(eventType, new List<EventMemHook * Object>()))
// 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")
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
| 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
| 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
| 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
| 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
| 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
| Some e -> raise e | None -> ()
member this.RegWrite(regId: Int32, value: Byte array) =
match binding.RegWrite(_eng.[0], regId, value) |> this.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
| Some e -> raise e | None -> ()
member this.RegRead(regId: Int32) =
let buffer = Array.zeroCreate<Byte> 8
this.RegRead(regId, buffer)
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
| Some e -> raise e | None -> ()
member this.EmuStop() =
match binding.EmuStop(_eng.[0]) |> this.CheckResult with
| Some e -> raise e | None -> ()
member this.Close() =
match binding.Close(_eng.[0]) |> this.CheckResult with
| Some e -> raise e | None -> ()
member this.ArchSupported(arch: Int32) =
binding.ArchSupported(arch)
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))
if _codeHooks |> Seq.isEmpty then
let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline))
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 -> ()
_codeHooks.Add(callback, userData)
member this.AddCodeHook(callback: CodeHook, beginAddr: Int64, endAddr: Int64) =
this.AddCodeHook(callback, null, beginAddr, endAddr)
member this.HookDel(callback: CodeHook) =
hookDel _codeHooks callback
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))
if _blockHooks |> Seq.isEmpty then
let funcPointer = Marshal.GetFunctionPointerForDelegate(new BlockHookInternal(trampoline))
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 -> ()
_blockHooks.Add(callback, userData)
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))
if _interruptHooks |> Seq.isEmpty then
let funcPointer = Marshal.GetFunctionPointerForDelegate(new InterruptHookInternal(trampoline))
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 -> ()
_interruptHooks.Add(callback, userData)
member this.AddInterruptHook(callback: InterruptHook) =
this.AddInterruptHook(callback, null, uint64 1, uint64 0)
member this.HookDel(callback: InterruptHook) =
hookDel _interruptHooks callback
member this.AddMemReadHook(callback: MemReadHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (user: IntPtr) =
_memReadHooks
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, userData))
if _memReadHooks |> Seq.isEmpty then
let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemReadHookInternal(trampoline))
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 -> ()
_memReadHooks.Add(callback, userData)
member this.HookDel(callback: MemReadHook) =
hookDel _memReadHooks callback
member this.AddMemWriteHook(callback: MemWriteHook, userData: Object, beginAddr: Int64, endAddr: Int64) =
let trampoline(u: IntPtr) (addr: Int64) (size: Int32) (value: Int64) (user: IntPtr) =
_memWriteHooks
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, addr, size, value, userData))
if _memWriteHooks |> Seq.isEmpty then
let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemWriteHookInternal(trampoline))
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 -> ()
_memWriteHooks.Add(callback, userData)
member this.HookDel(callback: MemWriteHook) =
hookDel _memWriteHooks callback
member this.AddEventMemHook(callback: EventMemHook, eventType: Int32, userData: Object) =
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
// 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 funcPointer = Marshal.GetFunctionPointerForDelegate(new EventMemHookInternal(trampoline))
let hh = new UIntPtr(allocate(IntPtr.Size))
match binding.HookAddNoarg(_eng.[0], hh, eventFlag, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0) |> this.CheckResult with
| Some e -> raise e | None -> ()
)
// 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) =
this.AddEventMemHook(callback, eventType, null)
member this.HookDel(callback: EventMemHook) =
let callbacks = (_memEventHooks.Values |> Seq.concat).ToList()
hookDel callbacks callback
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 funcPointer = Marshal.GetFunctionPointerForDelegate(new InHookInternal(trampoline))
let hh = new UIntPtr(allocate(IntPtr.Size))
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_IN) |> this.CheckResult with
| Some e -> raise e | None -> ()
_inHooks.Add(callback, userData)
member this.AddInHook(callback: InHook) =
this.AddInHook(callback, null)
member this.AddOutHook(callback: OutHook, userData: Object) =
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))
if _outHooks |> Seq.isEmpty then
let funcPointer = Marshal.GetFunctionPointerForDelegate(new OutHookInternal(trampoline))
let hh = new UIntPtr(allocate(IntPtr.Size))
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_OUT) |> this.CheckResult with
| Some e -> raise e | None -> ()
_outHooks.Add(callback, userData)
member this.AddOutHook(callback: OutHook) =
this.AddOutHook(callback, null)
member this.AddSyscallHook(callback: SyscallHook, userData: Object) =
let trampoline(u: IntPtr) (user: IntPtr) =
_syscallHooks
|> Seq.iter(fun (callback, userData) -> callback.Invoke(this, userData))
if _syscallHooks |> Seq.isEmpty then
let funcPointer = Marshal.GetFunctionPointerForDelegate(new SyscallHookInternal(trampoline))
let hh = new UIntPtr(allocate(IntPtr.Size))
match binding.HookAddArg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), IntPtr.Zero, uint64 0, uint64 0, X86.UC_X86_INS_SYSCALL) |> this.CheckResult with
| Some e -> raise e | None -> ()
_syscallHooks.Add(callback, userData)
member this.AddSyscallHook(callback: SyscallHook) =
this.AddSyscallHook(callback, null)
member this.Version() =
let (major, minor) = (new UIntPtr(), new UIntPtr())
let combined = binding.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
_disposablePointers.Clear()
member this.Dispose() =
this.Dispose(true)
GC.SuppressFinalize(this)
override this.Finalize() =
this.Dispose(false)
interface IDisposable with
member this.Dispose() =
this.Dispose()

View File

@@ -3,8 +3,8 @@ using Gee.External.Capstone.X86;
using System;
using System.Diagnostics;
using System.Text;
using UnicornManaged;
using UnicornManaged.Const;
using UnicornEngine;
using UnicornEngine.Const;
namespace UnicornSamples
{

View File

@@ -6,7 +6,7 @@
<AssemblyName>UnicornSamples</AssemblyName>
<Copyright>Copyright © Antonio Parata 2016</Copyright>
<RepositoryUrl>https://github.com/unicorn-engine/unicorn</RepositoryUrl>
<Version>2.0.0</Version>
<Version>2.0.2-rc1</Version>
<ProjectGuid>{B80B5987-1E24-4309-8BF9-C4F91270F21C}</ProjectGuid>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
@@ -17,9 +17,9 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\UnicornManaged\UnicornManaged.fsproj">
<ProjectReference Include="..\UnicornEngine\UnicornEngine.fsproj">
<Project>{0c21f1c1-2725-4a46-9022-1905f85822a5}</Project>
<Name>UnicornManaged</Name>
<Name>UnicornEngine</Name>
</ProjectReference>
</ItemGroup>

View File

@@ -3,8 +3,8 @@ using Gee.External.Capstone.X86;
using System;
using System.Diagnostics;
using System.Text;
using UnicornManaged;
using UnicornManaged.Const;
using UnicornEngine;
using UnicornEngine.Const;
namespace UnicornSamples
{

View File

@@ -4,13 +4,13 @@ const (
API_MAJOR = 2
API_MINOR = 0
API_PATCH = 1
API_EXTRA = 255
API_PATCH = 2
API_EXTRA = 1
VERSION_MAJOR = 2
VERSION_MINOR = 0
VERSION_PATCH = 1
VERSION_EXTRA = 255
VERSION_PATCH = 2
VERSION_EXTRA = 1
SECOND_SCALE = 1000000
MILISECOND_SCALE = 1000
ARCH_ARM = 1

View File

@@ -6,13 +6,13 @@ public interface UnicornConst {
public static final int UC_API_MAJOR = 2;
public static final int UC_API_MINOR = 0;
public static final int UC_API_PATCH = 1;
public static final int UC_API_EXTRA = 255;
public static final int UC_API_PATCH = 2;
public static final int UC_API_EXTRA = 1;
public static final int UC_VERSION_MAJOR = 2;
public static final int UC_VERSION_MINOR = 0;
public static final int UC_VERSION_PATCH = 1;
public static final int UC_VERSION_EXTRA = 255;
public static final int UC_VERSION_PATCH = 2;
public static final int UC_VERSION_EXTRA = 1;
public static final int UC_SECOND_SCALE = 1000000;
public static final int UC_MILISECOND_SCALE = 1000;
public static final int UC_ARCH_ARM = 1;

View File

@@ -7,13 +7,13 @@ interface
const UC_API_MAJOR = 2;
UC_API_MINOR = 0;
UC_API_PATCH = 1;
UC_API_EXTRA = 255;
UC_API_PATCH = 2;
UC_API_EXTRA = 1;
UC_VERSION_MAJOR = 2;
UC_VERSION_MINOR = 0;
UC_VERSION_PATCH = 1;
UC_VERSION_EXTRA = 255;
UC_VERSION_PATCH = 2;
UC_VERSION_EXTRA = 1;
UC_SECOND_SCALE = 1000000;
UC_MILISECOND_SCALE = 1000;
UC_ARCH_ARM = 1;

View File

@@ -8,6 +8,7 @@ import subprocess
import shutil
import sys
import platform
import setuptools
from distutils import log
from distutils.core import setup
@@ -29,7 +30,7 @@ SRC_DIR = os.path.join(ROOT_DIR, 'src')
UC_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..')
BUILD_DIR = os.path.join(UC_DIR, 'build_python')
VERSION = "2.0.1.post1"
VERSION = "2.0.2"
if SYSTEM == 'darwin':
LIBRARY_FILE = "libunicorn.2.dylib"

View File

@@ -1,4 +1,4 @@
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const, riscv_const
from .unicorn_const import *
from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__

View File

@@ -94,7 +94,7 @@ _path_list = [os.getenv('LIBUNICORN_PATH', None),
for _path in _path_list:
if _path is None: continue
_uc = _load_lib(_path, _lib.get(sys.platform, "libunicorn.so"))
_uc = _load_lib(_path, _lib.get(sys.platform, "libunicorn.so.2"))
if _uc is not None:
break

View File

@@ -2,13 +2,13 @@
UC_API_MAJOR = 2
UC_API_MINOR = 0
UC_API_PATCH = 1
UC_API_EXTRA = 255
UC_API_PATCH = 2
UC_API_EXTRA = 1
UC_VERSION_MAJOR = 2
UC_VERSION_MINOR = 0
UC_VERSION_PATCH = 1
UC_VERSION_EXTRA = 255
UC_VERSION_PATCH = 2
UC_VERSION_EXTRA = 1
UC_SECOND_SCALE = 1000000
UC_MILISECOND_SCALE = 1000
UC_ARCH_ARM = 1

View File

@@ -4,13 +4,13 @@ module UnicornEngine
UC_API_MAJOR = 2
UC_API_MINOR = 0
UC_API_PATCH = 1
UC_API_EXTRA = 255
UC_API_PATCH = 2
UC_API_EXTRA = 1
UC_VERSION_MAJOR = 2
UC_VERSION_MINOR = 0
UC_VERSION_PATCH = 1
UC_VERSION_EXTRA = 255
UC_VERSION_PATCH = 2
UC_VERSION_EXTRA = 1
UC_SECOND_SCALE = 1000000
UC_MILISECOND_SCALE = 1000
UC_ARCH_ARM = 1

View File

@@ -84,6 +84,43 @@ fn build_with_cmake() {
config.generator("Ninja");
}
let mut archs = String::new();
if std::env::var("CARGO_FEATURE_ARCH_X86").is_ok() {
archs.push_str("x86;");
}
if std::env::var("CARGO_FEATURE_ARCH_ARM").is_ok() {
archs.push_str("arm;");
}
if std::env::var("CARGO_FEATURE_ARCH_AARCH64").is_ok() {
archs.push_str("aarch64;");
}
if std::env::var("CARGO_FEATURE_ARCH_RISCV").is_ok() {
archs.push_str("riscv;");
}
if std::env::var("CARGO_FEATURE_ARCH_MIPS").is_ok() {
archs.push_str("mips;");
}
if std::env::var("CARGO_FEATURE_ARCH_SPARC").is_ok() {
archs.push_str("sparc;");
}
if std::env::var("CARGO_FEATURE_ARCH_M68K").is_ok() {
archs.push_str("m68k;");
}
if std::env::var("CARGO_FEATURE_ARCH_PPC").is_ok() {
archs.push_str("ppc;");
}
if std::env::var("CARGO_FEATURE_ARCH_S390X").is_ok() {
archs.push_str("s390x;");
}
if std::env::var("CARGO_FEATURE_ARCH_TRICORE").is_ok() {
archs.push_str("tricore;");
}
if !archs.is_empty() {
archs.pop();
}
// need to clear build target and append "build" to the path because
// unicorn's CMakeLists.txt doesn't properly support 'install', so we use
// the build artifacts from the build directory, which cmake crate sets
@@ -91,6 +128,7 @@ fn build_with_cmake() {
let dst = config
.define("UNICORN_BUILD_TESTS", "OFF")
.define("UNICORN_INSTALL", "OFF")
.define("UNICORN_ARCH", archs)
.no_build_target(true)
.build();
println!(

View File

@@ -1,10 +1,11 @@
#![allow(non_camel_case_types)]
#![allow(dead_code)]
use crate::Unicorn;
use crate::{Unicorn, UnicornInner};
use super::unicorn_const::{uc_error, Arch, HookType, MemRegion, MemType, Mode, Query};
use core::ffi::c_void;
use alloc::rc::Weak;
use core::{cell::UnsafeCell, ffi::c_void};
use libc::{c_char, c_int};
pub type uc_handle = *mut c_void;
@@ -89,7 +90,7 @@ extern "C" {
pub struct UcHook<'a, D: 'a, F: 'a> {
pub callback: F,
pub uc: Unicorn<'a, D>,
pub uc: Weak<UnsafeCell<UnicornInner<'a, D>>>,
}
pub trait IsUcHook<'a> {}
@@ -106,8 +107,11 @@ where
F: FnMut(&mut crate::Unicorn<D>, u64, usize) -> u64,
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, offset, size)
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, offset, size)
}
pub extern "C" fn mmio_write_callback_proxy<D, F>(
@@ -120,8 +124,11 @@ pub extern "C" fn mmio_write_callback_proxy<D, F>(
F: FnMut(&mut crate::Unicorn<D>, u64, usize, u64),
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, offset, size, value);
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, offset, size, value);
}
pub extern "C" fn code_hook_proxy<D, F>(
@@ -133,8 +140,11 @@ pub extern "C" fn code_hook_proxy<D, F>(
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, address, size);
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, address, size);
}
pub extern "C" fn block_hook_proxy<D, F>(
@@ -146,8 +156,11 @@ pub extern "C" fn block_hook_proxy<D, F>(
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, address, size);
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, address, size);
}
pub extern "C" fn mem_hook_proxy<D, F>(
@@ -162,8 +175,11 @@ where
F: FnMut(&mut crate::Unicorn<D>, MemType, u64, usize, i64) -> bool,
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, mem_type, address, size as usize, value)
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, mem_type, address, size as usize, value)
}
pub extern "C" fn intr_hook_proxy<D, F>(uc: uc_handle, value: u32, user_data: *mut UcHook<D, F>)
@@ -171,8 +187,11 @@ where
F: FnMut(&mut crate::Unicorn<D>, u32),
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, value);
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, value);
}
pub extern "C" fn insn_in_hook_proxy<D, F>(
@@ -180,12 +199,16 @@ pub extern "C" fn insn_in_hook_proxy<D, F>(
port: u32,
size: usize,
user_data: *mut UcHook<D, F>,
) where
) -> u32
where
F: FnMut(&mut crate::Unicorn<D>, u32, usize) -> u32,
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, port, size);
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, port, size)
}
pub extern "C" fn insn_invalid_hook_proxy<D, F>(uc: uc_handle, user_data: *mut UcHook<D, F>) -> bool
@@ -193,8 +216,11 @@ where
F: FnMut(&mut crate::Unicorn<D>) -> bool,
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc)
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc)
}
pub extern "C" fn insn_out_hook_proxy<D, F>(
@@ -207,8 +233,11 @@ pub extern "C" fn insn_out_hook_proxy<D, F>(
F: FnMut(&mut crate::Unicorn<D>, u32, usize, u32),
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc, port, size, value);
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc, port, size, value);
}
pub extern "C" fn insn_sys_hook_proxy<D, F>(uc: uc_handle, user_data: *mut UcHook<D, F>)
@@ -216,6 +245,9 @@ where
F: FnMut(&mut crate::Unicorn<D>),
{
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.get_handle());
(user_data.callback)(&mut user_data.uc);
let mut user_data_uc = Unicorn {
inner: user_data.uc.upgrade().unwrap(),
};
debug_assert_eq!(uc, user_data_uc.get_handle());
(user_data.callback)(&mut user_data_uc);
}

View File

@@ -369,17 +369,13 @@ impl<'a, D> Unicorn<'a, D> {
let mut read_data = read_callback.map(|c| {
Box::new(ffi::UcHook {
callback: c,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
})
});
let mut write_data = write_callback.map(|c| {
Box::new(ffi::UcHook {
callback: c,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
})
});
@@ -388,12 +384,18 @@ impl<'a, D> Unicorn<'a, D> {
self.get_handle(),
address,
size,
ffi::mmio_read_callback_proxy::<D, R> as _,
match read_data {
Some(_) => ffi::mmio_read_callback_proxy::<D, R> as _,
None => ptr::null_mut(),
},
match read_data {
Some(ref mut d) => d.as_mut() as *mut _ as _,
None => ptr::null_mut(),
},
ffi::mmio_write_callback_proxy::<D, W> as _,
match write_data {
Some(_) => ffi::mmio_write_callback_proxy::<D, W> as _,
None => ptr::null_mut(),
},
match write_data {
Some(ref mut d) => d.as_mut() as *mut _ as _,
None => ptr::null_mut(),
@@ -586,7 +588,8 @@ impl<'a, D> Unicorn<'a, D> {
return Err(uc_error::ARCH);
}
let err: uc_error = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) };
let err: uc_error =
unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) };
if err == uc_error::OK {
boxed = value.into_boxed_slice();
@@ -622,9 +625,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
@@ -654,9 +655,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
@@ -697,9 +696,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
@@ -730,9 +727,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
@@ -763,9 +758,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
@@ -796,9 +789,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
@@ -830,9 +821,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {
@@ -870,9 +859,7 @@ impl<'a, D> Unicorn<'a, D> {
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
uc: Unicorn {
inner: self.inner.clone(),
},
uc: Rc::downgrade(&self.inner),
});
let err = unsafe {