Merge pull request #494 from sashs/master

Bugfixes and new samples for ruby bindings
This commit is contained in:
Nguyen Anh Quynh 2016-03-28 08:13:32 +07:00
commit 56d70845da
10 changed files with 508 additions and 3 deletions

106
bindings/ruby/sample_arm.rb Normal file
View file

@ -0,0 +1,106 @@
#!/usr/bin/env ruby
require 'unicorn'
require 'unicorn/arm_const'
include Unicorn
# code to be emulated
ARM_CODE = "\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3
THUMB_CODE = "\x83\xb0" # sub sp, #0xc
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
$hook_block = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size])
end
# callback for tracing instructions
$hook_code = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size])
end
# Test ARM
def test_arm()
puts("Emulate ARM code")
begin
# Initialize emulator in ARM mode
mu = Uc.new UC_ARCH_ARM, UC_MODE_ARM
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, ARM_CODE)
# initialize machine registers
mu.reg_write(UC_ARM_REG_R0, 0x1234)
mu.reg_write(UC_ARM_REG_R2, 0x6789)
mu.reg_write(UC_ARM_REG_R3, 0x3333)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, $hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, $hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + ARM_CODE.bytesize)
# now print out some registers
puts(">>> Emulation done. Below is the CPU context")
r0 = mu.reg_read(UC_ARM_REG_R0)
r1 = mu.reg_read(UC_ARM_REG_R1)
puts(">>> R0 = 0x%x" % r0)
puts(">>> R1 = 0x%x" % r1)
rescue UcError => e
puts("ERROR: %s" % e)
end
end
def test_thumb()
puts("Emulate THUMB code")
begin
# Initialize emulator in thumb mode
mu = Uc.new UC_ARCH_ARM, UC_MODE_THUMB
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, THUMB_CODE)
# initialize machine registers
mu.reg_write(UC_ARM_REG_SP, 0x1234)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, $hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, $hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + THUMB_CODE.bytesize)
# now print out some registers
puts(">>> Emulation done. Below is the CPU context")
sp = mu.reg_read(UC_ARM_REG_SP)
puts(">>> SP = 0x%x" % sp)
rescue UcError => e
puts("ERROR: %s" % e)
end
end
test_arm()
puts("=" * 20)
test_thumb()

View file

@ -0,0 +1,69 @@
#!/usr/bin/env ruby
# Sample code for ARM64 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
# Ruby sample ported by Sascha Schirra <sashs82@gmail.com>
require 'unicorn'
require 'unicorn/arm64_const'
include Unicorn
# code to be emulated
ARM64_CODE = "\xab\x01\x0f\x8b" #add x11, x13, x15
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
$hook_block = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size])
end
# callback for tracing instructions
$hook_code = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size])
end
# Test ARM64
def test_arm64()
puts("Emulate ARM64 code")
begin
# Initialize emulator in ARM mode
mu = Uc.new UC_ARCH_ARM64, UC_MODE_ARM
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, ARM64_CODE)
# initialize machine registers
mu.reg_write(UC_ARM64_REG_X11, 0x1234)
mu.reg_write(UC_ARM64_REG_X13, 0x6789)
mu.reg_write(UC_ARM64_REG_X15, 0x3333)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, $hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, $hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + ARM64_CODE.bytesize)
# now print out some registers
puts(">>> Emulation done. Below is the CPU context")
x11 = mu.reg_read(UC_ARM64_REG_X11)
x13 = mu.reg_read(UC_ARM64_REG_X13)
x15 = mu.reg_read(UC_ARM64_REG_X15)
puts(">>> X11 = 0x%x" % x11)
rescue UcError => e
puts("ERROR: %s" % e)
end
end
test_arm64()

View file

@ -0,0 +1,65 @@
#!/usr/bin/env ruby
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
# Ruby sample ported by Sascha Schirra <sashs82@gmail.com>
require 'unicorn'
require 'unicorn/m68k_const'
include Unicorn
# code to be emulated
M68K_CODE = "\x76\xed" # movq #-19, %d3
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
$hook_block = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size])
end
# callback for tracing instructions
$hook_code = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size])
end
# Test m68k
def test_m68k()
puts("Emulate M68K code")
begin
# Initialize emulator in m68k mode
mu = Uc.new UC_ARCH_M68K, UC_MODE_BIG_ENDIAN
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, M68K_CODE)
# initialize machine registers
mu.reg_write(UC_M68K_REG_D3, 0x1234)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, $hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, $hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + M68K_CODE.bytesize)
# now print out some registers
puts(">>> Emulation done. Below is the CPU context")
d3 = mu.reg_read(UC_M68K_REG_D3)
puts(">>> D3 = 0x%x" % d3)
rescue UcError => e
puts("ERROR: %s" % e)
end
end
test_m68k()

View file

@ -0,0 +1,104 @@
#!/usr/bin/env ruby
# Sample code for MIPS of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
# Ruby sample ported by Sascha Schirra <sashs82@gmail.com>
require 'unicorn'
require 'unicorn/mips_const'
include Unicorn
# code to be emulated
MIPS_CODE_EB = "\x34\x21\x34\x56" # ori $at, $at, 0x3456;
MIPS_CODE_EL = "\x56\x34\x21\x34" # ori $at, $at, 0x3456;
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
$hook_block = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size])
end
# callback for tracing instructions
$hook_code = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size])
end
# Test MIPS EB
def test_mips_eb()
puts("Emulate MIPS code (big-endian)")
begin
# Initialize emulator in MIPS32 + EB mode
mu = Uc.new UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, MIPS_CODE_EB)
# initialize machine registers
mu.reg_write(UC_MIPS_REG_1, 0x6789)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, $hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, $hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EB.bytesize)
# now puts out some registers
puts(">>> Emulation done. Below is the CPU context")
r1 = mu.reg_read(UC_MIPS_REG_1)
puts(">>> r1 = 0x%x" % r1)
rescue UcError => e
puts("ERROR: %s" % e)
end
end
# Test MIPS EL
def test_mips_el()
puts("Emulate MIPS code (little-endian)")
begin
# Initialize emulator in MIPS32 + EL mode
mu = Uc.new UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, MIPS_CODE_EL)
# initialize machine registers
mu.reg_write(UC_MIPS_REG_1, 0x6789)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, $hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, $hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EL.bytesize)
# now puts out some registers
puts(">>> Emulation done. Below is the CPU context")
r1 = mu.reg_read(UC_MIPS_REG_1)
puts(">>> r1 = 0x%x" % r1)
rescue UcError => e
puts("ERROR: %s" % e)
end
end
test_mips_eb()
puts("=" * 20)
test_mips_el()

View file

@ -0,0 +1,65 @@
#!/usr/bin/env ruby
# Sample code for SPARC of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
# Ruby sample ported by Sascha Schirra <sashs82@gmail.com>
require 'unicorn'
require 'unicorn/sparc_const'
include Unicorn
# code to be emulated
SPARC_CODE = "\x86\x00\x40\x02" # add %g1, %g2, %g3;
# memory address where emulation starts
ADDRESS = 0x10000
# callback for tracing basic blocks
$hook_block = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size])
end
# callback for tracing instructions
$hook_code = Proc.new do |uc, address, size, user_data|
puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size])
end
# Test SPARC
def test_sparc()
puts("Emulate SPARC code")
begin
# Initialize emulator in SPARC EB mode
mu = Uc.new UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN
# map 2MB memory for this emulation
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(ADDRESS, SPARC_CODE)
# initialize machine registers
mu.reg_write(UC_SPARC_REG_G1, 0x1230)
mu.reg_write(UC_SPARC_REG_G2, 0x6789)
mu.reg_write(UC_SPARC_REG_G3, 0x5555)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, $hook_block)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, $hook_code)
# emulate machine code in infinite time
mu.emu_start(ADDRESS, ADDRESS + SPARC_CODE.bytesize)
# now puts out some registers
puts(">>> Emulation done. Below is the CPU context")
g3 = mu.reg_read(UC_SPARC_REG_G3)
puts(">>> G3 = 0x%x" %g3)
rescue UcError => e
puts("ERROR: %s" % e)
end
end
test_sparc()

View file

@ -0,0 +1,97 @@
#!/usr/bin/env ruby
require 'unicorn'
require 'unicorn/x86_const'
include Unicorn
F_GRANULARITY = 0x8
F_PROT_32 = 0x4
F_LONG = 0x2
F_AVAILABLE = 0x1
A_PRESENT = 0x80
A_PRIV_3 = 0x60
A_PRIV_2 = 0x40
A_PRIV_1 = 0x20
A_PRIV_0 = 0x0
A_CODE = 0x10
A_DATA = 0x10
A_TSS = 0x0
A_GATE = 0x0
A_DATA_WRITABLE = 0x2
A_CODE_READABLE = 0x2
A_DIR_CON_BIT = 0x4
S_GDT = 0x0
S_LDT = 0x4
S_PRIV_3 = 0x3
S_PRIV_2 = 0x2
S_PRIV_1 = 0x1
S_PRIV_0 = 0x0
def create_selector(idx, flags)
to_ret = flags
to_ret |= idx << 3
return to_ret
end
def create_gdt_entry(base, limit, access, flags)
to_ret = limit & 0xffff;
to_ret |= (base & 0xffffff) << 16;
to_ret |= (access & 0xff) << 40;
to_ret |= ((limit >> 16) & 0xf) << 48;
to_ret |= (flags & 0xff) << 52;
to_ret |= ((base >> 24) & 0xff) << 56;
return [to_ret].pack('Q')
end
def write_gdt(uc, gdt, mem)
gdt.each_index do |idx|
offset = idx * GDT_ENTRY_SIZE
uc.mem_write(mem + offset, gdt[idx])
end
end
CODE_ADDR = 0x40000
CODE_SIZE = 0x1000
GDT_ADDR = 0x3000
GDT_LIMIT = 0x1000
GDT_ENTRY_SIZE = 0x8
GS_SEGMENT_ADDR = 0x5000
GS_SEGMENT_SIZE = 0x1000
uc = Uc.new UC_ARCH_X86, UC_MODE_32
uc.mem_map(GDT_ADDR, GDT_LIMIT)
uc.mem_map(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE)
uc.mem_map(CODE_ADDR, CODE_SIZE)
gdt = Array.new (31) {|i| create_gdt_entry(0,0,0,0)}
gdt[15] = create_gdt_entry(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32)
gdt[16] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) # Data Segment
gdt[17] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_CODE | A_CODE_READABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) # Code Segment
gdt[18] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_0 | A_DIR_CON_BIT, F_PROT_32) # Stack Segment
write_gdt(uc, gdt, GDT_ADDR)
uc.reg_write(UC_X86_REG_GDTR, [0, GDT_ADDR, gdt.length * GDT_ENTRY_SIZE-1, 0x0])
selector = create_selector(15, S_GDT | S_PRIV_3)
uc.reg_write(UC_X86_REG_GS, selector)
selector = create_selector(16, S_GDT | S_PRIV_3)
uc.reg_write(UC_X86_REG_DS, selector)
selector = create_selector(17, S_GDT | S_PRIV_3)
uc.reg_write(UC_X86_REG_CS, selector)
selector = create_selector(18, S_GDT | S_PRIV_0)
uc.reg_write(UC_X86_REG_SS, selector)

View file

@ -367,7 +367,6 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){
err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_syscall,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1));
break;
}
err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));
}
else if(htype == UC_HOOK_INTR){
err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end));

View file

@ -7,4 +7,4 @@
/pkg/
/spec/reports/
/tmp/
.gem
*.gem

View file

@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
spec.version = Unicorn::VERSION
spec.authors = ["Sascha Schirra"]
spec.email = ["sashs@scoding.de"]
spec.license = GPLv2
spec.license = 'GPL-2.0'
spec.summary = %q{Ruby binding for Unicorn-Engine}
spec.description = %q{Ruby binding for Unicorn-Engine <unicorn-engine.org>}
spec.homepage = "https://unicorn-engine.org"