PE加载器的实现

来源: http://blog.vckbase.com/windowssky
  对于加壳软件的开发者,掌握PE Loader的实现是最基本的技术;因为壳运行结束后,你要仿照PE加载器去Load映象体,我曾看过UPX的开源代码,全手工打造PE,实现的也是极其复杂,是学习加壳,脱壳和开发加壳软件的上乘资料.

  在ReatOs和Nt4.0上找到了其实现,前者实现的比较清晰,不过还是看看Nt4.0的实现吧

//KiThreadStartup->向Kernel APC插入LdrInitializeThunk->向User APC插入
//LdrInitializeThunk;详请参见PspCreateThread的实现
//
//注:Kernel APC与User APC的区别:
//          1)前者是在APC_LEVEL上运行,后者是在PASSIVE_LEVEL上运行
//          2)只有KTHREAD中的AlertAble或KTHREAD-ApcState-UserApcPending
//              为1的情况下,User APC中的Routine才会被执行
//
//ring0下启动ring3下的程序就是通过kernel下操作User APC实现的(向Explorer.exe中插入一个User APC)
//详请参考: http://www.codeproject.com/useritems/KernelExec.asp


//扯远了,还是来看看LdrInitializeThunk和LdrInitialize的实现吧
;++
;
; VOID
; LdrInitializeThunk(
;    IN PVOID NormalContext,
;    IN PVOID SystemArgument1,
;    IN PVOID SystemArgument2
;    )
;
; Routine Description:
;
;    This function computes a pointer to the context record on the stack
;    and jumps to the LdrpInitialize function with that pointer as its
;    parameter.
;
; Arguments:
;
;    NormalContext - User Mode APC context parameter (ignored).
;
;    SystemArgument1 - User Mode APC system argument 1 (ignored).
;
;    SystemArgument2 - User Mode APC system argument 2 (ignored).
;
; Return Value:
;
;    None.
;
;--

cPublicProc _LdrInitializeThunk , 4

NormalContext  equ [esp + 4]
SystemArgument1 equ [esp + 8]
SystemArgument2 equ [esp + 12]
Context        equ [esp + 16]

        lea    eax,Context            ; Calculate address of context record
        mov    NormalContext,eax      ; Pass as first parameter to
if DEVL
        xor    ebp,ebp                ; Mark end of frame pointer list
endif
IFDEF STD_CALL
        jmp    _LdrpInitialize@12      ; LdrpInitialize
ELSE
        jmp    _LdrpInitialize        ; LdrpInitialize
ENDIF

stdENDP _LdrInitializeThunk

_TEXT  ends
        end



VOID
LdrpInitialize (
    IN PCONTEXT Context,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    )

/*++

Routine Description:

    This function is called as a User-Mode APC routine as the first
    user-mode code executed by a new thread. It's function is to initialize
    loader context, perform module initialization callouts...

Arguments:

    Context - Supplies an optional context buffer that will be restore
              after all DLL initialization has been completed.  If this
              parameter is NULL then this is a dynamic snap of this module.
              Otherwise this is a static snap prior to the user process
              gaining control.

    SystemArgument1 - Supplies the base address of the System Dll.

    SystemArgument2 - not used.

Return Value:

    None.

--*/

{
    NTSTATUS st, InitStatus;
    PPEB Peb;
    PTEB Teb;
    UNICODE_STRING UnicodeImageName;
    MEMORY_BASIC_INFORMATION MemInfo;
    BOOLEAN AlreadyFailed;
    LARGE_INTEGER DelayValue;

    SystemArgument2;

    AlreadyFailed = FALSE;
    Peb = NtCurrentPeb();
    Teb = NtCurrentTeb();

    if (!Peb->Ldr) {
#if defined(MIPS) || defined(_ALPHA_)
        ULONG temp;
#if defined(MIPS)
        Peb->ProcessStarterHelper = (PVOID)LdrProcessStarterHelper;
#endif
        //
        // Set GP register
        //
        LdrpGpValue =(ULONG)RtlImageDirectoryEntryToData(
                Peb->ImageBaseAddress,
                TRUE,
                IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
                &temp
                );
        if (Context != NULL) {
            LdrpSetGp( LdrpGpValue );
#if defined(_MIPS_)
            Context->XIntGp = (LONG)LdrpGpValue;
#else
            Context->IntGp = LdrpGpValue;
#endif
        }
#endif // MIPS || ALPHA

        NtGlobalFlag = Peb->NtGlobalFlag;
#if DBG
        if (TRUE)
#else
        if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
#endif
        {
            PWSTR pw;

            pw = (PWSTR)Peb->ProcessParameters->ImagePathName.Buffer;
            if (!(Peb->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
                pw = (PWSTR)((PCHAR)pw + (ULONG)(Peb->ProcessParameters));
                }
            UnicodeImageName.Buffer = pw;
            UnicodeImageName.Length = Peb->ProcessParameters->ImagePathName.Length;
            UnicodeImageName.MaximumLength = UnicodeImageName.Length;

            st = LdrQueryImageFileExecutionOptions( &UnicodeImageName,
                                                    L"GlobalFlag",
                                                    REG_DWORD,
                                                    &NtGlobalFlag,
                                                    sizeof( NtGlobalFlag ),
                                                    NULL
                                                  );
            if (!NT_SUCCESS( st )) {
                UnicodeImageName.Length = 0;

                if (Peb->BeingDebugged) {
                    NtGlobalFlag |= FLG_HEAP_ENABLE_FREE_CHECK |
                                    FLG_HEAP_ENABLE_TAIL_CHECK |
                                    FLG_HEAP_VALIDATE_PARAMETERS;
                    }
                }
        }

#if DBG && FLG_HEAP_PAGE_ALLOCS

        if ( NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS ) {

            //
            //  Turn on BOOLEAN RtlpDebugPageHeap to indicate that
            //  new heaps should be created with debug page heap manager
            //  when possible.  Also force off other heap debug flags
            //  that can cause conflicts with the debug page heap
            //  manager.
            //

            RtlpDebugPageHeap = TRUE;

            NtGlobalFlag &= ~( FLG_HEAP_ENABLE_TAGGING |
                              FLG_HEAP_ENABLE_TAG_BY_DLL
                            );

            }

#endif // DBG && FLG_HEAP_PAGE_ALLOCS

    }
#if defined(MIPS) || defined(_ALPHA_)
    else
    if (Context != NULL) {
        LdrpSetGp( LdrpGpValue );
#if defined(_MIPS_)
        Context->XIntGp = (LONG)LdrpGpValue;
#else
        Context->IntGp = LdrpGpValue;
#endif
    }
#endif // MIPS || ALPHA

    ShowSnaps = (BOOLEAN)(FLG_SHOW_LDR_SNAPS & NtGlobalFlag);

    //
    // Serialize for here on out
    //

    Peb->LoaderLock = (PVOID)&LoaderLock;
    if ( !RtlTryEnterCriticalSection(&LoaderLock) ) {
        if ( LoaderLockInitialized ) {
            RtlEnterCriticalSection(&LoaderLock);
            }
        else {

            //
            // drop into a 30ms delay loop
            //

            DelayValue.QuadPart = Int32x32To64( 30, -10000 );
            while ( !LoaderLockInitialized ) {
                NtDelayExecution(FALSE,&DelayValue);
                }
            RtlEnterCriticalSection(&LoaderLock);
            }
        }

    if (Teb->DeallocationStack == NULL) {
        st = NtQueryVirtualMemory(
                NtCurrentProcess(),
                Teb->NtTib.StackLimit,
                MemoryBasicInformation,
                (PVOID)&MemInfo,
                sizeof(MemInfo),
                NULL
                );
        if ( !NT_SUCCESS(st) ) {
            LdrpInitializationFailure(st);
            RtlRaiseStatus(st);
            return;
            }
        else {
            Teb->DeallocationStack = MemInfo.AllocationBase;
        }
    }

    InitStatus = STATUS_SUCCESS;
    try {
        if (!Peb->Ldr) {
            LdrpInLdrInit = TRUE;
#if DBG
            //
            // Time the load.
            //

            if (LdrpDisplayLoadTime) {
                NtQueryPerformanceCounter(&BeginTime, NULL);
            }
#endif // DBG

            try {
                //
                //This function initializes the loader for the process.
                //This includes:

                //    - Initializing the loader data table

                //    - Connecting to the loader subsystem

                //    - Initializing all staticly linked DLLs

                InitStatus = LdrpInitializeProcess( Context,
                                                    SystemArgument1,
                                                    UnicodeImageName.Length ? &UnicodeImageName : NULL
                                                  );
                }
            except ( EXCEPTION_EXECUTE_HANDLER ) {
                InitStatus = GetExceptionCode();
                AlreadyFailed = TRUE;
                LdrpInitializationFailure(GetExceptionCode());
                }
#if DBG
            if (LdrpDisplayLoadTime) {
                NtQueryPerformanceCounter(&EndTime, NULL);
                NtQueryPerformanceCounter(&ElapsedTime, &Interval);
                ElapsedTime.QuadPart = EndTime.QuadPart - BeginTime.QuadPart;
                DbgPrint("/nLoadTime %ld In units of %ld cycles/second /n",
                    ElapsedTime.LowPart,
                    Interval.LowPart
                    );

                ElapsedTime.QuadPart = EndTime.QuadPart - InitbTime.QuadPart;
                DbgPrint("InitTime %ld/n",
                    ElapsedTime.LowPart
                    );
                DbgPrint("Compares %d Bypasses %d Normal Snaps %d/nSecOpens %d SecCreates %d Maps %d Relocates %d/n",
                    LdrpCompareCount,
                    LdrpSnapBypass,
                    LdrpNormalSnap,
                    LdrpSectionOpens,
                    LdrpSectionCreates,
                    LdrpSectionMaps,
                    LdrpSectionRelocates
                    );
            }
#endif // DBG

            if (!NT_SUCCESS(InitStatus)) {
#if DBG
                DbgPrint("LDR: LdrpInitializeProcess failed - %X/n", InitStatus);
#endif // DBG
            }

        } else {
            if ( Peb->InheritedAddressSpace ) {
                InitStatus = LdrpForkProcess();
                }
            else {

#if defined (WX86)
                if (Teb->Vdm) {
                    InitStatus = LdrpInitWx86(Teb->Vdm, Context, TRUE);
                    }
#endif

                //    This function is called by a thread that is terminating cleanly.
                //It's purpose is to call all of the processes DLLs to notify them
                //that the thread is detaching.

                LdrpInitializeThread();
                }
        }
    } finally {
        LdrpInLdrInit = FALSE;
        RtlLeaveCriticalSection(&LoaderLock);
        }

    NtTestAlert();

    if (!NT_SUCCESS(InitStatus)) {

        if ( AlreadyFailed == FALSE ) {
            LdrpInitializationFailure(InitStatus);
            }
        RtlRaiseStatus(InitStatus);
    }


}

详细实现参见:
nt4/private/ntos/dll/ldrinit.c
nt4/private/ntos/dll/ldrapi.c
nt4/private/ntos/dll/ldrsnap.c

reatos实现参见:
ReactOS030/dll/ntdll/ldr/startup.c
ReactOS030/dll/ntdll/ldr/utils.c
ReactOS030/dll/ntdll/ldr/elf.c

你可能感兴趣的:(function,user,null,System,Parameters,initialization)