# This file is part of Metasm, the Ruby assembly manipulation suite # Copyright (C) 2007 Yoann GUILLOT # # Licence is LGPL, see LICENCE in the top-level directory # # in this exemple we will patch a process specified on the commandline (pid or part of image name) # the IAT entry matching /WriteFile/ will be replaced by a pointer to a malicious code we inject, # which calls back the original function. # Our shellcode will display the first bytes of the data to be written, using MessageBoxW (whose # pointer is also retrieved from the target IAT) # # usage: ruby w32hook.rb notepad ; then go in notepad, type some words and save to a file # require 'metasm' include Metasm include WinAPI # open target WinOS.get_debug_privilege if not pr = WinOS.find_process(ARGV.first) # display list of running processes if no target found puts WinOS.list_processes.sort_by { |pr_| pr_.pid } exit end raise 'cannot open target process' if not pr.handle # read the target PE structure pe = LoadedPE.load pr.memory[pr.modules[0].addr, 0x1000000] pe.decode_header pe.decode_imports # find iat entries target = nil target_p = nil msgboxw_p = nil iat_entry_len = pe.encode_xword(0).length # 64bits portable ! (shellcode probably won't work) pe.imports.each { |id| id.imports.each_with_index { |i, idx| case i.name when 'MessageBoxW' msgboxw_p = pr.modules[0].addr + id.iat_p + iat_entry_len * idx when /WriteFile/ target_p = pr.modules[0].addr + id.iat_p + iat_entry_len * idx target = id.iat[idx] end } } raise "iat entries not found" if not target or not msgboxw_p # here we write our shellcode (no need to code position-independant) sc = Shellcode.assemble(Ia32.new, < msgboxw_p, 'target' => target raw = sc.encode_string # inject the shellcode pr.memory[injected, raw.length] = raw # rewrite iat entry iat_h = pe.encode_xword(injected).data pr.memory[target_p, iat_h.length] = iat_h # done WinAPI.closehandle(pr.handle)