垃圾堆——windowssky
人生就象一场旅行 不必在乎目的地 在乎的是沿途的风景以及看风景的心情
<2009年1月>
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

留言簿(1)

随笔分类

随笔档案

文章档案

相册

NDIS IFS

内核研究

基础知识

安全技术

操作系统

病毒技术

网络技术

逆向工程

驱动开发

搜索

最新评论

阅读排行榜

评论排行榜

 
VC知识库BLOG   首页  新随笔  联系  聚合  登录 
  随笔-21 文章-0 评论-31 Trackbacks-0

  对于加壳软件的开发者,掌握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

posted on 2007-07-30 10:36 垃圾一堆 阅读(4245) 评论(3)  编辑 收藏
Comments
  • # re: PE加载器的实现
    Eric
    Posted @ 2007-08-17 21:57
    nt4\private\ntos\dll这个路径好熟悉啊,好像是win2k原代码
  • # re: PE加载器的实现
    aker
    Posted @ 2007-12-29 18:25
    我来学习:)
  • # re: PE加载器的实现
    me
    Posted @ 2008-01-19 16:02
    C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin
标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]