仿照windows的loader实现的pe-loader

转载 2011年01月19日 16:38:00

   本人接触pe文件格式不久,参考网上的一些资料写了一个pe loader,主要是通过把需要加载的文件的所所有section加载到相应的RVA上,然后进行重定位处理、导入表和导出表处理、资源段处理。由于本loader.exe会被加载到0x0f400000处,因此可以把0x400000给被加载的文件预留了,这样可以避免重定位所带来的性能损耗。导入表的处理主要是通过调用GetProcAddress获取导入表中函数的地址。导出表一般仅在dll中使用,而此主要是用于load exe文件,所以不用做任何处理。资源段处理资料不多,我这里好像有些问题,加载console程序可以正常执行,但是当加载一部分gui程序则不能成功,而令一些gui程序则会成功。望高手能指教一二。
    下面是源代码部分:

view plaincopy to clipboardprint?
/* 
 *LocalFile是对读文件操作的一个简单封装 
 */ 
//LocalFile.h  
#pragma once  
 
class CLocalFile  
{  
public:  
    CLocalFile(const char * name);  
    ~CLocalFile(void);  
 
    int Read(size_t offset, size_t size, void *ppBuf);  
 
    size_t GetSize() const { return m_size;}  
 
private:  
    HANDLE           m_fd;  
    size_t          m_size;  
};  
 
//LocalFile.cpp  
#include "LocalFile.h"  
 
CLocalFile::CLocalFile(const char * name)  
{  
    assert(NULL != name);  
    assert(0 != name[0]);  
 
    m_fd = CreateFileA(name, GENERIC_READ,  
                        FILE_SHARE_READ, NULL,  
                        OPEN_EXISTING,  
                        FILE_ATTRIBUTE_NORMAL, NULL);  
    if (INVALID_HANDLE_VALUE == m_fd) {  
        printf("Open file %s failed, error: %d!/n",name, GetLastError());  
        return ;  
    }  
 
    m_size = GetFileSize(m_fd, NULL);  
    return;  
}  
 
CLocalFile::~CLocalFile(void)  
{  
    if (NULL != m_fd) {  
        CloseHandle(m_fd);  
    }  
}  
 
int CLocalFile::Read(size_t offset,  
                     size_t size,  
                     void * pBuf)  
{  
    DWORD ret;  
    ULONG rdsize;  
 
    ret = SetFilePointer(m_fd, offset, NULL, FILE_BEGIN);  
    if (INVALID_SET_FILE_POINTER == ret) {  
        ret = GetLastError();  
        printf("Seek file failed, error: %d!/n", ret);  
        return ret;  
    }  
 
    if (!ReadFile(m_fd, pBuf, size, &rdsize, NULL)) {  
        ret = GetLastError();  
        printf("Read file failed, error: %d/n", ret);  
        return ret;  
    }  
 
    return 0;  
}  
 
//loader.cpp  
 
#include "LocalFile.h"  
 
/*把该loader.exe的加载地址设置为0x0f400000,从而可以把0x00400000地址 
 *预留给将要被加载的程序,从而可以避免因地址重定位而带来的性能损耗。 
 */ 
#pragma comment(linker, "/BASE:0x0f400000")  
 
inline int CDECL DebugPrint(const char *fmt,...)  
{  
    int nLength = 0;  
#if defined(_DEBUG)  
    va_list ap;  
    va_start(ap, fmt);  
    nLength = vprintf(fmt, ap);  
    va_end(ap);  
#endif  
    return nLength;  
}  
 
void DumpPeInfo(PeInfo *pInfo)  
{  
    DebugPrint("------------headers info------------/n" /  
               "imageBase:        0x%x. /n" /  
               "entryPoint:       0x%x. /n" /  
               "sections:         0x%x. /n" /  
               "imageSize:        0x%x. /n" /  
               "exportRva:        0x%x. /n" /  
               "exportSize:       0x%x. /n" /  
               "importRva:        0x%x. /n" /  
               "importSize:       0x%x. /n" /  
               "resourceRva:      0x%x. /n" /  
               "resourceSize:     0x%x. /n" /  
               "relocRva:         0x%x. /n" /  
               "relocSize:        0x%x. /n" /  
               "debugRva:         0x%x. /n" /  
               "debugSize:        0x%x. /n" /  
               "offsetSections:   0x%x. /n" /  
               "fileType:         %s. /n",  
                pInfo->imageBase,  
                pInfo->entryPoint,  
                pInfo->sections,  
                pInfo->imageSize,  
                pInfo->exRva,  
                pInfo->exSize,  
                pInfo->imRva,  
                pInfo->imSize,  
                pInfo->resRva,  
                pInfo->resSize,  
                pInfo->relocRva,  
                pInfo->relocSize,  
                pInfo->dbgRva,  
                pInfo->dbgSize,  
                pInfo->offsetSection,  
                pInfo->fileType == 0 ? "exe":"dll");  
}  
 
BOOL IsPEFile(CLocalFile& lf)  
{  
    IMAGE_DOS_HEADER dh;  
    IMAGE_NT_HEADERS nh;  
 
    lf.Read(0, sizeof(IMAGE_DOS_HEADER), &dh);  
    if (IMAGE_DOS_SIGNATURE != dh.e_magic) {  
        return FALSE;  
    }  
 
    lf.Read(dh.e_lfanew, sizeof(IMAGE_NT_HEADERS), &nh);  
    if (IMAGE_NT_SIGNATURE != nh.Signature) {  
        return FALSE;  
    }  
 
    return TRUE;  
}  
 
BOOL ParseNTHeader(CLocalFile &lf, PeInfo &pe)  
{  
    IMAGE_DOS_HEADER dh;  
    IMAGE_NT_HEADERS nh;  
    PIMAGE_FILE_HEADER pfh;  
    PIMAGE_OPTIONAL_HEADER32 poh;  
 
    lf.Read(0, sizeof(IMAGE_DOS_HEADER), &dh);  
    pe.offsetSection = dh.e_lfanew + sizeof(IMAGE_NT_HEADERS);  
    lf.Read(dh.e_lfanew, sizeof(IMAGE_NT_HEADERS), &nh);  
 
    pfh = &nh.FileHeader;  
    poh = &nh.OptionalHeader;  
 
    assert(IMAGE_FILE_MACHINE_I386 == pfh->Machine);  
    assert(pfh->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32));  
 
    pe.sections = pfh->NumberOfSections;  
    pe.imageBase = poh->ImageBase;  
    pe.entryPoint = poh->AddressOfEntryPoint;  
    pe.imageSize = poh->SizeOfImage;  
 
    pe.exRva = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;  
    pe.exSize = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;  
    pe.imRva = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;  
    pe.imSize = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;  
    pe.resRva = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;  
    pe.resSize = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size;  
    pe.relocRva = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;  
    pe.relocSize = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;  
    pe.dbgRva = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;  
    pe.dbgSize = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;  
 
    pe.fileType = pfh->Characteristics == IMAGE_FILE_DLL ? IMAGE_FILE_DLL : 0;  
 
    DumpPeInfo(&pe);  
 
    return TRUE;  
}  
 
BOOL LoadSections(CLocalFile &lf, PeInfo &pe, MODULEINFO &mi)  
{  
    PIMAGE_SECTION_HEADER psh, ptmp;  
    DWORD protect = 0, oldProtect = 0;  
    char name[9] = "/0";  
 
    psh = (PIMAGE_SECTION_HEADER)_alloca(pe.sections * sizeof(IMAGE_SECTION_HEADER));  
    if (NULL == psh) {  
        printf("Memory not enough!/n");  
        return FALSE;  
    }  
    lf.Read(pe.offsetSection, pe.sections * sizeof(IMAGE_SECTION_HEADER), psh);  
    ptmp = psh;  
 
    DebugPrint("/n/n------------sections info------------/n" /  
               "name/tVA/tSOD/tPTR/tPTR/tPTL/tNOR/tNOL/tCrt/n");  
 
    /* 循环从被加载的文件中读取各个section内容,并存放在该section所指定的 
     * VirtualAddress地址空间中。 
     */ 
    for (int i = 0; i < pe.sections; ++i, ptmp++) {  
        memcpy(name, ptmp->Name, 8);  
 
        if (NULL != ptmp->PointerToRawData && 0 != ptmp->SizeOfRawData) {  
            lf.Read(ptmp->PointerToRawData,  
                        ptmp->SizeOfRawData,  
                        (void *)((DWORD)mi.lpBaseOfDll + ptmp->VirtualAddress));  
        }  
 
 
        /* 此处代码主要功能是根据各个区段的Characteristics值, 
         * 来设置其所在内存的页属性,但因在RelocPeModule机制重定位时还需要对相关内存 
         * 进行写入,因此此处的代码应该在RelocPeModule函数调用之后才能执行。 
         */ 
#if 0   
        if (ptmp->Characteristics & IMAGE_SCN_MEM_READ) {  
            protect = PAGE_READONLY;  
        }  
        if (ptmp->Characteristics & IMAGE_SCN_MEM_WRITE) {  
            protect = PAGE_READWRITE;  
        }  
        if (ptmp->Characteristics & IMAGE_SCN_MEM_EXECUTE) {  
            if (protect & PAGE_READONLY) {  
                protect = PAGE_EXECUTE_READ;  
            }  
            else if (protect & PAGE_READWRITE) {  
                protect = PAGE_EXECUTE_READWRITE;  
            }  
            else {  
                protect = PAGE_EXECUTE;  
            }  
        }  
 
        if (!VirtualProtect((LPVOID)(ptmp->VirtualAddress + (DWORD)mi.lpBaseOfDll),  
                            ptmp->SizeOfRawData, protect, &oldProtect)) {  
            printf("Set memory protection failed, error: %d/n", GetLastError());  
            return FALSE;  
        }  
#endif  
        DebugPrint("%-8s" /  
                   "0x%x/t" /  
                   "0x%x/t" /  
                   "0x%x/t" /  
                   "0x%x/t" /  
                   "0x%x/t" /  
                   "0x%x/t" /  
                   "0x%x/t" /  
                   "0x%x/n",  
                   name,  
                   ptmp->VirtualAddress,  
                   ptmp->SizeOfRawData,  
                   ptmp->PointerToRawData,  
                   ptmp->PointerToRelocations,  
                   ptmp->PointerToLinenumbers,  
                   ptmp->NumberOfRelocations,  
                   ptmp->NumberOfLinenumbers,  
                   ptmp->Characteristics);  
    }  
 
    return TRUE;  
}  
 
BOOL FixupResource(PIMAGE_RESOURCE_DIRECTORY pRes, DWORD imagebase, int offsetRlc)  
{  
    PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry;  
    DWORD nEntries;  
 
    nEntries = pRes->NumberOfIdEntries + pRes->NumberOfNamedEntries;  
 
    pEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pRes + sizeof(IMAGE_RESOURCE_DIRECTORY));  
 
    for (DWORD i = 0; i < nEntries; ++i, ++pEntry) {  
 
        if (IMAGE_RESOURCE_DATA_IS_DIRECTORY & pEntry->OffsetToData) {  
            PIMAGE_RESOURCE_DIRECTORY pRes2;  
            PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry2;  
            DWORD nEntries2;  
 
            pRes2 = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pRes  
                        + (~IMAGE_RESOURCE_DATA_IS_DIRECTORY & pEntry->OffsetToData));  
            nEntries2 = pRes2->NumberOfIdEntries + pRes2->NumberOfNamedEntries;  
            pEntry2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pRes2 + sizeof(IMAGE_RESOURCE_DIRECTORY));  
              
            for (DWORD j = 0; j < nEntries2; ++j, ++pEntry2) {  
                if (IMAGE_RESOURCE_NAME_IS_STRING & pEntry2->Name) {  
                    PIMAGE_RESOURCE_DIR_STRING_U pDirStr;  
                    pDirStr = (PIMAGE_RESOURCE_DIR_STRING_U)((DWORD)pRes  
                                + (~IMAGE_RESOURCE_NAME_IS_STRING & pEntry2->Name));  
                }  
                if (IMAGE_RESOURCE_DATA_IS_DIRECTORY & pEntry2->OffsetToData) {  
                    PIMAGE_RESOURCE_DIRECTORY pRes3;  
                    PIMAGE_RESOURCE_DIRECTORY_ENTRY pEntry3;  
                    DWORD nEntries3;  
 
                    pRes3 = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)pRes  
                                + (~IMAGE_RESOURCE_DATA_IS_DIRECTORY & pEntry2->OffsetToData));  
                    nEntries3 = pRes3->NumberOfIdEntries + pRes3->NumberOfNamedEntries;  
                    pEntry3 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)pRes3 + sizeof(IMAGE_RESOURCE_DIRECTORY));  
 
                    for (DWORD k = 0; k < nEntries3; ++k) {  
                        PIMAGE_RESOURCE_DATA_ENTRY pData;  
 
                        assert(~IMAGE_RESOURCE_DATA_IS_DIRECTORY & pEntry3->OffsetToData);  
 
                        pData = (PIMAGE_RESOURCE_DATA_ENTRY)((DWORD)pRes + pEntry3->OffsetToData);  
                        pData->OffsetToData += (DWORD)imagebase;  
                    }  
                }  
            }  
 
        }  
    }  
 
    return TRUE;  
}  
 
BOOL RelocPeModule(PIMAGE_BASE_RELOCATION pBlc, DWORD imagebase, int offsetRlc)  
{  
    DWORD vaddr, count, offset, type;  
    WORD *items = NULL;  
 
    while (NULL != pBlc->VirtualAddress) {  
        vaddr = imagebase + pBlc->VirtualAddress;  
 
        count = (pBlc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1;  
        items = (WORD *)((char *)pBlc + sizeof(IMAGE_BASE_RELOCATION));  
 
        for (DWORD i = 0; i < count; ++i) {  
            offset = items[i] & 0x0fff;  
            type = items[i] >> 12;  
 
            if (type == 3) {  
                *(DWORD *)(vaddr + offset) += offsetRlc;  
            }  
        }  
        pBlc = (PIMAGE_BASE_RELOCATION)(items + count);  
    }  
 
    return TRUE;  
}  
 
BOOL FixupExport(PIMAGE_EXPORT_DIRECTORY pExp, DWORD imagebase)  
{  
    return TRUE;  
}  
 
BOOL FixupImport(PIMAGE_IMPORT_DESCRIPTOR pImp, DWORD imagebase)  
{  
    PIMAGE_THUNK_DATA pOrgThunk, pFirstThunk;  
    PIMAGE_IMPORT_BY_NAME pImportName;  
 
    DebugPrint("/n/n------------import table info------------/n");  
 
    while (NULL != pImp->OriginalFirstThunk) {  
        pImp->Name += imagebase;  
 
        DebugPrint("DLL: %s/n", pImp->Name);  
 
        FARPROC fpFun;  
        HINSTANCE hInstance = LoadLibraryA((LPCSTR)pImp->Name);  
        if (NULL == hInstance) {  
            printf("Load library %s failed, error: %d/n", pImp->Name, GetLastError());  
            return FALSE;  
        }  
 
        pOrgThunk = (PIMAGE_THUNK_DATA)(imagebase + pImp->OriginalFirstThunk);  
        pFirstThunk = (PIMAGE_THUNK_DATA)(imagebase + pImp->FirstThunk);  
 
        while (NULL != *(DWORD *)pOrgThunk) {  
            if (pOrgThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32) {  
                fpFun = GetProcAddress(hInstance, (LPCSTR)(pOrgThunk->u1.Ordinal & 0x0000ffff));  
 
                //DebugPrint("/t0x%x/n", pOrgThunk->u1.Ordinal);  
            }  
            else {  
                pImportName = (PIMAGE_IMPORT_BY_NAME)(imagebase + pOrgThunk->u1.AddressOfData);  
                fpFun = GetProcAddress(hInstance, (LPCSTR)pImportName->Name);  
 
                //DebugPrint("/t%s/n", pImportName->Name);  
            }  
 
            //DebugPrint("/t/t0x%x/n", fpFun);  
 
            pFirstThunk->u1.Ordinal = (LONG)fpFun;  
              
            ++pFirstThunk;  
            ++pOrgThunk;  
        }  
        FreeLibrary(hInstance);  
 
        ++pImp;  
    }  
 
    return TRUE;  
}  
 
int LoadPeModule(const char * name, int argc, _TCHAR* argv[])  
{  
    CLocalFile lf(name);  
    LPVOID addr;  
    PeInfo pe;  
    MODULEINFO mi;  
 
    /* 验证是否为合法的pe文件 */ 
    assert(IsPEFile(lf));  
 
    /* 处理nt header,获取pe文件的相关信息 */ 
    ParseNTHeader(lf, pe);  
 
    /*为image按照imageBase优先原则分配空间地址。 
     *如该空间地址已被reserved或commit,则重新分配一个可用的空间地址, 
     *但此种情况下需要做基址重定位处理。*/ 
    addr = VirtualAlloc((LPVOID)(pe.imageBase),  
                                pe.imageSize,  
                                MEM_RESERVE | MEM_COMMIT,  
                                PAGE_EXECUTE_READWRITE);  
    if (NULL == addr) {  
        printf("VirtualAlloc failed, error: %d/n", GetLastError());  
        addr = VirtualAlloc(NULL, pe.imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);  
        if (NULL == addr) {  
            printf("VirtualAlloc failed, error: %d/n", GetLastError());  
            return -1;  
        }  
    }  
    memset((void *)addr, 0, pe.imageSize);  
 
    mi.EntryPoint = (LPVOID)pe.entryPoint;  
    mi.lpBaseOfDll = (LPVOID)addr;  
    mi.SizeOfImage = pe.imageSize;  
 
    /* 把sections加载到内存 */ 
    LoadSections(lf, pe, mi);  
 
    /* 如果实际分配的空间地址和pe文件的基址不一样,则需要做基址重定位处理 */ 
    if ((int)mi.lpBaseOfDll != pe.imageBase) {  
        if (0 == pe.relocSize) {  
            printf("Cannot reloc address!/n");  
            return -1;  
        }  
        PIMAGE_BASE_RELOCATION pBrlc = (PIMAGE_BASE_RELOCATION)((DWORD)mi.lpBaseOfDll + pe.relocRva);  
        RelocPeModule(pBrlc, (DWORD)mi.lpBaseOfDll, (DWORD)mi.lpBaseOfDll - pe.imageBase);  
    }  
 
    /* 如果该pe文件有导出表,则处理导出表区段 */ 
    if (0 != pe.exSize) {  
        PIMAGE_EXPORT_DIRECTORY pExp = (PIMAGE_EXPORT_DIRECTORY)((DWORD)mi.lpBaseOfDll + pe.exRva);  
        FixupExport(pExp, (DWORD)mi.lpBaseOfDll);  
    }  
 
    /* 如果pe文件有资源文件,则需要处理资源区段 */ 
    if (0 != pe.resSize) {  
        PIMAGE_RESOURCE_DIRECTORY pRes = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)mi.lpBaseOfDll + pe.resRva);  
        FixupResource(pRes, (DWORD)mi.lpBaseOfDll, (DWORD)mi.lpBaseOfDll - pe.imageBase);  
    }  
 
    /* 如果pe文件有导入表,则需要处理导入表区段 */ 
    if (0 != pe.imSize) {  
        PIMAGE_IMPORT_DESCRIPTOR pImp = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)mi.lpBaseOfDll + pe.imRva);  
        FixupImport(pImp, (DWORD)mi.lpBaseOfDll);  
    }  
 
    DebugPrint("/n/nentry: 0x%x/n/n", (DWORD)mi.EntryPoint + (DWORD)mi.lpBaseOfDll);  
 
    /* 进入该pe文件的entry pointer,执行该pe文件 */ 
    __asm {  
        push argc;  
        push argv;  
        mov eax, mi.EntryPoint;  
        add eax, mi.lpBaseOfDll;  
        call eax;  
    }  
}  
 
int _tmain(int argc, _TCHAR* argv[])  
{  
    //LoadPeModule("HelloWorld.exe", argc - 1, argv + 1);  
    LoadPeModule("btnlook.exe", argc - 1, argv + 1);  
 
    return 0;  

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lf8289/archive/2010/02/09/5301269.aspx

相关文章推荐

Win7 内核重载 1 ——内核版PELoader

重载重点,其实就是自己实现一个山寨版的Windows PELoader  ,重载其实就是将一个模块自己重新加载一份到别的内存,运行它。 所谓内核重载,则是将内核文件即:ntkrnlpa.exe ...
  • zfdyq0
  • zfdyq0
  • 2014-12-19 20:50
  • 3023

PE Loader

/* *LocalFile是对读文件操作的一个简单封装 */ //LocalFile.h #pragma once class CLocalFile { public: CLocalFile(...

仿照windows的loader实现的pe-loader

本人接触pe文件格式不久,参考网上的一些资料写了一个pe loader,主要是通过把需要加载的文件的所所有section加载到相应的RVA上,然后进行重定位处理、导入表和导出表处理、资源段处理。由于本...
  • lf8289
  • lf8289
  • 2010-02-09 09:25
  • 3500

windows下的pe loader源代码

  • 2010-02-09 09:58
  • 386KB
  • 下载

PE文件加节感染之Win32.Loader.bx.V病毒分析

一、病毒名称:Win32.Loader.bx.V 二、分析工具:IDA 5.5、OllyDebug、StudPE 三、PE病毒简介: PE病毒感染的方式比较多,也比较复杂也比较难分析,下面就针对PE文...

Windows.7.Loader.zip

  • 2012-07-24 10:04
  • 1.39MB
  • 下载

zend-loader-php5.5-windows-x86

  • 2016-08-25 15:37
  • 150KB
  • 下载

Microsoft Windows CE 5.0 Board Support Package, Boot Loader, and Kernel Startup Sequence

Microsoft Windows CE 5.0 Board Support Package, Boot Loader, and Kernel Startup SequenceWindows CE 5...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)