class Metasm::WinOS

Public Class Methods

check_process(pid) click to toggle source

returns true if the process pid exists and we can open it with QUERY_INFORMATION

# File metasm/os/windows.rb, line 1655
def check_process(pid)
        if h = WinAPI.openprocess(WinAPI::PROCESS_QUERY_INFORMATION, 0, pid)
                WinAPI.closehandle(h)
                true
        end
end
check_tid(tid, pid=nil) click to toggle source

check if the thread is alive and can be read with QUERY_INFO and optionally if it belongs to pid

# File metasm/os/windows.rb, line 1669
def check_tid(tid, pid=nil)
        if h = WinAPI.openthread(WinAPI::THREAD_QUERY_INFORMATION, 0, tid)
                WinAPI.closehandle(h)
                not pid or list_threads(pid).include?(tid)
        end
end
create_debugger(path) click to toggle source

create a debugger for the target pid/path

# File metasm/os/windows.rb, line 1584
def create_debugger(path)
        WinDebugger.new(path)
end
createthread(target, startaddr) click to toggle source

creates a new thread in the target process, with the specified start address

# File metasm/os/windows.rb, line 1633
def createthread(target, startaddr)
        WinAPI.createremotethread(target.handle, 0, 0, startaddr, 0, 0, 0)
end
fixup_shellcode_relocs(shellcode, target, remote_mem) click to toggle source
# File metasm/os/windows.rb, line 1614
def fixup_shellcode_relocs(shellcode, target, remote_mem)
        ext = shellcode.reloc_externals
        binding = {}
        while e = ext.pop
                next if binding[e]
                next if not lib = WindowsExports::EXPORT[e]  # XXX could scan all exports... LoadLibrary ftw
                next if not m = target.modules.find { |m_| m_.path.downcase.include? lib.downcase }
                lib = LoadedPE.load(remote_mem[m.addr, 0x1000_0000])
                lib.decode_header
                lib.decode_exports
                lib.export.exports.each { |e_|
                        next if not e_.name or not e_.target
                        binding[e_.name] = m.addr + lib.label_rva(e_.target)
                }
                shellcode.fixup! binding
        end
end
get_debug_privilege() click to toggle source

try to enable debug privilege in current process

# File metasm/os/windows.rb, line 1494
def get_debug_privilege
        # TODO use real structs / new_func_c
        htok = [0].pack('L')
        return if not WinAPI.openprocesstoken(WinAPI.getcurrentprocess(), WinAPI::TOKEN_ADJUST_PRIVILEGES | WinAPI::TOKEN_QUERY, htok)
        luid = [0, 0].pack('LL')
        return if not WinAPI.lookupprivilegevaluea(nil, WinAPI::SE_DEBUG_NAME, luid)

        # priv.PrivilegeCount = 1;
        # priv.Privileges[0].Luid = luid;
        # priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        priv = luid.unpack('LL').unshift(1).push(WinAPI::SE_PRIVILEGE_ENABLED).pack('LLLL')
        return if not WinAPI.adjusttokenprivileges(htok.unpack('L').first, 0, priv, 0, nil, nil)

        true
end
inject_run_shellcode(target, shellcode) click to toggle source

calls ::inject_shellcode and createthread

# File metasm/os/windows.rb, line 1638
def inject_run_shellcode(target, shellcode)
        raise "failed to inject shellcode" if not addr = inject_shellcode(target, shellcode)
        createthread(target, addr)
end
inject_shellcode(target, shellcode) click to toggle source

Injects a shellcode into the memory space of targetproc target is a WinOS::Process shellcode may be a String (raw shellcode) or an EncodedData With an EncodedData, unresolved relocations are solved using exports of modules from the target address space ; also the shellcode need not be position-independant.

# File metasm/os/windows.rb, line 1594
def inject_shellcode(target, shellcode)
        raise 'cannot open target memory' if not remote_mem = target.memory
        return if not injectaddr = WinAPI.virtualallocex(target.handle, 0, shellcode.length,
                        WinAPI::MEM_COMMIT | WinAPI::MEM_RESERVE, WinAPI::PAGE_EXECUTE_READWRITE)
        puts 'remote buffer at %x' % injectaddr if $VERBOSE

        if shellcode.kind_of? EncodedData
                fixup_shellcode_relocs(shellcode, target, remote_mem)
                shellcode.fixup! shellcode.binding(injectaddr)
                r = shellcode.reloc.values.map { |r_| r_.target }
                raise "unresolved shellcode relocs #{r.join(', ')}" if not r.empty?
                shellcode = shellcode.data
        end

        # inject the shellcode
        remote_mem[injectaddr, shellcode.length] = shellcode

        injectaddr
end
list_heaps(pid) click to toggle source

returns the heaps of the process, from a toolhelp snapshot SNAPHEAPLIST this is a hash heap_addr => { :flags => integer (heap flags)

:shared => bool (from flags)
:default => bool (from flags) }
# File metasm/os/windows.rb, line 1565
def list_heaps(pid)
        h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPHEAPLIST, pid)
        return [] if h == WinAPI::INVALID_HANDLE_VALUE
        ret = {}
        he = WinAPI.alloc_c_struct('HEAPLIST32', :dwsize => :size)
        return [] if not WinAPI.heap32listfirst(h, he)
        loop do
                hash = ret[he.th32heapid] = { :flags => he.dwflags }
                hash[:default] = true if hash[:flags] & WinAPI::HF32_DEFAULT == WinAPI::HF32_DEFAULT
                hash[:shared]  = true if hash[:flags] & WinAPI::HF32_SHARED  == WinAPI::HF32_SHARED
                # TODO there are lots of other flags in there ! like 0x1000 / 0x8000
                break if WinAPI.heap32listnext(h, he) == 0
        end
        WinAPI.closehandle(h)
        ret
end
list_modules(pid) click to toggle source

retrieve the list of Modules for a process with addr/size/path filled

# File metasm/os/windows.rb, line 1528
def list_modules(pid)
        h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPMODULE, pid)
        return [] if h == WinAPI::INVALID_HANDLE_VALUE
        list = []
        me = WinAPI.alloc_c_struct('MODULEENTRY32', :dwsize => :size)
        return [] if not WinAPI.module32first(h, me)
        loop do
                m = Process::Module.new
                m.addr = me.modbaseaddr
                m.size = me.modbasesize
                m.path = me.szexepath.to_strz
                list << m
                break if WinAPI.module32next(h, me) == 0
        end
        WinAPI.closehandle(h)
        list
end
list_processes() click to toggle source

returns an array of Processes with pid/ppid/path filled

# File metasm/os/windows.rb, line 1511
def list_processes
        h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPPROCESS, 0)
        list = []
        pe = WinAPI.alloc_c_struct('PROCESSENTRY32', :dwsize => :size)
        return if not WinAPI.process32first(h, pe)
        loop do
                p = Process.new(pe.th32processid)
                p.ppid = pe.th32parentprocessid
                p.path = pe.szexefile.to_strz
                list << p if p.pid != 0
                break if WinAPI.process32next(h, pe) == 0
        end
        WinAPI.closehandle(h)
        list
end
list_threads(pid=nil) click to toggle source

returns the list of thread ids of the system, optionally filtering by pid

# File metasm/os/windows.rb, line 1547
def list_threads(pid=nil)
        h = WinAPI.createtoolhelp32snapshot(WinAPI::TH32CS_SNAPTHREAD, 0)
        list = []
        te = WinAPI.alloc_c_struct('THREADENTRY32', :dwsize => :size)
        return [] if not WinAPI.thread32first(h, te)
        loop do
                list << te.th32threadid if not pid or te.th32ownerprocessid == pid
                break if WinAPI.thread32next(h, te) == 0
        end
        WinAPI.closehandle(h)
        list
end
open_process(pid) click to toggle source

returns the Process associated to pid if it is alive

# File metasm/os/windows.rb, line 1650
def open_process(pid)
        Process.new(pid) if check_process(pid)
end
open_process_handle(h) click to toggle source

returns a Process associated to the process handle

# File metasm/os/windows.rb, line 1644
def open_process_handle(h)
        pid = WinAPI.getprocessid(h) rescue 0
        Process.new(pid, h)
end
open_thread(tid) click to toggle source

returns the Thread associated to a tid if it is alive

# File metasm/os/windows.rb, line 1663
def open_thread(tid)
        Thread.new(tid) if check_tid(tid)
end
version() click to toggle source

returns the [major, minor] version of the windows os

# File metasm/os/windows.rb, line 1677
def version
        v = WinAPI.getversion
        [v & 0xff, (v>>8) & 0xff]
end