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.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. 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
@@ -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
+ }