Ignore:
Timestamp:
Nov 10, 2006, 4:04:42 AM (19 years ago)
Author:
bird
Message:

Put the PE module interpreter thru the wringer and learnt how much the window file mapping API sucks.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kLdr/kLdrRdrFile.c

    r2860 r2861  
    3535
    3636#elif defined(__WIN32__) || defined(__WIN64__) || defined(__WIN__)
     37# define WIN32_NO_STATUS
    3738# include <Windows.h>
    3839# ifndef __WIN__
    3940#  define __WIN__
    4041# endif
     42# include <ntsecapi.h>
     43# include <ntstatus.h>
     44
     45  /// @todo find a non-conflicting header with NTSTATUS, NTAPI, ++
     46  typedef LONG NTSTATUS;
     47  #define NT_SUCCESS(x) ((x)>=0)
     48
     49  typedef struct _OBJECT_ATTRIBUTES
     50  {
     51      ULONG   Length;
     52      HANDLE  RootDirectory;
     53      PUNICODE_STRING ObjectName;
     54      ULONG   Attributes;
     55      PVOID   SecurityDescriptor;
     56      PVOID   SecurityQualityOfService;
     57  } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
     58
     59  typedef enum _SECTION_INHERIT
     60  {
     61      ViewShare = 1,
     62      ViewUnmap = 2
     63  } SECTION_INHERIT;
     64
     65# define NTOSAPI __declspec(dllimport)
     66# define NtCurrentProcess() GetCurrentProcess()
     67
     68# ifndef MEM_DOS_LIM
     69#  define MEM_DOS_LIM 0x40000000UL
     70# endif
     71
     72  NTOSAPI
     73  NTSTATUS
     74  NTAPI
     75  NtCreateSection(
     76      OUT PHANDLE SectionHandle,
     77      IN ACCESS_MASK DesiredAccess,
     78      IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
     79      IN PLARGE_INTEGER SectionSize OPTIONAL,
     80      IN ULONG Protect,
     81      IN ULONG Attributes,
     82      IN HANDLE FileHandle OPTIONAL
     83  );
     84
     85  NTOSAPI
     86  NTSTATUS
     87  NTAPI
     88  NtMapViewOfSection(
     89      IN HANDLE SectionHandle,
     90      IN HANDLE ProcessHandle,
     91      IN OUT PVOID *BaseAddress,
     92      IN ULONG ZeroBits,
     93      IN ULONG CommitSize,
     94      IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
     95      IN OUT PSIZE_T ViewSize,
     96      IN SECTION_INHERIT InheritDisposition,
     97      IN ULONG AllocationType,
     98      IN ULONG Protect
     99  );
     100
     101  NTOSAPI
     102  NTSTATUS
     103  NTAPI
     104  NtUnmapViewOfSection(
     105      IN HANDLE ProcessHandle,
     106      IN PVOID BaseAddress
     107  );
     108
     109  NTOSAPI
     110  NTSTATUS
     111  NTAPI
     112  NtClose(
     113      IN HANDLE Handle
     114  );
     115
     116  NTOSAPI
     117  NTSTATUS
     118  NTAPI
     119  ZwProtectVirtualMemory(
     120      IN HANDLE ProcessHandle,
     121      IN OUT PVOID *BaseAddress,
     122      IN OUT PULONG ProtectSize,
     123      IN ULONG NewProtect,
     124      OUT PULONG OldProtect
     125  );
     126# define NtProtectVirtualMemory ZwProtectVirtualMemory
     127
     128  NTOSAPI
     129  NTSTATUS
     130  NTAPI
     131  NtAllocateVirtualMemory(
     132      IN HANDLE ProcessHandle,
     133      IN OUT PVOID *BaseAddress,
     134      IN ULONG ZeroBits,
     135      IN OUT PULONG AllocationSize,
     136      IN ULONG AllocationType,
     137      IN ULONG Protect
     138  );
     139
     140  NTOSAPI
     141  NTSTATUS
     142  NTAPI
     143  NtFreeVirtualMemory(
     144      IN HANDLE ProcessHandle,
     145      IN OUT PVOID *BaseAddress,
     146      IN OUT PULONG FreeSize,
     147      IN ULONG FreeType
     148  );
    41149
    42150#else
     
    46154#include <kLdr.h>
    47155#include "kLdrHlp.h"
     156
     157
     158/*******************************************************************************
     159*   Defined Constants And Macros                                               *
     160*******************************************************************************/
     161/** @def KLDRRDRFILE_STRICT
     162 * Define KLDRRDRFILE_STRICT to enabled strict checks in KLDRRDRFILE. */
     163#define KLDRRDRFILE_STRICT 1
     164
     165/** @def KLDRRDRFILE_ASSERT
     166 * Assert that an expression is true when KLDRRDRFILE_STRICT is defined.
     167 */
     168#ifdef KLDRRDRFILE_STRICT
     169# define KLDRRDRFILE_ASSERT(expr)  kldrHlpAssert(expr)
     170#else
     171# define KLDRRDRFILE_ASSERT(expr)  do {} while (0)
     172#endif
    48173
    49174
     
    102227*******************************************************************************/
    103228static void     kldrRdrFileDone(PKLDRRDR pRdr);
    104 static int      kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb);
    105 static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb);
    106 static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt);
    107 static int      kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
    108 static int      kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
    109 static int      kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed);
     229static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
     230static int      kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments);
     231static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
     232static int      kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
     233static int      kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
     234static int      kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments);
     235static int      kldrRdrFileMap(PKLDRRDR pRdr, void *ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
     236static int      kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
    110237static size_t   kldrRdrFilePageSize(PKLDRRDR pRdr);
    111238static const char *kldrRdrFileName(PKLDRRDR pRdr);
     
    136263    kldrRdrFileName,
    137264    kldrRdrFilePageSize,
    138     kldrRdrFilePrepare,
    139265    kldrRdrFileMap,
    140     kldrRdrFileRefreshMap,
     266    kldrRdrFileRefresh,
    141267    kldrRdrFileProtect,
    142268    kldrRdrFileUnmap,
    143     kldrRdrFileUnprepare,
    144269    kldrRdrFileDone,
    145270    42
    146271};
     272
     273
     274#if defined(__WIN__) || defined(__NT__)
     275/**
     276 * Converts a kLdr segment protection to NT protection for a mapping.
     277 *
     278 * @returns Nt page protection.
     279 * @param   enmProt     kLdr protection.
     280 */
     281static ULONG kldrRdrFileGetNtMapProt(KLDRPROT enmProt)
     282{
     283    switch (enmProt)
     284    {
     285        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
     286        case KLDRPROT_READONLY:             return PAGE_READONLY;
     287        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
     288        case KLDRPROT_WRITECOPY:            return PAGE_WRITECOPY;
     289        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
     290        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
     291        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
     292        case KLDRPROT_EXECUTE_WRITECOPY:    return PAGE_EXECUTE_WRITECOPY;
     293        default:                            return ~(ULONG)0;
     294    }
     295}
     296
     297
     298/**
     299 * Converts a kLdr segment protection to NT protection for a allocation.
     300 *
     301 * @returns Nt page protection.
     302 * @param   enmProt     kLdr protection.
     303 */
     304static ULONG kldrRdrFileGetNtAllocProt(KLDRPROT enmProt)
     305{
     306    switch (enmProt)
     307    {
     308        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
     309        case KLDRPROT_READONLY:             return PAGE_READONLY;
     310        case KLDRPROT_WRITECOPY:
     311        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
     312        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
     313        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
     314        case KLDRPROT_EXECUTE_WRITECOPY:
     315        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
     316        default:                            return ~(ULONG)0;
     317    }
     318}
     319#endif
    147320
    148321
     
    159332 * @param   pFile   The instance data.
    160333 * @param   pv      The base of the region.
    161  * @param   cb      The size of the region.
    162334 */
    163 static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv, size_t cb)
     335static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv)
    164336{
    165337    int32_t i = pFile->cPreps;
    166338    while (i-- > 0)
    167         if (    pFile->aPreps[i].pv == pv
    168             ||  pFile->aPreps[i].cb == cb)
     339        if (pFile->aPreps[i].pv == pv)
    169340            return &pFile->aPreps[i];
    170341    return NULL;
     
    172343
    173344
    174 /**
    175  * Finds a prepared mapping region containing the specified region.
    176  *
    177  * @returns Pointer to the aPrep entry.
    178  * @param   pFile   The instance data.
    179  * @param   pv      The base of the sub region.
    180  * @param   cb      The size of the sub region.
    181  */
    182 static PKLDRRDRFILEPREP kldrRdrFileFindPrepWithin(PKLDRRDRFILE pFile, void *pv, size_t cb)
    183 {
    184     int32_t i = pFile->cPreps;
    185     while (i-- > 0)
    186         if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv < pFile->aPreps[i].cb)
    187         {
    188             if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv + cb <= pFile->aPreps[i].cb)
    189                 return &pFile->aPreps[i];
    190             return NULL;
    191         }
    192     return NULL;
    193 }
    194 
    195 
    196 /** @copydoc KLDRRDR::pfnUnprepare */
    197 static int      kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb)
     345/** @copydoc KLDRRDR::pfnUnmap */
     346static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
    198347{
    199348    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    200     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
     349    PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
     350    int                 rc;
    201351    if (!pPrep)
    202352        return KLDR_ERR_INVALID_PARAMETER;
    203353
    204     return -1;
    205 }
    206 
    207 
    208 /** @copydoc KLDRRDR::pfnUnmap */
    209 static int      kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb)
     354#if defined(__WIN__) || defined(__NT__)
     355    if (pPrep->hSection != NULL)
     356    {
     357        /** @todo implement me. */
     358        return -1;
     359    }
     360#endif
     361
     362    rc = kldrRdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
     363
     364    /* remove the mapping data on success. */
     365    if (!rc)
     366    {
     367        pRdrFile->cPreps--;
     368        if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
     369            *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
     370    }
     371    return rc;
     372}
     373
     374
     375/** Generic implementation of kldrRdrFileUnmap. */
     376static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments)
     377{
     378    kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
     379    return kldrHlpPageFree(pPrep->pv, pPrep->cb);
     380}
     381
     382
     383/** @copydoc KLDRRDR::pfnProtect */
     384static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
    210385{
    211386    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    212     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
     387    PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
    213388    if (!pPrep)
    214389        return KLDR_ERR_INVALID_PARAMETER;
    215390
    216     return -1;
    217 }
    218 
    219 
    220 /** @copydoc KLDRRDR::pfnProtect */
    221 static int      kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt)
     391#if defined(__WIN__) || defined(__NT__)
     392    if (pPrep->hSection != NULL)
     393    {
     394        /** @todo implement me. */
     395        return -1;
     396    }
     397#endif
     398
     399    return kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
     400}
     401
     402
     403/** Generic implementation of kldrRdrFileProtect. */
     404static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
     405{
     406    uint32_t i;
     407
     408    /*
     409     * Iterate the segments and apply memory protection changes.
     410     */
     411    for (i = 0; i < cSegments; i++)
     412    {
     413        int rc;
     414        void *pv;
     415        KLDRPROT enmProt;
     416
     417        if (paSegments[i].RVA == NIL_KLDRADDR)
     418            continue;
     419
     420        /* calc new protection. */
     421        enmProt = paSegments[i].enmProt;
     422        if (fUnprotectOrProtect)
     423        {
     424            switch (enmProt)
     425            {
     426                case KLDRPROT_NOACCESS:
     427                case KLDRPROT_READONLY:
     428                case KLDRPROT_READWRITE:
     429                case KLDRPROT_WRITECOPY:
     430                    enmProt = KLDRPROT_READWRITE;
     431                    break;
     432                case KLDRPROT_EXECUTE:
     433                case KLDRPROT_EXECUTE_READ:
     434                case KLDRPROT_EXECUTE_READWRITE:
     435                case KLDRPROT_EXECUTE_WRITECOPY:
     436                    enmProt = KLDRPROT_EXECUTE_READWRITE;
     437                    break;
     438                default:
     439                    KLDRRDRFILE_ASSERT(!"bad enmProt");
     440                    return -1;
     441            }
     442        }
     443        else
     444        {
     445            /* copy on write -> normal write. */
     446            if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
     447                enmProt = KLDRPROT_EXECUTE_READWRITE;
     448            else if (enmProt == KLDRPROT_WRITECOPY)
     449                enmProt = KLDRPROT_READWRITE;
     450        }
     451
     452        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     453
     454        rc = kldrHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
     455        if (rc)
     456            break;
     457    }
     458
     459    return 0;
     460}
     461
     462
     463/** @copydoc KLDRRDR::pfnRefresh */
     464static int      kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
    222465{
    223466    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    224     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
     467    PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
    225468    if (!pPrep)
    226469        return KLDR_ERR_INVALID_PARAMETER;
    227470
    228     return -1;
    229 }
    230 
    231 
    232 /** @copydoc KLDRRDR::pfnRefreshMap */
    233 static int      kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
     471#if defined(__WIN__) || defined(__NT__)
     472    if (pPrep->hSection != NULL)
     473    {
     474        /** @todo implement me. */
     475        return -1;
     476    }
     477#endif
     478
     479    return kldrRdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
     480}
     481
     482
     483/** Generic implementation of kldrRdrFileRefresh. */
     484static int      kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments)
     485{
     486    int rc;
     487    int rc2;
     488    uint32_t i;
     489
     490    /*
     491     * Make everything writable again.
     492     */
     493    rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
     494    if (rc)
     495    {
     496        kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
     497        return rc;
     498    }
     499
     500    /*
     501     * Clear everything.
     502     */
     503    /** @todo only zero the areas not covered by raw file bits. */
     504    kLdrHlpMemSet(pPrep->pv, 0, pPrep->cb);
     505
     506    /*
     507     * Reload all the segments.
     508     * We could possibly skip some segments, but we currently have
     509     * no generic way of figuring out which at the moment.
     510     */
     511    for (i = 0; i < cSegments; i++)
     512    {
     513        void *pv;
     514
     515        if (    paSegments[i].RVA == NIL_KLDRADDR
     516            ||  !paSegments[i].cbFile)
     517            continue;
     518
     519        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     520        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
     521        if (rc)
     522            break;
     523    }
     524
     525    /*
     526     * Protect the bits again.
     527     */
     528    rc2 = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
     529    if (rc2 && rc)
     530        rc = rc2;
     531
     532    return rc;
     533}
     534
     535
     536/** @copydoc KLDRRDR::pfnMap */
     537static int      kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
    234538{
    235539    PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    236     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
    237     if (!pPrep)
    238         return KLDR_ERR_INVALID_PARAMETER;
    239 
    240     return -1;
    241 }
    242 
    243 
    244 /** @copydoc KLDRRDR::pfnMap */
    245 static int      kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
    246 {
    247     PKLDRRDRFILE        pRdrFile = (PKLDRRDRFILE)pRdr;
    248     PKLDRRDRFILEPREP    pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
    249     if (!pPrep)
    250         return KLDR_ERR_INVALID_PARAMETER;
    251 
    252     return -1;
    253 }
    254 
    255 
    256 /** @copydoc KLDRRDR:pfnPrepare */
    257 static int      kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed)
    258 {
    259 #ifdef __OS2__
    260 
    261 
    262 #elif defined(__WIN__)
    263 
    264 #else
    265 # error "port me."
    266 #endif
    267     return -1;
     540    PKLDRRDRFILEPREP    pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
     541    KLDRSIZE            cbTotal;
     542    const size_t        cbPage = pRdr->pOps->pfnPageSize(pRdr);
     543    int                 rc;
     544    uint32_t            i;
     545
     546    if (pRdrFile->cPreps >= KLDR_ELEMENTS(pRdrFile->aPreps))
     547        return KLDR_ERR_TOO_MANY_MAPPINGS;
     548
     549    /*
     550     * Calc the total mapping space needed.
     551     */
     552    cbTotal = 0;
     553    for (i = 0; i < cSegments; i++)
     554    {
     555        KLDRSIZE uRVASegmentEnd;
     556        if (paSegments[i].RVA == NIL_KLDRADDR)
     557            continue;
     558        uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
     559        if (cbTotal < uRVASegmentEnd)
     560            cbTotal = uRVASegmentEnd;
     561    }
     562    pPrep->cb = (size_t)cbTotal;
     563    if (pPrep->cb != cbTotal)
     564        return KLDR_ERR_ADDRESS_OVERFLOW;
     565    pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
     566
     567#if defined(__WIN__) || defined(__NT__)
     568    /*
     569     * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
     570     * trying to map a PE image and the kernel can parse the file for it self, the
     571     * API just isn't up to scratch.
     572     *
     573     * Problems:
     574     *      1. Reserving memory for the views is risky because you can't reserve and
     575     *         map into the reserved space. So, other threads might grab the memory
     576     *         before we get to it.
     577     *      2. The page aligning of file offsets makes it impossible to map most
     578     *         executable images since these are commonly sector aligned.
     579     *      3. When mapping a read+execute file, its not possible to create section
     580     *         larger than the file since the section size is bound to the data file
     581     *         size. This wouldn't have been such a problem if it was possible to
     582     *         map views beyond the section restriction, i.e. have a file size and
     583     *         view size.
     584     *      4. Only x86 can map views at page granularity it seems, and that only
     585     *         using an undocument flag. The default granularity is 64KB.
     586     *      5. There is more crappyness here...
     587     *
     588     * So, first we'll have to check if we can the file using the crappy NT APIs.
     589     * Chances are we can't.
     590     */
     591    for (i = 0; i < cSegments; i++)
     592    {
     593        if (paSegments[i].RVA == NIL_KLDRADDR)
     594            continue;
     595
     596        /* The file backing of the segments must be page aligned. */
     597        if (    paSegments[i].cbFile
     598            &&  paSegments[i].offFile & (cbPage - 1))
     599            break;
     600
     601        /* Only page alignment gaps between the file size and the mapping size. */
     602        if (    paSegments[i].cbFile
     603            &&  (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
     604            break;
     605
     606        /* The mapping addresses of the segments must be page aligned.
     607         * Non-x86 will probably require 64KB alignment here. */
     608        if (paSegments[i].RVA & (cbPage - 1))
     609            break;
     610
     611        /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
     612        if (    !paSegments[i].cbFile
     613            &&  (paSegments[i].RVA & 0xffff))
     614            break;
     615    }
     616    /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
     617    if (i == cSegments)
     618    {
     619        /* WOW! it may work out! Incredible! */
     620        SIZE_T          ViewSize;
     621        LARGE_INTEGER   SectionOffset;
     622        LARGE_INTEGER   MaxiumSize;
     623        NTSTATUS        Status;
     624        PVOID           pv;
     625
     626        MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
     627        if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
     628            MaxiumSize.QuadPart = cbTotal;
     629
     630        Status = NtCreateSection(&pPrep->hSection,
     631                                 SECTION_MAP_EXECUTE | SECTION_MAP_READ,    /* desired access */
     632                                 NULL,                                      /* object attributes */
     633                                 &MaxiumSize,
     634                                 PAGE_EXECUTE_WRITECOPY,                    /* page attributes */
     635                                 SEC_COMMIT,                                /* section attributes */
     636                                 pRdrFile->File);
     637        if (!NT_SUCCESS(Status))
     638            return (int)Status;
     639
     640        /*
     641         * Determin the base address.
     642         */
     643        if (fFixed)
     644            pPrep->pv = *ppvBase;
     645        else
     646        {
     647            pv = NULL;
     648            ViewSize = (size_t)cbTotal;
     649
     650            Status = NtAllocateVirtualMemory(NtCurrentProcess(),
     651                                             &pv,
     652                                             0,                             /* ZeroBits */
     653                                             &ViewSize,
     654                                             MEM_RESERVE,
     655                                             PAGE_READONLY);
     656            if (NT_SUCCESS(Status))
     657            {
     658                pPrep->pv = *ppvBase = pv;
     659                ViewSize = 0;
     660                Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
     661            }
     662            if (!NT_SUCCESS(Status))
     663            {
     664                NtClose(pPrep->hSection);
     665                return Status;
     666            }
     667        }
     668
     669        /*
     670         * Map the segments.
     671         */
     672        for (i = 0; i < cSegments; i++)
     673        {
     674            ULONG fPageProt;
     675
     676            if (paSegments[i].RVA == NIL_KLDRADDR)
     677                continue;
     678
     679            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     680            if (paSegments[i].cbFile)
     681            {
     682                SectionOffset.QuadPart = paSegments[i].offFile;
     683                ViewSize = paSegments[i].cbFile;
     684                fPageProt = kldrRdrFileGetNtMapProt(paSegments[i].enmProt);
     685                // STATUS_MAPPED_ALIGNMENT
     686                // STATUS_CONFLICTING_ADDRESSES
     687                // STATUS_INVALID_VIEW_SIZE
     688                Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
     689                                            &pv,
     690                                            0,                                  /* ZeroBits */
     691                                            0,                                  /* CommitSize */
     692                                            &SectionOffset,                     /* SectionOffset */
     693                                            &ViewSize,
     694                                            ViewUnmap,
     695                                            MEM_DOS_LIM,                        /* AllocationType */
     696                                            fPageProt);
     697                /* do we have to zero anything? */
     698                if (    NT_SUCCESS(Status)
     699                    &&  0/*later*/)
     700                {
     701                    //ULONG OldPageProt = 0;
     702                    //NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, ,
     703                }
     704            }
     705            else
     706            {
     707                ViewSize = paSegments[i].cbMapped;
     708                fPageProt = kldrRdrFileGetNtAllocProt(paSegments[i].enmProt);
     709                Status = NtAllocateVirtualMemory(NtCurrentProcess(),
     710                                                 &pv,
     711                                                 0,                             /* ZeroBits */
     712                                                 &ViewSize,
     713                                                 MEM_COMMIT,
     714                                                 fPageProt);
     715            }
     716            if (!NT_SUCCESS(Status))
     717                break;
     718        }
     719
     720        /*
     721         * On success, commit the mapping and return.
     722         */
     723        if (NT_SUCCESS(Status))
     724        {
     725            pRdrFile->cPreps++;
     726            return 0;
     727        }
     728
     729        /* bail out and fall back on the generic code. */
     730        while (i-- > 0)
     731        {
     732            PVOID pv;
     733
     734            if (paSegments[i].RVA == NIL_KLDRADDR)
     735                continue;
     736
     737            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     738            if (paSegments[i].cbFile)
     739                NtUnmapViewOfSection(NtCurrentProcess(), pv);
     740            else
     741                NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
     742        }
     743        NtClose(pPrep->hSection);
     744    }
     745    /* else: fall back to the generic code */
     746    pPrep->hSection = NULL;
     747#endif
     748
     749    /*
     750     * Use the generic map emulation.
     751     */
     752    pPrep->pv = fFixed ? *ppvBase : NULL;
     753    rc = kldrRdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
     754    if (!rc)
     755    {
     756        *ppvBase = pPrep->pv;
     757        pRdrFile->cPreps++;
     758    }
     759
     760    return rc;
     761}
     762
     763
     764/** Generic implementation of kldrRdrFileMap. */
     765static int  kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
     766{
     767    int rc;
     768    uint32_t i;
     769
     770    /*
     771     * Generic mapping code using kldrHlpPageAlloc(), kldrHlpPageFree() and kldrHlpPageProtect().
     772     */
     773    rc = kldrHlpPageAlloc(&pPrep->pv, pPrep->cb, KLDRPROT_EXECUTE_READWRITE, fFixed);
     774    if (rc)
     775        return rc;
     776
     777    /*
     778     * Load the data.
     779     */
     780    for (i = 0; i < cSegments; i++)
     781    {
     782        void *pv;
     783
     784        if (    paSegments[i].RVA == NIL_KLDRADDR
     785            ||  !paSegments[i].cbFile)
     786            continue;
     787
     788        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
     789        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
     790        if (rc)
     791            break;
     792    }
     793
     794    /*
     795     * Set segment protection.
     796     */
     797    if (!rc)
     798    {
     799        rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
     800        if (!rc)
     801            return 0;
     802        kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
     803    }
     804
     805    /* bailout */
     806    kldrHlpPageFree(pPrep->pv, pPrep->cb);
     807    return rc;
    268808}
    269809
     
    5721112    SecAttr.lpSecurityDescriptor = NULL;
    5731113    SecAttr.nLength = 0;
    574     File = CreateFile(pszFilename, GENERIC_READ, FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL);
     1114    File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL);
    5751115    if (File == INVALID_HANDLE_VALUE)
    5761116        return GetLastError();
Note: See TracChangeset for help on using the changeset viewer.