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