From d92bee414dbcc71fca476ba6cb0ec946edd3d19d Mon Sep 17 00:00:00 2001 From: Antonio Parata Date: Fri, 16 Oct 2015 17:02:49 +0200 Subject: [PATCH] Implemented exception as error management mechanism and removed the error codes --- bindings/dotnet/Unicorn/Unicorn.fs | 62 +++++++++----- bindings/dotnet/Unicorn/Unicorn.fsproj | 2 +- .../dotnet/Unicorn/UnicornEngineException.fs | 30 +++++++ bindings/dotnet/UnicornTests/ShellcodeTest.cs | 82 +++++++++++++------ bindings/dotnet/UnicornTests/Utils.cs | 31 +++++-- 5 files changed, 151 insertions(+), 56 deletions(-) create mode 100644 bindings/dotnet/Unicorn/UnicornEngineException.fs diff --git a/bindings/dotnet/Unicorn/Unicorn.fs b/bindings/dotnet/Unicorn/Unicorn.fs index 7e4e34bd..79108c1d 100644 --- a/bindings/dotnet/Unicorn/Unicorn.fs +++ b/bindings/dotnet/Unicorn/Unicorn.fs @@ -73,29 +73,44 @@ and Unicorn(arch: Int32, mode: Int32) = let err = NativeUnicornEngine.uc_open(uint32 arch, uint32 mode, _eng) checkResult(err, "Unable to open the Unicorn Engine") + 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: UInt64, size: UIntPtr, perm: Int32) = - NativeUnicornEngine.mem_map(_eng.[0], address, size, uint32 perm) + match NativeUnicornEngine.mem_map(_eng.[0], address, size, uint32 perm) |> this.CheckResult with + | Some e -> raise e | None -> () - member this.MemWrite(address: UInt64, buffer: Byte array) = - NativeUnicornEngine.mem_write(_eng.[0], address, buffer, new UIntPtr(uint32 buffer.Length)) + member this.MemWrite(address: UInt64, value: Byte array) = + match NativeUnicornEngine.mem_write(_eng.[0], address, value, new UIntPtr(uint32 value.Length)) |> this.CheckResult with + | Some e -> raise e | None -> () - member this.MemRead(address: UInt64, value: Byte array) = - NativeUnicornEngine.mem_read(_eng.[0], address, value, new UIntPtr(uint32 value.Length)) + member this.MemRead(address: UInt64, memValue: Byte array) = + match NativeUnicornEngine.mem_read(_eng.[0], address, memValue, new UIntPtr(uint32 memValue.Length)) |> this.CheckResult with + | Some e -> raise e | None -> () member this.RegWrite(regId: Int32, value: Byte array) = - NativeUnicornEngine.reg_write(_eng.[0], regId, value) + match NativeUnicornEngine.reg_write(_eng.[0], regId, value) |> this.CheckResult with + | Some e -> raise e | None -> () member this.RegRead(regId: Int32, regValue: Byte array) = - NativeUnicornEngine.reg_read(_eng.[0], regId, regValue) + match NativeUnicornEngine.reg_read(_eng.[0], regId, regValue) |> this.CheckResult with + | Some e -> raise e | None -> () member this.EmuStart(beginAddr: UInt64, untilAddr: UInt64, timeout: UInt64, count: UIntPtr) = - NativeUnicornEngine.emu_start(_eng.[0], beginAddr, untilAddr, timeout, count) + match NativeUnicornEngine.emu_start(_eng.[0], beginAddr, untilAddr, timeout, count) |> this.CheckResult with + | Some e -> raise e | None -> () member this.EmuStop() = - NativeUnicornEngine.emu_stop(_eng.[0]) + match NativeUnicornEngine.emu_stop(_eng.[0]) |> this.CheckResult with + | Some e -> raise e | None -> () member this.Close() = - NativeUnicornEngine.close(_eng.[0]) + match NativeUnicornEngine.close(_eng.[0]) |> this.CheckResult with + | Some e -> raise e | None -> () member this.ArchSupported(arch: Int32) = NativeUnicornEngine.arch_supported(arch) @@ -117,7 +132,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_CODE, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr), hh) + 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 -> () member this.HookDel(callback: CodeHook) = hookDel _codeHooks callback @@ -132,7 +148,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new BlockHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_BLOCK, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr), hh) + 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 -> () member this.HookDel(callback: BlockHook) = hookDel _blockHooks callback @@ -147,7 +164,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new InterruptHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_noarg(_eng.[0], hh, Common.UC_HOOK_INTR, new UIntPtr(funcPointer.ToPointer()), id), hh) + 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 -> () member this.HookDel(callback: InterruptHook) = hookDel _interruptHooks callback @@ -162,7 +180,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemReadHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_MEM_READ, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr), hh) + 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 -> () member this.HookDel(callback: MemReadHook) = hookDel _memReadHooks callback @@ -177,7 +196,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemWriteHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_arg0_arg1(_eng.[0], hh, Common.UC_HOOK_MEM_WRITE, new UIntPtr(funcPointer.ToPointer()), id, beginAdd, endAddr), hh) + 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 -> () member this.HookDel(callback: MemWriteHook) = hookDel _memWriteHooks callback @@ -193,7 +213,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new EventMemHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_noarg(_eng.[0], hh, check, new UIntPtr(funcPointer.ToPointer()), id), hh) + match NativeUnicornEngine.hook_add_noarg(_eng.[0], hh, check, new UIntPtr(funcPointer.ToPointer()), id) |> this.CheckResult with + | Some e -> raise e | None -> () // test all the events types agains the input eventType [ @@ -221,7 +242,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new InHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_arg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), id, new IntPtr(X86.UC_X86_INS_IN)), hh) + 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 -> () member this.AddOutHook(callback: OutHook, userData: Object) = let trampoline(u: IntPtr) (port: Int32) (size: Int32) (value: Int32) (user: IntPtr) = @@ -233,7 +255,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new OutHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_arg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), id, new IntPtr(X86.UC_X86_INS_OUT)), hh) + 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 -> () member this.AddSyscallHook(callback: SyscallHook, userData: Object) = let trampoline(u: IntPtr) (user: IntPtr) = @@ -245,7 +268,8 @@ and Unicorn(arch: Int32, mode: Int32) = let funcPointer = Marshal.GetFunctionPointerForDelegate(new SyscallHookInternal(trampoline)) let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) - (NativeUnicornEngine.hook_add_arg0(_eng.[0], hh, Common.UC_HOOK_INSN, new UIntPtr(funcPointer.ToPointer()), id, new IntPtr(X86.UC_X86_INS_SYSCALL)), hh) + 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 -> () member this.Version() = let (major, minor) = (new UIntPtr(), new UIntPtr()) diff --git a/bindings/dotnet/Unicorn/Unicorn.fsproj b/bindings/dotnet/Unicorn/Unicorn.fsproj index adc80fff..8f6ee136 100644 --- a/bindings/dotnet/Unicorn/Unicorn.fsproj +++ b/bindings/dotnet/Unicorn/Unicorn.fsproj @@ -51,9 +51,9 @@ - + diff --git a/bindings/dotnet/Unicorn/UnicornEngineException.fs b/bindings/dotnet/Unicorn/UnicornEngineException.fs new file mode 100644 index 00000000..7b1cd845 --- /dev/null +++ b/bindings/dotnet/Unicorn/UnicornEngineException.fs @@ -0,0 +1,30 @@ +(* + +.NET bindings for the UnicornEngine Emulator Engine + +Copyright(c) 2015 Antonio Parata + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*) + +namespace UnicornEngine + +open System + +type UnicornEngineException(errNo: Int32, msg: String) = + inherit ApplicationException(msg) + + member this.ErrorNo = errNo + diff --git a/bindings/dotnet/UnicornTests/ShellcodeTest.cs b/bindings/dotnet/UnicornTests/ShellcodeTest.cs index bba47f29..e254fb4a 100644 --- a/bindings/dotnet/UnicornTests/ShellcodeTest.cs +++ b/bindings/dotnet/UnicornTests/ShellcodeTest.cs @@ -1,4 +1,25 @@ -using System; +/* + +.NET bindings for the UnicornEngine Emulator Engine + +Copyright(c) 2015 Antonio Parata + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -49,33 +70,40 @@ namespace UnicornTests public static void RunTest(Byte[] code, UInt64 address) { - var u = new Unicorn(Common.UC_ARCH_X86, Common.UC_MODE_32); - Console.WriteLine("Unicorn version: {0}", u.Version()); + try + { + 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 - Utils.CheckError(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 - Utils.CheckError(u.MemWrite(address, code)); + // write machine code to be emulated to memory + u.MemWrite(address, code); - // initialize machine registers - Utils.CheckError(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 - Utils.CheckError(u.AddCodeHook(CodeHookCallback, null, 1, 0).Item1); + // tracing all instructions by having @begin > @end + u.AddCodeHook(CodeHookCallback, null, 1, 0); - // handle interrupt ourself - Utils.CheckError(u.AddInterruptHook(InterruptHookCallback, null).Item1); + // handle interrupt ourself + u.AddInterruptHook(InterruptHookCallback, null); - // handle SYSCALL - Utils.CheckError(u.AddSyscallHook(SyscallHookCallback, null).Item1); + // 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) + { + Console.Error.WriteLine("Emulation FAILED! " + ex.Message); + } } private static void CodeHookCallback(Unicorn u, UInt64 addr, Int32 size, Object userData) @@ -83,11 +111,11 @@ namespace UnicornTests Console.Write("Tracing >>> 0x{0} ", addr.ToString("X")); var eipBuffer = new Byte[4]; - Utils.CheckError(u.RegRead(X86.UC_X86_REG_EIP, eipBuffer)); + u.RegRead(X86.UC_X86_REG_EIP, eipBuffer); var effectiveSize = Math.Min(16, size); var tmp = new Byte[effectiveSize]; - Utils.CheckError(u.MemRead(addr, tmp)); + u.MemRead(addr, tmp); foreach (var t in tmp) { @@ -100,7 +128,7 @@ namespace UnicornTests private static void SyscallHookCallback(Unicorn u, Object userData) { var eaxBuffer = new Byte[4]; - Utils.CheckError(u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer)); + u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer); var eax = Utils.ToInt(eaxBuffer); Console.WriteLine("Syscall >>> EAX = 0x{0}", eax.ToString("X")); @@ -119,8 +147,8 @@ namespace UnicornTests var eaxBuffer = new Byte[4]; var eipBuffer = new Byte[4]; - Utils.CheckError(u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer)); - Utils.CheckError(u.RegRead(X86.UC_X86_REG_EIP, eipBuffer)); + u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer); + u.RegRead(X86.UC_X86_REG_EIP, eipBuffer); var eax = Utils.ToInt(eaxBuffer); var eip = Utils.ToInt(eipBuffer); @@ -142,8 +170,8 @@ namespace UnicornTests // EDX = buffer size var edxBuffer = new Byte[4]; - Utils.CheckError(u.RegRead(X86.UC_X86_REG_ECX, ecxBuffer)); - Utils.CheckError(u.RegRead(X86.UC_X86_REG_EDX, edxBuffer)); + u.RegRead(X86.UC_X86_REG_ECX, ecxBuffer); + u.RegRead(X86.UC_X86_REG_EDX, edxBuffer); var ecx = Utils.ToInt(ecxBuffer); var edx = Utils.ToInt(edxBuffer); @@ -151,7 +179,7 @@ namespace UnicornTests // read the buffer in var size = Math.Min(256, edx); var buffer = new Byte[size]; - Utils.CheckError(u.MemRead(ecx, buffer)); + u.MemRead(ecx, buffer); var content = Encoding.Default.GetString(buffer); Console.WriteLine( diff --git a/bindings/dotnet/UnicornTests/Utils.cs b/bindings/dotnet/UnicornTests/Utils.cs index 882e8ded..557a9a34 100644 --- a/bindings/dotnet/UnicornTests/Utils.cs +++ b/bindings/dotnet/UnicornTests/Utils.cs @@ -1,4 +1,25 @@ -using System; +/* + +.NET bindings for the UnicornEngine Emulator Engine + +Copyright(c) 2015 Antonio Parata + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -20,14 +41,6 @@ namespace UnicornTests return res; } - public static void CheckError(Int32 err) - { - if (err != Common.UC_ERR_OK) - { - throw new ApplicationException("Operation failed, error: " + err); - } - } - public static Byte[] Int64ToBytes(UInt64 intVal) { var res = new Byte[8];