• C/C++遍历某进程的模块


    1. Module32Next

    	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); // 进程快照句柄
    	PROCESSENTRY32 process = {sizeof(PROCESSENTRY32)}; // 快照信息
    
    	// 遍历进程,找到 QQMusic.exe
    	while (Process32Next(hProcessSnap,&process)){
    		string s_szExeFile = process.szExeFile; // char* 转 string
    		if(s_szExeFile == "QQMusic.exe"){
    			// 初始化
    			CString strModule;	// 模块名称
    			HANDLE  hModuleSnap  =  ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,process.th32ProcessID); 	// 模块快照句柄
    			MODULEENTRY32 me32 = {0};  // 模块入口
    			me32.dwSize = sizeof(MODULEENTRY32);  // 申请空间
    			
    			// 打印模块名
    			while(::Module32Next(hModuleSnap,&me32)){
    				strModule.Format("%s",me32.szModule);
    				cout << strModule.GetBuffer() << endl;
    			}    
    		}
    	}
    

    2. CreateTool

    	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,10620);
        if (INVALID_HANDLE_VALUE == hSnapshot){return 0; }
        MODULEENTRY32 mi; 
        mi.dwSize = sizeof(MODULEENTRY32); 
        BOOL bRet = Module32First(hSnapshot,&mi);
        while (bRet)
        {
    		std::wcout.imbue(std::locale("chs"));    
    		cout << hex << "dwSize:" << (DWORD)mi.dwSize << endl;
    		cout << hex << "th32ModuleID:" << (DWORD)mi.th32ModuleID << endl;
    		cout << hex << "th32ProcessID:" << (DWORD)mi.th32ProcessID << endl;
    		cout << hex << "GlblcntUsage:" << (DWORD)mi.GlblcntUsage << endl;
    		cout << hex << "ProccntUsage:" << (DWORD)mi.ProccntUsage << endl;
    		cout << hex << "modBaseAddr:" << (ULONG32)mi.modBaseAddr << endl;
    		cout << hex << "modBaseSize:" << (DWORD)mi.modBaseSize << endl;
    		cout << hex << "hModule:" << (HMODULE)mi.hModule << endl;
    		wcout << "szModule:" << mi.szModule << endl;
    		wcout << "szExePath:" << mi.szExePath << endl;
    		cout << "" << endl;
    
            bRet = Module32Next(hSnapshot,&mi);
        }
    

    效果图:

    PEB

    对于应用层,直接使用 fs/gs 寄存器获取 peb 地址,对于内核层,使用 _EPROCESS + 偏移的方式获取 peb:

    _PEB 中有一个 _PEB_LDR_DATA 类型的成员 Ldr:

    Ldr 中有有一个 _LIST_ENTRY 类型的成员 InMemoryOrderModuleList :

    这个 _LIST_ENTRY 是一个 _LDR_DATA_TABLE_ENTRY 结构的双向链表,遍历这个链表就可以枚举到进程内所有的模块:

    nt!_LDR_DATA_TABLE_ENTRY
       +0x000 InLoadOrderLinks : _LIST_ENTRY
       +0x010 InMemoryOrderLinks : _LIST_ENTRY
       +0x020 InInitializationOrderLinks : _LIST_ENTRY
       +0x030 DllBase          : Ptr64 Void
       +0x038 EntryPoint       : Ptr64 Void
       +0x040 SizeOfImage      : Uint4B
       +0x048 FullDllName      : _UNICODE_STRING
       +0x058 BaseDllName      : _UNICODE_STRING
       +0x068 FlagGroup        : [4] UChar
       +0x068 Flags            : Uint4B
       +0x068 PackagedBinary   : Pos 0, 1 Bit
       +0x068 MarkedForRemoval : Pos 1, 1 Bit
       +0x068 ImageDll         : Pos 2, 1 Bit
       +0x068 LoadNotificationsSent : Pos 3, 1 Bit
       +0x068 TelemetryEntryProcessed : Pos 4, 1 Bit
       +0x068 ProcessStaticImport : Pos 5, 1 Bit
       +0x068 InLegacyLists    : Pos 6, 1 Bit
       +0x068 InIndexes        : Pos 7, 1 Bit
       +0x068 ShimDll          : Pos 8, 1 Bit
       +0x068 InExceptionTable : Pos 9, 1 Bit
       +0x068 ReservedFlags1   : Pos 10, 2 Bits
       +0x068 LoadInProgress   : Pos 12, 1 Bit
       +0x068 LoadConfigProcessed : Pos 13, 1 Bit
       +0x068 EntryProcessed   : Pos 14, 1 Bit
       +0x068 ProtectDelayLoad : Pos 15, 1 Bit
       +0x068 ReservedFlags3   : Pos 16, 2 Bits
       +0x068 DontCallForThreads : Pos 18, 1 Bit
       +0x068 ProcessAttachCalled : Pos 19, 1 Bit
       +0x068 ProcessAttachFailed : Pos 20, 1 Bit
       +0x068 CorDeferredValidate : Pos 21, 1 Bit
       +0x068 CorImage         : Pos 22, 1 Bit
       +0x068 DontRelocate     : Pos 23, 1 Bit
       +0x068 CorILOnly        : Pos 24, 1 Bit
       +0x068 ChpeImage        : Pos 25, 1 Bit
       +0x068 ReservedFlags5   : Pos 26, 2 Bits
       +0x068 Redirected       : Pos 28, 1 Bit
       +0x068 ReservedFlags6   : Pos 29, 2 Bits
       +0x068 CompatDatabaseProcessed : Pos 31, 1 Bit
       +0x06c ObsoleteLoadCount : Uint2B
       +0x06e TlsIndex         : Uint2B
       +0x070 HashLinks        : _LIST_ENTRY
       +0x080 TimeDateStamp    : Uint4B
       +0x088 EntryPointActivationContext : Ptr64 _ACTIVATION_CONTEXT
       +0x090 Lock             : Ptr64 Void
       +0x098 DdagNode         : Ptr64 _LDR_DDAG_NODE
       +0x0a0 NodeModuleLink   : _LIST_ENTRY
       +0x0b0 LoadContext      : Ptr64 _LDRP_LOAD_CONTEXT
       +0x0b8 ParentDllBase    : Ptr64 Void
       +0x0c0 SwitchBackContext : Ptr64 Void
       +0x0c8 BaseAddressIndexNode : _RTL_BALANCED_NODE
       +0x0e0 MappingInfoIndexNode : _RTL_BALANCED_NODE
       +0x0f8 OriginalBase     : Uint8B
       +0x100 LoadTime         : _LARGE_INTEGER
       +0x108 BaseNameHashValue : Uint4B
       +0x10c LoadReason       : _LDR_DLL_LOAD_REASON
       +0x110 ImplicitPathOptions : Uint4B
       +0x114 ReferenceCount   : Uint4B
       +0x118 DependentLoadFlags : Uint4B
       +0x11c SigningLevel     : UChar
    

    EnumProcessModules

    HMODULE* phMods = NULL;
        HANDLE hProcess = NULL;
        DWORD dwNeeded = 0;
        DWORD i = 0;
        TCHAR szModName[MAX_PATH] = {};
    
        hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
        if (NULL == hProcess)
        {
            printf("不能打开进程[ID:0x%x]句柄,错误码:0x%08x
    ",dwProcessId);
            return;
        }
    
        EnumProcessModules(hProcess, NULL, 0, &dwNeeded);
        phMods = (HMODULE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwProcessId);
    
        if( EnumProcessModules(hProcess, phMods, dwNeeded, &dwNeeded))
        {
            for ( i = 0; i < (dwNeeded / sizeof(HMODULE)); i++ )
            {
                ZeroMemory(szModName,MAX_PATH*sizeof(TCHAR));
                //在这如果使用GetModuleFileName,有的模块名称获取不到,函数返回无法找到该模块的错误
                if ( GetModuleFileNameEx(hProcess, phMods[i], szModName,MAX_PATH))
                {
                    printf("%ws
    ", szModName);
                }
            }
        }
    
        HeapFree(GetProcessHeap(), 0, phMods);
        CloseHandle( hProcess );
    

    版权声明: 本博客,文章与代码均为学习时整理的笔记,博客中除去明确标注有参考文献的文章,其他文章【均为原创】作品,转载请务必【添加出处】,您添加出处是我创作的动力!

    警告:如果您恶意转载本人文章,则您的整站文章,将会变为我的原创作品,请相互尊重!
  • 相关阅读:
    Mysql中表名作为参数的问题
    Mysql中时间的操作笔记
    关于ThreadAbortExcption异常处理
    数据库中判断为空后使用默认值的函数
    网页嵌入地图的方式
    常用网络CMD命令
    前端html和css
    C#查看文件目录操作、复制、替换
    网站日志统计查询工具
    SQL查看表数据占用空间代码
  • 原文地址:https://www.cnblogs.com/LyShark/p/15020139.html
Copyright © 2020-2023  润新知