metasm 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/BUGS +11 -0
- data/CREDITS +17 -0
- data/README +270 -0
- data/TODO +114 -0
- data/doc/code_organisation.txt +146 -0
- data/doc/const_missing.txt +16 -0
- data/doc/core_classes.txt +75 -0
- data/doc/feature_list.txt +53 -0
- data/doc/index.txt +59 -0
- data/doc/install_notes.txt +170 -0
- data/doc/style.css +3 -0
- data/doc/use_cases.txt +18 -0
- data/lib/metasm.rb +80 -0
- data/lib/metasm/arm.rb +12 -0
- data/lib/metasm/arm/debug.rb +39 -0
- data/lib/metasm/arm/decode.rb +167 -0
- data/lib/metasm/arm/encode.rb +77 -0
- data/lib/metasm/arm/main.rb +75 -0
- data/lib/metasm/arm/opcodes.rb +177 -0
- data/lib/metasm/arm/parse.rb +130 -0
- data/lib/metasm/arm/render.rb +55 -0
- data/lib/metasm/compile_c.rb +1457 -0
- data/lib/metasm/dalvik.rb +8 -0
- data/lib/metasm/dalvik/decode.rb +196 -0
- data/lib/metasm/dalvik/main.rb +60 -0
- data/lib/metasm/dalvik/opcodes.rb +366 -0
- data/lib/metasm/decode.rb +213 -0
- data/lib/metasm/decompile.rb +2659 -0
- data/lib/metasm/disassemble.rb +2068 -0
- data/lib/metasm/disassemble_api.rb +1280 -0
- data/lib/metasm/dynldr.rb +1329 -0
- data/lib/metasm/encode.rb +333 -0
- data/lib/metasm/exe_format/a_out.rb +194 -0
- data/lib/metasm/exe_format/autoexe.rb +82 -0
- data/lib/metasm/exe_format/bflt.rb +189 -0
- data/lib/metasm/exe_format/coff.rb +455 -0
- data/lib/metasm/exe_format/coff_decode.rb +901 -0
- data/lib/metasm/exe_format/coff_encode.rb +1078 -0
- data/lib/metasm/exe_format/dex.rb +457 -0
- data/lib/metasm/exe_format/dol.rb +145 -0
- data/lib/metasm/exe_format/elf.rb +923 -0
- data/lib/metasm/exe_format/elf_decode.rb +979 -0
- data/lib/metasm/exe_format/elf_encode.rb +1375 -0
- data/lib/metasm/exe_format/macho.rb +827 -0
- data/lib/metasm/exe_format/main.rb +228 -0
- data/lib/metasm/exe_format/mz.rb +164 -0
- data/lib/metasm/exe_format/nds.rb +172 -0
- data/lib/metasm/exe_format/pe.rb +437 -0
- data/lib/metasm/exe_format/serialstruct.rb +246 -0
- data/lib/metasm/exe_format/shellcode.rb +114 -0
- data/lib/metasm/exe_format/xcoff.rb +167 -0
- data/lib/metasm/gui.rb +23 -0
- data/lib/metasm/gui/cstruct.rb +373 -0
- data/lib/metasm/gui/dasm_coverage.rb +199 -0
- data/lib/metasm/gui/dasm_decomp.rb +369 -0
- data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
- data/lib/metasm/gui/dasm_graph.rb +1354 -0
- data/lib/metasm/gui/dasm_hex.rb +543 -0
- data/lib/metasm/gui/dasm_listing.rb +599 -0
- data/lib/metasm/gui/dasm_main.rb +906 -0
- data/lib/metasm/gui/dasm_opcodes.rb +291 -0
- data/lib/metasm/gui/debug.rb +1228 -0
- data/lib/metasm/gui/gtk.rb +884 -0
- data/lib/metasm/gui/qt.rb +495 -0
- data/lib/metasm/gui/win32.rb +3004 -0
- data/lib/metasm/gui/x11.rb +621 -0
- data/lib/metasm/ia32.rb +14 -0
- data/lib/metasm/ia32/compile_c.rb +1523 -0
- data/lib/metasm/ia32/debug.rb +193 -0
- data/lib/metasm/ia32/decode.rb +1167 -0
- data/lib/metasm/ia32/decompile.rb +564 -0
- data/lib/metasm/ia32/encode.rb +314 -0
- data/lib/metasm/ia32/main.rb +233 -0
- data/lib/metasm/ia32/opcodes.rb +872 -0
- data/lib/metasm/ia32/parse.rb +327 -0
- data/lib/metasm/ia32/render.rb +91 -0
- data/lib/metasm/main.rb +1193 -0
- data/lib/metasm/mips.rb +11 -0
- data/lib/metasm/mips/compile_c.rb +7 -0
- data/lib/metasm/mips/decode.rb +253 -0
- data/lib/metasm/mips/encode.rb +51 -0
- data/lib/metasm/mips/main.rb +72 -0
- data/lib/metasm/mips/opcodes.rb +443 -0
- data/lib/metasm/mips/parse.rb +51 -0
- data/lib/metasm/mips/render.rb +43 -0
- data/lib/metasm/os/gnu_exports.rb +270 -0
- data/lib/metasm/os/linux.rb +1112 -0
- data/lib/metasm/os/main.rb +1686 -0
- data/lib/metasm/os/remote.rb +527 -0
- data/lib/metasm/os/windows.rb +2027 -0
- data/lib/metasm/os/windows_exports.rb +745 -0
- data/lib/metasm/parse.rb +876 -0
- data/lib/metasm/parse_c.rb +3938 -0
- data/lib/metasm/pic16c/decode.rb +42 -0
- data/lib/metasm/pic16c/main.rb +17 -0
- data/lib/metasm/pic16c/opcodes.rb +68 -0
- data/lib/metasm/ppc.rb +11 -0
- data/lib/metasm/ppc/decode.rb +264 -0
- data/lib/metasm/ppc/decompile.rb +251 -0
- data/lib/metasm/ppc/encode.rb +51 -0
- data/lib/metasm/ppc/main.rb +129 -0
- data/lib/metasm/ppc/opcodes.rb +410 -0
- data/lib/metasm/ppc/parse.rb +52 -0
- data/lib/metasm/preprocessor.rb +1277 -0
- data/lib/metasm/render.rb +130 -0
- data/lib/metasm/sh4.rb +8 -0
- data/lib/metasm/sh4/decode.rb +336 -0
- data/lib/metasm/sh4/main.rb +292 -0
- data/lib/metasm/sh4/opcodes.rb +381 -0
- data/lib/metasm/x86_64.rb +12 -0
- data/lib/metasm/x86_64/compile_c.rb +1025 -0
- data/lib/metasm/x86_64/debug.rb +59 -0
- data/lib/metasm/x86_64/decode.rb +268 -0
- data/lib/metasm/x86_64/encode.rb +264 -0
- data/lib/metasm/x86_64/main.rb +135 -0
- data/lib/metasm/x86_64/opcodes.rb +118 -0
- data/lib/metasm/x86_64/parse.rb +68 -0
- data/misc/bottleneck.rb +61 -0
- data/misc/cheader-findpppath.rb +58 -0
- data/misc/hexdiff.rb +74 -0
- data/misc/hexdump.rb +55 -0
- data/misc/metasm-all.rb +13 -0
- data/misc/objdiff.rb +47 -0
- data/misc/objscan.rb +40 -0
- data/misc/pdfparse.rb +661 -0
- data/misc/ppc_pdf2oplist.rb +192 -0
- data/misc/tcp_proxy_hex.rb +84 -0
- data/misc/txt2html.rb +440 -0
- data/samples/a.out.rb +31 -0
- data/samples/asmsyntax.rb +77 -0
- data/samples/bindiff.rb +555 -0
- data/samples/compilation-steps.rb +49 -0
- data/samples/cparser_makestackoffset.rb +55 -0
- data/samples/dasm-backtrack.rb +38 -0
- data/samples/dasmnavig.rb +318 -0
- data/samples/dbg-apihook.rb +228 -0
- data/samples/dbghelp.rb +143 -0
- data/samples/disassemble-gui.rb +102 -0
- data/samples/disassemble.rb +133 -0
- data/samples/dump_upx.rb +95 -0
- data/samples/dynamic_ruby.rb +1929 -0
- data/samples/elf_list_needed.rb +46 -0
- data/samples/elf_listexports.rb +33 -0
- data/samples/elfencode.rb +25 -0
- data/samples/exeencode.rb +128 -0
- data/samples/factorize-headers-elfimports.rb +77 -0
- data/samples/factorize-headers-peimports.rb +109 -0
- data/samples/factorize-headers.rb +43 -0
- data/samples/gdbclient.rb +583 -0
- data/samples/generate_libsigs.rb +102 -0
- data/samples/hotfix_gtk_dbg.rb +59 -0
- data/samples/install_win_env.rb +78 -0
- data/samples/lindebug.rb +924 -0
- data/samples/linux_injectsyscall.rb +95 -0
- data/samples/machoencode.rb +31 -0
- data/samples/metasm-shell.rb +91 -0
- data/samples/pe-hook.rb +69 -0
- data/samples/pe-ia32-cpuid.rb +203 -0
- data/samples/pe-mips.rb +35 -0
- data/samples/pe-shutdown.rb +78 -0
- data/samples/pe-testrelocs.rb +51 -0
- data/samples/pe-testrsrc.rb +24 -0
- data/samples/pe_listexports.rb +31 -0
- data/samples/peencode.rb +19 -0
- data/samples/peldr.rb +494 -0
- data/samples/preprocess-flatten.rb +19 -0
- data/samples/r0trace.rb +308 -0
- data/samples/rubstop.rb +399 -0
- data/samples/scan_pt_gnu_stack.rb +54 -0
- data/samples/scanpeexports.rb +62 -0
- data/samples/shellcode-c.rb +40 -0
- data/samples/shellcode-dynlink.rb +146 -0
- data/samples/source.asm +34 -0
- data/samples/struct_offset.rb +47 -0
- data/samples/testpe.rb +32 -0
- data/samples/testraw.rb +45 -0
- data/samples/win32genloader.rb +132 -0
- data/samples/win32hooker-advanced.rb +169 -0
- data/samples/win32hooker.rb +96 -0
- data/samples/win32livedasm.rb +33 -0
- data/samples/win32remotescan.rb +133 -0
- data/samples/wintrace.rb +92 -0
- data/tests/all.rb +8 -0
- data/tests/dasm.rb +39 -0
- data/tests/dynldr.rb +35 -0
- data/tests/encodeddata.rb +132 -0
- data/tests/ia32.rb +82 -0
- data/tests/mips.rb +116 -0
- data/tests/parse_c.rb +239 -0
- data/tests/preprocessor.rb +269 -0
- data/tests/x86_64.rb +62 -0
- metadata +255 -0
data/samples/wintrace.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
|
7
|
+
#
|
8
|
+
# this is a simple executable tracer for Windows using the
|
9
|
+
# Metasm windows debug api abstraction
|
10
|
+
# all callbacks are full ruby, so this is extremely slow !
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'metasm'
|
14
|
+
Metasm.require 'samples/metasm-shell'
|
15
|
+
|
16
|
+
class Tracer < Metasm::WinDbgAPI
|
17
|
+
def initialize(*a)
|
18
|
+
super(*a)
|
19
|
+
@label = {}
|
20
|
+
@prog = Metasm::ExeFormat.new(Metasm::Ia32.new)
|
21
|
+
loop
|
22
|
+
puts 'finished'
|
23
|
+
end
|
24
|
+
|
25
|
+
def handler_newprocess(pid, tid, info)
|
26
|
+
hide_debugger(pid, tid, info)
|
27
|
+
Metasm::WinAPI::DBG_CONTINUE
|
28
|
+
end
|
29
|
+
|
30
|
+
def handler_newthread(pid, tid, info)
|
31
|
+
do_singlestep(pid, tid)
|
32
|
+
Metasm::WinAPI::DBG_CONTINUE
|
33
|
+
end
|
34
|
+
|
35
|
+
def handler_exception(pid, tid, info)
|
36
|
+
do_singlestep(pid, tid) if @hthread[pid] and @hthread[pid][tid]
|
37
|
+
case info.code
|
38
|
+
when Metasm::WinAPI::STATUS_SINGLE_STEP
|
39
|
+
Metasm::WinAPI::DBG_CONTINUE
|
40
|
+
else super(pid, tid, info)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def handler_loaddll(pid, tid, info)
|
45
|
+
# update @label with exported symbols
|
46
|
+
pe = Metasm::LoadedPE.load(@mem[pid][info.imagebase, 0x1000000])
|
47
|
+
pe.decode_header
|
48
|
+
pe.decode_exports
|
49
|
+
libname = read_str_indirect(pid, info.imagename, info.unicode)
|
50
|
+
if pe.export
|
51
|
+
libname = pe.export.libname if libname == ''
|
52
|
+
pe.export.exports.each { |e|
|
53
|
+
next if not r = pe.label_rva(e.target)
|
54
|
+
@label[info.imagebase + r] = libname + '!' + (e.name || "ord_#{e.ordinal}")
|
55
|
+
}
|
56
|
+
end
|
57
|
+
super(pid, tid, info)
|
58
|
+
end
|
59
|
+
|
60
|
+
# dumps the opcode at eip, sets the trace flag
|
61
|
+
def do_singlestep(pid, tid)
|
62
|
+
ctx = get_context(pid, tid)
|
63
|
+
eip = ctx[:eip]
|
64
|
+
|
65
|
+
if l = @label[eip]
|
66
|
+
puts l + ':'
|
67
|
+
end
|
68
|
+
if $VERBOSE
|
69
|
+
bin = @mem[pid][eip, 16]
|
70
|
+
di = @prog.cpu.decode_instruction(Metasm::EncodedData.new(bin), eip)
|
71
|
+
puts "#{'%08X' % eip} #{di.instruction}"
|
72
|
+
end
|
73
|
+
|
74
|
+
ctx[:eflags] |= 0x100
|
75
|
+
end
|
76
|
+
|
77
|
+
# resets the DebuggerPresent field of the PEB
|
78
|
+
def hide_debugger(pid, tid, info)
|
79
|
+
peb = @mem[pid][info.threadlocalbase + 0x30, 4].unpack('L').first
|
80
|
+
@mem[pid][peb + 2, 2] = [0].pack('S')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
if $0 == __FILE__
|
85
|
+
Metasm::WinOS.get_debug_privilege
|
86
|
+
if ARGV.empty?
|
87
|
+
# display list of running processes if no target found
|
88
|
+
puts Metasm::WinOS.list_processes.sort_by { |pr_| pr_.pid }
|
89
|
+
abort 'target needed'
|
90
|
+
end
|
91
|
+
Tracer.new ARGV.shift.dup
|
92
|
+
end
|
data/tests/all.rb
ADDED
data/tests/dasm.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
require 'metasm'
|
9
|
+
|
10
|
+
class TestPreproc < Test::Unit::TestCase
|
11
|
+
include Metasm
|
12
|
+
|
13
|
+
def asm_dasm(src)
|
14
|
+
@cpu ||= Ia32.new
|
15
|
+
raw = Shellcode.assemble(src, @cpu).encode_string
|
16
|
+
dasm = Shellcode.decode(raw, @cpu).disassembler
|
17
|
+
dasm.disassemble_fast(0)
|
18
|
+
dasm
|
19
|
+
end
|
20
|
+
|
21
|
+
def do_test_bd2(src, bd)
|
22
|
+
d = asm_dasm(src)
|
23
|
+
calc_bd = d.compose_bt_binding(*d.decoded[0].block.list)
|
24
|
+
calc_bd.delete_if { |k, v| k.to_s =~ /flag/ }
|
25
|
+
assert_equal bd, calc_bd
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_compose_bt_binding
|
29
|
+
do_test_bd2 'mov eax, 1 mov ebx, 2', :eax => Expression[1], :ebx => Expression[2]
|
30
|
+
do_test_bd2 'mov eax, 1 push eax', :eax => Expression[1], Indirection[:esp, 4] => Expression[1], :esp => Expression[:esp, :+, -4]
|
31
|
+
do_test_bd2 'mov [eax], ebx mov [eax], ecx', Indirection[:eax, 4] => Expression[:ecx]
|
32
|
+
do_test_bd2 'add eax, 4 mov [eax], ecx', Indirection[:eax, 4] => Expression[:ecx], :eax => Expression[:eax, :+, 4]
|
33
|
+
do_test_bd2 'mov [eax], ecx mov ebx, eax', :ebx => Expression[:eax], Indirection[:eax, 4] => Expression[:ecx], Indirection[:ebx, 4] => Expression[:ecx]
|
34
|
+
do_test_bd2 'mov [eax], ecx add eax, 4', :eax => Expression[:eax, :+, 4], Indirection[[:eax, :+, -4], 4] => Expression[:ecx]
|
35
|
+
do_test_bd2 'mov [eax+4], ecx add eax, 4', :eax => Expression[:eax, :+, 4], Indirection[:eax, 4] => Expression[:ecx]
|
36
|
+
do_test_bd2 'push 1 push 2', :esp => Expression[:esp, :+, -8], Indirection[:esp, 4] => Expression[2], Indirection[[:esp, :+, 4], 4] => Expression[1]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
data/tests/dynldr.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'metasm'
|
8
|
+
|
9
|
+
class TestDynldr < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def test_dynldr
|
12
|
+
str = "1234"
|
13
|
+
d = Metasm::DynLdr
|
14
|
+
d.new_api_c('int memcpy(char*, char*, int)')
|
15
|
+
d.memcpy(str, "9999", 2)
|
16
|
+
assert_equal('9934', str)
|
17
|
+
|
18
|
+
c_src = <<EOS
|
19
|
+
int sprintf(char*, char*, ...);
|
20
|
+
void fufu(int i, char* ptr)
|
21
|
+
{
|
22
|
+
sprintf(ptr, "lolzor %i\\n", i);
|
23
|
+
}
|
24
|
+
EOS
|
25
|
+
buf = 'aaaaaaaaaaaaaaaaaa'
|
26
|
+
d.new_func_c(c_src) { d.fufu(42, buf) }
|
27
|
+
assert_equal("lolzor 42\n\000aaaaaaa", buf)
|
28
|
+
|
29
|
+
if d.host_cpu.shortname == 'ia32'
|
30
|
+
ret = d.new_func_asm('int __fastcall bla(int)', "lea eax, [ecx+1]\nret") { d.bla(42) }
|
31
|
+
assert_equal(43, ret)
|
32
|
+
assert_equal(false, d.respond_to?(:bla))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
require 'metasm/exe_format/shellcode'
|
9
|
+
|
10
|
+
class TestEncodedData < Test::Unit::TestCase
|
11
|
+
def compile(src)
|
12
|
+
p = Metasm::Shellcode.assemble(Metasm::UnknownCPU.new(32, :little), src)
|
13
|
+
p.encoded
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_basic
|
17
|
+
e = compile <<EOS
|
18
|
+
toto db 42
|
19
|
+
tutu db 48
|
20
|
+
dd bla
|
21
|
+
EOS
|
22
|
+
assert_equal(6, e.virtsize)
|
23
|
+
assert_equal(2, e.export.keys.length)
|
24
|
+
assert_equal(0, e.export['toto'])
|
25
|
+
assert_equal(1, e.reloc.keys.length)
|
26
|
+
assert_equal('bla', e.reloc[2].target.reduce.rexpr)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_slice
|
30
|
+
e = compile <<EOS
|
31
|
+
db 4 dup(1)
|
32
|
+
toto:
|
33
|
+
db 4 dup(2)
|
34
|
+
db 4 dup(?)
|
35
|
+
foo:
|
36
|
+
dd bla
|
37
|
+
tutu:
|
38
|
+
EOS
|
39
|
+
e1 = e[4, 8]
|
40
|
+
e2 = e[4..11]
|
41
|
+
e3 = e[4...12]
|
42
|
+
e4 = e['toto', 8]
|
43
|
+
e5 = e['toto'...'foo']
|
44
|
+
assert_equal([e1.data, e1.virtsize], [e2.data, e2.virtsize])
|
45
|
+
assert_equal([e1.data, e1.virtsize], [e3.data, e3.virtsize])
|
46
|
+
assert_equal([e1.data, e1.virtsize], [e4.data, e4.virtsize])
|
47
|
+
assert_equal([e1.data, e1.virtsize], [e5.data, e5.virtsize])
|
48
|
+
assert_equal(nil, e[53, 12])
|
49
|
+
assert_equal(2, e[2, 2].export['toto'])
|
50
|
+
assert_equal(4, e[0, 4].export['toto'])
|
51
|
+
assert_equal(1, e[0, 16].reloc.length)
|
52
|
+
assert_equal(0, e[0, 15].reloc.length)
|
53
|
+
assert_equal(0, e[13, 8].reloc.length)
|
54
|
+
assert_equal(1, e[12, 4].reloc.length)
|
55
|
+
assert_equal(16, e[0, 50].virtsize)
|
56
|
+
assert_equal(1, e[15, 50].virtsize)
|
57
|
+
e.align 5
|
58
|
+
assert_equal(20, e.virtsize)
|
59
|
+
e.align 5
|
60
|
+
assert_equal(20, e.virtsize)
|
61
|
+
e.fill 30
|
62
|
+
assert_equal(30, e.virtsize)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_slice2
|
66
|
+
e = compile <<EOS
|
67
|
+
db '1'
|
68
|
+
toto:
|
69
|
+
.pad
|
70
|
+
tutu:
|
71
|
+
db '0'
|
72
|
+
.offset toto+11
|
73
|
+
EOS
|
74
|
+
assert_equal(12, e.virtsize)
|
75
|
+
assert_equal(11, e.export['tutu'])
|
76
|
+
e[1..10] = 'abcdefghij'
|
77
|
+
assert_equal(12, e.virtsize)
|
78
|
+
assert_equal(2, e.export.length)
|
79
|
+
e[1, 10] = 'jihgfedcba'
|
80
|
+
assert_equal(12, e.virtsize)
|
81
|
+
e[1...11] = 'abcdefghij'
|
82
|
+
assert_equal(12, e.virtsize)
|
83
|
+
e.patch('toto', 'tutu', 'xxx')
|
84
|
+
assert_equal('1xxxdefghij0', e.data)
|
85
|
+
e[1..10] = 'z'
|
86
|
+
assert_equal(3, e.virtsize)
|
87
|
+
assert_equal(2, e.export['tutu'])
|
88
|
+
assert_raise(Metasm::EncodeError) { e.patch('toto', 'tutu', 'toolong') }
|
89
|
+
|
90
|
+
e = compile <<EOS
|
91
|
+
db '1'
|
92
|
+
dd rel
|
93
|
+
db '2'
|
94
|
+
EOS
|
95
|
+
assert_equal(1, e.reloc.length)
|
96
|
+
assert_equal(1, e[1, 4].reloc.length)
|
97
|
+
assert_equal(1, e[1..4].reloc.length)
|
98
|
+
assert_equal(1, e[1...5].reloc.length)
|
99
|
+
assert_equal(0, e[2, 8].reloc.length)
|
100
|
+
assert_equal(0, e[1, 3].reloc.length)
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_fixup
|
104
|
+
e = compile <<EOS
|
105
|
+
db 1
|
106
|
+
db toto + tata
|
107
|
+
dd tutu
|
108
|
+
EOS
|
109
|
+
assert_equal(2, e.reloc.length)
|
110
|
+
e.fixup!('toto' => 42)
|
111
|
+
assert_raise(Metasm::EncodeError) { e.fixup('tata' => 192349129) }
|
112
|
+
e.fixup('tata' => -12)
|
113
|
+
assert_equal(30.chr[0], e.data[1])
|
114
|
+
assert_equal(1, e.reloc.length)
|
115
|
+
assert_equal(2, e.offset_of_reloc('tutu'))
|
116
|
+
assert_equal(2, e.offset_of_reloc(Metasm::Expression[:+, 'tutu']))
|
117
|
+
e.fixup('tutu' => 1024)
|
118
|
+
assert_equal("\1\x1e\0\4\0\0", e.data)
|
119
|
+
|
120
|
+
ee = Metasm::Expression[:+, 'bla'].encode(:u16, :big)
|
121
|
+
ee.fixup('bla' => 1024)
|
122
|
+
assert_equal("\4\0", ee.data)
|
123
|
+
|
124
|
+
eee = compile <<EOS
|
125
|
+
db abc - def
|
126
|
+
def:
|
127
|
+
db 12 dup(?, 3 dup('x'))
|
128
|
+
abc:
|
129
|
+
EOS
|
130
|
+
assert_equal((12*4).chr[0], eee.data[0])
|
131
|
+
end
|
132
|
+
end
|
data/tests/ia32.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
require 'metasm'
|
9
|
+
|
10
|
+
class TestIa32 < Test::Unit::TestCase
|
11
|
+
@@cpu32 = Metasm::Ia32.new
|
12
|
+
@@cpu16 = Metasm::Ia32.new(16)
|
13
|
+
def assemble(src, cpu=@@cpu32)
|
14
|
+
Metasm::Shellcode.assemble(cpu, src).encode_string
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_equal(a, b) super(b, a) end
|
18
|
+
|
19
|
+
def test_basic
|
20
|
+
assert_equal(assemble("nop"), "\x90")
|
21
|
+
assert_equal(assemble("push eax"), "\x50")
|
22
|
+
assert_equal(assemble("push 2"), "\x6a\x02")
|
23
|
+
assert_equal(assemble("push 142"), "\x68\x8e\0\0\0")
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_sz
|
27
|
+
assert_equal(assemble("dec eax"), "\x48")
|
28
|
+
assert_equal(assemble("dec ax"), "\x66\x48")
|
29
|
+
assert_equal(assemble("dec al"), "\xfe\xc8")
|
30
|
+
assert_equal(assemble("arpl [edi+70h], bp"), "cop")
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_16
|
34
|
+
assert_equal(assemble("push 142", @@cpu16), "\x68\x8e\0")
|
35
|
+
assert_equal(assemble("code16 push 142", @@cpu16), "\x68\x8e\0")
|
36
|
+
assert_equal(assemble("code16 push 142"), "\x68\x8e\0")
|
37
|
+
assert_equal(assemble("push.i16 142"), "\x66\x68\x8e\0")
|
38
|
+
assert_equal(assemble("mov eax, 42"), "\xb8\x2a\0\0\0")
|
39
|
+
assert_equal(assemble("code16 mov ax, 42"), "\xb8\x2a\0")
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_jmp
|
43
|
+
assert_equal(assemble("jmp $"), "\xeb\xfe")
|
44
|
+
assert_equal(assemble("jmp.i32 $"), "\xe9\xfb\xff\xff\xff")
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_mrmsz
|
48
|
+
assert_equal(assemble("mov [eax], ebx"), "\x89\x18")
|
49
|
+
assert_equal(assemble("mov [eax], bl"), "\x88\x18")
|
50
|
+
assert_equal(assemble("mov ebx, [eax]"), "\x8b\x18")
|
51
|
+
assert_equal(assemble("mov bl, [eax]"), "\x8a\x18")
|
52
|
+
assert_equal(assemble("mov bl, [bx]"), "\x67\x8a\x1f")
|
53
|
+
assert_equal(assemble("mov bl, [bx]", @@cpu16), "\x8a\x1f")
|
54
|
+
assert_equal(assemble("code16 mov bl, [bx]"), "\x8a\x1f")
|
55
|
+
assert_equal(assemble("mov bl, [0]"), "\x8a\x1d\0\0\0\0")
|
56
|
+
assert_equal(assemble("mov.a16 bl, [0]"), "\x67\x8a\x1e\0\0")
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_err
|
60
|
+
assert_raise(Metasm::ParseError) { assemble("add eax") }
|
61
|
+
assert_raise(Metasm::ParseError) { assemble("add add, ebx") }
|
62
|
+
assert_raise(Metasm::ParseError) { assemble("add 42, ebx") }
|
63
|
+
assert_raise(Metasm::ParseError) { assemble("add [bx+ax]") }
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_C
|
67
|
+
src = "int bla(void) { volatile int i=0; return ++i; }"
|
68
|
+
assert_equal(Metasm::Shellcode.compile_c(@@cpu32, src).encode_string,
|
69
|
+
["5589E583EC04C745FC00000000FF45FC8B45FC89EC5DC3"].pack('H*'))
|
70
|
+
end
|
71
|
+
|
72
|
+
def disassemble(bin, cpu=@@cpu32)
|
73
|
+
Metasm::Shellcode.disassemble(cpu, bin)
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_dasm
|
77
|
+
d = disassemble("\x90")
|
78
|
+
assert_equal(d.decoded[0].class, Metasm::DecodedInstruction)
|
79
|
+
assert_equal(d.decoded[0].opcode.name, "nop")
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/tests/mips.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'metasm'
|
8
|
+
|
9
|
+
class TestMips < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def test_enc
|
12
|
+
sc = Metasm::Shellcode.assemble(Metasm::MIPS.new(:big), <<EOS)
|
13
|
+
;
|
14
|
+
; MIPS nul-free xor decoder
|
15
|
+
;
|
16
|
+
; (C) 2006 Julien TINNES
|
17
|
+
; <julien at cr0.org>
|
18
|
+
;
|
19
|
+
; The first four bytes in encoded shellcode must be the xor key
|
20
|
+
; This means that you have to put the xor key right after
|
21
|
+
; this xor decoder
|
22
|
+
; This key will be considered part of the encoded shellcode
|
23
|
+
; by this decoder and will be xored, thus becoming 4NULs, meaning nop
|
24
|
+
;
|
25
|
+
; This is Linux-only because I use the cacheflush system call
|
26
|
+
;
|
27
|
+
; You can use shellforge to assemble this, but be sure to discard all
|
28
|
+
; the nul bytes at the end (everything after x01\\x4a\\x54\\x0c)
|
29
|
+
;
|
30
|
+
; change 2 bytes in the first instruction's opcode with the number of passes
|
31
|
+
; the number of passes is the number of xor operations to apply, which should be
|
32
|
+
; 1 (for the key) + the number of 4-bytes words you have in your shellcode
|
33
|
+
; you must encode ~(number_of_passes + 1) (to ensure that you're nul-free)
|
34
|
+
|
35
|
+
|
36
|
+
;.text
|
37
|
+
;.align 2
|
38
|
+
;.globl main
|
39
|
+
;.ent main
|
40
|
+
;.type main,@function
|
41
|
+
|
42
|
+
main:
|
43
|
+
|
44
|
+
li $14, -5 ; 4 passes
|
45
|
+
nor $14, $14, $0 ; put number of passes in $14
|
46
|
+
|
47
|
+
li $11,-73 ; addend to calculated PC is 73
|
48
|
+
;.set noreorder
|
49
|
+
next:
|
50
|
+
bltzal $8, next
|
51
|
+
;.set reorder
|
52
|
+
slti $8, $0, 0x8282
|
53
|
+
nor $11, $11, $0 ; addend in $9
|
54
|
+
addu $25, $31, $11 ; $25 points to encoded shellcode +4
|
55
|
+
; addu $16, $31, $11 ; $16 too (enable if you want to pass correct parameters to cacheflush
|
56
|
+
|
57
|
+
; lui $2, 0xDDDD ; first part of the xor (old method)
|
58
|
+
slti $23, $0, 0x8282 ; store 0 in $23 (our counter)
|
59
|
+
; ori $17, $2, 0xDDDD ; second part of the xor (old method)
|
60
|
+
lw $17, -4($25) ; load xor key in $17
|
61
|
+
|
62
|
+
|
63
|
+
li $13, -5
|
64
|
+
nor $13, $13, $0 ; 4 in $13
|
65
|
+
|
66
|
+
addi $15, $13, -3 ; 1 in $15
|
67
|
+
loop:
|
68
|
+
lw $8, -4($25)
|
69
|
+
|
70
|
+
addu $23, $23, $15 ; increment counter
|
71
|
+
xor $3, $8, $17
|
72
|
+
sltu $30, $23, $14 ; enough loops?
|
73
|
+
sw $3, -4($25)
|
74
|
+
addi $6, $13, -1 ; 3 in $6 (for cacheflush)
|
75
|
+
bne $0, $30, loop
|
76
|
+
addu $25, $25, $13 ; next instruction to decode :)
|
77
|
+
|
78
|
+
|
79
|
+
; addiu $4, $16, -4 ; not checked by Linux
|
80
|
+
; li $5,40 ; not checked by Linux
|
81
|
+
; li $6,3 ; $6 is set above
|
82
|
+
|
83
|
+
; .set noreorder
|
84
|
+
li $2, 4147 ; cacheflush
|
85
|
+
;.ascii "\\x01JT\\x0c" ; nul-free syscall
|
86
|
+
syscall 0x52950
|
87
|
+
; .set reorder
|
88
|
+
|
89
|
+
|
90
|
+
; write last decoder opcode and decoded shellcode
|
91
|
+
; li $4,1 ; stdout
|
92
|
+
; addi $5, $16, -8
|
93
|
+
; li $6,40 ; how much to write
|
94
|
+
; .set noreorder
|
95
|
+
; li $2, 4004 ; write
|
96
|
+
; syscall
|
97
|
+
; .set reorder
|
98
|
+
|
99
|
+
|
100
|
+
nop ; encoded shellcoded must be here (xor key right here ;)
|
101
|
+
; $t9 (aka $25) points here
|
102
|
+
EOS
|
103
|
+
# ruby19 string.encoding. What a wonderful feature!
|
104
|
+
# if we use a "\x<80 or more>", the encoding is 8bits
|
105
|
+
# '' << "\x80" => 8bits
|
106
|
+
# '' << 0x80 => ascii
|
107
|
+
# Edata.data is ascii for now, so this is needed to make the test work.
|
108
|
+
str = ''
|
109
|
+
"\x24\x0e\xff\xfb\x01\xc0\x70\x27\x24\x0b\xff\xb7\x05\x10\xff\xff\x28\x08\x82\x82\x01\x60\x58\x27\x03\xeb\xc8\x21\x28\x17\x82\x82\x8f\x31\xff\xfc\x24\x0d\xff\xfb\x01\xa0\x68\x27\x21\xaf\xff\xfd\x8f\x28\xff\xfc\x02\xef\xb8\x21\x01\x11\x18\x26\x02\xee\xf0\x2b\xaf\x23\xff\xfc\x21\xa6\xff\xff\x17\xc0\xff\xf9\x03\x2d\xc8\x21\x24\x02\x10\x33\x01\x4a\x54\x0c\0\0\0\0".each_byte { |b| str << b }
|
110
|
+
assert_equal(str, sc.encoded.data)
|
111
|
+
|
112
|
+
dasm_src = Metasm::Shellcode.disassemble(Metasm::MIPS.new(:big), sc.encoded.data).to_s
|
113
|
+
lines = dasm_src.respond_to?(:lines) ? dasm_src.lines : dasm_src.to_a
|
114
|
+
assert_equal(28, lines.grep(/\S/).length)
|
115
|
+
end
|
116
|
+
end
|