枚举进程加载模块

Posted VB.Net

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了枚举进程加载模块相关的知识,希望对你有一定的参考价值。

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。

在教程 vb.net 教程 6-3 进程加载的模块 中详细讲解了使用 Process类的modules属性,该属性可以获取进程加载的所有Dll文件,详细使用可以参看上述博文。

但是在实际使用中存在一个问题:对于有些程序,不能获得其进程全部的加载模块。

例如,获得QQExternal的加载模块,如果使用.Net只能获得5个dll。但是通过其它工具,可以看到实际包含了很多dll:

通过调用系统api可以很好地解决这个问题。
调用的api声明如下:
打开进程,以便执行后续操作:
    Declare Function OpenProcess Lib "kernel32" Alias "OpenProcess" (
           ByVal dwDesiredAccess As Integer,
           ByVal bInheritHandle As Integer,
           ByVal dwProcessId As Integer
           ) As IntPtr

枚举进程模块:
    Declare Function EnumProcessModulesEx Lib "PSAPI.DLL" (
           ByVal hProcess As IntPtr,
           ByVal lphModule() As Long,
           ByVal cb As Integer,
           ByRef cbNeeded As Integer,
           ByVal dwFilterFlag As Integer
           ) As Integer

获得模块文件路径:
    Declare Function GetModuleFileNameEx Lib "PSAPI.DLL" Alias "GetModuleFileNameExA" (
          ByVal hProcess As IntPtr,
          ByVal hModule As IntPtr,
          ByVal lpFileName As System.Text.StringBuilder,
          ByVal nSize As Integer) As Integer

关闭句柄:
 Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Integer) As Integer

根据以上API函数,获得模块的代码如下:
 

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each pro As Process In Process.GetProcesses
            Dim lvPro As New ListViewItem(pro.ProcessName)
            lvPro.SubItems.Add(pro.Id)
            Me.ListView1.Items.Add(lvPro)
        Next

    End Sub

    Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged
        If ListView1.SelectedItems.Count <> 1 Then
            Exit Sub
        End If

        Dim lvpro As New ListViewItem()
        lvpro = ListView1.SelectedItems(0)
        Dim proid As Integer = Integer.Parse(lvpro.SubItems(1).Text)
        Dim prohandle As Integer = Integer.Parse(lvpro.SubItems(1).Text)
        Call listModNet(proid)
        Call listModApi(proid)
    End Sub

    Private Sub listModNet(ByVal proid As Integer)

        Dim pro As Process = Process.GetProcessById(proid)
        Dim lvMod As ListViewItem
        ListView2.Items.Clear()
        Try
            TextBox2.Text = pro.Modules.Count
            For Each proMod As ProcessModule In pro.Modules
                lvMod = New ListViewItem(proMod.ModuleName)
                lvMod.SubItems.Add(proMod.BaseAddress.ToInt64)
                lvMod.SubItems.Add(proMod.FileVersionInfo.FileVersion)
                lvMod.SubItems.Add(proMod.ModuleMemorySize)
                lvMod.SubItems.Add(proMod.FileName)
                ListView2.Items.Add(lvMod)
            Next
        Catch ex As Exception
            TextBox2.Text = "err:" & ex.Message
        End Try
    End Sub

    Public Const PROCESS_QUERY_INFORMATION = 1024
    Public Const PROCESS_VM_READ = 16
    Const LIST_MODULES_ALL = 3

    Declare Function OpenProcess Lib "kernel32" Alias "OpenProcess" (
           ByVal dwDesiredAccess As Integer,
           ByVal bInheritHandle As Integer,
           ByVal dwProcessId As Integer
           ) As IntPtr

    Declare Function EnumProcessModulesEx Lib "PSAPI.DLL" (
           ByVal hProcess As IntPtr,
           ByRef lphModule As IntPtr,
           ByVal cb As Integer,
           ByRef cbNeeded As Integer,
           ByVal dwFilterFlag As Integer
           ) As Integer

    Declare Function EnumProcessModulesEx Lib "PSAPI.DLL" (
           ByVal hProcess As IntPtr,
           ByVal lphModule() As Long,
           ByVal cb As Integer,
           ByRef cbNeeded As Integer,
           ByVal dwFilterFlag As Integer
           ) As Integer

    Declare Function GetModuleFileNameEx Lib "PSAPI.DLL" Alias "GetModuleFileNameExA" (
          ByVal hProcess As IntPtr,
          ByVal hModule As IntPtr,
          ByVal lpFileName As System.Text.StringBuilder,
          ByVal nSize As Integer) As Integer

    Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Integer) As Integer


    Private Sub listModApi(ByVal proid As Integer)
        ListBox1.Items.Clear()

        Dim prohandle As IntPtr
        prohandle = OpenProcess(PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ, 0, proid)

        Dim maxMod As Integer = 1024
        Dim pmod() As Long
        ReDim pmod(0)

        Dim cb As Integer
        cb = System.Runtime.InteropServices.Marshal.SizeOf(pmod(0))

        Dim cbneeded As Integer

        Dim result As Integer
        result = EnumProcessModulesEx(prohandle, pmod, 8, cbneeded, LIST_MODULES_ALL)
        cb = cbneeded / 8
        ReDim pmod(cb - 1)
        result = EnumProcessModulesEx(prohandle, pmod, cb * 8, cbneeded, LIST_MODULES_ALL)

        If result = 0 Then
            TextBox1.Text = "err:" & Err.LastDllError
        Else
            TextBox1.Text = cbneeded / 8
            For i As Integer = 0 To pmod.Count - 1
                Dim modfilename As New System.Text.StringBuilder(255)
                result = GetModuleFileNameEx(prohandle, pmod(i), modfilename, 255)
                ListBox1.Items.Add(modfilename)
            Next
        End If

        CloseHandle(prohandle)

    End Sub

对于部分进程,需要使用管理员权限才能打开查看。

运行时如下:

 可以看到.Net中获得5个模块,但是通过API可以发现,QQExternal的进程下有105个模块,相差比较大。但是原因尚不明确。

关于API的调用,请参看以下博文:

第27章 API的调用

由于.net平台下C#和vb.NET很相似,本文也可以为C#爱好者提供参考。

学习更多vb.net知识,请参看vb.net 教程 目录

以上是关于枚举进程加载模块的主要内容,如果未能解决你的问题,请参考以下文章

枚举进程加载模块

枚举进程加载模块

枚举进程加载模块

API的调用

Python 检测PE所启用保护方式

PowerTool(杀毒辅助工具) V4.6 中文免费绿色版