首页
社区
课程
招聘
[旧帖] [求助]自己写的PE加载器碰到了一严重问题 0.00雪花
发表于: 2009-9-23 09:34 2740

[旧帖] [求助]自己写的PE加载器碰到了一严重问题 0.00雪花

2009-9-23 09:34
2740

下面是我写的加载器,可能有些杂乱

DWORD Load(wchar_t* name)
{
        fstream f;
        f.open(name, ios_base::in | ios_base::binary);
       
        if (!f.is_open())
                return 0;

        //只是暂时获取头信息
        char buff[1024];
        DWORD currAddr = (DWORD)buff;
        DWORD offset = 0;
       
        f.read(buff, 1024);

        IMAGE_DOS_HEADER dosHeader;                //Dos头
        IMAGE_NT_HEADERS ntHeader;                //NT头
        IMAGE_FILE_HEADER fileHeader;        //文件头
        IMAGE_OPTIONAL_HEADER optHeader;//可选头
        IMAGE_DATA_DIRECTORY* pDataDir;        //数据目录
        IMAGE_IMPORT_DESCRIPTOR* pImportDes;        //导入描述符
        IMAGE_SECTION_HEADER* pSecHeader;        //节头目录

        //得到dos头,指针向前移动。
        memcpy(&dosHeader, (void *)buff, sizeof(IMAGE_DOS_HEADER));

        //初始化NT头
        memcpy(&ntHeader, (void *)(buff + dosHeader.e_lfanew), sizeof(IMAGE_NT_HEADERS));
        currAddr += dosHeader.e_lfanew;//当前地址指向NT头

        //初始化文件头
        memcpy(&fileHeader, (void *)(currAddr + sizeof(DWORD)), sizeof(IMAGE_FILE_HEADER));
        currAddr += ( sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) );//当前地址指向可选头

        //初始化可选头
        memcpy(&optHeader, (void *)currAddr, sizeof(IMAGE_OPTIONAL_HEADER));

        DWORD sectionAlignment = optHeader.SectionAlignment;
        DWORD sizeOfImage = optHeader.SizeOfImage;
        WORD nrOfSection = fileHeader.NumberOfSections;
       
        currAddr += sizeof(IMAGE_OPTIONAL_HEADER);                //指向节目录
        pSecHeader = (IMAGE_SECTION_HEADER*)currAddr;

        //将文件加载到内存
        DWORD handle = (DWORD)new char[sizeOfImage];
        memset((void*)handle, 0, sizeOfImage);
        DWORD p = handle;

        //将DOS头和DOS存根一起COPY
        memcpy((void*)p, buff, dosHeader.e_lfanew);
        p += dosHeader.e_lfanew;
       
        //NT头
        ntHeader.OptionalHeader.ImageBase = handle;        //重写基地址
        memcpy((void*)p, &ntHeader, sizeof(IMAGE_NT_HEADERS));
        p += sizeof(IMAGE_NT_HEADERS);

        //节表,直接从流中读取
        offset = (DWORD)pSecHeader - (DWORD)buff;
        f.seekg(offset);
        f.read((char *)p, sizeof(IMAGE_SECTION_HEADER) * nrOfSection);
        p += sizeof(IMAGE_SECTION_HEADER) * nrOfSection;
       
        //装载节,从流中获取
        for (int i = 0 ; i < nrOfSection ; i++)
        {
                f.seekg(pSecHeader[i].PointerToRawData);
                f.read((char*)(handle + pSecHeader[i].VirtualAddress), pSecHeader[i].Misc.VirtualSize);
                offset += pSecHeader[i].Misc.VirtualSize;
        }

        //初始化数据目录,输入表目录
        //这里修改的都必须是new出来的空间里的数据
        offset = dosHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);//到OPT头

        pDataDir = ((IMAGE_OPTIONAL_HEADER*)(handle + offset))->DataDirectory;
        pImportDes = (IMAGE_IMPORT_DESCRIPTOR *)(handle + pDataDir[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

        //所有节都装载完毕,重构导入表
        for (int i = 0 ; pImportDes[i].Name != 0 ; i++)
        {
                HMODULE h = GetModuleHandleA((char *)(handle + pImportDes[i].Name));
                if (!h)
                {
                        h = LoadLibraryA((char *)(handle + pImportDes[i].Name));
                        if (!h)
                                continue;
                }

                //修正FirstTrunk使其指向导出函数的地址
                IMAGE_THUNK_DATA32* pOriThunkData = (IMAGE_THUNK_DATA32*)(handle + pImportDes[i].OriginalFirstThunk);
                IMAGE_THUNK_DATA32* pThunkData = (IMAGE_THUNK_DATA32*)(handle + pImportDes[i].FirstThunk);

                for (int j = 0 ; pOriThunkData[j].u1.Ordinal != 0 ; j++)
                {
                        //32位为1,THUNK表示HINT,否则表示函数名的RVA
                        if (pOriThunkData[j].u1.Ordinal & 0x80000000)
                        {
                                DWORD hint = pOriThunkData[j].u1.Ordinal & 0x7FFFFFFF;
                                pThunkData[j].u1.Function = GetProcAddrByHint((DWORD)h, hint);
                        }
                        else
                        {
                                IMAGE_IMPORT_BY_NAME* tmp = (IMAGE_IMPORT_BY_NAME*)(handle + pOriThunkData[j].u1.AddressOfData);
                                pThunkData[j].u1.Function = GetProcAddrByName((DWORD)h, (char*)(tmp->Name));
                        }
                }
        }
        //输入表重构完毕
        return handle;
}

DWORD GetProcAddrByHint(DWORD module, DWORD hint)
{
        WORD index = 0;
        IMAGE_EXPORT_DIRECTORY* pExpDir = NULL;
        WORD* ordinals = NULL;
        DWORD* addrFun = NULL;

        DWORD offset = ((IMAGE_DOS_HEADER*)module)->e_lfanew;
        pExpDir = (IMAGE_EXPORT_DIRECTORY*)(module + ((IMAGE_NT_HEADERS*)(module + offset))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
        ordinals = (WORD*)((DWORD)module + pExpDir->AddressOfNameOrdinals);
        addrFun = (DWORD*)((DWORD)module + pExpDir->AddressOfFunctions);

        index = hint - pExpDir->Base;
        index = ordinals[index];
        return (DWORD)module + addrFun[index];
}

DWORD GetProcAddrByName(DWORD module, char* name)
{
        int nr = 0;
        WORD index = 0;
        IMAGE_EXPORT_DIRECTORY* pExpDir = NULL;

        WORD* ordinals = NULL;
        DWORD* addrFun = NULL;
        DWORD* names = NULL;

        DWORD offset = ((IMAGE_DOS_HEADER*)module)->e_lfanew;
        pExpDir = (IMAGE_EXPORT_DIRECTORY*)(module + ((IMAGE_NT_HEADERS*)(module + offset))->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
        ordinals = (WORD*)((DWORD)module + pExpDir->AddressOfNameOrdinals);
        addrFun = (DWORD*)((DWORD)module + pExpDir->AddressOfFunctions);
        names = (DWORD*)((DWORD)module + pExpDir->AddressOfNames);

        nr = pExpDir->NumberOfNames;
        for (int i = 0 ; i < nr ; i++)
        {
                if (!strcmp((char*)(module + names[i]),name))//equal
                {
                        index = ordinals[i];
                        return (DWORD)module + addrFun[index];
                }
        }
       
        return 0;
}

=======================================
这里是目标DLL
__declspec(dllexport) void __stdcall ofun()
{
//        printf("%d",20);
}

=======================================
这里是主程序
        DWORD h = Load(L"decorate name.dll");
//        HMODULE h = LoadLibrary(L"decorate name.dll");
        typedef void (*pfn)();
        DWORD addr = GetProcAddrByName((DWORD)h, "?ofun@@YGXXZ");
        pfn p = (pfn)addr;
        p();

如果目标DLL的printf("%d",20)被注释掉了,那么p()的调用就OK(至少地址是对的)
如果printf没被注释掉,用我自己的LOAD加载DLL,在调用到printf时会出现访问异常,而使用系统的LOADLIBRARY则没问题,我看了下汇编代码:
00421078 55               push        ebp  
00421079 8B EC            mov         ebp,esp
0042107B 6A 14            push        14h  
0042107D 68 4C 35 00 10   push        1000354Ch
00421082 FF 15 F0 61 00 10 call        dword ptr ds:[100061F0h]
00421088 83 C4 08         add         esp,8
0042108B 5D               pop         ebp  

在call dword ptr ds:[100061F0h]处异常发生,DS此时=0;

下面是LOADLIBRARY:
10001010 55               push        ebp  
10001011 8B EC            mov         ebp,esp
10001013 6A 14            push        14h  
10001015 68 4C 35 00 10   push        offset ___xi_z+13Ch (1000354Ch)
1000101A FF 15 F0 61 00 10 call        dword ptr [__imp__printf (100061F0h)]
10001020 83 C4 08         add         esp,8

问题出在哪里,有人能告诉我吗?


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

收藏
免费 7
支持
分享
最新回复 (5)
雪    币: 370
活跃值: (52)
能力值: ( LV13,RANK:350 )
在线值:
发帖
回帖
粉丝
2
没有处理重定位问题
2009-9-23 17:39
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
我看了几篇文章都没对怎么处理重定位做详细的描述,能提示下吗?
2009-9-24 10:14
0
雪    币: 1450
活跃值: (35)
能力值: (RANK:680 )
在线值:
发帖
回帖
粉丝
4
通过重定位数据块对需要重定位的RVA进行重定位:
*addr = *addr + (trueBase - originalBase)

以前写过一个类似程序, 现在找不到了. LZ去google下PE结构就会明白如何做.
2009-9-24 12:30
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
恩明白了

主要是因为有些地址是写的绝对地址所以需要在装载时重定位,谢谢
2009-9-24 13:01
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我在修改导入表前添加了重定位信息的修改,但是问题依旧存在,为什么呢
//修改重定位数据
        pReloc = (IMAGE_BASE_RELOCATION*)(handle + pDataDir[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
       
        while (pReloc->VirtualAddress != 0)
        {
                DWORD base = pReloc->VirtualAddress;
                int nr = (pReloc->SizeOfBlock - 8) / 2;
                for (int i = 0 ; i < nr ; i++)
                {       
                        WORD entry = *(WORD*)(pReloc + 8 + i * sizeof(WORD));

                        if (!entry)
                                continue;

                        DWORD* pData = (DWORD*)(handle + pReloc->VirtualAddress + (entry & 0x0FFF));
                        switch ( entry >> 12)//高4位表示重定位类型
                        {
                                case IMAGE_REL_BASED_HIGHLOW:
                                        *pData = *pData + delta;
                                        break;
                        }
                }
                pReloc = (IMAGE_BASE_RELOCATION*)((DWORD)pReloc + pReloc->SizeOfBlock);
        }
2009-9-24 13:44
0
游客
登录 | 注册 方可回帖
返回
//