peloader.c

来自「适合KS8695X」· C语言 代码 · 共 587 行 · 第 1/2 页

C
587
字号
/****************************************************************************
*
*                       SciTech MGL Graphics Library
*
*  ========================================================================
*
*    The contents of this file are subject to the SciTech MGL Public
*    License Version 1.0 (the "License"); you may not use this file
*    except in compliance with the License. You may obtain a copy of
*    the License at http://www.scitechsoft.com/mgl-license.txt
*
*    Software distributed under the License is distributed on an
*    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
*    implied. See the License for the specific language governing
*    rights and limitations under the License.
*
*    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
*
*    The Initial Developer of the Original Code is SciTech Software, Inc.
*    All Rights Reserved.
*
*  ========================================================================
*
* Language:     ANSI C
* Environment:  Any
*
* Description:  Module to implement a simple Portable Binary DLL loader
*               library. This library can be used to load PE DLL's under
*               any Intel based OS, provided the DLL's do not have any
*               imports in the import table.
*
*               NOTE: This loader module expects the DLL's to be built with
*                     Watcom C++ and may produce unexpected results with
*                     DLL's linked by another compiler.
*
****************************************************************************/

#include "drvlib/peloader.h"
#include "pmapi.h"
#include "drvlib/os/os.h"
#include "drvlib/libc/init.h"
#if (defined(__WINDOWS32__) || defined(__DRIVER__)) && defined(CHECKED)
#define WIN32_LEAN_AND_MEAN
#define STRICT
#include <windows.h>
#endif
#include "drvlib/pe.h"

/*--------------------------- Global variables ----------------------------*/

static int          result = PE_ok;

/*------------------------- Implementation --------------------------------*/

/****************************************************************************
PARAMETERS:
f           - Handle to open file to read driver from
startOffset - Offset to the start of the driver within the file

RETURNS:
Handle to loaded PE DLL, or NULL on failure.

REMARKS:
This function loads a Portable Binary DLL library from disk, relocates
the code and returns a handle to the loaded library. This function is the
same as the regular PE_loadLibrary except that it take a handle to an
open file and an offset within that file for the DLL to load.
****************************************************************************/
static int PE_readHeader(
    FILE *f,
    long startOffset,
    FILE_HDR *filehdr,
    OPTIONAL_HDR *opthdr)
{
    EXE_HDR exehdr;
    ulong   offset,signature;

    /* Read the EXE header and check for valid header signature */
    result = PE_invalidDLLImage;
    fseek(f, startOffset, SEEK_SET);
    if (fread(&exehdr, 1, sizeof(exehdr), f) != sizeof(exehdr))
	return false;
    if (exehdr.signature != 0x5A4D)
	return false;

    /* Now seek to the start of the PE header defined at offset 0x3C
     * in the MS-DOS EXE header, and read the signature and check it.
     */
    fseek(f, startOffset+0x3C, SEEK_SET);
    if (fread(&offset, 1, sizeof(offset), f) != sizeof(offset))
	return false;
    fseek(f, startOffset+offset, SEEK_SET);
    if (fread(&signature, 1, sizeof(signature), f) != sizeof(signature))
	return false;
    if (signature != 0x00004550)
	return false;

    /* Now read the PE file header and check that it is correct */
    if (fread(filehdr, 1, sizeof(*filehdr), f) != sizeof(*filehdr))
	return false;
    if (filehdr->Machine != IMAGE_FILE_MACHINE_I386)
	return false;
    if (!(filehdr->Characteristics & IMAGE_FILE_32BIT_MACHINE))
	return false;
    if (!(filehdr->Characteristics & IMAGE_FILE_DLL))
	return false;
    if (fread(opthdr, 1, sizeof(*opthdr), f) != sizeof(*opthdr))
	return false;
    if (opthdr->Magic != 0x10B)
	return false;

    /* Success, so return true! */
    return true;
}

/****************************************************************************
PARAMETERS:
f           - Handle to open file to read driver from
startOffset - Offset to the start of the driver within the file

RETURNS:
Size of the DLL file on disk, or -1 on error

REMARKS:
This function scans the headers for a Portable Binary DLL to determine the
length of the DLL file on disk.
{secret}
****************************************************************************/
ulong PEAPI PE_getFileSize(
    FILE *f,
    ulong startOffset)
{
    FILE_HDR        filehdr;
    OPTIONAL_HDR    opthdr;
    SECTION_HDR     secthdr;
    ulong           size;
    int             i;

    /* Read the PE file headers from disk */
    if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
	return 0xFFFFFFFF;

    /* Scan all the section headers summing up the total size */
    size = opthdr.SizeOfHeaders;
    for (i = 0; i < filehdr.NumberOfSections; i++) {
	if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
	    return 0xFFFFFFFF;
	size += secthdr.SizeOfRawData;
	}
    return size;
}

/****************************************************************************
DESCRIPTION:
Loads a Portable Binary DLL into memory from an open file

HEADER:
peloader.h

PARAMETERS:
f           - Handle to open file to read driver from
startOffset - Offset to the start of the driver within the file
size        - Place to store the size of the driver loaded
shared      - True to load module into shared memory

RETURNS:
Handle to loaded PE DLL, or NULL on failure.

REMARKS:
This function loads a Portable Binary DLL library from disk, relocates
the code and returns a handle to the loaded library. This function is the
same as the regular PE_loadLibrary except that it take a handle to an
open file and an offset within that file for the DLL to load.

SEE ALSO:
PE_loadLibrary, PE_getProcAddress, PE_freeLibrary
****************************************************************************/
PE_MODULE * PEAPI PE_loadLibraryExt(
    FILE *f,
    ulong startOffset,
    ulong *size,
    ibool shared)
{
    FILE_HDR        filehdr;
    OPTIONAL_HDR    opthdr;
    SECTION_HDR     secthdr;
    ulong           offset,pageOffset;
    ulong           text_off,text_addr,text_size;
    ulong           data_off,data_addr,data_size,data_end;
    ulong           export_off,export_addr,export_size,export_end;
    ulong           reloc_off,reloc_size;
    ulong           image_size;
    int             i,delta,numFixups;
    ushort          relocType,*fixup;
    PE_MODULE       *hMod = NULL;
    void            *reloc = NULL;
    BASE_RELOCATION *baseReloc;
    InitLibC_t      InitLibC;

    /* Read the PE file headers from disk */
    if (!PE_readHeader(f,startOffset,&filehdr,&opthdr))
	return NULL;

    /* Scan all the section headers and find the necessary sections */
    text_off = data_off = reloc_off = export_off = 0;
    text_addr = text_size = 0;
    data_addr = data_size = data_end = 0;
    export_addr = export_size = export_end = 0;
    reloc_size = 0;
    for (i = 0; i < filehdr.NumberOfSections; i++) {
	if (fread(&secthdr, 1, sizeof(secthdr), f) != sizeof(secthdr))
	    goto Error;
	if (strcmp(secthdr.Name, ".edata") == 0 || strcmp(secthdr.Name, ".rdata") == 0) {
	    /* Exports section */
	    export_off = secthdr.PointerToRawData;
	    export_addr = secthdr.VirtualAddress;
	    export_size = secthdr.SizeOfRawData;
	    export_end = export_addr + export_size;
	    }
	else if (strcmp(secthdr.Name, ".idata") == 0) {
	    /* Imports section, ignore */
	    }
	else if (strcmp(secthdr.Name, ".reloc") == 0) {
	    /* Relocations section */
	    reloc_off = secthdr.PointerToRawData;
	    reloc_size = secthdr.SizeOfRawData;
	    }
	else if (!text_off && secthdr.Characteristics & IMAGE_SCN_CNT_CODE) {
	    /* Code section */
	    text_off = secthdr.PointerToRawData;
	    text_addr = secthdr.VirtualAddress;
	    text_size = secthdr.SizeOfRawData;
	    }
	else if (!data_off && secthdr.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
	    /* Data section */
	    data_off = secthdr.PointerToRawData;
	    data_addr = secthdr.VirtualAddress;
	    data_size = secthdr.SizeOfRawData;
	    data_end = data_addr + data_size;
	    }
	}

    /* Check to make sure that we have all the sections we need */
    if (!text_off || !data_off || !export_off || !reloc_off) {
	result = PE_invalidDLLImage;
	goto Error;
	}

    /* Find the size of the image to load allocate memory for it */
    image_size = MAX(export_end,data_end) - text_addr;
    *size = sizeof(PE_MODULE) + image_size + 4096;
    if (shared)
	hMod = PM_mallocShared(*size);
    else
	hMod = PM_malloc(*size);
    reloc = PM_malloc(reloc_size);
    if (!hMod || !reloc) {
	result = PE_outOfMemory;
	goto Error;
	}

    hMod->text = (uchar*)ROUND_4K((ulong)hMod + sizeof(PE_MODULE));
    hMod->data = (uchar*)((ulong)hMod->text + (data_addr - text_addr));
    hMod->export = (uchar*)((ulong)hMod->text + (export_addr - text_addr));
    hMod->textBase = text_addr;
    hMod->dataBase = data_addr;
    hMod->exportBase = export_addr;
    hMod->exportDir = opthdr.DataDirectory[0].RelVirtualAddress - export_addr;
    hMod->shared = shared;

    /* Now read the section images from disk */
    result = PE_invalidDLLImage;
    fseek(f, startOffset+text_off, SEEK_SET);
    if (fread(hMod->text, 1, text_size, f) != text_size)
	goto Error;
    fseek(f, startOffset+data_off, SEEK_SET);
    if (fread(hMod->data, 1, data_size, f) != data_size)
	goto Error;
    fseek(f, startOffset+export_off, SEEK_SET);
    if (fread(hMod->export, 1, export_size, f) != export_size)
	goto Error;
    fseek(f, startOffset+reloc_off, SEEK_SET);
    if (fread(reloc, 1, reloc_size, f) != reloc_size)
	goto Error;

    /* Now perform relocations on all sections in the image */
    delta = (ulong)hMod->text - opthdr.ImageBase - text_addr;
    baseReloc = (BASE_RELOCATION*)reloc;
    for (;;) {
	/* Check for termination condition */
	if (!baseReloc->PageRVA || !baseReloc->BlockSize)
	    break;

	/* Do fixups */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?