metasm 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
4
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
5
|
+
#
|
|
6
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# this exemple illustrates the use of the PTrace class to hijack a syscall in a running process
|
|
10
|
+
# the next syscall made is patched to run the syscall with the arguments of our choice, then
|
|
11
|
+
# run the original intended syscall
|
|
12
|
+
# Works on linux/x86
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
require 'metasm'
|
|
17
|
+
|
|
18
|
+
class SyscallHooker < Metasm::PTrace
|
|
19
|
+
CTX = ['EBX', 'ECX', 'EDX', 'ESI', 'EDI', 'EAX', 'ESP', 'EBP', 'EIP', 'ORIG_EAX']
|
|
20
|
+
|
|
21
|
+
def inject(sysnr, *args)
|
|
22
|
+
sysnr = syscallnr[sysnr] || sysnr
|
|
23
|
+
|
|
24
|
+
syscall
|
|
25
|
+
puts '[*] waiting syscall'
|
|
26
|
+
Process.waitpid(@pid)
|
|
27
|
+
|
|
28
|
+
savedctx = CTX.inject({}) { |ctx, reg| ctx.update reg => peekusr(REGS_I386[reg]) }
|
|
29
|
+
|
|
30
|
+
eip = (savedctx['EIP'] - 2) & 0xffffffff
|
|
31
|
+
fu = readmem(eip, 2)
|
|
32
|
+
if fu == "\xcd\x80"
|
|
33
|
+
mode = :int80
|
|
34
|
+
elsif fu == "\xeb\xf3" and readmem(eip-14, 7).unpack('H*').first == "51525589e50f34" # aoenthuasn
|
|
35
|
+
mode = :sysenter
|
|
36
|
+
elsif fu == "\x0f\x05"
|
|
37
|
+
mode = :syscall
|
|
38
|
+
else
|
|
39
|
+
puts 'unhandled syscall convention, aborting, code = ' + readmem(eip-4, 8).unpack('H*').first
|
|
40
|
+
cont
|
|
41
|
+
return self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
if args.length > 5
|
|
45
|
+
puts 'too may arguments, unsupported, aborting'
|
|
46
|
+
else
|
|
47
|
+
puts "[*] hooking #{syscallnr.index(savedctx['ORIG_EAX'])}"
|
|
48
|
+
|
|
49
|
+
# stack pointer to store buffers to
|
|
50
|
+
esp_ptr = savedctx['ESP']
|
|
51
|
+
write_string = lambda { |s|
|
|
52
|
+
esp_ptr -= s.length
|
|
53
|
+
esp_ptr &= 0xffff_fff0
|
|
54
|
+
writemem(esp_ptr, s)
|
|
55
|
+
[esp_ptr].pack('L').unpack('l').first
|
|
56
|
+
}
|
|
57
|
+
set_arg = lambda { |a|
|
|
58
|
+
case a
|
|
59
|
+
when String; write_string[a + 0.chr]
|
|
60
|
+
when Array; write_string[a.map { |aa| set_arg[aa] }.pack('L*')]
|
|
61
|
+
else a
|
|
62
|
+
end
|
|
63
|
+
}
|
|
64
|
+
args.zip(CTX).map { |arg, reg|
|
|
65
|
+
# set syscall args, put buffers on the stack as needed
|
|
66
|
+
pokeusr(REGS_I386[reg], set_arg[arg])
|
|
67
|
+
}
|
|
68
|
+
# patch syscall number
|
|
69
|
+
pokeusr(REGS_I386['ORIG_EAX'], sysnr)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# run hooked syscall
|
|
73
|
+
syscall
|
|
74
|
+
Process.waitpid(@pid)
|
|
75
|
+
retval = peekusr(REGS_I386['EAX'])
|
|
76
|
+
puts "[*] retval: #{'%X' % retval}#{" (Errno::#{ERRNO.index(-retval)})" if retval < 0}"
|
|
77
|
+
|
|
78
|
+
if syscallnr.index(sysnr) == 'execve' and retval >= 0
|
|
79
|
+
cont
|
|
80
|
+
return self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# restore eax & eip to run the orig syscall
|
|
84
|
+
savedctx['EIP'] -= 2
|
|
85
|
+
savedctx['EAX'] = savedctx['ORIG_EAX']
|
|
86
|
+
savedctx.each { |reg, val| pokeusr(REGS_I386[reg], val) }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
self
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if $0 == __FILE__
|
|
94
|
+
SyscallHooker.new(ARGV.shift.to_i).inject('write', 2, "testic\n", 7).detach
|
|
95
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
4
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
5
|
+
#
|
|
6
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
7
|
+
|
|
8
|
+
require 'metasm'
|
|
9
|
+
$opts = { :execlass => Metasm::MachO }
|
|
10
|
+
load File.join(File.dirname(__FILE__), 'exeencode.rb')
|
|
11
|
+
|
|
12
|
+
__END__
|
|
13
|
+
.text
|
|
14
|
+
|
|
15
|
+
str db "Hello, World !\n", 0
|
|
16
|
+
strlen equ $-str
|
|
17
|
+
.align 8
|
|
18
|
+
|
|
19
|
+
.entrypoint
|
|
20
|
+
push strlen
|
|
21
|
+
push str
|
|
22
|
+
push 1 // stdout
|
|
23
|
+
mov eax, 4 // sys_write
|
|
24
|
+
push eax
|
|
25
|
+
int 80h
|
|
26
|
+
add esp, 12
|
|
27
|
+
|
|
28
|
+
push 0
|
|
29
|
+
mov eax, 1 // sys_exit
|
|
30
|
+
push eax
|
|
31
|
+
int 80h
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
3
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
4
|
+
#
|
|
5
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
6
|
+
|
|
7
|
+
# modifies the standard ruby class String to add #decode and #encode methods
|
|
8
|
+
# they will respectively disassemble binary data / assemble asm source
|
|
9
|
+
# the default CPU is x86 32bits, change it using eg String.cpu = Metasm::MIPS.new(:big) (mips bigendian)
|
|
10
|
+
#
|
|
11
|
+
# it also defines the toplevel 'asm' method, that will start an interactive
|
|
12
|
+
# assembler shell (type in assembly statements, they are shown assembled in binary escaped form)
|
|
13
|
+
#
|
|
14
|
+
# eg:
|
|
15
|
+
# ruby metasm-shell
|
|
16
|
+
# > nop ; nop
|
|
17
|
+
# "\x90\x90"
|
|
18
|
+
# > exit
|
|
19
|
+
|
|
20
|
+
require 'metasm'
|
|
21
|
+
|
|
22
|
+
class String
|
|
23
|
+
@@cpu = Metasm::Ia32.new
|
|
24
|
+
class << self
|
|
25
|
+
def cpu() @@cpu end
|
|
26
|
+
def cpu=(c)
|
|
27
|
+
c = Metasm.const_get(c).new if c.kind_of? String
|
|
28
|
+
@@cpu=c
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# encodes the current string as a Shellcode, returns the resulting EncodedData
|
|
33
|
+
def encode_edata
|
|
34
|
+
s = Metasm::Shellcode.assemble @@cpu, self
|
|
35
|
+
s.encoded
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# encodes the current string as a Shellcode, returns the resulting binary String
|
|
39
|
+
# outputs warnings on unresolved relocations
|
|
40
|
+
def encode
|
|
41
|
+
ed = encode_edata
|
|
42
|
+
if not ed.reloc.empty?
|
|
43
|
+
puts 'W: encoded string has unresolved relocations: ' + ed.reloc.map { |o, r| r.target.inspect }.join(', ')
|
|
44
|
+
end
|
|
45
|
+
ed.fill
|
|
46
|
+
ed.data
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# decodes the current string as a Shellcode, with specified base address
|
|
50
|
+
# returns the resulting Disassembler
|
|
51
|
+
def decode_blocks(base_addr=0, eip=base_addr)
|
|
52
|
+
sc = Metasm::Shellcode.decode(self, @@cpu)
|
|
53
|
+
sc.base_addr = base_addr
|
|
54
|
+
sc.disassemble(eip)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# decodes the current string as a Shellcode, with specified base address
|
|
58
|
+
# returns the asm source equivallent
|
|
59
|
+
def decode(base_addr=0, eip=base_addr)
|
|
60
|
+
decode_blocks(base_addr, eip).to_s
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# get in interactive assembler mode
|
|
65
|
+
def asm
|
|
66
|
+
puts 'type "exit" or "quit" to quit', 'use ";" for newline', ''
|
|
67
|
+
while (print "asm> " ; $stdout.flush ; l = gets)
|
|
68
|
+
break if %w[quit exit].include? l.chomp
|
|
69
|
+
if l.chomp == 'help'
|
|
70
|
+
puts "Metasm assembly shell: type in opcodes to see their binary form",
|
|
71
|
+
"You can use ';' to type multi-line stuff",
|
|
72
|
+
"e.g. 'nop nop' will display \"\\x90\\x90\""
|
|
73
|
+
next
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
begin
|
|
77
|
+
data = l.gsub(';', "\n")
|
|
78
|
+
next if data.strip.empty?
|
|
79
|
+
data = data.encode
|
|
80
|
+
puts '"' + data.unpack('C*').map { |c| '\\x%02x' % c }.join + '"'
|
|
81
|
+
rescue Metasm::Exception => e
|
|
82
|
+
puts "Error: #{e.class} #{e.message}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
puts
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if __FILE__ == $0
|
|
90
|
+
asm
|
|
91
|
+
end
|
data/samples/pe-hook.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
3
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
4
|
+
#
|
|
5
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# in this file, we open an existing PE, add some code to its last section and
|
|
10
|
+
# patch the entrypoint so that we are executed at program start
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
require 'metasm'
|
|
14
|
+
|
|
15
|
+
# read original file
|
|
16
|
+
raise 'need a target filename' if not target = ARGV.shift
|
|
17
|
+
pe_orig = Metasm::PE.decode_file(target)
|
|
18
|
+
pe = pe_orig.mini_copy
|
|
19
|
+
pe.mz.encoded = pe_orig.encoded[0, pe_orig.coff_offset-4]
|
|
20
|
+
pe.mz.encoded.export = pe_orig.encoded[0, 512].export.dup
|
|
21
|
+
pe.header.time = pe_orig.header.time
|
|
22
|
+
|
|
23
|
+
has_mb = pe.imports.find { |id| id.imports.find { |i| i.name == 'MessageBoxA' } } ? 1 : 0
|
|
24
|
+
# hook code to run on start
|
|
25
|
+
newcode = Metasm::Shellcode.assemble(pe.cpu, <<EOS).encoded
|
|
26
|
+
hook_entrypoint:
|
|
27
|
+
pushad
|
|
28
|
+
#if ! #{has_mb}
|
|
29
|
+
push hook_libname
|
|
30
|
+
call [iat_LoadLibraryA]
|
|
31
|
+
push hook_funcname
|
|
32
|
+
push eax
|
|
33
|
+
call [iat_GetProcAddress]
|
|
34
|
+
#else
|
|
35
|
+
mov eax, [iat_MessageBoxA]
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
push 0
|
|
39
|
+
push hook_title
|
|
40
|
+
push hook_msg
|
|
41
|
+
push 0
|
|
42
|
+
call eax
|
|
43
|
+
|
|
44
|
+
popad
|
|
45
|
+
jmp entrypoint
|
|
46
|
+
|
|
47
|
+
.align 4
|
|
48
|
+
hook_msg db '(c) David Hasselhoff', 0
|
|
49
|
+
hook_title db 'Hooked on a feeling', 0
|
|
50
|
+
#if ! #{has_mb}
|
|
51
|
+
hook_libname db 'user32', 0
|
|
52
|
+
hook_funcname db 'MessageBoxA', 0
|
|
53
|
+
#endif
|
|
54
|
+
EOS
|
|
55
|
+
|
|
56
|
+
# modify last section
|
|
57
|
+
s = Metasm::PE::Section.new
|
|
58
|
+
s.name = '.hook'
|
|
59
|
+
s.encoded = newcode
|
|
60
|
+
s.characteristics = %w[MEM_READ MEM_WRITE MEM_EXECUTE]
|
|
61
|
+
s.encoded.fixup!('entrypoint' => pe.optheader.image_base + pe.optheader.entrypoint) # tell the original entrypoint address to our hook
|
|
62
|
+
pe.sections << s
|
|
63
|
+
pe.invalidate_header
|
|
64
|
+
|
|
65
|
+
# patch entrypoint
|
|
66
|
+
pe.optheader.entrypoint = 'hook_entrypoint'
|
|
67
|
+
|
|
68
|
+
# save
|
|
69
|
+
pe.encode_file(target.sub(/\.exe$/i, '-patch.exe'))
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
3
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
4
|
+
#
|
|
5
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# this sample shows the compilation of a slightly more complex program
|
|
10
|
+
# it displays in a messagebox the result of CPUID
|
|
11
|
+
#
|
|
12
|
+
|
|
13
|
+
require 'metasm'
|
|
14
|
+
|
|
15
|
+
pe = Metasm::PE.assemble Metasm::Ia32.new, <<EOS
|
|
16
|
+
.text
|
|
17
|
+
m_cpuid macro nr
|
|
18
|
+
xor ebx, ebx
|
|
19
|
+
and ecx, ebx
|
|
20
|
+
and edx, ebx
|
|
21
|
+
mov eax, nr
|
|
22
|
+
cpuid
|
|
23
|
+
endm
|
|
24
|
+
|
|
25
|
+
.entrypoint
|
|
26
|
+
|
|
27
|
+
push ebx push ecx push edx
|
|
28
|
+
|
|
29
|
+
m_cpuid(0)
|
|
30
|
+
mov [cpuname], ebx
|
|
31
|
+
mov [cpuname+4], edx
|
|
32
|
+
mov [cpuname+8], ecx
|
|
33
|
+
and byte ptr [cpuname+12], 0
|
|
34
|
+
|
|
35
|
+
m_cpuid(0x8000_0000)
|
|
36
|
+
and eax, 0x8000_0000
|
|
37
|
+
jz extended_unsupported
|
|
38
|
+
|
|
39
|
+
m_str_cpuid macro nr
|
|
40
|
+
m_cpuid(0x8000_0002 + nr)
|
|
41
|
+
mov [cpubrand + 16*nr + 0], eax
|
|
42
|
+
mov [cpubrand + 16*nr + 4], ebx
|
|
43
|
+
mov [cpubrand + 16*nr + 8], ecx
|
|
44
|
+
mov [cpubrand + 16*nr + 12], edx
|
|
45
|
+
endm
|
|
46
|
+
|
|
47
|
+
m_str_cpuid(0)
|
|
48
|
+
m_str_cpuid(1)
|
|
49
|
+
m_str_cpuid(2)
|
|
50
|
+
|
|
51
|
+
extended_unsupported:
|
|
52
|
+
and byte ptr[cpubrand+48], 0
|
|
53
|
+
|
|
54
|
+
push cpubrand
|
|
55
|
+
push cpuname
|
|
56
|
+
push format
|
|
57
|
+
push buffer
|
|
58
|
+
call wsprintf
|
|
59
|
+
add esp, 4*4
|
|
60
|
+
|
|
61
|
+
push 0
|
|
62
|
+
push title
|
|
63
|
+
push buffer
|
|
64
|
+
push 0
|
|
65
|
+
call messagebox
|
|
66
|
+
|
|
67
|
+
pop edx pop ecx pop ebx
|
|
68
|
+
|
|
69
|
+
xor eax, eax
|
|
70
|
+
ret
|
|
71
|
+
|
|
72
|
+
.import user32 MessageBoxA messagebox
|
|
73
|
+
.import user32 wsprintfA wsprintf
|
|
74
|
+
|
|
75
|
+
#define PE_HOOK_TARGET
|
|
76
|
+
#ifdef PE_HOOK_TARGET
|
|
77
|
+
; import these to be a good target for pe-hook.rb
|
|
78
|
+
.import kernel32 LoadLibraryA
|
|
79
|
+
.import kernel32 GetProcAddress
|
|
80
|
+
#endif
|
|
81
|
+
|
|
82
|
+
.data
|
|
83
|
+
format db 'CPU: %s\\nBrandstring: %s', 0
|
|
84
|
+
title db 'cpuid', 0
|
|
85
|
+
|
|
86
|
+
.bss
|
|
87
|
+
buffer db 1025 dup(?)
|
|
88
|
+
.align 4
|
|
89
|
+
cpuname db 3*4+1 dup(?)
|
|
90
|
+
.align 4
|
|
91
|
+
cpubrand db 3*4*4+1 dup(?)
|
|
92
|
+
|
|
93
|
+
EOS
|
|
94
|
+
|
|
95
|
+
pe.encode_file('metasm-cpuid.exe')
|
|
96
|
+
|
|
97
|
+
__END__
|
|
98
|
+
|
|
99
|
+
// original C code (more complete)
|
|
100
|
+
|
|
101
|
+
#include <unistd.h>
|
|
102
|
+
#include <stdio.h>
|
|
103
|
+
|
|
104
|
+
static char *featureinfo[32] = {
|
|
105
|
+
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8",
|
|
106
|
+
"apic", "unk10", "sep", "mtrr", "pge", "mca", "cmov", "pat",
|
|
107
|
+
"pse36", "psn", "clfsh", "unk20", "ds", "acpi", "mmx",
|
|
108
|
+
"fxsr", "sse", "sse2", "ss", "htt", "tm", "unk30", "pbe"
|
|
109
|
+
}, *extendinfo[32] = {
|
|
110
|
+
"sse3", "unk1", "unk2", "monitor", "ds-cpl", "unk5-vt", "unk6", "est",
|
|
111
|
+
"tm2", "unk9", "cnxt-id", "unk12", "cmpxchg16b", "unk14", "unk15",
|
|
112
|
+
"unk16", "unk17", "unk18", "unk19", "unk20", "unk21", "unk22", "unk23",
|
|
113
|
+
"unk24", "unk25", "unk26", "unk27", "unk28", "unk29", "unk30", "unk31"
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
#define cpuid(id) __asm__( "cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(id), "b"(0), "c"(0), "d"(0))
|
|
117
|
+
#define b(val, base, end) ((val << (31-end)) >> (31-end+base))
|
|
118
|
+
int main(void)
|
|
119
|
+
{
|
|
120
|
+
unsigned long eax, ebx, ecx, edx;
|
|
121
|
+
unsigned long i, max;
|
|
122
|
+
int support_extended;
|
|
123
|
+
|
|
124
|
+
printf("%8s - %8s %8s %8s %8s\n", "query", "eax", "ebx", "ecx", "edx");
|
|
125
|
+
|
|
126
|
+
max = 0;
|
|
127
|
+
for (i=0 ; i<=max ; i++) {
|
|
128
|
+
cpuid(i);
|
|
129
|
+
if (!i)
|
|
130
|
+
max = eax;
|
|
131
|
+
printf("%.8lX - %.8lX %.8lX %.8lX %.8lX\n", i, eax, ebx, ecx, edx);
|
|
132
|
+
}
|
|
133
|
+
printf("\n");
|
|
134
|
+
|
|
135
|
+
max = 0x80000000;
|
|
136
|
+
for (i=0x80000000 ; i<=max ; i++) {
|
|
137
|
+
cpuid(i);
|
|
138
|
+
if (!(i << 1)) {
|
|
139
|
+
max = eax;
|
|
140
|
+
support_extended = eax >> 31;
|
|
141
|
+
}
|
|
142
|
+
printf("%.8lX - %.8lX %.8lX %.8lX %.8lX\n", i, eax, ebx, ecx, edx);
|
|
143
|
+
}
|
|
144
|
+
printf("\n");
|
|
145
|
+
|
|
146
|
+
cpuid(0);
|
|
147
|
+
printf("identification: \"%.4s%.4s%.4s\"\n", (char *)&ebx, (char *)&edx, (char *)&ecx);
|
|
148
|
+
|
|
149
|
+
printf("cpu information:\n");
|
|
150
|
+
cpuid(1);
|
|
151
|
+
printf(" family %ld model %ld stepping %ld efamily %ld emodel %ld\n",
|
|
152
|
+
b(eax, 8, 11), b(eax, 4, 7), b(eax, 0, 3), b(eax, 20, 27), b(eax, 16, 19));
|
|
153
|
+
printf(" brand %ld cflush sz %ld*8 nproc %ld apicid %ld\n",
|
|
154
|
+
b(ebx, 0, 7), b(ebx, 8, 15), b(ebx, 16, 23), b(ebx, 24, 31));
|
|
155
|
+
|
|
156
|
+
printf(" feature information:");
|
|
157
|
+
for (i=0 ; i<32 ; i++)
|
|
158
|
+
if (edx & (1 << i))
|
|
159
|
+
printf(" %s", featureinfo[i]);
|
|
160
|
+
|
|
161
|
+
printf("\n extended information:");
|
|
162
|
+
for (i=0 ; i<32 ; i++)
|
|
163
|
+
if (ecx & (1 << i))
|
|
164
|
+
printf(" %s", extendinfo[i]);
|
|
165
|
+
printf("\n");
|
|
166
|
+
|
|
167
|
+
if (!support_extended)
|
|
168
|
+
return 0;
|
|
169
|
+
|
|
170
|
+
printf("extended cpuid:\n", eax);
|
|
171
|
+
cpuid(0x80000001);
|
|
172
|
+
printf(" %.8lX %.8lX %.8lX %.8lX + ", eax, ebx, ecx & ~1, edx & ~0x00800102);
|
|
173
|
+
if (ecx & 1)
|
|
174
|
+
printf(" lahf64");
|
|
175
|
+
|
|
176
|
+
if (edx & (1 << 11))
|
|
177
|
+
printf(" syscall64");
|
|
178
|
+
if (edx & (1 << 20))
|
|
179
|
+
printf(" nx");
|
|
180
|
+
if (edx & (1 << 29))
|
|
181
|
+
printf(" em64t");
|
|
182
|
+
|
|
183
|
+
char brandstring[48];
|
|
184
|
+
unsigned long *p = (unsigned long*)brandstring;
|
|
185
|
+
cpuid(0x80000002);
|
|
186
|
+
*p++ = eax;
|
|
187
|
+
*p++ = ebx;
|
|
188
|
+
*p++ = ecx;
|
|
189
|
+
*p++ = edx;
|
|
190
|
+
cpuid(0x80000003);
|
|
191
|
+
*p++ = eax;
|
|
192
|
+
*p++ = ebx;
|
|
193
|
+
*p++ = ecx;
|
|
194
|
+
*p++ = edx;
|
|
195
|
+
cpuid(0x80000004);
|
|
196
|
+
*p++ = eax;
|
|
197
|
+
*p++ = ebx;
|
|
198
|
+
*p++ = ecx;
|
|
199
|
+
*p++ = edx;
|
|
200
|
+
printf("\n brandstring: \"%.48s\"\n", brandstring);
|
|
201
|
+
|
|
202
|
+
return 0;
|
|
203
|
+
}
|