首页
社区
课程
招聘
通过peb自己实现GetModuleHandle
发表于: 2022-10-21 14:42 9324

通过peb自己实现GetModuleHandle

2022-10-21 14:42
9324

peb 进程环境块

下面是peb部分结构
在peb偏移0xc的位置有这样一个结构体
_PEB_LDR_DATA
这个结构体里面存储这个程序所有的加载的模块

dt _PEB_LDR_DATA结构体,里面有三个双向链表,链表中程序加载的模块信息
模块基址,,模块的入口,模块的大小,模块的绝对路径和名称
我们要实现GetModuleHandle的关键就是遍历这个链表,获取模块的入口地址

粗体文本

c代码的实现:
这里需要注意teb里面的字符串是Unicode编码的,所以需要自己转换一下

 
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
+0x002 BeingDebugged    : 0x1 ''
+0x003 BitField         : 0 ''
+0x003 ImageUsesLargePages : 0y0
+0x003 IsProtectedProcess : 0y0
+0x003 IsImageDynamicallyRelocated : 0y0
+0x003 SkipPatchingUser32Forwarders : 0y0
+0x003 IsPackagedProcess : 0y0
+0x003 IsAppContainer   : 0y0
+0x003 IsProtectedProcessLight : 0y0
+0x003 IsLongPathAwareProcess : 0y0
+0x004 Mutant           : 0xffffffff Void
+0x008 ImageBaseAddress : 0x00400000 Void
 /*----当前进程保存那些的模块---*/
+0x00c Ldr              : 0x77b089c0 _PEB_LDR_DATA 
 /*----------------------------*/
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
+0x002 BeingDebugged    : 0x1 ''
+0x003 BitField         : 0 ''
+0x003 ImageUsesLargePages : 0y0
+0x003 IsProtectedProcess : 0y0
+0x003 IsImageDynamicallyRelocated : 0y0
+0x003 SkipPatchingUser32Forwarders : 0y0
+0x003 IsPackagedProcess : 0y0
+0x003 IsAppContainer   : 0y0
+0x003 IsProtectedProcessLight : 0y0
+0x003 IsLongPathAwareProcess : 0y0
+0x004 Mutant           : 0xffffffff Void
+0x008 ImageBaseAddress : 0x00400000 Void
 /*----当前进程保存那些的模块---*/
+0x00c Ldr              : 0x77b089c0 _PEB_LDR_DATA 
 /*----------------------------*/
+0x000 Length           : 0x30
+0x004 Initialized      : 0x1 ''
+0x008 SsHandle         : (null)
 /*加载模块的顺序的列表*/
+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x6d3778 - 0x6d9880 ]
 /*内存顺序模块列表*/
+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x6d3780 - 0x6d9888 ]
 /*初始化顺序模块列表*/
+0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x6d3670 - 0x6d9890 ]
+0x024 EntryInProgress  : (null)
+0x028 ShutdownInProgress : 0 ''
+0x02c ShutdownThreadId : (null)
+0x000 Length           : 0x30
+0x004 Initialized      : 0x1 ''
+0x008 SsHandle         : (null)
 /*加载模块的顺序的列表*/
+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x6d3778 - 0x6d9880 ]
 /*内存顺序模块列表*/
+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x6d3780 - 0x6d9888 ]
 /*初始化顺序模块列表*/
+0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x6d3670 - 0x6d9890 ]
+0x024 EntryInProgress  : (null)
+0x028 ShutdownInProgress : 0 ''
+0x02c ShutdownThreadId : (null)
 
HMODULE MyGetModuleHandle(LPCTSTR lpModuleName) {
    LIST_ENTRY* pListEntry = NULL;
    LDR_DATA_TABLE_ENTRY* pLdrDataTableEntry = NULL;
    PEB* pPeb = NULL;
    pPeb = (PPEB)__readfsdword(0x30);//拿到peb
    //peb数据
    pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pPeb->Ldr->InMemoryOrderModuleList.Flink;
    //peb的节点
    pListEntry = pPeb->Ldr->InMemoryOrderModuleList.Flink;
    strlwr((char*)lpModuleName);//强制转换为小写
    if (!strcmp(lpModuleName,"")) {//为空直接返回
        return (HMODULE)pLdrDataTableEntry->Reserved2[0];
    }
    int nSize = strlen(lpModuleName);
    int nRet = (int)strstr(lpModuleName, ".");
    if (nRet==0)//没找到 我们给字符串加上.dll
    {
        strcat((char*)lpModuleName,".dll");
    }
    else if (nRet==((int)lpModuleName+ nSize-1)) {
        char* addr = (char*)lpModuleName + nSize-1;
        addr[0] = '\0';
    }
    do
    {
        char str[100] = {0};
        int nASize = WideCharToMultiByte(CP_UTF8, 0, pLdrDataTableEntry->FullDllName.Buffer, pLdrDataTableEntry->FullDllName.Length, NULL, 0, NULL, NULL);
        WideCharToMultiByte( CP_UTF8, 0, pLdrDataTableEntry->FullDllName.Buffer, pLdrDataTableEntry->FullDllName.Length, str, nASize, NULL, NULL);
        strlwr(str);
        //判断
         nRet = strcmp(lpModuleName, str);
        if (nRet == 0) {//相等 返回句柄
            return (HMODULE)pLdrDataTableEntry->Reserved2[0];
        }
        pLdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)pListEntry->Flink;
        pListEntry = pListEntry->Flink;
    } while (pListEntry != pPeb->Ldr->InMemoryOrderModuleList.Flink);
    return NULL;
};
 
int main()
{
    char dllName[30] = "kernel32.dll";
    HMODULE hHandle = MyGetModuleHandle(dllName);
}
HMODULE MyGetModuleHandle(LPCTSTR lpModuleName) {
    LIST_ENTRY* pListEntry = NULL;
    LDR_DATA_TABLE_ENTRY* pLdrDataTableEntry = NULL;
    PEB* pPeb = NULL;
    pPeb = (PPEB)__readfsdword(0x30);//拿到peb

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-11-28 16:20 被mb_kbkqyusp编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (3)
雪    币: 27
活跃值: (127)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

系统的 GetModuleHandle 支持文件名末尾带点,表示模块名称没有扩展名。支持路径,但只匹配文件名。这个实现过于简陋,且问题很多。

  1. LPCTSTR 是不确定类型,与 UNICODE 宏是否定义有关。
    不能简单地视为 char 指针,不能直接使用 str 开头的字符串函数。

  2. 如果要模仿 Windows API 应该实现 LPCWSTR、LPCSTR 两个版本。
    实现 Unicode 版本,ANSI 版本则仅执行编码转换和调用转发。

  3. 获取 PEB 结构体指针的 __readfsdword(0x30) 只适用于 x86 程序。
    编译为 x64 时应当使用 __readgsqword 且偏移量也和 x86 不同。

  4. 查找文件扩展名应该使用 wcsrchr (strrchr) 之类的函数搜索 L'.' 字符。
    使用 wcsstr (strstr) 正向搜索 L"." 字符串的方式不够严谨。

  5. 未对输入指针判空,强行修改输入只读字符串参数,代码习惯不好。

  6. 每次循环都对输入字符串参数进行转码,逻辑冗余。

获取 PEB 的指针,应该使用如下代码,可适配 X86 和 X64 平台。
暂不考虑 ARM64,否则需要判断 _M_IX86 宏。

static inline struct _PEB *NtCurrentPeb(void)
{
#if defined(_M_X64) // _M_AMD64
    return (struct _PEB *)__readgsqword(FIELD_OFFSET(TEB, ProcessEnvironmentBlock));
#else
    return (struct _PEB *)__readfsdword(FIELD_OFFSET(TEB, ProcessEnvironmentBlock));
#endif
}
最后于 2022-10-28 14:56 被Xenophon编辑 ,原因:
2022-10-28 14:50
2
雪    币: 4490
活跃值: (5109)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
3

楼上说得对

最后于 2022-10-28 17:18 被sonyps编辑 ,原因:
2022-10-28 15:19
0
雪    币: 583
活跃值: (997)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
Xenophon 系统的 GetModuleHandle 支持文件名末尾带点,表示模块名称没有扩展名。支持路径,但只匹配文件名。这个实现过于简陋,且问题很多。LPCTSTR 是不确定类型,与 UNICODE 宏是否定义 ...
感谢大佬指教
2022-11-6 00:58
0
游客
登录 | 注册 方可回帖
返回
//