Merge pull request #190 from enkomio/master

Implemented error mechanism based on exception raising
This commit is contained in:
Nguyen Anh Quynh 2015-10-17 00:28:54 +08:00
commit 88397649be
5 changed files with 151 additions and 56 deletions

View file

@ -73,29 +73,44 @@ and Unicorn(arch: Int32, mode: Int32) =
let err = NativeUnicornEngine.uc_open(uint32 arch, uint32 mode, _eng) let err = NativeUnicornEngine.uc_open(uint32 arch, uint32 mode, _eng)
checkResult(err, "Unable to open the Unicorn Engine") 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) = 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) = member this.MemWrite(address: UInt64, value: Byte array) =
NativeUnicornEngine.mem_write(_eng.[0], address, buffer, new UIntPtr(uint32 buffer.Length)) 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) = member this.MemRead(address: UInt64, memValue: Byte array) =
NativeUnicornEngine.mem_read(_eng.[0], address, value, new UIntPtr(uint32 value.Length)) 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) = 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) = 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) = 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() = 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() = 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) = member this.ArchSupported(arch: Int32) =
NativeUnicornEngine.arch_supported(arch) NativeUnicornEngine.arch_supported(arch)
@ -117,7 +132,8 @@ and Unicorn(arch: Int32, mode: Int32) =
let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new CodeHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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) = member this.HookDel(callback: CodeHook) =
hookDel _codeHooks callback hookDel _codeHooks callback
@ -132,7 +148,8 @@ and Unicorn(arch: Int32, mode: Int32) =
let funcPointer = Marshal.GetFunctionPointerForDelegate(new BlockHookInternal(trampoline)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new BlockHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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) = member this.HookDel(callback: BlockHook) =
hookDel _blockHooks callback hookDel _blockHooks callback
@ -147,7 +164,8 @@ and Unicorn(arch: Int32, mode: Int32) =
let funcPointer = Marshal.GetFunctionPointerForDelegate(new InterruptHookInternal(trampoline)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new InterruptHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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) = member this.HookDel(callback: InterruptHook) =
hookDel _interruptHooks callback hookDel _interruptHooks callback
@ -162,7 +180,8 @@ and Unicorn(arch: Int32, mode: Int32) =
let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemReadHookInternal(trampoline)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemReadHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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) = member this.HookDel(callback: MemReadHook) =
hookDel _memReadHooks callback hookDel _memReadHooks callback
@ -177,7 +196,8 @@ and Unicorn(arch: Int32, mode: Int32) =
let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemWriteHookInternal(trampoline)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new MemWriteHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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) = member this.HookDel(callback: MemWriteHook) =
hookDel _memWriteHooks callback hookDel _memWriteHooks callback
@ -193,7 +213,8 @@ and Unicorn(arch: Int32, mode: Int32) =
let funcPointer = Marshal.GetFunctionPointerForDelegate(new EventMemHookInternal(trampoline)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new EventMemHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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 // 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 funcPointer = Marshal.GetFunctionPointerForDelegate(new InHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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) = member this.AddOutHook(callback: OutHook, userData: Object) =
let trampoline(u: IntPtr) (port: Int32) (size: Int32) (value: Int32) (user: IntPtr) = 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 funcPointer = Marshal.GetFunctionPointerForDelegate(new OutHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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) = member this.AddSyscallHook(callback: SyscallHook, userData: Object) =
let trampoline(u: IntPtr) (user: IntPtr) = let trampoline(u: IntPtr) (user: IntPtr) =
@ -245,7 +268,8 @@ and Unicorn(arch: Int32, mode: Int32) =
let funcPointer = Marshal.GetFunctionPointerForDelegate(new SyscallHookInternal(trampoline)) let funcPointer = Marshal.GetFunctionPointerForDelegate(new SyscallHookInternal(trampoline))
let hh = new UIntPtr(Marshal.AllocHGlobal(IntPtr.Size).ToPointer()) 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() = member this.Version() =
let (major, minor) = (new UIntPtr(), new UIntPtr()) let (major, minor) = (new UIntPtr(), new UIntPtr())

View file

@ -51,9 +51,9 @@
<Compile Include="Const\Mips.fs" /> <Compile Include="Const\Mips.fs" />
<Compile Include="Const\Sparc.fs" /> <Compile Include="Const\Sparc.fs" />
<Compile Include="Const\X86.fs" /> <Compile Include="Const\X86.fs" />
<Compile Include="Const\UcError.fs" />
<Compile Include="Hooks.fs" /> <Compile Include="Hooks.fs" />
<Compile Include="NativeUnicorn.fs" /> <Compile Include="NativeUnicorn.fs" />
<Compile Include="UnicornEngineException.fs" />
<Compile Include="Unicorn.fs" /> <Compile Include="Unicorn.fs" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -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

View file

@ -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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -49,33 +70,40 @@ namespace UnicornTests
public static void RunTest(Byte[] code, UInt64 address) public static void RunTest(Byte[] code, UInt64 address)
{ {
var u = new Unicorn(Common.UC_ARCH_X86, Common.UC_MODE_32); try
Console.WriteLine("Unicorn version: {0}", u.Version()); {
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 // map 2MB of memory for this emulation
Utils.CheckError(u.MemMap(address, new UIntPtr(2 * 1024 * 1024), Common.UC_PROT_ALL)); u.MemMap(address, new UIntPtr(2 * 1024 * 1024), Common.UC_PROT_ALL);
// write machine code to be emulated to memory // write machine code to be emulated to memory
Utils.CheckError(u.MemWrite(address, code)); u.MemWrite(address, code);
// initialize machine registers // initialize machine registers
Utils.CheckError(u.RegWrite(X86.UC_X86_REG_ESP, Utils.Int64ToBytes(address + 0x200000))); u.RegWrite(X86.UC_X86_REG_ESP, Utils.Int64ToBytes(address + 0x200000));
// tracing all instructions by having @begin > @end // tracing all instructions by having @begin > @end
Utils.CheckError(u.AddCodeHook(CodeHookCallback, null, 1, 0).Item1); u.AddCodeHook(CodeHookCallback, null, 1, 0);
// handle interrupt ourself // handle interrupt ourself
Utils.CheckError(u.AddInterruptHook(InterruptHookCallback, null).Item1); u.AddInterruptHook(InterruptHookCallback, null);
// handle SYSCALL // handle SYSCALL
Utils.CheckError(u.AddSyscallHook(SyscallHookCallback, null).Item1); u.AddSyscallHook(SyscallHookCallback, null);
Console.WriteLine(">>> Start tracing linux code"); Console.WriteLine(">>> Start tracing linux code");
// emulate machine code in infinite time // emulate machine code in infinite time
u.EmuStart(address, address + (UInt64)code.Length, 0u, new UIntPtr(0)); 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) 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")); Console.Write("Tracing >>> 0x{0} ", addr.ToString("X"));
var eipBuffer = new Byte[4]; 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 effectiveSize = Math.Min(16, size);
var tmp = new Byte[effectiveSize]; var tmp = new Byte[effectiveSize];
Utils.CheckError(u.MemRead(addr, tmp)); u.MemRead(addr, tmp);
foreach (var t in tmp) foreach (var t in tmp)
{ {
@ -100,7 +128,7 @@ namespace UnicornTests
private static void SyscallHookCallback(Unicorn u, Object userData) private static void SyscallHookCallback(Unicorn u, Object userData)
{ {
var eaxBuffer = new Byte[4]; 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); var eax = Utils.ToInt(eaxBuffer);
Console.WriteLine("Syscall >>> EAX = 0x{0}", eax.ToString("X")); Console.WriteLine("Syscall >>> EAX = 0x{0}", eax.ToString("X"));
@ -119,8 +147,8 @@ namespace UnicornTests
var eaxBuffer = new Byte[4]; var eaxBuffer = new Byte[4];
var eipBuffer = new Byte[4]; var eipBuffer = new Byte[4];
Utils.CheckError(u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer)); u.RegRead(X86.UC_X86_REG_EAX, eaxBuffer);
Utils.CheckError(u.RegRead(X86.UC_X86_REG_EIP, eipBuffer)); u.RegRead(X86.UC_X86_REG_EIP, eipBuffer);
var eax = Utils.ToInt(eaxBuffer); var eax = Utils.ToInt(eaxBuffer);
var eip = Utils.ToInt(eipBuffer); var eip = Utils.ToInt(eipBuffer);
@ -142,8 +170,8 @@ namespace UnicornTests
// EDX = buffer size // EDX = buffer size
var edxBuffer = new Byte[4]; var edxBuffer = new Byte[4];
Utils.CheckError(u.RegRead(X86.UC_X86_REG_ECX, ecxBuffer)); u.RegRead(X86.UC_X86_REG_ECX, ecxBuffer);
Utils.CheckError(u.RegRead(X86.UC_X86_REG_EDX, edxBuffer)); u.RegRead(X86.UC_X86_REG_EDX, edxBuffer);
var ecx = Utils.ToInt(ecxBuffer); var ecx = Utils.ToInt(ecxBuffer);
var edx = Utils.ToInt(edxBuffer); var edx = Utils.ToInt(edxBuffer);
@ -151,7 +179,7 @@ namespace UnicornTests
// read the buffer in // read the buffer in
var size = Math.Min(256, edx); var size = Math.Min(256, edx);
var buffer = new Byte[size]; var buffer = new Byte[size];
Utils.CheckError(u.MemRead(ecx, buffer)); u.MemRead(ecx, buffer);
var content = Encoding.Default.GetString(buffer); var content = Encoding.Default.GetString(buffer);
Console.WriteLine( Console.WriteLine(

View file

@ -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.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -20,14 +41,6 @@ namespace UnicornTests
return res; 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) public static Byte[] Int64ToBytes(UInt64 intVal)
{ {
var res = new Byte[8]; var res = new Byte[8];