Криптор исполняемых файлов. РЭволюция =).

  • Автор темы Admin

Admin

#1
Администратор
Регистрация
31.12.2019
Сообщения
7,569
Реакции
36
Всем привет друзья!


Снова конкурс, а значит снова появился повод поделиться чем-то интересным и полезным с комьюнити.
Хочу выразить огромный респект организаторам, за то что нашли крутой способ для форума собрать классный контент, повышать репутацию форума и притянуть молодых.


В моей прошлой конкурсной статье вами были заданы вопросы про загрузчик, и я тогда ответил:




Сказано - сделано.


hidden_code_1508778570.jpg



Загрузчик это действительно отдельная, интересная тема, к которой нужно подойти основательно и расставить все точки над i.
Проект криптора, описанный в прошлой статье, содержит уже откомпилированные версии шеллкодов загрузчика в память, без исходного кода.
В этой статье я поделюсь с вами его полным исходным кодом, опишу что он делает и как происходит обработка и мэппинг файла в память в нюансах.
Мы поговорим о том, чем это решение отличается от системного загрузчика, посмотрим относительно кода системного загрузчика в XP.
Порассуждаем о пользе прямого мэппинга в памяти перед инжектами, такими как RunPE и иже с ними.


Немного предыстории:
Появившийся как концепт, способ загрузки RunPE был практически идеальным решением загрузки бинарика в память на рубеже 08-12гг.
Тогда антивирусы еще относительно плохо умели хучить вызовы и перехватывать управление вновь созданного процесса, проверяя его контекст.
По сути проактивные системы проходили своё становление как самостоятельные технологии и во главе угла стояли сигнатурный и эвристические
алгоритмы обнаружения крипторов.


Принцип работы RunPE достаточно прост:
Стаб (контейнер криптованного файла) пораждает новый приостановленный процесс через CreateProcess с флагом CREATE_SUSPENDED,
получает контекст главного потока через GetThreadContext, после чего приостановленный процесс анмепится с помощью NtUnmapViewOfSection
и по адресу ImageBase выделяется память через VirtualAllocEx с флагом PAGE_EXECUTE_READWRITE.
Далее в выделенную память через WriteProcessMemory записываются хидер криптованного файла и секции.
Финальные штрихи это установка нового контекста на точку входа для главного потока через SetThreadContext и восстановление
приостановленного потока через ResumeThread.


Для поддержки x64 файлов в RunPE требовалось совершить минимум изменений с учетом смещений и регистров (eax\rax, ebx\rbx и т.д.) и вот уже готова полноценная поддержка х64 файлов.
В целом история с RunPE довольно простая, очень стабильная и хорошо отрабатывающая практически любые типы нативных PE файлов, будь то хитрые
заглушки в TLS, аномальные заголовоки, упакованные файлы и т.д.


Одна беда - технологию с того времени так затерли до дыр, что любой уважающий себя антивирус научился определять этот способ загрузки в память,
что напрочь отменяло бы саму идею сокрытия криптуемого файла от антивирусов. С появлением механизмов сканирования памяти эта технология окончательно умерла.


Есть еще промежуточные способы загрузки в память, я отнесу их к RunPE-подобным и назову их инжектами. В данной статье их рассматривать я не буду.


LoadPE:
Первые попытки нативной (почему нативной - опишу ниже) загрузки бинарного файла в память (в паблике) выкладывал покойный Great, как раз на дамаге и на васме.
Те наработки хоть и отражали суть концепции, хотя и работали кое как, но умели обрабатывать только ограниченное количество самых стандартных PE файлов.
Любые отклонения от эталонного PE формата - и загрузка такого файла в память фейлилась.
Позже свои наработки отрывками выкладывал el-, тоже на дамаге.


Многие "мастера" не стали заморачиваться со своим кодом и рипнули загрузчик с криптованных семплов, тупо вставив в свой криптор, мол ведь и так работает.
Ну а некоторым, как мне, захотелось разобраться в сути технологии и написать своё решение, которое было бы способно обрабатывать доминирующее большинство PE файлов,
с учетом разных хитрых, нестандартных техник, поддерживающее как 86 так и 64 архитектуры PE формата.
И вот на базе этих наработок и путем долгих реверсов оригинального загрузчика винды, технология нативной загрузки в память шлифовалась, пока не выкатилось готовое решение.


Почему я называю этот способ нативным? Да потому, что в отличие от незамысловатого RunPE, в LoadPE нам нужно руками воспроизводить действия, которые обычно выполняет
сам загрузчик винды.


Рассмотрим механизм, который используется в нативном загрузчике винды:


В основе загрузки любого модуля лежит функция LoadLibrary, точнее её более низкоуровневые функции из ntdll, такие как LdrLoadDll и LdrpLoadDll.
Код:
NTSTATUS
LdrpInitializeProcess (
    IN PCONTEXT Context OPTIONAL,
    IN PVOID SystemDllBase,
    IN PUNICODE_STRING UnicodeImageName,
    IN BOOLEAN UseCOR,
    IN BOOLEAN ImageFileOptionsPresent
    )


/*++


Routine Description:


    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


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.


    SystemDllBase - Supplies the base address of the system dll.


    UnicodeImageName - Base name + extension of the image


    UseCOR - TRUE if the image is a COM+ runtime image, FALSE otherwise


    ImageFileOptionsPresent - Hint about existing any ImageFileExecutionOption key.
            If the key is missing the ApplicationCompatibilityGoo and
            DebugProcessHeapOnly entries won't be checked again.


Return Value:


    Status value


--*/




NTSTATUS
NTAPI
LdrpLoadDll(
    ULONG Flags OPTIONAL,
    IN PWSTR DllPath OPTIONAL,
    IN PULONG DllCharacteristics OPTIONAL,
    IN PUNICODE_STRING DllName,
    OUT PVOID *DllHandle,
    IN BOOLEAN RunInitRoutines
    )




/*++


Routine Description:


    This function loads a DLL into the calling process address space.


Arguments:


    DllPath - Supplies the search path to be used to locate the DLL.


    DllCharacteristics - Supplies an optional DLL characteristics flag,
        that if specified is used to match against the dll being loaded.


    DllName - Supplies the name of the DLL to load.


    DllHandle - Returns a handle to the loaded DLL.


Return Value:


    TBD


--*/


NTSTATUS
LdrpMapDll(
    IN PWSTR DllPath OPTIONAL,
    IN PWSTR DllName,
    IN PULONG DllCharacteristics OPTIONAL,
    IN BOOLEAN StaticLink,
    IN BOOLEAN Redirected,
    OUT PLDR_DATA_TABLE_ENTRY *LdrDataTableEntry
    )


/*++


Routine Description:


    This routine maps the DLL into the users address space.


Arguments:


    DllPath - Supplies an optional search path to be used to locate the DLL.


    DllName - Supplies the name of the DLL to load.


    StaticLink - TRUE if this DLL has a static link to it.


    LdrDataTableEntry - Supplies the address of the data table entry.


Return Value:


    Status value.


--*/
Настоятельно советую ознакомиться с полным кодом этих функций. Дабы вы не искали в моменте, я также выложу его далее,
чтобы не засорять основной посыл данной статьи.




Как можно увидеть, винда делает просто кучу дополнительных манипуляций при загрузке файла, дополнительные проверки, обработку всего и вся и в том числе нотификацию
о событиях.


Моя реализация выглядит гораздо проще, но от этого не менее эффективная и минимальный необходимый набор действий она выполняет.
А еще она после компляции весит чуть более 2 кб
yH5BAEAAAAALAAAAAABAAEAAAIBRAA7



Ок, давайте взглянем на мой загрузчик:
Он поддерживает x86\x64 PE файлы, как EXE так и DLL, а еще гибридные, которые одновеменно и EXE и DLL.
Умеет хэндлить ActCtx, SEH, стартап код, анпакинг с помощью aplib, восстанавливать Tls колбеки и многое другое.
Участки, отвечающие за обработку x64 PE обрамлены в соотвествующие дефайны #ifdef _WIN64.


Код:
VOID WINAPI pe2mem(PPE_LOADER_PARAMS params)
{
    DWORD_PTR Base = params->base;


    PIMAGE_NT_HEADERS pNt = ((PIMAGE_NT_HEADERS)((DWORD_PTR)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew));


     BOOL  IsImageDll = (pNt->FileHeader.Characteristics &  IMAGE_FILE_DLL) ? TRUE : FALSE; // for hybrids, our exe may be dll, we  must restore how exe, but fix peb how dll
    DWORD SizeOfBase = pNt->OptionalHeader.SizeOfImage;
pe2mem - основная функция загрузчика, принимает единственный параметр PPE_LOADER_PARAMS params.
В pNt читаем NtHeaders криптованного файла
В Base у нас адрес, по которому нужно загрузить файл.
В IsImageDll мы определяем, читая Characteristics какой файл перед нами EXE или DLL. (Это позволяет обрабатывать файлы тансформеры).
В SizeOfBase соотвественно размер образа.


Вот эта структура:
Код:
typedef struct _PE_LOADER_PARAMS
{
    DWORD_PTR    base; // ImageBase
    PVOID        file; // Pointer to file buffer
    DWORD        file_size; // File size
    DWORD        flags; // Additional flags
}PE_LOADER_PARAMS, *PPE_LOADER_PARAMS;
Думаю и так ясно что она делает, передаёт ImageBase, буфер файла, его размер и дополнительные параметры.


Код:
#ifndef _WIN64
    DWORD PrologLocalVarsSize = 0;


    if( !(params->flags & PE_LDR_FLAG_NOT_STUB) )
    {
        //find c++ seh_prolog4
        PBYTE pScan = (PBYTE)((DWORD_PTR)Base + pNt->OptionalHeader.AddressOfEntryPoint);
        for(int i = 0; i < 30; i++ )
        {
            if( *pScan==0xE9 && *(PWORD)(pScan + 3)==0xFFFF ) //  E9 9F FD FF FF jmp     __DllMainCRTStartup (exe)
                break;


            if( *pScan==0xE8 && *(PWORD)(pScan + 3)==0xFFFF ) //  E8 9F FD FF FF call     __DllMainCRTStartup (dll)
                break;


            pScan++;
        }


        if( *pScan!=0xE9 && *pScan!=0xE8 )
            return;


        pScan = (PBYTE)((INT_PTR)pScan + 5 + *(PINT_PTR)(pScan + 1)); // __DllMainCRTStartup
        if( *pScan==0x6A )
        {
            PrologLocalVarsSize = *(pScan + 1);
        }else if( *pScan==0x68 )
        {
            PrologLocalVarsSize = *(PDWORD)(pScan + 1);
        }else{
            return ;
        }
    }
#endif
Данный участок кода это такой лайфхак.
Если ваш стаб имеет код инициализации (т.н. startup код), у вас практически гарантированно возникнут проблемы на этом этапе.
Данный код позволяет проскипать пролог и получить его итоговый размер.
Нужно учитывать, что для каждой версии стартап кода сигнатура может отличаться. Данная реализация покрывает версии студий VC2008, VC2010.




Код:
    PEB* Peb  = GET_PEB();


    PLDR_DATA_TABLE_ENTRY Entry = (PLDR_DATA_TABLE_ENTRY)Peb->Ldr->InInitializationOrderModuleList.Flink;
    Entry = CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks);


    DWORD_PTR Ntdll = (DWORD_PTR)Entry->DllBase;
    DWORD_PTR NtdllEnds = Ntdll + Entry->SizeOfImage;


    // kernelbase ?
    while( hash_stringW(Entry->BaseDllName.Buffer)!=HASH_KERNEL32_DLL )
    {
        Entry = (PLDR_DATA_TABLE_ENTRY)Entry->InInitializationOrderLinks.Flink;
        Entry = CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks);
    }


    DWORD_PTR Kernel32 = (DWORD_PTR)Entry->DllBase;
    DWORD_PTR Kernel32Ends = Kernel32 + Entry->SizeOfImage;


    KernelProcs kprocs = {
        (TD_GetProcAddress)HASH_GetProcAddress,
        (TD_VirtualAlloc)HASH_VirtualAlloc,
        (TD_LoadLibraryA)HASH_LoadLibraryA,
        (TD_VirtualProtect)HASH_VirtualProtect,
        (TD_VirtualFree)HASH_VirtualFree,
        (TD_ActivateActCtx)HASH_ActivateActCtx,
        (TD_CreateActCtxA)HASH_CreateActCtxA,
        (TD_TlsAlloc)HASH_TlsAlloc,
        (TD_TlsSetValue)HASH_TlsSetValue,
        (TD_FlsFree)HASH_FlsFree,
        (TD_RtlAddFunctionTable)HASH_RtlAddFunctionTable,
        (TD_RtlDeleteFunctionTable)HASH_RtlDeleteFunctionTable,
        (TD_AcquireSRWLockShared)HASH_AcquireSRWLockShared,
        NULL
    };


    for(int i = 0; i < sizeof(KernelProcs)/sizeof(DWORD_PTR); i++)
    {
        *((PDWORD_PTR)&kprocs + i) = (DWORD_PTR)hash_find_proc((PVOID)Kernel32,*((PDWORD_PTR)&kprocs + i));
    }
В этом участке кода мы получаем указатель на Peb, узнаем адреса модулей NTDLL и KERNEL32.
Далее мы находим указатели на необходимые WinAPI функции по их хэшам, и заполняем структуру KernelProcs.
hash_find_proc позволяет по хэшу от строки найти функцию.


Код:
DWORD API_CALL hash_string(PCHAR String,BOOL IsUnicode)
{
    DWORD i;
    DWORD Result = 0;


    if( String )
    {
        for(i=0; *String ;i++)
        {
            Result = _rotl(Result,3);
            Result ^= ( *String>='A' && *String<='Z' ? *String | 0x20 : *String );
            String++;
            if( IsUnicode )
                String++;
        }


        Result &= ~IMAGE_ORDINAL_FLAG32;
    }


    return Result;
}
Данная функция позволяет хэшировать строку, в том числе юникодную, на выходе получить DWORD от этой строки.


Код:
    __debugbreak();


    PVOID SavedFile = kprocs.VirtualAlloc(NULL,params->file_size,MEM_COMMIT,PAGE_READWRITE);
    if( SavedFile )
    {
        if( params->flags & PE_LDR_FLAG_USE_APLIB )
        {
            aplib_depack_fast(params->file, SavedFile);
        }else{
            mem_copy(SavedFile,params->file,params->file_size);
        }


        PIMAGE_DOS_HEADER pDos;
        PIMAGE_NT_HEADERS pNt;


        // free fls data
        if( !(params->flags & PE_LDR_FLAG_NOT_STUB) && Peb->OSMajorVersion > 5 )
        {
            DWORD Count = Peb->FlsCount;
            for(int i = 0; i <= Count; i++)
            {
                __debugbreak();
                if( IN_DLL(Peb->FlsCallbacks[i].Base,Base,Base + SizeOfBase) )
                {
                    kprocs.FlsFree(i);
                }
            }
        }
В SavedFile выделям память в размере file_size.
Проверяем флаги, если PE_LDR_FLAG_USE_APLIB, то используем распаковку буфера с помощью алгоритма aPlib_depack.
Если в флаги не передан PE_LDR_FLAG_NOT_STUB и Peb->OSMajorVersion > 5, то пересчитываем Fls колбеки соответствующим образом.


Код:
aplib_depack_fast proc a:DWORD, b:DWORD
    ; aP_depack_asm_fast(const void *source, void *destination)


    mov    [rsp + 8], rsi
    mov    [rsp + 16], rdx
    push   rdi


    mov    rsi, rcx
    mov    rdi, rdx


    cld
    mov    dl, 80h


literal:
    mov    al, [rsi]
    add    rsi, 1
    mov    [rdi], al
    add    rdi, 1


    mov    r9, 2


nexttag:
    getbitM
    jnc    literal


    getbitM
    jnc    codepair


    xor    rax, rax
    getbitM
    jnc    shortmatch


    getbitM
    adc    rax, rax
    getbitM
    adc    rax, rax
    getbitM
    adc    rax, rax
    getbitM
    adc    rax, rax
    jz     thewrite


    mov    r9, rdi
    sub    r9, rax
    mov    al, [r9]


thewrite:
    mov    [rdi], al
    add    rdi, 1


    mov    r9, 2
    jmp    short nexttag


codepair:
    getgammaM rax
    sub    rax, r9
    mov    r9, 1
    jnz    normalcodepair


    getgammaM rcx
    domatchM r8


    jmp    nexttag


normalcodepair:
    add    rax, -1


    shl    rax, 8
    mov    al, [rsi]
    add    rsi, 1


    mov    r8, rax


    getgammaM rcx


    cmp    rax, 32000
    sbb    rcx, -1


    cmp    rax, 1280
    sbb    rcx, -1


    cmp    rax, 128
    adc    rcx, 0


    cmp    rax, 128
    adc    rcx, 0


    domatchM rax
    jmp    nexttag


shortmatch:
    mov    al, [rsi]
    add    rsi, 1


    xor    rcx, rcx
    db     0c0h, 0e8h, 001h
    jz     donedepacking


    adc    rcx, 2


    mov    r8, rax


    domatchM rax


    mov    r9, 1
    jmp    nexttag


donedepacking:
    mov    rax, rdi
    sub    rax, [rsp + 24]


    mov    rsi, [rsp + 16]
    pop    rdi


    ret
aplib_depack_fast endp
Алгоритм распаковки буфера aPlib_depack.


Код:
#ifdef _WIN64
        pDos = (PIMAGE_DOS_HEADER)Base;
        pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);


        DWORD_PTR SaveRegs[r_all];


        mem_zero(SaveRegs,sizeof(DWORD_PTR)*r_all);


        __debugbreak();
        PDWORD_PTR Rsp = (PDWORD_PTR)get_return();
        while( !IN_DLL(*Rsp,Kernel32,Kernel32Ends) && !IN_DLL(*Rsp,Ntdll,NtdllEnds) )
        {
            Rsp = find_next_rsp(SaveRegs,Rsp);
        }


#endif
В случае, если мы собраны под x64, находим Rsp.


Код:
        pDos = (PIMAGE_DOS_HEADER)SavedFile;
        pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);


        DWORD OldProtection;


        __debugbreak();


        if( kprocs.VirtualProtect((PVOID)Base,pNt->OptionalHeader.SizeOfImage,PAGE_EXECUTE_READWRITE,&OldProtection) )
        {
            PVOID NewImageBase = (PVOID)Base;


            mem_set(NewImageBase,0,pNt->OptionalHeader.SizeOfImage); // bugfix: must be NULL where not writed something


            mem_copy(NewImageBase, pDos, pNt->OptionalHeader.SizeOfHeaders);


            PIMAGE_SECTION_HEADER Sections = IMAGE_FIRST_SECTION(pNt);


            for (INT i = 0; i < pNt->FileHeader.NumberOfSections; i++)
            {
                 mem_copy((PVOID)((DWORD_PTR)NewImageBase +  Sections->VirtualAddress), (PVOID)((DWORD_PTR)pDos +  Sections->PointerToRawData), Sections->SizeOfRawData);
                Sections++;
            }


            PIMAGE_DOS_HEADER pNewDos = (PIMAGE_DOS_HEADER)NewImageBase;
            PIMAGE_NT_HEADERS pNewNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pNewDos + pNewDos->e_lfanew);


            process_peb(NewImageBase,IsImageDll,(PVOID)Base);
             process_resource(&kprocs,NewImageBase); //bugfix:  manifest must be processed first, and other dll may be after that, or  import may fail call [NULL]
            process_import(&kprocs,NewImageBase);
            process_relocs(NewImageBase); //
            process_tls(&kprocs,NewImageBase); // tls must be after relocs, because they fix StartDataAddress and other info
В данном участке кода мы получаем указатели на DOS и Nt заголовки.
Меняем аттрибуты выделенной памяти на PAGE_EXECUTE_READWRITE.
Копируем заголовки, секции.
Обрабатываем Peb.
Обрабатываем ресурсы.
Обрабатываем импорт.
Обрабатываем релоки.
Обрабатываем TLS.


Код:
VOID __fastcall process_peb(PVOID ImageData,BOOL IsImageDll,PVOID OldImageBase)
{
    PEB* Peb = GET_PEB();


    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);


    if( !IsImageDll )
    {
        Peb->ImageBaseAddress = (DWORD_PTR)ImageData;
    }


    PLDR_DATA_TABLE_ENTRY Entry = (PLDR_DATA_TABLE_ENTRY)Peb->Ldr->InMemoryOrderModuleList.Flink;
    while( Entry!= (PLDR_DATA_TABLE_ENTRY)&Peb->Ldr->InMemoryOrderModuleList )
    {
        Entry = CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InMemoryOrderLinks);


        if( Entry->DllBase==OldImageBase )
        {
            Entry->DllBase = ImageData;
            Entry->EntryPoint = (PVOID)((DWORD_PTR)pDos + pNt->OptionalHeader.AddressOfEntryPoint);
            Entry->SizeOfImage = pNt->OptionalHeader.SizeOfImage;


            break;
        }


        Entry = (PLDR_DATA_TABLE_ENTRY)Entry->InMemoryOrderLinks.Flink;
    }
}
Обрабатываем Peb.


Код:
VOID __fastcall process_resource(KernelProcs* Procs,PVOID ImageData)
{
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);


     PIMAGE_RESOURCE_DIRECTORY Resource =  (PIMAGE_RESOURCE_DIRECTORY)((DWORD_PTR)pDos +  pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);


    if (Resource!=(PIMAGE_RESOURCE_DIRECTORY)pDos)
    {
        CHAR Name[8];
        ULONG_PTR Cookie;


        *(PDWORD)Name = 'a';


        ACTCTXA Ctx;


        Ctx.cbSize = sizeof(ACTCTXA);
        Ctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID;
        Ctx.lpResourceName = MAKEINTRESOURCEA(1);
        Ctx.lpSource = Name;
        Ctx.wProcessorArchitecture = 0;
        Ctx.lpAssemblyDirectory = NULL;
        Ctx.lpApplicationName = NULL;
        Ctx.hModule = (HMODULE)ImageData;


        HANDLE hCtx = Procs->CreateActCtxA(&Ctx);
        if( hCtx!=INVALID_HANDLE_VALUE )
        {
            Procs->ActivateActCtx(hCtx,&Cookie);
        }
    }
}
Обрабатываем ресурсы тушки.
Тут важный момент - activation context . Начиная с 7ки в винде в ресурсах появилось понятие manifest или RESID=24. Это нужно в том числе для правильной работы UAC.
Эта функция правильным образом хэндлит такие ресурсы. Читать подробнее тут.




Код:
VOID __fastcall process_import(KernelProcs *Procs,PVOID ImageData)
{
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);


     PIMAGE_IMPORT_DESCRIPTOR Import =  (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)pDos +  pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);


    if (Import!=(PIMAGE_IMPORT_DESCRIPTOR)pDos)
    {
        while (Import->Name != 0)
        {
            PCHAR DllName = (PCHAR)((DWORD_PTR)pDos + Import->Name);


            HMODULE Dll = Procs->LoadLibraryA(DllName);


            if (!Dll)
                return ;


             PDWORD_PTR pImport = (Import->OriginalFirstThunk ?  (PDWORD_PTR)((DWORD_PTR)pDos + Import->OriginalFirstThunk) :  (PDWORD_PTR)((DWORD_PTR)pDos + Import->FirstThunk));
            PDWORD_PTR pAddress = (PDWORD_PTR)((DWORD_PTR)pDos + Import->FirstThunk);


            while (*pImport)
            {
                DWORD_PTR FuncAddress = NULL;


#ifdef _WIN64
                if ((*pImport & IMAGE_ORDINAL_FLAG64)) // ordinal
#else
                if ((*pImport & IMAGE_ORDINAL_FLAG32)) // ordinal
#endif
                {
                    DWORD_PTR Ordinal = (*pImport & 0xFFFF);


                    FuncAddress = (DWORD_PTR)Procs->GetProcAddress(Dll, (PCHAR)Ordinal);
                }else{
                    PCHAR FuncName = (PCHAR)((DWORD_PTR)pDos + *pImport + 2);


                    FuncAddress = (DWORD_PTR)Procs->GetProcAddress(Dll, FuncName);
                }


                *pAddress++ = FuncAddress;


                pImport++;
            }


            Import++;
        }
    }
}
Обрабатываем таблицу импорта тушки.
В том числе и по ординалу для всяких модулей вроде comctl32 и прочих.
Многие делают это не совсем правильно. Вот правильный вариант.


Код:
VOID __fastcall process_relocs(PVOID ImageData)
{
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);


     PIMAGE_BASE_RELOCATION BaseRelocs =  (PIMAGE_BASE_RELOCATION)((DWORD_PTR)pDos +  pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);


    INT_PTR Delta;


    if (BaseRelocs!=(PIMAGE_BASE_RELOCATION)pDos)
    {
        PIMAGE_BASE_RELOCATION Reloc = BaseRelocs;


        Delta = (INT_PTR)ImageData - pNt->OptionalHeader.ImageBase;


        do
        {
            PIMAGE_FIXUP_ENTRY Fixup = (PIMAGE_FIXUP_ENTRY)((DWORD_PTR)Reloc + sizeof(IMAGE_BASE_RELOCATION));
            for (int r = 0, sz = (Reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; r < sz; r++)
            {
                if (Fixup->Type == IMAGE_REL_BASED_HIGHLOW)
                {
                    *(PINT)((DWORD_PTR)pDos + Reloc->VirtualAddress + Fixup->Offset) += Delta;
                }else if (Fixup->Type==IMAGE_REL_BASED_DIR64)
                {
                    if(Reloc->VirtualAddress + Fixup->Offset==0x63D88 )
                    {
                        Delta = (INT)ImageData - pNt->OptionalHeader.ImageBase;
                    }
                    *(PINT_PTR)((DWORD_PTR)pDos + Reloc->VirtualAddress + Fixup->Offset) += Delta;
                }


                Fixup++;
            }


            Reloc = (PIMAGE_BASE_RELOCATION)((DWORD_PTR)Reloc + Reloc->SizeOfBlock);
        } while (Reloc->VirtualAddress);
    }
}
Обрабатываем таблицу смещений.


Код:
VOID __fastcall process_tls(KernelProcs* Procs,PVOID ImageData)
{
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)ImageData;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);


     PIMAGE_TLS_DIRECTORY Tls = (PIMAGE_TLS_DIRECTORY)((DWORD_PTR)pDos +  pNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);


    if( Tls!=(PIMAGE_TLS_DIRECTORY)pDos )
    {
         PBYTE pTlsData =  (PBYTE)Procs->VirtualAlloc(NULL,Tls->EndAddressOfRawData -  Tls->StartAddressOfRawData,MEM_COMMIT,PAGE_READWRITE);


        if( pTlsData )
        {
            mem_copy(pTlsData,Tls->StartAddressOfRawData,Tls->EndAddressOfRawData - Tls->StartAddressOfRawData);


            Procs->TlsSetValue(Procs->TlsAlloc(),pTlsData);


            PDWORD_PTR Ptrs = (PDWORD_PTR)Procs->VirtualAlloc(NULL,1088*sizeof(DWORD_PTR),MEM_COMMIT,PAGE_READWRITE);
            if( Ptrs )
            {
                if( *(PDWORD_PTR)Tls->AddressOfIndex==-1 )
                {
                    Ptrs[0] = (DWORD_PTR)pTlsData;
                }else{
                    Ptrs[ *(PDWORD_PTR)Tls->AddressOfIndex ] = (DWORD_PTR)pTlsData;
                }


                // http://svn.netlabs.org/repos/libc/trunk/libc/include/klibc/nt/fib.h
#ifdef _WIN64
                __writegsqword(0x58,(DWORD_PTR)Ptrs);
#else
                __writefsdword(0x2C,(DWORD_PTR)Ptrs);
#endif
            }
        }
    }
}
Обрабатываем TLS колбеки.
На неумении обрабатывать TLS сыпятся очень многие крипторы.
Эта функция обрабатывает основные типы TLS колбеков и таким образом многократно увеличивает покрытие файлов с TLS.


Код:
#ifdef _WIN64
            PIMAGE_DOS_HEADER pNtdllDos = (PIMAGE_DOS_HEADER)Ntdll;
            PIMAGE_NT_HEADERS pNtdllNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)pNtdllDos + pNtdllDos->e_lfanew);


            PIMAGE_SECTION_HEADER pTextSection = IMAGE_FIRST_SECTION(pNtdllNt);


            PVOID LdrpInvertedFunctionTable = NULL;


            PBYTE stext = (PBYTE)((DWORD_PTR)pNtdllDos + pTextSection->VirtualAddress);
            for(int i = 0; i < pTextSection->Misc.VirtualSize; i++)
            {
                if( *(stext + i)==0xE8 )
                {
                    DWORD_PTR Address = (DWORD_PTR)((INT_PTR)stext + i + 5 + *(PINT32)(stext + i + 1));
                    if( Address==(DWORD_PTR)kprocs.AcquireSRWLockShared )
                    {
                        PBYTE pMov = stext + i + 5;
                        PBYTE pStart = pMov;


                        if( *pMov==0x44 ) pMov++; // mov r9d
                        if( *pMov==0x8B )
                        {
                            pMov++;


                            if( *pMov==0x0D || *pMov==0x15 )
                            {
                                pMov++;


                                 LdrpInvertedFunctionTable =  (PVOID)((INT_PTR)pStart + (pMov - (stext + i + 5)) + 4 + *(PINT32)pMov);
                                break;
                            }
                        }
                    }
                }
            }
Тут снова важный момент. Подробнее тут.


Обработка секции кода с помощью AcquireSRWLockShared, чтобы правильно готовить синхронизацию на чтение и запись.


Код:
            __debugbreak();


            if( LdrpInvertedFunctionTable )
            {
                __debugbreak();
                if( Peb->OSMajorVersion==6 && Peb->OSMinorVersion > 1 ) // 8++
                {
                    PRTL_INVERTED_FUNCTION_TABLE8 table = (PRTL_INVERTED_FUNCTION_TABLE8)LdrpInvertedFunctionTable;
                    for(int i = 0; i < table->Count; i++)
                    {
                        if( table->Entries[i].ImageBase==(PVOID)Base )
                        {
                            table->Entries[i].ImageBase = NewImageBase;
                            table->Entries[i].ImageSize = pNewNt->OptionalHeader.SizeOfImage;
                             table->Entries[i].ExceptionDirectory =  (PIMAGE_RUNTIME_FUNCTION_ENTRY)((DWORD_PTR)NewImageBase +  pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress);
                             table->Entries[i].ExceptionDirectorySize =   pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
                            break;
                        }
                    }
                }else{ // < 7
                    PRTL_INVERTED_FUNCTION_TABLE7 table = (PRTL_INVERTED_FUNCTION_TABLE7)LdrpInvertedFunctionTable;
                    for(int i = 0; i < table->Count; i++)
                    {
                        if( table->Entries[i].ImageBase==(PVOID)Base )
                        {
                            table->Entries[i].ImageBase = NewImageBase;
                            table->Entries[i].ImageSize = pNewNt->OptionalHeader.SizeOfImage;
                             table->Entries[i].ExceptionDirectory =  (PIMAGE_RUNTIME_FUNCTION_ENTRY)((DWORD_PTR)NewImageBase +  pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress);
                             table->Entries[i].ExceptionDirectorySize =   pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
                            break;
                        }
                    }
                }
            }
#endif
Правильная обработка таблицы исключений для Peb->OSMajorVersion==6 && Peb->OSMinorVersion > 1 // 8++.


Код:
#ifndef _WIN64


            // remove SAFESEH if exists
            if( pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress )
            {
                pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = NULL;
                pNewNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = NULL;
            }


            // restore seh
            PSEH_FRAME Seh = (PSEH_FRAME)__readfsdword(0);
            while( IN_DLL(Seh->Callback,Base,Base + SizeOfBase) )
            {
                Seh = Seh->Next;
            }
            __writefsdword(0,(DWORD_PTR)Seh);


            // find ebp end
            PSTACK_FRAME Ebp = (PSTACK_FRAME)read_ebp();
             while( !IN_DLL(Ebp->ReturnAddress,Kernel32,Kernel32Ends)  && !IN_DLL(Ebp->ReturnAddress,Ntdll,NtdllEnds) )
            {
                Ebp = Ebp->Next;
            }


             restore_regs(Ebp,(pNt->FileHeader.Characteristics &  IMAGE_FILE_DLL),PrologLocalVarsSize,(DWORD_PTR)NewImageBase +  pNt->OptionalHeader.AddressOfEntryPoint);
#else
            restore_regs(
                 SaveRegs,(pNt->FileHeader.Characteristics &  IMAGE_FILE_DLL),(DWORD_PTR)NewImageBase +  pNt->OptionalHeader.AddressOfEntryPoint);
#endif
        }


        kprocs.VirtualFree(SavedFile,NULL,MEM_RELEASE);
    }
}
Правильно обрабатываем SEH.


Код:
restore_regs proc EbpFrame,IsDll,PrologSize,Ep
    ; ecx - ebp
    ; edx - is dll
    ; stack - Ep
    ;int 3


    mov ecx, EbpFrame
    .if IsDll
        ; skip mov esi, esp, after all regs will restored
        add dword ptr [ecx + 4], 2
    .else
        ; msvc2008
        mov edx, ecx
        sub edx, PrologSize
        mov ebx , dword ptr [edx - 014h]
        mov esi , dword ptr [edx - 018h]
        mov edi , dword ptr [edx - 01Ch]
    .endif
   
    mov edx, Ep
   
    ; correct stack
    mov ebp, dword ptr [ecx]
    lea esp, [ecx + 4]
   
    ;int 3
    jmp edx
restore_regs endp
restore_regs - Восстанавливаем пролог, корректируем стек и переходим по точке входа в замепленномый образ.




Код:
#ifdef _WIN64
PDWORD_PTR __fastcall find_next_rsp(PDWORD_PTR regs,PDWORD_PTR Rsp)
{
    ldasm_data dasm;


    dasm.lde_flags_table = lde_get_table();
    dasm.lde_flags_table_ex = lde_get_table_ex();


    PBYTE pCode = (PBYTE)*Rsp; // return address
    DWORD len = 0;
    DWORD r11;


    Rsp = Rsp + 1;


    do
    {
        pCode = pCode + len;
   
        len = lde_length(&dasm,LDE_CPU_TYPE_X64,pCode);
        if( !len )
            return NULL;


        DWORD Step = 0;
        DWORD creg,offset;


        if( len==8 )
        {
            /*
            .text:0000000140001DB1 48 8B 84 24 98 01 00 00                       mov     rax, [rsp+198h]
            .text:0000000140001DB9 48 8B 8C 24 98 01 00 00                       mov     rcx, [rsp+198h]
            .text:0000000140001DC1 48 8B 94 24 98 01 00 00                       mov     rdx, [rsp+198h]
            .text:0000000140001DC9 48 8B 9C 24 98 01 00 00                       mov     rbx, [rsp+198h]
            .text:0000000140001DD1 48 8B A4 24 98 01 00 00                       mov     rsp, [rsp+198h]
            .text:0000000140001DD9 48 8B AC 24 98 01 00 00                       mov     rbp, [rsp+198h]
            .text:0000000140001DE1 48 8B B4 24 98 01 00 00                       mov     rsi, [rsp+198h]
            .text:0000000140001DE9 48 8B BC 24 98 01 00 00                       mov     rdi, [rsp+198h]


            .text:0000000140001DF1 4C 8B 84 24 98 01 00 00                       mov     r8, [rsp+198h]
            .text:0000000140001DF9 4C 8B 8C 24 98 01 00 00                       mov     r9, [rsp+198h]
            .text:0000000140001E01 4C 8B 94 24 98 01 00 00                       mov     r10, [rsp+198h]
            .text:0000000140001E09 4C 8B 9C 24 98 01 00 00                       mov     r11, [rsp+198h]
            .text:0000000140001E11 4C 8B A4 24 98 01 00 00                       mov     r12, [rsp+198h]
            .text:0000000140001E19 4C 8B AC 24 98 01 00 00                       mov     r13, [rsp+198h]
            .text:0000000140001E21 4C 8B B4 24 98 01 00 00                       mov     r14, [rsp+198h]
            .text:0000000140001E29 4C 8B BC 24 98 01 00 00                       mov     r15, [rsp+198h]
            */
            if( (*(PWORD)pCode==0x8B48 || *(PWORD)pCode==0x8B4C) && pCode[3]==0x24 )
            {
                if( *pCode==0x4C ) Step += r_step;


                creg   = (*(pCode + 2) - 0x84)/8;
                offset = *(PDWORD)(pCode + 4);


                regs[Step + creg] = *(PDWORD_PTR)((PBYTE)Rsp + offset);
            }
            /*
            .text:0000000140001D01 48 8D 84 24 98 01 00 00                       lea     rax, [rsp+198h]
            .text:0000000140001D09 48 8D 8C 24 98 01 00 00                       lea     rcx, [rsp+198h]
            .text:0000000140001D11 48 8D 94 24 98 01 00 00                       lea     rdx, [rsp+198h]
            .text:0000000140001D19 48 8D 9C 24 98 01 00 00                       lea     rbx, [rsp+198h]
            .text:0000000140001D21 48 8D A4 24 98 01 00 00                       lea     rsp, [rsp+198h]
            .text:0000000140001D29 48 8D AC 24 98 01 00 00                       lea     rbp, [rsp+198h]
            .text:0000000140001D31 48 8D B4 24 98 01 00 00                       lea     rsi, [rsp+198h]
            .text:0000000140001D39 48 8D BC 24 98 01 00 00                       lea     rdi, [rsp+198h]


            .text:0000000140001D41 4C 8D 84 24 98 01 00 00                       lea     r8, [rsp+198h]
            .text:0000000140001D49 4C 8D 8C 24 98 01 00 00                       lea     r9, [rsp+198h]
            .text:0000000140001D51 4C 8D 94 24 98 01 00 00                       lea     r10, [rsp+198h]
            .text:0000000140001D59 4C 8D 9C 24 98 01 00 00                       lea     r11, [rsp+198h]
            .text:0000000140001D61 4C 8D A4 24 98 01 00 00                       lea     r12, [rsp+198h]
            .text:0000000140001D69 4C 8D AC 24 98 01 00 00                       lea     r13, [rsp+198h]
            .text:0000000140001D71 4C 8D B4 24 98 01 00 00                       lea     r14, [rsp+198h]
            .text:0000000140001D79 4C 8D BC 24 98 01 00 00                       lea     r15, [rsp+198h]
            */
            if( (*(PWORD)pCode==0x8D48 || *(PWORD)pCode==0x8D4C) && pCode[3]==0x24 )
            {
                if( *pCode==0x4C ) Step += r_step;


                creg   = (*(pCode + 2) - 0x84)/8;
                offset = *(PDWORD)(pCode + 4);


                regs[Step + creg] = (DWORD_PTR)Rsp + offset;
            }
        }else if( len==5 )
        {
            /*
            .text:0000000140001D61 48 8B 44 24 11                                mov     rax, [rsp+11h]
            .text:0000000140001D66 48 8B 4C 24 11                                mov     rcx, [rsp+11h]
            .text:0000000140001D6B 48 8B 54 24 11                                mov     rdx, [rsp+11h]
            .text:0000000140001D70 48 8B 5C 24 11                                mov     rbx, [rsp+11h]
            .text:0000000140001D75 48 8B 64 24 11                                mov     rsp, [rsp+11h]
            .text:0000000140001D7A 48 8B 6C 24 11                                mov     rbp, [rsp+11h]
            .text:0000000140001D7F 48 8B 74 24 11                                mov     rsi, [rsp+11h]
            .text:0000000140001D84 48 8B 7C 24 11                                mov     rdi, [rsp+11h]


            .text:0000000140001D89 4C 8B 44 24 11                                mov     r8, [rsp+11h]
            .text:0000000140001D8E 4C 8B 4C 24 11                                mov     r9, [rsp+11h]
            .text:0000000140001D93 4C 8B 54 24 11                                mov     r10, [rsp+11h]
            .text:0000000140001D98 4C 8B 5C 24 11                                mov     r11, [rsp+11h]
            .text:0000000140001D9D 4C 8B 64 24 11                                mov     r12, [rsp+11h]
            .text:0000000140001DA2 4C 8B 6C 24 11                                mov     r13, [rsp+11h]
            .text:0000000140001DA7 4C 8B 74 24 11                                mov     r14, [rsp+11h]
            .text:0000000140001DAC 4C 8B 7C 24 11                                mov     r15, [rsp+11h]
            */
            if( (*(PWORD)pCode==0x8B48 || *(PWORD)pCode==0x8B4C) && pCode[3]==0x24 )
            {
                if( *pCode==0x4C ) Step += r_step;


                creg   = (*(pCode + 2) - 0x44)/8;
                offset = *(pCode + 4);


                regs[Step + creg] = *(PDWORD_PTR)((PBYTE)Rsp + offset);
            }
            /*
            .text:0000000140001CB1 48 8D 44 24 11                                lea     rax, [rsp+11h]
            .text:0000000140001CB6 48 8D 4C 24 11                                lea     rcx, [rsp+11h]
            .text:0000000140001CBB 48 8D 54 24 11                                lea     rdx, [rsp+11h]
            .text:0000000140001CC0 48 8D 5C 24 11                                lea     rbx, [rsp+11h]
            .text:0000000140001CC5 48 8D 64 24 11                                lea     rsp, [rsp+11h]
            .text:0000000140001CCA 48 8D 6C 24 11                                lea     rbp, [rsp+11h]
            .text:0000000140001CCF 48 8D 74 24 11                                lea     rsi, [rsp+11h]
            .text:0000000140001CD4 48 8D 7C 24 11                                lea     rdi, [rsp+11h]


            .text:0000000140001CD9 4C 8D 44 24 11                                lea     r8, [rsp+11h]
            .text:0000000140001CDE 4C 8D 4C 24 11                                lea     r9, [rsp+11h]
            .text:0000000140001CE3 4C 8D 54 24 11                                lea     r10, [rsp+11h]
            .text:0000000140001CE8 4C 8D 5C 24 11                                lea     r11, [rsp+11h]
            .text:0000000140001CED 4C 8D 64 24 11                                lea     r12, [rsp+11h]
            .text:0000000140001CF2 4C 8D 6C 24 11                                lea     r13, [rsp+11h]
            .text:0000000140001CF7 4C 8D 74 24 11                                lea     r14, [rsp+11h]
            .text:0000000140001CFC 4C 8D 7C 24 11                                lea     r15, [rsp+11h]
            */
            if( (*(PWORD)pCode==0x8D48 || *(PWORD)pCode==0x8D4C) && pCode[3]==0x24 )
            {
                if( *pCode==0x4C ) Step += r_step;


                creg   = (*(pCode + 2) - 0x44)/8;
                offset = *(pCode + 4);


                regs[Step + creg] = (DWORD_PTR)Rsp + offset;
            }
        }else if( len==1 || len==2 )
        {
            /*
            .text:0000000140001D61 58                                            pop     rax
            .text:0000000140001D62 59                                            pop     rcx
            .text:0000000140001D63 5A                                            pop     rdx
            .text:0000000140001D64 5B                                            pop     rbx
            .text:0000000140001D65 5C                                            pop     rsp
            .text:0000000140001D66 5D                                            pop     rbp
            .text:0000000140001D67 5E                                            pop     rsi
            .text:0000000140001D68 5F                                            pop     rdi
            .text:0000000140001D69 41 58                                         pop     r8
            .text:0000000140001D6B 41 59                                         pop     r9
            .text:0000000140001D6D 41 5A                                         pop     r10
            .text:0000000140001D6F 41 5B                                         pop     r11
            .text:0000000140001D71 41 5C                                         pop     r12
            .text:0000000140001D73 41 5D                                         pop     r13
            .text:0000000140001D75 41 5E                                         pop     r14
            .text:0000000140001D77 41 5F                                         pop     r15
            */
            BOOL next = FALSE;
            if( *pCode>=0x5B && *pCode<=0x5F ) // only rbp - rdi
            {
                next = true;
                creg = *pCode - 0x58;
            }else if( *pCode==0x41 && *(pCode + 1)>=0x5C && *(pCode + 1)<=0x5F) // only r12-r15
            {
                next = true;
                creg = *(pCode + 1) - 0x58;
                Step += r_step;
            }


            if( next )
            {
                regs[Step + creg] = *(PDWORD_PTR)Rsp;
                Rsp = Rsp + 1;
            }
        }else if (len==4 && *pCode==0x48 && *(PWORD)(pCode + 1)==0xC483 )
        {
            // .text:0000000140001C51 48 83 C4 28                                   add     rsp, 28h


            Rsp = (PDWORD_PTR)((PBYTE)Rsp + pCode[3]);
        }else if( len==7 && *pCode==0x48 && *(PWORD)(pCode + 1)==0xC481 )
        {
            // .text:0000000140001BE6 48 81 C4 88 00 00 00                          add     rsp, 88h


            Rsp = (PDWORD_PTR)((PBYTE)Rsp + *(PDWORD)(pCode + 3) );
        }else if( len==3 && *pCode==0x49 && *(PWORD)(pCode + 1)==0xE38B )
        {
            //.text:0000000140002680 49 8B E3                                      mov     rsp, r11
            Rsp = (PDWORD_PTR)regs[r_r11];
        }


    } while (*pCode!=0xC3);


    regs[r_rsp] = (DWORD_PTR)Rsp;


    return Rsp;
}
Для x64 PE находим Rsp.


Код:
DWORD __fastcall lde_length(ldasm_data *ld,LDE_CPU_TYPE CpuType, PVOID Memory)
{
    BYTE *p = (PBYTE)Memory;
    BYTE s, op, f;
    BYTE rexw, pr_66, pr_67;


    s = rexw = pr_66 = pr_67 = 0;


    /* dummy check */
    if (!Memory)
        return 0;


    /* init output data */
    mem_zero(ld, sizeof(ldasm_data) - sizeof(PBYTE) - sizeof(PBYTE));


    /* phase 1: parse prefixies */
    while (ld->lde_flags_table[*p] & OP_PREFIX)
    {
        if (*p == 0x66)
            pr_66 = 1;
        if (*p == 0x67)
            pr_67 = 1;


        p++; s++;
        ld->flags |= F_PREFIX;


        if (s == 15) {
            ld->flags |= F_INVALID;
            return s;
        }
    }


    /* parse REX prefix */
    if (CpuType == LDE_CPU_TYPE_X64 && *p >> 4 == 4)
    {
        ld->rex = *p;
        rexw = (ld->rex >> 3) & 1;
        ld->flags |= F_REX;
        p++; s++;
    }


    /* can be only one REX prefix */
    if (CpuType == LDE_CPU_TYPE_X64 && *p >> 4 == 4)
    {
        ld->flags |= F_INVALID;
        s++;
        return s;
    }


    /* phase 2: parse op Memory */
    ld->opcd_offset = (BYTE)(p - (BYTE*)Memory);
    ld->opcd_size = 1;
    op = *p++; s++;


    /* is 2 byte opcede? */
    if (op == 0x0F)
    {
        op = *p++; s++;
        ld->opcd_size++;
        f = ld->lde_flags_table_ex[op];
        if (f & OP_INVALID){
            ld->flags |= F_INVALID;
            return s;
        }
        /* for SSE instructions */
        if (f & OP_EXTENDED) {
            op = *p++; s++;
            ld->opcd_size++;
        }
    }
    else {
        f = ld->lde_flags_table[op];
        /* pr_66 = pr_67 for opMemorys A0-A3 */
        if (op >= 0xA0 && op <= 0xA3)
            pr_66 = pr_67;
    }


    /* phase 3: parse ModR/M, SIB and DISP */
    if (f & OP_MODRM) {
        BYTE mod = (*p >> 6);
        BYTE ro = (*p & 0x38) >> 3;
        BYTE rm = (*p & 7);


        ld->modrm = *p++; s++;
        ld->flags |= F_MODRM;


        /* in F6,F7 opMemorys immediate data present if R/O == 0 */
        if (op == 0xF6 && (ro == 0 || ro == 1))
            f |= OP_DATA_I8;
        if (op == 0xF7 && (ro == 0 || ro == 1))
            f |= OP_DATA_I16_I32_I64;


        /* is SIB byte exist? */
        if (mod != 3 && rm == 4 && !(!CpuType == LDE_CPU_TYPE_X64 && pr_67)) {
            ld->sib = *p++; s++;
            ld->flags |= F_SIB;


            /* if base == 5 and mod == 0 */
            if ((ld->sib & 7) == 5 && mod == 0) {
                ld->disp_size = 4;
            }
        }




        if (!mod)
        {
            if (CpuType == LDE_CPU_TYPE_X64) {
                if (rm == 5) {
                    ld->disp_size = 4;
                    if (CpuType == LDE_CPU_TYPE_X64)
                        ld->flags |= F_RELATIVE;
                }
            }
            else if (pr_67) {
                if (rm == 6)
                    ld->disp_size = 2;
            }
            else {
                if (rm == 5)
                    ld->disp_size = 4;
            }
        }
        else if (mod == 1)
        {
            ld->disp_size = 1;
        }
        else if (mod == 2)
        {
            if (CpuType == LDE_CPU_TYPE_X64)
                ld->disp_size = 4;
            else if (pr_67)
                ld->disp_size = 2;
            else
                ld->disp_size = 4;
        }


        if (ld->disp_size) {
            ld->disp_offset = (BYTE)(p - (BYTE *)Memory);
            p += ld->disp_size;
            s += ld->disp_size;
            ld->flags |= F_DISP;
        }
    }


    /* phase 4: parse immediate data */
    if (rexw && f & OP_DATA_I16_I32_I64)
        ld->imm_size = 8;
    else if (f & OP_DATA_I16_I32 || f & OP_DATA_I16_I32_I64)
        ld->imm_size = 4 - (pr_66 << 1);


    /* if exist, add OP_DATA_I16 and OP_DATA_I8 size */
    ld->imm_size += f & 3;


    if (ld->imm_size) {
        s += ld->imm_size;
        ld->imm_offset = (BYTE)(p - (BYTE *)Memory);
        ld->flags |= F_IMM;
        if (f & OP_RELATIVE)
            ld->flags |= F_RELATIVE;
    }


    /* instruction is too long */
    if (s > 15)
    {
        ld->flags |= F_INVALID;
        s = 0;
    }


    return s;
}
Дизассемлер длин.


Что касается преимуществ данного способа меппинга - это отсутствие вызовов, таких как порождение нового процесса или получение и смена контекста, работа с потоками, на которые могли бы триггерить проактивки.
Для более скрытного использования загрузчика можно подружить его в syscallы и будет вообще малина.


Скачать проект можно тут: https://gofile.io/d/CxBJFb
В этот раз для получения пароля на архив нужно немножко больше навыков, чем юзать онлайн encode-decode утилиты, зато интересно и по-приколу =D.


Дано массив размером 10
Инициализатор генератора случайных чисел на 0x1337 (seed).
Пароль это результат суммы всех сгенерированных случайных чисел массива в виде хэша от алгоритма whirlpool в lowercase.
На выходе должно получиться что-то вроде 5350b5db7c67126b3c910cbf2..........................................................aed190a232756b082652e4f0c0fcf333c1990ba05c7febf (всего 206 символов).
Хэш от строки в whirlpool можно получить тут https://www.tools4noobs.com/online_tools/hash/.


Пример питон скрипта который можно дописать:
Код:
import random as r
SIZE = 10
rnd_seed = int(0x1337)
r.seed(a=rnd_seed)
result = 0
array = [r.randint(1, 10) for _ in range (SIZE)]


Собирался проект на VC2010.
Для правильной работы Custom build Rules (инлайн масма) нужно скопировать файлы
"masm64.rules"
"masm32.rules"
в C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\BuildCustomizations.
Подробнее тут.


В архиве намеренно отсутствует файл get_first_section.exe - его задача вытащить сырой блок кода из секции кода, считай дампер шеллкода, но это совсем для ленивых и я не рекомендую вам использовать автоматизацию в таких случаях.
Проще загрузить собранный загрузчик в x32\x64dbg и ручками его вытащить и сохранить - это ваше домашнее задание.


Вместо заключения:
В коде сознательно присутствуют некоторые ошибки от дураков, чтобы не копипастили бездумно. Просьба не шарить исправленный.
Ответственно могу заявить, что перед вами наиболее полный из возможных, загрзчик бинариков в память на сегодняший день (не считая виндового
yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
).
Как итог, скомбинировав проект криптора из прошлой статьи с загрузчиком из этой статьи, можно получить свой полноценный криптор.
Как-нибудь в другой раз мы рассмотрим процесс морфинга шеллкода и алгоритмы и способы антиэмуляции, но это уже тема для дугой статьи
yH5BAEAAAAALAAAAAABAAEAAAIBRAA7

Спасибо за внимание.
Вложение: https://vk.cc/bVuCoH

Код:
NTSTATUS

NTAPI

LdrpLoadDll(

    ULONG Flags OPTIONAL,

    IN PWSTR DllPath OPTIONAL,

    IN PULONG DllCharacteristics OPTIONAL,

    IN PUNICODE_STRING DllName,

    OUT PVOID *DllHandle,

    IN BOOLEAN RunInitRoutines

    )

{

    PPEB Peb;

    PTEB Teb;

    NTSTATUS st;

    PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;

    PWSTR ActualDllName;

    PWCH p, pp;

    UNICODE_STRING ActualDllNameStr;

    WCHAR FreeBuffer[LDR_MAX_PATH + 1];

    BOOLEAN Redirected = ((Flags & LDRP_LOAD_DLL_FLAG_DLL_IS_REDIRECTED) != 0);

    const InLdrInit = LdrpInLdrInit;

    PVOID LockCookie = NULL;


    Peb = NtCurrentPeb();

    Teb = NtCurrentTeb();


    st = STATUS_SUCCESS;


    //

    // Except during process initializeation, grab loader lock and Snap All Links to specified DLL

    //


    if (!InLdrInit)

        RtlEnterCriticalSection(&LdrpLoaderLock);


    try {

        p = DllName->Buffer;

        pp = NULL;

        while (*p) {

            if (*p++ == (WCHAR)'.') {

                //

                // pp will point to first character after last '.'

                //

                pp = p;

                }

            }



        ActualDllName = FreeBuffer;

        if ( DllName->Length >= sizeof(FreeBuffer)) {

            return STATUS_NAME_TOO_LONG;

            }

        RtlMoveMemory(ActualDllName, DllName->Buffer, DllName->Length);



        if (!pp || *pp == (WCHAR)'\\') {

            //

            // No extension found (just ..\)

            //

            if (DllName->Length + sizeof(DllExtension) >= sizeof(FreeBuffer)) {

                DbgPrintEx(

                    DPFLTR_LDR_ID,

                    LDR_ERROR_DPFLTR,

                    "LDR: %s - Dll name missing extension; with extension added the length is too long\n"

                    "   DllName: (@ %p) \"%wZ\"\n"

                    "   DllName->Length: %u\n",

                    __FUNCTION__,

                    DllName, DllName,

                    DllName->Length);


                return STATUS_NAME_TOO_LONG;

            }


            RtlMoveMemory((PCHAR)ActualDllName+DllName->Length, DllExtension, sizeof(DllExtension));

        } else

            ActualDllName[DllName->Length >> 1] = UNICODE_NULL;


        if (ShowSnaps) {

            DbgPrint("LDR: LdrLoadDll, loading %ws from %ws\n",

                     ActualDllName,

                     ARGUMENT_PRESENT(DllPath) ? DllPath : L""

                     );

            }



        RtlInitUnicodeString(&ActualDllNameStr,ActualDllName);

        ActualDllNameStr.MaximumLength = sizeof(FreeBuffer);


        if (!LdrpCheckForLoadedDll( DllPath,

                                    &ActualDllNameStr,

                                    FALSE,

                                    Redirected,

                                    &LdrDataTableEntry)) {

            st = LdrpMapDll(DllPath,

                            ActualDllName,

                            DllCharacteristics,

                            FALSE,

                            Redirected,

                            &LdrDataTableEntry);


            if (!NT_SUCCESS(st))

                return st;


            //

            // Register dll with the stack tracing module.

            // This is used for getting reliable stack traces on X86.

            //


#if defined(_X86_)

            RtlpStkMarkDllRange (LdrDataTableEntry);

#endif


            if (ARGUMENT_PRESENT( DllCharacteristics ) &&

                *DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE) {

                LdrDataTableEntry->EntryPoint = 0;

                LdrDataTableEntry->Flags &= ~LDRP_IMAGE_DLL;

            }


            //

            // and walk the import descriptor.

            //


            if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) {


                try {

                    //

                    // if the image is COR-ILONLY, then don't walk the import descriptor

                    // as it is assumed that it only imports %windir%\system32\mscoree.dll, otherwise

                    // walk the import descriptor table of the dll.

                    //


                    if ((LdrDataTableEntry->Flags & LDRP_COR_IMAGE) == 0) {

                        st = LdrpWalkImportDescriptor(

                                  DllPath,

                                  LdrDataTableEntry

                                  );

                    }

                } __except(LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {

                    st = GetExceptionCode();

                    DbgPrintEx(

                        DPFLTR_LDR_ID,

                        LDR_ERROR_DPFLTR,

                        "LDR: %s - Exception %x thrown by LdrpWalkImportDescriptor\n",

                        __FUNCTION__,

                        st);

                }


                if ( LdrDataTableEntry->LoadCount != 0xffff )

                    LdrDataTableEntry->LoadCount++;


                LdrpReferenceLoadedDll(LdrDataTableEntry);


                if (!NT_SUCCESS(st)) {

                    LdrDataTableEntry->EntryPoint = NULL;

                    InsertTailList(

                        &NtCurrentPeb()->Ldr->InInitializationOrderModuleList,

                        &LdrDataTableEntry->InInitializationOrderLinks);


                    LdrpClearLoadInProgress();


                    if (ShowSnaps)

                        DbgPrint("LDR: Unloading %wZ due to error %x walking import descriptors\n", DllName, st);


                    LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);


                    return st;

                    }

                }

            else {

                if ( LdrDataTableEntry->LoadCount != 0xffff ) {

                    LdrDataTableEntry->LoadCount++;

                    }

                }


            //

            // Add init routine to list

            //


            InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,

                           &LdrDataTableEntry->InInitializationOrderLinks);



            //

            // If the loader data base is not fully setup, this load was because

            // of a forwarder in the static load set. Can't run init routines

            // yet because the load counts are NOT set

            //


            if ( RunInitRoutines && LdrpLdrDatabaseIsSetup ) {


                //

                // Shim engine callback. This is the chance to patch

                // dynamically loaded modules.

                //


                if (g_pfnSE_DllLoaded != NULL) {

                    (*g_pfnSE_DllLoaded)(LdrDataTableEntry);

                }


                try {


                    st = LdrpRunInitializeRoutines(NULL);

                    if ( !NT_SUCCESS(st) ) {

                        if (ShowSnaps) {

                            DbgPrint("LDR: Unloading %wZ because either its init routine or one of its static imports failed; status = 0x%08lx", DllName, st);

                        }


                        LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);

                        }

                    }

                __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {

                    st = GetExceptionCode();


                    DbgPrintEx(

                        DPFLTR_LDR_ID,

                        LDR_ERROR_DPFLTR,

                        "LDR: %s - Exception %08lx thrown running initialization routines for %wZ\n",

                        __FUNCTION__,

                        st,

                        &LdrDataTableEntry->FullDllName);


                    LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);


                    return st;

                    }

                }

            else {

                st = STATUS_SUCCESS;

                }


            }

        else {


            //

            // Count it. And everything that it imports.

            //


            if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL &&

                 LdrDataTableEntry->LoadCount != 0xffff  ) {


                LdrDataTableEntry->LoadCount++;


                LdrpReferenceLoadedDll(LdrDataTableEntry);


                //

                // Now clear the Load in progress bits

                //


                LdrpClearLoadInProgress();


                }

            else {

                if ( LdrDataTableEntry->LoadCount != 0xffff ) {

                    LdrDataTableEntry->LoadCount++;

                    }

                }

            }

        }

    __finally {

        if (!InLdrInit)

            RtlLeaveCriticalSection(&LdrpLoaderLock);

    }


    if (NT_SUCCESS(st))

        *DllHandle = (PVOID)LdrDataTableEntry->DllBase;

    else

        *DllHandle = NULL;


    return st;

}

Код:
NTSTATUS

LdrpMapDll(

    IN PWSTR DllPath OPTIONAL,

    IN PWSTR DllName,

    IN PULONG DllCharacteristics OPTIONAL,

    IN BOOLEAN StaticLink,

    IN BOOLEAN Redirected,

    OUT PLDR_DATA_TABLE_ENTRY *LdrDataTableEntry

    )


/*++


Routine Description:


    This routine maps the DLL into the users address space.


Arguments:


    DllPath - Supplies an optional search path to be used to locate the DLL.


    DllName - Supplies the name of the DLL to load.


    StaticLink - TRUE if this DLL has a static link to it.


    LdrDataTableEntry - Supplies the address of the data table entry.


Return Value:


    Status value.


--*/


{

    NTSTATUS st = STATUS_INTERNAL_ERROR;

    PVOID ViewBase = NULL;

    PTEB Teb = NtCurrentTeb();

    SIZE_T ViewSize;

    HANDLE Section, DllFile;

    UNICODE_STRING FullDllName, BaseDllName;

    UNICODE_STRING NtFileName;

    PLDR_DATA_TABLE_ENTRY Entry;

    PIMAGE_NT_HEADERS NtHeaders;

    PVOID ArbitraryUserPointer;

    BOOLEAN KnownDll;

    UNICODE_STRING CollidingDll;

    PUCHAR ImageBase, ImageBounds, ScanBase, ScanTop;

    PLDR_DATA_TABLE_ENTRY ScanEntry;

    PLIST_ENTRY ScanHead,ScanNext;

    BOOLEAN CollidingDllFound;

    NTSTATUS ErrorStatus;

    ULONG_PTR ErrorParameters[2];

    ULONG ErrorResponse;

    IMAGE_COR20_HEADER *Cor20Header;

    ULONG Cor20HeaderSize;

    BOOLEAN Cor20ILOnly = FALSE;

    PVOID OriginalViewBase;

    NTSTATUS stTemp;

    PWSTR AppCompatDllName = NULL;


    //

    // Get section handle of DLL being snapped

    //


#if LDRDBG

    if (ShowSnaps) {

        DbgPrint("LDR: LdrpMapDll: Image Name %ws, Search Path %ws\n",

                DllName,

                ARGUMENT_PRESENT(DllPath) ? DllPath : L""

                );

    }

#endif


    Entry = NULL;

    KnownDll = FALSE;

    Section = NULL;


    LdrpEnsureLoaderLockIsHeld();


    // No capturing etc. of the globals since we "know" that the loader lock is taken to synchronize access.

    if (LdrpAppCompatDllRedirectionCallbackFunction != NULL) {

        st = (*LdrpAppCompatDllRedirectionCallbackFunction)(

                0,              // Flags - reserved for the future

                DllName,

                DllPath,

                DllCharacteristics,

                LdrpAppCompatDllRedirectionCallbackData,

                &AppCompatDllName);

        if (!NT_SUCCESS(st)) {

            DbgPrintEx(

                DPFLTR_LDR_ID,

                LDR_ERROR_DPFLTR,

                "LDR: %s - call back to app compat redirection function @ %p (cb data: %p) failed with status %x\n",

                __FUNCTION__,

                LdrpAppCompatDllRedirectionCallbackFunction,

                LdrpAppCompatDllRedirectionCallbackData,

                st);


            goto Exit;

        }


        if (AppCompatDllName != NULL) {

            Redirected = TRUE;

            DllName = AppCompatDllName;

        }

    }


    if ((LdrpKnownDllObjectDirectory != NULL) && !Redirected) {

        PCWCH p = DllName;

        WCHAR wch;


        //

        // Skip the KnownDll check if this is an explicit path.

        //


        while ((wch = *p) != L'\0') {

            p++;

            if (RTL_IS_PATH_SEPARATOR(wch))

                break;

        }


        // If we hit the end of the string, there must have not been a path separator.

        if (wch == L'\0') {

            st = LdrpCheckForKnownDll(DllName, &FullDllName, &BaseDllName, &Section);

            if ((!NT_SUCCESS(st)) && (st != STATUS_DLL_NOT_FOUND)) {

                DbgPrintEx(

                    DPFLTR_LDR_ID,

                    LDR_ERROR_DPFLTR,

                    "LDR: %s - call to LdrpCheckForKnownDll(\"%ws\", ...) failed with status %x\n",

                    __FUNCTION__,

                    DllName,

                    st);


                goto Exit;

            }

        }

    }


    if (Section == NULL) {

        st = LdrpResolveDllName(DllPath, DllName, Redirected, &FullDllName, &BaseDllName, &DllFile);

        if (!NT_SUCCESS(st)) {

            if (st == STATUS_DLL_NOT_FOUND) {

                if (StaticLink) {

                    UNICODE_STRING ErrorDllName, ErrorDllPath;

                    PUNICODE_STRING ErrorStrings[2] = { &ErrorDllName, &ErrorDllPath };

                    ULONG ErrorResponse;


                    RtlInitUnicodeString(&ErrorDllName,DllName);

                    RtlInitUnicodeString(&ErrorDllPath,ARGUMENT_PRESENT(DllPath) ? DllPath : LdrpDefaultPath.Buffer);


                    NtRaiseHardError(

                        STATUS_DLL_NOT_FOUND,

                        2,              // Number of error strings

                        0x00000003,

                        (PULONG_PTR)ErrorStrings,

                        OptionOk,

                        &ErrorResponse);


                    if (LdrpInLdrInit)

                        LdrpFatalHardErrorCount++;

                }

            } else {

                DbgPrintEx(

                    DPFLTR_LDR_ID,

                    LDR_ERROR_DPFLTR,

                    "LDR: %s - call to LdrpResolveDllName on dll \"%ws\" failed with status %x\n",

                    __FUNCTION__,

                    DllName,

                    st);

            }




            goto Exit;

        }


        if (ShowSnaps) {

            PSZ type;

            PSZ type2;

            type = StaticLink ? "STATIC" : "DYNAMIC";

            type2 = Redirected ? "REDIRECTED" : "NON_REDIRECTED";


            DbgPrint(

                "LDR: Loading (%s, %s) %wZ\n",

                type,

                type2,

                &FullDllName);

        }


        if (!RtlDosPathNameToNtPathName_U(

                FullDllName.Buffer,

                &NtFileName,

                NULL,

                NULL)) {

            st = STATUS_OBJECT_PATH_SYNTAX_BAD;

            DbgPrintEx(

                DPFLTR_LDR_ID,

                LDR_ERROR_DPFLTR,

                "LDR: %s - call to RtlDosPathNameToNtPathName_U on path \"%wZ\" failed; returning status %x\n",

                __FUNCTION__,

                &FullDllName,

                st);

            goto Exit;

        }


        st = LdrpCreateDllSection(&NtFileName,

                                  DllFile,

                                  &BaseDllName,

                                  DllCharacteristics,

                                  &Section);


        if (!NT_SUCCESS(st)) {

            DbgPrintEx(

                DPFLTR_LDR_ID,

                LDR_ERROR_DPFLTR,

                "LDR: %s - LdrpCreateDllSection (%wZ) failed with status %x\n",

                __FUNCTION__,

                &NtFileName,

                st);


            LdrpFreeUnicodeString(&FullDllName);

            // We do not free BaseDllName since it's just a substring of FullDllName.


            RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);

            goto Exit;

        }

        RtlFreeHeap(RtlProcessHeap(), 0, NtFileName.Buffer);

#if DBG

        LdrpSectionCreates++;

#endif

    } else {

        KnownDll = TRUE;

    }


    ViewBase = NULL;

    ViewSize = 0;


#if DBG

    LdrpSectionMaps++;

    if (LdrpDisplayLoadTime) {

        NtQueryPerformanceCounter(&MapBeginTime, NULL);

    }

#endif


    //

    // arrange for debugger to pick up the image name

    //


    ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;

    Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;

    st = NtMapViewOfSection(

            Section,

            NtCurrentProcess(),

            (PVOID *)&ViewBase,

            0L,

            0L,

            NULL,

            &ViewSize,

            ViewShare,

            0L,

            PAGE_READWRITE

            );

    Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;


    if (!NT_SUCCESS(st)) {

        DbgPrintEx(

            DPFLTR_LDR_ID,

            LDR_ERROR_DPFLTR,

            "LDR: %s - failed to map view of section; status = %x\n",

            __FUNCTION__,

            st);


        goto Exit;

    }


    NtHeaders = RtlImageNtHeader(ViewBase);

    if ( !NtHeaders ) {

        NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);

        st = STATUS_INVALID_IMAGE_FORMAT;

        DbgPrintEx(

            DPFLTR_LDR_ID,

            LDR_ERROR_DPFLTR,

            "LDR: %s - unable to map ViewBase (%p) to image headers; failing with status %x\n",

            __FUNCTION__,

            ViewBase,

            st);

        goto Exit;

        }


#if _WIN64

    if (st != STATUS_IMAGE_NOT_AT_BASE &&

        (NtCurrentPeb()->NtGlobalFlag & FLG_LDR_TOP_DOWN) &&

        !(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)) {


        // The image was loaded at its preferred base and has relocs.  Map

        // it again using the default ViewBase.  This will collide with the

        // initial mapping, and force the mm to choose a new base address.

        // On Win64, the mm will do this top-down, forcing the DLL to

        // be mapped above 4gb if possible, to catch pointer truncations.

        PCUNICODE_STRING SystemDll;

        PVOID AlternateViewBase;

        ULONG_PTR AlternateViewSize;

        NTSTATUS AlternateSt;

        BOOLEAN LoadTopDown;


        LoadTopDown = TRUE;

        SystemDll = &User32String;

        if (RtlEqualUnicodeString(&BaseDllName, &User32String, TRUE)) {

            LoadTopDown = FALSE;

        } else {

            SystemDll = &Kernel32String;

            if (RtlEqualUnicodeString(&BaseDllName, &Kernel32String, TRUE)) {

                LoadTopDown = FALSE;

            }

        }

        if (LoadTopDown) {

            //

            // Map the image again.  It will collide with itself, and

            // the 64-bit mm will find a new base address for it,

            // working top-down

            //

            AlternateViewBase = NULL;

            AlternateViewSize = 0;

            ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;

            Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;

            AlternateSt = NtMapViewOfSection(

                    Section,

                    NtCurrentProcess(),

                    (PVOID *)&AlternateViewBase,

                    0L,

                    0L,

                    NULL,

                    &AlternateViewSize,

                    ViewShare,

                    0L,

                    PAGE_READWRITE

                    );

            Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;

            if (NT_SUCCESS(AlternateSt)) {

                //

                // Success.  Unmap the original image from the low

                // part of the address space and keep the new mapping

                // which was allocated top-down.

                //

                NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);

                ViewSize = AlternateViewSize;

                ViewBase = AlternateViewBase;

                NtHeaders = RtlImageNtHeader(ViewBase);

                st = AlternateSt;

                if ( !NtHeaders ) {

                    NtUnmapViewOfSection(NtCurrentProcess(),AlternateViewBase);

                    NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);

                    st = STATUS_INVALID_IMAGE_FORMAT;

                    goto Exit;

                }

            }

        }

    }

#endif


#if defined (BUILD_WOW6432)

    if (NtHeaders->OptionalHeader.SectionAlignment < NATIVE_PAGE_SIZE) {

        if (!NT_SUCCESS(stTemp = LdrpWx86FormatVirtualImage(&FullDllName, (PIMAGE_NT_HEADERS32)NtHeaders, ViewBase))) {

            st = stTemp;

            DbgPrintEx(

                DPFLTR_LDR_ID,

                LDR_ERROR_DPFLTR,

                "LDR: %s - Call to LdrpWx86FormatVirtualImage(%ls) failed with status 0x%08lx\n",

                __FUNCTION__,

                FullDllName.Buffer,

                st);


            goto Exit;

        }

    }

#endif


    Cor20Header = RtlImageDirectoryEntryToData(ViewBase,

                                               TRUE,

                                               IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,

                                               &Cor20HeaderSize);

    OriginalViewBase = ViewBase;


    //

    // if this is an IL_ONLY image, then validate the image now

    //


    if ((Cor20Header != NULL) &&

        ((Cor20Header->Flags & COMIMAGE_FLAGS_ILONLY) != 0)) {

        

        // This is wacky but code later on depends on the fact that st *was* STATUS_IMAGE_MACHINE_TYPE_MISMATCH

        // and got overwritten with STATUS_SUCCESS.  This in effect means that COR images can never have

        // relocation information.  -mgrier 5/21/2001, XP Bug #400007.

        st = LdrpCheckCorImage (Cor20Header,

                                &FullDllName,

                                &ViewBase,

                                &Cor20ILOnly);


        if (!NT_SUCCESS(st))

            goto Exit;

    }



#if DBG

    if (LdrpDisplayLoadTime) {

        NtQueryPerformanceCounter(&MapEndTime, NULL);

        MapElapsedTime.QuadPart = MapEndTime.QuadPart - MapBeginTime.QuadPart;

        DbgPrint("Map View of Section Time %ld %ws\n", MapElapsedTime.LowPart, DllName);

    }

#endif


    //

    // Allocate a data table entry.

    //


    Entry = LdrpAllocateDataTableEntry(ViewBase);


    if (!Entry) {

        DbgPrintEx(

            DPFLTR_LDR_ID,

            LDR_ERROR_DPFLTR,

            "LDR: %s - failed to allocate new data table entry for %p\n",

            __FUNCTION__,

            ViewBase);


        st = STATUS_NO_MEMORY;

        goto Exit;

    }


    Entry->Flags = 0;


    if (StaticLink)

        Entry->Flags |= LDRP_STATIC_LINK;


    if (Redirected)

        Entry->Flags |= LDRP_REDIRECTED;


    Entry->LoadCount = 0;


    Entry->FullDllName = FullDllName;

    FullDllName.Length = 0;

    FullDllName.MaximumLength = 0;

    FullDllName.Buffer = NULL;


    Entry->BaseDllName = BaseDllName;

    BaseDllName.Length = 0;

    BaseDllName.MaximumLength = 0;

    BaseDllName.Buffer = NULL;


    Entry->EntryPoint = LdrpFetchAddressOfEntryPoint(Entry->DllBase);


#if LDRDBG

    if (ShowSnaps)

        DbgPrint(

            "LDR: LdrpMapDll: Full Name %wZ, Base Name %wZ\n",

            &Entry->FullDllName,

            &Entry->BaseDllName);

#endif


    LdrpInsertMemoryTableEntry(Entry);


    LdrpSendDllLoadedNotifications(Entry, (st == STATUS_IMAGE_NOT_AT_BASE) ? LDR_DLL_LOADED_FLAG_RELOCATED : 0);


    if ( st == STATUS_IMAGE_MACHINE_TYPE_MISMATCH ) {


        PIMAGE_NT_HEADERS ImageHeader = RtlImageNtHeader( NtCurrentPeb()->ImageBaseAddress );


        //

        // apps compiled for NT 3.x and below can load cross architecture

        // images

        //


        ErrorStatus = STATUS_SUCCESS;

        ErrorResponse = ResponseCancel;


        if ( ImageHeader->OptionalHeader.MajorSubsystemVersion <= 3 ) {


            Entry->EntryPoint = 0;


            //

            // Hard Error Time

            //


            //

            // Its error time...

            //


            ErrorParameters[0] = (ULONG_PTR)&FullDllName;


            ErrorStatus = NtRaiseHardError(

                            STATUS_IMAGE_MACHINE_TYPE_MISMATCH,

                            1,

                            1,

                            ErrorParameters,

                            OptionOkCancel,

                            &ErrorResponse

                            );

            }

        if ( NT_SUCCESS(ErrorStatus) && ErrorResponse == ResponseCancel ) {



#if defined(_AMD64_) // || defined(_IA64_)



            RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable,

                                           Entry->DllBase);


#endif


            RemoveEntryList(&Entry->InLoadOrderLinks);

            RemoveEntryList(&Entry->InMemoryOrderLinks);

            RemoveEntryList(&Entry->HashLinks);

            LdrpDeallocateDataTableEntry(Entry);


            if ( ImageHeader->OptionalHeader.MajorSubsystemVersion <= 3 ) {

                if ( LdrpInLdrInit ) {

                    LdrpFatalHardErrorCount++;

                    }

                }

            st = STATUS_INVALID_IMAGE_FORMAT;

            goto Exit;

            }

        }

    else {

        if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) {

            Entry->Flags |= LDRP_IMAGE_DLL;

            }


        if (!(Entry->Flags & LDRP_IMAGE_DLL)) {

            Entry->EntryPoint = 0;

            }

        }


    *LdrDataTableEntry = Entry;


    if (st == STATUS_IMAGE_NOT_AT_BASE) {


        Entry->Flags |= LDRP_IMAGE_NOT_AT_BASE;


        //

        // now find the colliding dll. If we can not find a dll,

        // then the colliding dll must be dynamic memory

        //


        ImageBase = (PUCHAR)NtHeaders->OptionalHeader.ImageBase;

        ImageBounds = ImageBase + ViewSize;


        CollidingDllFound = FALSE;


        ScanHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;

        ScanNext = ScanHead->Flink;


        while ( ScanNext != ScanHead ) {

            ScanEntry = CONTAINING_RECORD(ScanNext, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);

            ScanNext = ScanNext->Flink;


            ScanBase = (PUCHAR)ScanEntry->DllBase;

            ScanTop = ScanBase + ScanEntry->SizeOfImage;


            //

            // when we unload, the memory order links flink field is nulled.

            // this is used to skip the entry pending list removal.

            //


            if ( !ScanEntry->InMemoryOrderLinks.Flink ) {

                continue;

                }


            //

            // See if the base address of the scan image is within the relocating dll

            // or if the top address of the scan image is within the relocating dll

            //


            if ( (ImageBase >= ScanBase && ImageBase <= ScanTop)


                 ||


                 (ImageBounds >= ScanBase && ImageBounds <= ScanTop)


                 ||


                 (ScanBase >= ImageBase && ScanBase <= ImageBounds)


                 ){


                CollidingDllFound = TRUE;

                CollidingDll = ScanEntry->FullDllName;

                break;

                }

            }


        if ( !CollidingDllFound ) {

            RtlInitUnicodeString(&CollidingDll, L"Dynamically Allocated Memory");

            }


#if DBG

        if ( BeginTime.LowPart || BeginTime.HighPart ) {

            DbgPrint(

                "\nLDR: %s Relocating Image Name %ws\n",

                __FUNCTION__,

                DllName

                );

        }

        LdrpSectionRelocates++;

#endif


        if (Entry->Flags & LDRP_IMAGE_DLL) {


            BOOLEAN AllowRelocation;

            PCUNICODE_STRING SystemDll;


            if (!(NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)) {

                PVOID pBaseRelocs;

                ULONG BaseRelocCountBytes = 0;


                //

                // If the image doesn't have the reloc stripped bit set and there's no

                // relocs in the data directory, allow this through.  This is probably

                // a pure forwarder dll or data w/o relocs.

                //


                pBaseRelocs = RtlImageDirectoryEntryToData(

                        ViewBase, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &BaseRelocCountBytes);


                if (!pBaseRelocs && !BaseRelocCountBytes)

                    goto NoRelocNeeded;

            }


            //

            // decide whether or not to allow the relocation

            // certain system dll's like user32 and kernel32 are not relocatable

            // since addresses within these dll's are not always stored per process

            // do not allow these dll's to be relocated

            //


            AllowRelocation = TRUE;

            SystemDll = &User32String;

            if ( RtlEqualUnicodeString(&Entry->BaseDllName, SystemDll, TRUE)) {

                AllowRelocation = FALSE;

            } else {

                SystemDll = &Kernel32String;

                if (RtlEqualUnicodeString(&Entry->BaseDllName, SystemDll, TRUE))

                    AllowRelocation = FALSE;

            }


            if ( !AllowRelocation && KnownDll ) {


                //

                // totally disallow the relocation since this is a knowndll

                // that matches our system binaries and is being relocated

                //


                //

                // Hard Error Time

                //


                ErrorParameters[0] = (ULONG_PTR)SystemDll;

                ErrorParameters[1] = (ULONG_PTR)&CollidingDll;


                NtRaiseHardError(

                    STATUS_ILLEGAL_DLL_RELOCATION,

                    2,

                    3,

                    ErrorParameters,

                    OptionOk,

                    &ErrorResponse);


                if ( LdrpInLdrInit ) {

                    LdrpFatalHardErrorCount++;

                }


                st = STATUS_CONFLICTING_ADDRESSES;

                goto skipreloc;

            }


            st = LdrpSetProtection(ViewBase, FALSE, StaticLink );

            if (NT_SUCCESS(st)) {

                __try {

                    st = LdrRelocateImage(ViewBase,

                                "LDR",

                                STATUS_SUCCESS,

                                STATUS_CONFLICTING_ADDRESSES,

                                STATUS_INVALID_IMAGE_FORMAT);

                } __except (LdrpGenericExceptionFilter(GetExceptionInformation(), __FUNCTION__)) {

                    st = GetExceptionCode();

                }


                if (NT_SUCCESS(st)) {

                    //

                    // If we did relocations, then map the section again.

                    // this will force the debug event

                    //


                    //

                    // arrange for debugger to pick up the image name

                    //


                    ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;

                    Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;


                    st = NtMapViewOfSection(

                        Section,

                        NtCurrentProcess(),

                        (PVOID *)&ViewBase,

                        0L,

                        0L,

                        NULL,

                        &ViewSize,

                        ViewShare,

                        0L,

                        PAGE_READWRITE);


                    if ((st != STATUS_CONFLICTING_ADDRESSES) && !NT_SUCCESS(st)) {

                        DbgPrintEx(

                            DPFLTR_LDR_ID,

                            LDR_ERROR_DPFLTR,

                            "[%x,%x] LDR: Failed to map view of section; ntstatus = %x\n",

                            HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),

                            HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),

                            st);


                        goto Exit;

                    }


                    Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;


                    st = LdrpSetProtection(ViewBase, TRUE, StaticLink);

                }

            }

skipreloc:

            //

            // if the set protection failed, or if the relocation failed, then

            // remove the partially loaded dll from the lists and clear entry

            // that it has been freed.

            //


            if ( !NT_SUCCESS(st) ) {


#if defined(_AMD64_) // || defined(_IA64_)



                RtlRemoveInvertedFunctionTable(&LdrpInvertedFunctionTable,

                                               Entry->DllBase);


#endif


                RemoveEntryList(&Entry->InLoadOrderLinks);

                RemoveEntryList(&Entry->InMemoryOrderLinks);

                RemoveEntryList(&Entry->HashLinks);

                if (ShowSnaps) {

                    DbgPrint("LDR: Fixups unsuccessfully re-applied @ %p\n",

                           ViewBase);

                }

                goto Exit;

            }


            if (ShowSnaps) {               

                DbgPrint("LDR: Fixups successfully re-applied @ %p\n",

                       ViewBase);               

            }

        } else {

NoRelocNeeded:

            st = STATUS_SUCCESS;


            //

            // arrange for debugger to pick up the image name

            //


            ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;

            Teb->NtTib.ArbitraryUserPointer = (PVOID)FullDllName.Buffer;


            st = NtMapViewOfSection(

                Section,

                NtCurrentProcess(),

                (PVOID *)&ViewBase,

                0L,

                0L,

                NULL,

                &ViewSize,

                ViewShare,

                0L,

                PAGE_READWRITE

                );

            Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;


            // If the thing was relocated, we get back the failure status STATUS_CONFLICTING_ADDRESSES

            // but of all the strange things, the relocations aren't done.  I have questions in to folks

            // asking about this behavior but who knows how many legacy apps depend on dlls that statically

            // link to EXEs which from time to time are not loaded at their default addresses.  -mgrier 4/9/2001

            if ((st != STATUS_CONFLICTING_ADDRESSES) && !NT_SUCCESS(st))

                DbgPrintEx(

                    DPFLTR_LDR_ID,

                    LDR_ERROR_DPFLTR,

                    "[%x,%x] LDR: %s - NtMapViewOfSection on no reloc needed dll failed with status %x\n",

                    HandleToULong(NtCurrentTeb()->ClientId.UniqueProcess),

                    HandleToULong(NtCurrentTeb()->ClientId.UniqueThread),

                    __FUNCTION__,

                    st);

            else

                st = STATUS_SUCCESS;


            if (ShowSnaps)

                DbgPrint("LDR: Fixups won't be re-applied to non-Dll @ %p\n", ViewBase);

        }

    }


    //

    // if this is NOT an IL_ONLY image, then validate the image now after applying the

    // fixups

    //


    if ((Cor20Header != NULL) &&

        ((Cor20Header->Flags & COMIMAGE_FLAGS_ILONLY) == 0)) {

        

        st = LdrpCheckCorImage (Cor20Header,

                                &FullDllName,

                                &ViewBase,

                                &Cor20ILOnly);

        if (!NT_SUCCESS (st)) {

            goto Exit;

        }

    }


    if (Cor20ILOnly) {

        Entry->Flags |= LDRP_COR_IMAGE;

    }


    if (ViewBase != OriginalViewBase) {

        Entry->Flags |= LDRP_COR_OWNS_UNMAP;

    }


#if defined (_ALPHA_)

    //

    // Find and apply Alpha architecture fixups for this dll

    //

    if (Entry->Flags & LDRP_IMAGE_DLL)

        AlphaFindArchitectureFixups(NtHeaders, ViewBase, StaticLink);

#endif


#if defined(_X86_)

    if ( LdrpNumberOfProcessors > 1 && (Entry->Flags & LDRP_IMAGE_DLL) ) {

        LdrpValidateImageForMp(Entry);

        }

#endif


    ViewBase = NULL;


Exit:

    if (ViewBase != NULL) {

        if (Cor20ILOnly)

            LdrpCorUnloadImage(ViewBase);


        if (ViewBase == OriginalViewBase)

            NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);

    }


    if (Section != NULL)

        NtClose(Section);


    if (AppCompatDllName != NULL)

        (*RtlFreeStringRoutine)(AppCompatDllName);


    if (FullDllName.Buffer != NULL)

        LdrpFreeUnicodeString(&FullDllName);


#if DBG

    if (!NT_SUCCESS(st) && (ShowSnaps || st != STATUS_DLL_NOT_FOUND))

        DbgPrint("LDR: %s(%ws) failing 0x%lx\n", __FUNCTION__, DllName, st);

#endif


    return st;

}


NTSTATUS
LdrpInitializeProcess (
    IN PCONTEXT Context OPTIONAL,
    IN PVOID SystemDllBase,
    IN PUNICODE_STRING UnicodeImageName,
    IN BOOLEAN UseCOR,
    IN BOOLEAN ImageFileOptionsPresent
    )

/*++

Routine Description:

    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

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.

    SystemDllBase - Supplies the base address of the system dll.

    UnicodeImageName - Base name + extension of the image

    UseCOR - TRUE if the image is a COM+ runtime image, FALSE otherwise

    ImageFileOptionsPresent - Hint about existing any ImageFileExecutionOption key.
            If the key is missing the ApplicationCompatibilityGoo and
            DebugProcessHeapOnly entries won't be checked again.

Return Value:

    Status value

--*/

{
    PPEB Peb;
    NTSTATUS st;
    PWCH p, pp;
    UNICODE_STRING CurDir;
    UNICODE_STRING FullImageName;
    UNICODE_STRING CommandLine;
    ULONG DebugProcessHeapOnly = 0 ;
    HANDLE LinkHandle;
    static WCHAR SystemDllPathBuffer[DOS_MAX_PATH_LENGTH];
    UNICODE_STRING SystemDllPath;
    PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    UNICODE_STRING Unicode;
    OBJECT_ATTRIBUTES Obja;
    BOOLEAN StaticCurDir = FALSE;
    ULONG i;
    PIMAGE_NT_HEADERS NtHeader;
    PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
    ULONG ProcessHeapFlags;
    RTL_HEAP_PARAMETERS HeapParameters;
    NLSTABLEINFO InitTableInfo;
    LARGE_INTEGER LongTimeout;
    UNICODE_STRING NtSystemRoot;
    LONG_PTR Diff;
    ULONG_PTR OldBase;
    PWSTR pw ;
    PVOID pAppCompatExeData;

    UNICODE_STRING ImagePathName; // for .local dll redirection, xwu
    PWCHAR ImagePathNameBuffer = NULL;
    BOOL DotLocalExists = FALSE;

    typedef NTSTATUS (NTAPI * PKERNEL32_PROCESS_INIT_POST_IMPORT_FUNCTION)();
    PKERNEL32_PROCESS_INIT_POST_IMPORT_FUNCTION Kernel32ProcessInitPostImportFunction = NULL;
    const ANSI_STRING Kernel32ProcessInitPostImportFunctionName = RTL_CONSTANT_STRING("BaseProcessInitPostImport");

    LDRP_CHECKPOINT();

    NtDllBase = SystemDllBase;

    Peb = NtCurrentPeb();
    NtHeader = RtlImageNtHeader( Peb->ImageBaseAddress );

    if (!NtHeader) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - failing because we were unable to map the image base address (%p) to the PIMAGE_NT_HEADERS\n",
            __FUNCTION__,
            Peb->ImageBaseAddress);

        return STATUS_INVALID_IMAGE_FORMAT;
    }

    LDRP_CHECKPOINT();

    if (
#if defined(_WIN64)
        NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC &&
#endif
        NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE ) {

        //
        // Native subsystems load slower, but validate their DLLs
        // This is to help CSR detect bad images faster
        //

        LdrpVerifyDlls = TRUE;

        }

    //
    // capture app compat data and clear shim data field
    //

#if defined(_WIN64)
    //
    // If this is an x86 image, then let 32-bit ntdll read
    // and reset the appcompat pointer
    //

    if (UseWOW64 == FALSE)
#endif
    {
        pAppCompatExeData = Peb->pShimData;
        Peb->pShimData = NULL;
    }

#if defined(BUILD_WOW6432)
    {
        //
        // The process is running in WOW64.  Sort out the optional header
        // format and reformat the image if its page size is smaller than
        // the native page size.
        //
        PIMAGE_NT_HEADERS32 NtHeader32 = (PIMAGE_NT_HEADERS32)NtHeader;

        st = STATUS_SUCCESS;

        if (NtHeader32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386 &&
            NtHeader32->OptionalHeader.SectionAlignment < NATIVE_PAGE_SIZE &&
            !NT_SUCCESS(st = LdrpWx86FormatVirtualImage(NULL,
                                 NtHeader32,
                                 Peb->ImageBaseAddress
                                 ))) {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - failing wow64 process initialization because:\n"
                "   FileHeader.Machine (%u) != IMAGE_FILE_MACHINE_I386 (%u) or\n"
                "   OptionalHeader.SectionAlignment (%u) >= NATIVE_PAGE_SIZE (%u) or\n"
                "   LdrpWxFormatVirtualImage failed (ntstatus %x)\n",
                __FUNCTION__,
                NtHeader32->FileHeader.Machine, IMAGE_FILE_MACHINE_I386,
                NtHeader32->OptionalHeader.SectionAlignment, NATIVE_PAGE_SIZE,
                st);

            if (st == STATUS_SUCCESS)
                st = STATUS_INVALID_IMAGE_FORMAT;

            return st;
        }
    }
#endif

    LdrpNumberOfProcessors = Peb->NumberOfProcessors;
    RtlpTimeout = Peb->CriticalSectionTimeout;
    LongTimeout.QuadPart = Int32x32To64( 3600, -10000000 );

    if (ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters)) {
        FullImageName = ProcessParameters->ImagePathName;
        CommandLine = ProcessParameters->CommandLine;
    } else {
        RtlInitEmptyUnicodeString(&FullImageName, NULL, 0);
        RtlInitEmptyUnicodeString(&CommandLine, NULL, 0);
    }

    LDRP_CHECKPOINT();

    RtlInitNlsTables(
        Peb->AnsiCodePageData,
        Peb->OemCodePageData,
        Peb->UnicodeCaseTableData,
        &InitTableInfo);

    RtlResetRtlTranslations(&InitTableInfo);

#if defined(_WIN64)
    if (UseWOW64 || UseCOR) {
        //
        // Ignore image config data when initializing the 64-bit loader.
        // The 32-bit loader in ntdll32 will look at the config data
        // and do the right thing.
        //
        ImageConfigData = NULL;
    } else
#endif
    {

        ImageConfigData = RtlImageDirectoryEntryToData( Peb->ImageBaseAddress,
                                                        TRUE,
                                                        IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
                                                        &i
                                                      );
    }

    RtlZeroMemory( &HeapParameters, sizeof( HeapParameters ) );
    ProcessHeapFlags = HEAP_GROWABLE | HEAP_CLASS_0;
    HeapParameters.Length = sizeof( HeapParameters );
    if (ImageConfigData != NULL && i == sizeof( *ImageConfigData )) {
        Peb->NtGlobalFlag &= ~ImageConfigData->GlobalFlagsClear;
        Peb->NtGlobalFlag |= ImageConfigData->GlobalFlagsSet;

        if (ImageConfigData->CriticalSectionDefaultTimeout != 0) {
            //
            // Convert from milliseconds to NT time scale (100ns)
            //
            RtlpTimeout.QuadPart = Int32x32To64( (LONG)ImageConfigData->CriticalSectionDefaultTimeout,
                                                 -10000);

            }

        if (ImageConfigData->ProcessHeapFlags != 0) {
            ProcessHeapFlags = ImageConfigData->ProcessHeapFlags;
            }

        if (ImageConfigData->DeCommitFreeBlockThreshold != 0) {
            HeapParameters.DeCommitFreeBlockThreshold = ImageConfigData->DeCommitFreeBlockThreshold;
            }

        if (ImageConfigData->DeCommitTotalFreeThreshold != 0) {
            HeapParameters.DeCommitTotalFreeThreshold = ImageConfigData->DeCommitTotalFreeThreshold;
            }

        if (ImageConfigData->MaximumAllocationSize != 0) {
            HeapParameters.MaximumAllocationSize = ImageConfigData->MaximumAllocationSize;
            }

        if (ImageConfigData->VirtualMemoryThreshold != 0) {
            HeapParameters.VirtualMemoryThreshold = ImageConfigData->VirtualMemoryThreshold;
            }
        }

//    //
//    // Check if the image has the fast heap flag set
//    //
//
//    if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_FAST_HEAP) {
//        RtlpDisableHeapLookaside = 0;
//    } else {
//        RtlpDisableHeapLookaside = 1;
//    }

    LDRP_CHECKPOINT();

    ShowSnaps = ((FLG_SHOW_LDR_SNAPS & Peb->NtGlobalFlag) != 0);

    //
    // This field is non-zero if the image file that was used to create this
    // process contained a non-zero value in its image header.  If so, then
    // set the affinity mask for the process using this value.  It could also
    // be non-zero if the parent process created us suspended and poked our
    // PEB with a non-zero value before resuming.
    //
    if (Peb->ImageProcessAffinityMask) {
        st = NtSetInformationProcess( NtCurrentProcess(),
                                      ProcessAffinityMask,
                                      &Peb->ImageProcessAffinityMask,
                                      sizeof( Peb->ImageProcessAffinityMask )
                                    );
        if (NT_SUCCESS( st )) {
            KdPrint(( "LDR: Using ProcessAffinityMask of 0x%Ix from image.\n",
                      Peb->ImageProcessAffinityMask
                   ));
            }
        else {
            KdPrint(( "LDR: Failed to set ProcessAffinityMask of 0x%Ix from image (Status == %08x).\n",
                      Peb->ImageProcessAffinityMask, st
                   ));
            }
        }

    if (RtlpTimeout.QuadPart < LongTimeout.QuadPart) {
        RtlpTimoutDisable = TRUE;
        }

    if (ShowSnaps) {
        DbgPrint( "LDR: PID: 0x%x started - '%wZ'\n",
                  NtCurrentTeb()->ClientId.UniqueProcess,
                  &CommandLine
                );
    }

    LDRP_CHECKPOINT();

    for(i=0;i<LDRP_HASH_TABLE_SIZE;i++) {
        InitializeListHead(&LdrpHashTable[i]);
    }

    //
    // Initialize the critical section package.
    //

    LDRP_CHECKPOINT();

    st = RtlpInitDeferedCriticalSection();
    if (!NT_SUCCESS (st)) {
        return st;
    }

    Peb->TlsBitmap = (PVOID)&TlsBitMap;
    Peb->TlsExpansionBitmap = (PVOID)&TlsExpansionBitMap;

    RtlInitializeBitMap (
        &TlsBitMap,
        &Peb->TlsBitmapBits[0],
        RTL_BITS_OF(Peb->TlsBitmapBits)
        );

    RtlInitializeBitMap (
        &TlsExpansionBitMap,
        &Peb->TlsExpansionBitmapBits[0],
        RTL_BITS_OF(Peb->TlsExpansionBitmapBits)
        );

    InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);

    LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
    LoaderLockInitialized = TRUE;

    LDRP_CHECKPOINT();

    //
    // Initialize the stack trace data base if requested
    //

    if ((Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
        || LdrpShouldCreateStackTraceDb) {

        PVOID BaseAddress = NULL;
        SIZE_T ReserveSize = 8 * RTL_MEG;

        st = LdrQueryImageFileExecutionOptions(UnicodeImageName,
                                               L"StackTraceDatabaseSizeInMb",
                                               REG_DWORD,
                                               &ReserveSize,
                                               sizeof(ReserveSize),
                                               NULL
                                               );

        //
        // Sanity check the value read from registry.
        //

        if (! NT_SUCCESS(st)) {
            ReserveSize = 8 * RTL_MEG;
        }
        else {
            if (ReserveSize < 8) {
                ReserveSize = 8 * RTL_MEG;
            }
            else  if (ReserveSize > 128) {
                ReserveSize = 128 * RTL_MEG;
            }
            else {
                ReserveSize *=  RTL_MEG;
            }

            DbgPrint( "LDR: Stack trace database size is %u Mb \n", ReserveSize / RTL_MEG);
        }

        st = NtAllocateVirtualMemory( NtCurrentProcess(),
            (PVOID *)&BaseAddress,
            0,
            &ReserveSize,
            MEM_RESERVE,
            PAGE_READWRITE);
        if (NT_SUCCESS(st)) {
            st = RtlInitializeStackTraceDataBase( BaseAddress,
                0,
                ReserveSize
                );
            if ( !NT_SUCCESS( st ) ) {
                NtFreeVirtualMemory( NtCurrentProcess(),
                    (PVOID *)&BaseAddress,
                    &ReserveSize,
                    MEM_RELEASE
                    );
            }
            else {

                //
                // If the stack trace db is not created due to page heap
                // enabling then we can set the NT heap debugging flags.
                // If we create it due to page heap then we should not
                // enable these flags because page heap and NT debug heap
                // do not coexist peacefully.
                //

                if (! LdrpShouldCreateStackTraceDb) {
                    Peb->NtGlobalFlag |= FLG_HEAP_VALIDATE_PARAMETERS;
                }
            }
        }
    }

    //
    // Initialize the loader data based in the PEB.
    //

    st = RtlInitializeCriticalSection(&FastPebLock);
    if ( !NT_SUCCESS(st) ) {
        return st;
        }

    st = RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
    if ( !NT_SUCCESS(st) ) {
        return st;
        }

    //
    // Initialize the Wmi stuff.
    //

    WmipInitializeDll();

    InitializeListHead(&RtlpCalloutEntryList);

#if defined(_AMD64_) || defined(_IA64_)

    InitializeListHead(&RtlpDynamicFunctionTable);

#endif

    InitializeListHead(&LdrpDllNotificationList);

    Peb->FastPebLock = &FastPebLock;
    Peb->FastPebLockRoutine = (PVOID)&RtlEnterCriticalSection;
    Peb->FastPebUnlockRoutine = (PVOID)&RtlLeaveCriticalSection;

    LDRP_CHECKPOINT();

    RtlInitializeHeapManager();

    LDRP_CHECKPOINT();

#if defined(_WIN64)
    if ((UseWOW64) ||
        (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {

        //
        // Create a heap using all defaults.  The 32-bit process heap
        // will be created later by ntdll32 using the parameters from the exe.
        //
        Peb->ProcessHeap = RtlCreateHeap( ProcessHeapFlags,
                                          NULL,
                                          0,
                                          0,
                                          NULL,
                                          &HeapParameters
                                        );
    } else
#endif
    {

        if (NtHeader->OptionalHeader.MajorSubsystemVersion <= 3 &&
            NtHeader->OptionalHeader.MinorSubsystemVersion < 51
           ) {
            ProcessHeapFlags |= HEAP_CREATE_ALIGN_16;
            }

        Peb->ProcessHeap = RtlCreateHeap( ProcessHeapFlags,
                                          NULL,
                                          NtHeader->OptionalHeader.SizeOfHeapReserve,
                                          NtHeader->OptionalHeader.SizeOfHeapCommit,
                                          NULL,             // Lock to use for serialization
                                          &HeapParameters);
    }

    if (Peb->ProcessHeap == NULL) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - unable to create process heap\n",
            __FUNCTION__);

        return STATUS_NO_MEMORY;
    }

    {
        //
        // Create the loader private heap.
        //
        RTL_HEAP_PARAMETERS LdrpHeapParameters;
        RtlZeroMemory( &LdrpHeapParameters, sizeof(LdrpHeapParameters));
        LdrpHeapParameters.Length = sizeof(LdrpHeapParameters);
        LdrpHeap = RtlCreateHeap(
                        HEAP_GROWABLE | HEAP_CLASS_1,
                        NULL,
                        64 * 1024, // 0 is ok here, 64k is a chosen tuned number
                        24 * 1024, // 0 is ok here, 24k is a chosen tuned number
                        NULL,
                        &LdrpHeapParameters);

        if (LdrpHeap == NULL) {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s failing process initialization due to inability to create loader private heap.\n",
                __FUNCTION__);
            return STATUS_NO_MEMORY;
        }
    }
    LDRP_CHECKPOINT();

    NtdllBaseTag = RtlCreateTagHeap( Peb->ProcessHeap,
                                     0,
                                     L"NTDLL!",
                                     L"!Process\0"                  // Heap Name
                                     L"CSRSS Client\0"
                                     L"LDR Database\0"
                                     L"Current Directory\0"
                                     L"TLS Storage\0"
                                     L"DBGSS Client\0"
                                     L"SE Temporary\0"
                                     L"Temporary\0"
                                     L"LocalAtom\0"
                                   );

    RtlInitializeAtomPackage( MAKE_TAG( ATOM_TAG ) );

    LDRP_CHECKPOINT();

    //
    // Allow only the process heap to have page allocations turned on
    //

    if (ImageFileOptionsPresent) {

        st = LdrQueryImageFileExecutionOptions( UnicodeImageName,
                                                L"DebugProcessHeapOnly",
                                                REG_DWORD,
                                                &DebugProcessHeapOnly,
                                                sizeof( DebugProcessHeapOnly ),
                                                NULL
                                              );
        if (NT_SUCCESS( st )) {
            if ( RtlpDebugPageHeap &&
                 ( DebugProcessHeapOnly != 0 ) ) {

                RtlpDebugPageHeap = FALSE ;
            }
        }
    }

    LDRP_CHECKPOINT();

    SystemDllPath.Buffer = SystemDllPathBuffer;
    SystemDllPath.Length = 0;
    SystemDllPath.MaximumLength = sizeof(SystemDllPathBuffer);

    RtlInitUnicodeString( &NtSystemRoot, USER_SHARED_DATA->NtSystemRoot );
    RtlAppendUnicodeStringToString( &SystemDllPath, &NtSystemRoot );
    RtlAppendUnicodeToString( &SystemDllPath, L"\\System32\\" );

    RtlInitUnicodeString(&Unicode, L"\\KnownDlls");
    InitializeObjectAttributes( &Obja,
                                  &Unicode,
                                  OBJ_CASE_INSENSITIVE,
                                  NULL,
                                  NULL
                                );
    st = NtOpenDirectoryObject(
            &LdrpKnownDllObjectDirectory,
            DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
            &Obja);
    if ( !NT_SUCCESS(st) ) {
        LdrpKnownDllObjectDirectory = NULL;
        // KnownDlls directory doesn't exist - assume it's system32.
        RtlInitUnicodeString(&LdrpKnownDllPath, SystemDllPath.Buffer);
        LdrpKnownDllPath.Length -= sizeof(WCHAR);    // remove trailing '\'
    } else {

        //
        // Open up the known dll pathname link
        // and query its value
        //

        RtlInitUnicodeString(&Unicode, L"KnownDllPath");
        InitializeObjectAttributes( &Obja,
                                      &Unicode,
                                      OBJ_CASE_INSENSITIVE,
                                      LdrpKnownDllObjectDirectory,
                                      NULL
                                    );
        st = NtOpenSymbolicLinkObject( &LinkHandle,
                                       SYMBOLIC_LINK_QUERY,
                                       &Obja
                                     );
        if (NT_SUCCESS( st )) {
            LdrpKnownDllPath.Length = 0;
            LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
            LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
            st = NtQuerySymbolicLinkObject( LinkHandle,
                                            &LdrpKnownDllPath,
                                            NULL
                                          );
            NtClose(LinkHandle);
            if ( !NT_SUCCESS(st) ) {
                DbgPrintEx(
                    DPFLTR_LDR_ID,
                    LDR_ERROR_DPFLTR,
                    "LDR: %s - failed call to NtQuerySymbolicLinkObject with status %x\n",
                    __FUNCTION__,
                    st);

                return st;
            }
        } else {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - failed call to NtOpenSymbolicLinkObject with status %x\n",
                __FUNCTION__,
                st);
            return st;
        }
    }

    LDRP_CHECKPOINT();

    if (ProcessParameters) {

        //
        // If the process was created with process parameters,
        // then extract:
        //
        //      - Library Search Path
        //
        //      - Starting Current Directory
        //

        if (ProcessParameters->DllPath.Length)
            LdrpDefaultPath = ProcessParameters->DllPath;
        else
            LdrpInitializationFailure(STATUS_INVALID_PARAMETER);

        StaticCurDir = TRUE;
        CurDir = ProcessParameters->CurrentDirectory.DosPath;

#define DRIVE_ROOT_DIRECTORY_LENGTH 3 /* (sizeof("X:\\") - 1) */
        if (CurDir.Buffer == NULL || CurDir.Buffer[ 0 ] == UNICODE_NULL || CurDir.Length == 0) {
            CurDir.Buffer = (RtlAllocateStringRoutine)((DRIVE_ROOT_DIRECTORY_LENGTH + 1) * sizeof(WCHAR));
            if (CurDir.Buffer == NULL) {
                DbgPrintEx(
                    DPFLTR_LDR_ID,
                    LDR_ERROR_DPFLTR,
                    "LDR: %s - unable to allocate current working directory buffer\n",
                    __FUNCTION__);

                RtlRaiseStatus(STATUS_NO_MEMORY);
            }

            RtlMoveMemory( CurDir.Buffer,
                           USER_SHARED_DATA->NtSystemRoot,
                           DRIVE_ROOT_DIRECTORY_LENGTH * sizeof( WCHAR )
                         );
            CurDir.Buffer[ DRIVE_ROOT_DIRECTORY_LENGTH ] = UNICODE_NULL;
        }
    }

    //
    // Make sure the module data base is initialized before we take any
    // exceptions.
    //

    LDRP_CHECKPOINT();

    Peb->Ldr = RtlAllocateHeap(LdrpHeap, MAKE_TAG( LDR_TAG ), sizeof(PEB_LDR_DATA));
    if (!Peb->Ldr) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - failed to allocate PEB_LDR_DATA\n",
            __FUNCTION__);

        RtlRaiseStatus(STATUS_NO_MEMORY);
    }

    Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
    Peb->Ldr->Initialized = TRUE;
    Peb->Ldr->SsHandle = NULL;
    Peb->Ldr->EntryInProgress = NULL;

    InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
    InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
    InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);

    //
    // Allocate the first data table entry for the image. Since we
    // have already mapped this one, we need to do the allocation by hand.
    // Its characteristics identify it as not a Dll, but it is linked
    // into the table so that pc correlation searching doesn't have to
    // be special cased.
    //

    LDRP_CHECKPOINT();
    LdrDataTableEntry = LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
    if (LdrDataTableEntry == NULL) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - failing process initialization due to inability allocate \"%wZ\"'s LDR_DATA_TABLE_ENTRY\n",
            __FUNCTION__,
            &FullImageName);

        RtlRaiseStatus(STATUS_NO_MEMORY);
    }

    LdrDataTableEntry->LoadCount = (USHORT)0xffff;
    LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase);
    LdrDataTableEntry->FullDllName = FullImageName;
    LdrDataTableEntry->Flags = (UseCOR) ? LDRP_COR_IMAGE : 0;
    LdrDataTableEntry->EntryPointActivationContext = NULL;

    // p = strrchr(FullImageName, '\\');
    // but not necessarily null terminated
    pp = UNICODE_NULL;
    p = FullImageName.Buffer;
    while (*p) {
        if (*p++ == (WCHAR)'\\') {
            pp = p;
        }
    }

    if (pp != NULL) {
        LdrDataTableEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)p - (ULONG_PTR)pp);
        LdrDataTableEntry->BaseDllName.MaximumLength = LdrDataTableEntry->BaseDllName.Length + sizeof(WCHAR);
        LdrDataTableEntry->BaseDllName.Buffer =
            (PWSTR)
                (((ULONG_PTR) LdrDataTableEntry->FullDllName.Buffer) +
                    (LdrDataTableEntry->FullDllName.Length - LdrDataTableEntry->BaseDllName.Length));

    } else {
        LdrDataTableEntry->BaseDllName = LdrDataTableEntry->FullDllName;
    }

    LdrpInsertMemoryTableEntry(LdrDataTableEntry);

    LdrDataTableEntry->Flags |= LDRP_ENTRY_PROCESSED;

    //
    // The process references the system DLL, so map this one next. Since
    // we have already mapped this one, we need to do the allocation by
    // hand. Since every application will be statically linked to the
    // system Dll, we'll keep the LoadCount initialized to 0.
    //

    LdrDataTableEntry = LdrpAllocateDataTableEntry(SystemDllBase);
    if (LdrDataTableEntry == NULL) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - failing process initialization due to inability to allocate NTDLL's LDR_DATA_TABLE_ENTRY\n",
            __FUNCTION__);

        RtlRaiseStatus(STATUS_NO_MEMORY);
    }

    LdrDataTableEntry->Flags = (USHORT)LDRP_IMAGE_DLL;
    LdrDataTableEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrDataTableEntry->DllBase);
    LdrDataTableEntry->LoadCount = (USHORT)0xffff;
    LdrDataTableEntry->EntryPointActivationContext = NULL;

    LdrDataTableEntry->FullDllName = SystemDllPath;
    RtlAppendUnicodeStringToString(&LdrDataTableEntry->FullDllName, &NtDllName);
    LdrDataTableEntry->BaseDllName = NtDllName;

    LdrpInsertMemoryTableEntry(LdrDataTableEntry);

#if defined(_AMD64_) // || defined(_IA64_)

    RtlInitializeHistoryTable();

#endif

    LdrpNtDllDataTableEntry = LdrDataTableEntry;

    if (ShowSnaps) {
        DbgPrint( "LDR: NEW PROCESS\n" );
        DbgPrint( "     Image Path: %wZ (%wZ)\n",
                  &LdrpImageEntry->FullDllName,
                  &LdrpImageEntry->BaseDllName
                );
        DbgPrint( "     Current Directory: %wZ\n", &CurDir );
        DbgPrint( "     Search Path: %wZ\n", &LdrpDefaultPath );
    }



    //
    // Add init routine to list
    //

    InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
                   &LdrDataTableEntry->InInitializationOrderLinks);

    //
    // Inherit the current directory
    //

    LDRP_CHECKPOINT();
    st = RtlSetCurrentDirectory_U(&CurDir);
    if (!NT_SUCCESS(st)) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - unable to set current directory to \"%wZ\"; status = %x\n",
            __FUNCTION__,
            &CurDir,
            st);

        if (!StaticCurDir)
            RtlFreeUnicodeString(&CurDir);

        CurDir = NtSystemRoot;
        st = RtlSetCurrentDirectory_U(&CurDir);
        if (!NT_SUCCESS(st))
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - unable to set current directory to NtSystemRoot; status = %x\n",
                __FUNCTION__,
                &CurDir);
        }
    else {
        if ( !StaticCurDir ) {
            RtlFreeUnicodeString(&CurDir);
            }
        }
    if (ProcessParameters->Flags & RTL_USER_PROC_APP_MANIFEST_PRESENT) {
        // Application manifests prevent .local detection.
        //
        // Note that we don't clear the flag so that someone like app compat
        // can forcibly set it to reenable .local + app manifest behavior.
    } else {
        //
        // Fusion 1.0 fixup : check the existence of .local, and set
        // a flag in PPeb->ProcessParameters.Flags
        //
        // Setup the global for this process that decides whether we want DLL
        // redirection on or not. LoadLibrary() and GetModuleHandle() look at this
        // boolean.

        ImagePathName.Length = ProcessParameters->ImagePathName.Length ;
        ImagePathName.MaximumLength =  ProcessParameters->ImagePathName.Length + sizeof(DLL_REDIRECTION_LOCAL_SUFFIX);
        ImagePathNameBuffer = (PWCHAR) RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TEMP_TAG ), ImagePathName.MaximumLength);
        if (ImagePathNameBuffer == NULL) {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - unable to allocate heap for the image's .local path\n",
                __FUNCTION__);

            return STATUS_NO_MEMORY;
        }

        pw = (PWSTR)ProcessParameters->ImagePathName.Buffer;
        if (!(ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
            pw = (PWSTR)((PCHAR)pw + (ULONG_PTR)(ProcessParameters));
        }

        RtlCopyMemory(ImagePathNameBuffer, pw,ProcessParameters->ImagePathName.Length);

        ImagePathName.Buffer = ImagePathNameBuffer;

        // Now append the suffix:
        st = RtlAppendUnicodeToString(&ImagePathName, DLL_REDIRECTION_LOCAL_SUFFIX);
        if (!NT_SUCCESS(st)) {
    #if DBG
            DbgPrint("RtlAppendUnicodeToString fails with status %lx\n", st);
    #endif
            RtlFreeHeap(RtlProcessHeap(), 0, ImagePathNameBuffer);
            return st;
        }

        // RtlDoesFileExists_U() wants a null-terminated string.
        ImagePathNameBuffer[ImagePathName.Length / sizeof(WCHAR)] = UNICODE_NULL;
        DotLocalExists = RtlDoesFileExists_U(ImagePathNameBuffer);

        if (DotLocalExists)  // set the flag in Peb->ProcessParameters->flags
            ProcessParameters->Flags |=  RTL_USER_PROC_DLL_REDIRECTION_LOCAL ;

        RtlFreeHeap(RtlProcessHeap(), 0, ImagePathNameBuffer); //cleanup
    }

    //
    // Second round of application verifier initialization. We need to split
    // this into two phases because some verifier things must happen very early
    // in the game and other things rely on other things being already initialized
    // (exception dispatching, system heap, etc.).
    //

    if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER) {
        AVrfInitializeVerifier (FALSE, NULL, 1);
    }

#if defined(_WIN64)
    //
    // Load in WOW64 if the image is supposed to run simulated
    //
    if (UseWOW64) {
        /*CONST*/ static UNICODE_STRING Wow64DllName = RTL_CONSTANT_STRING(L"wow64.dll");
        CONST static ANSI_STRING Wow64LdrpInitializeProcName = RTL_CONSTANT_STRING("Wow64LdrpInitialize");
        CONST static ANSI_STRING Wow64PrepareForExceptionProcName = RTL_CONSTANT_STRING("Wow64PrepareForException");
        CONST static ANSI_STRING Wow64ApcRoutineProcName = RTL_CONSTANT_STRING("Wow64ApcRoutine");

        st = LdrLoadDll(NULL, NULL, &Wow64DllName, &Wow64Handle);
        if (!NT_SUCCESS(st)) {
            if (ShowSnaps) {
                DbgPrint("LDR: wow64.dll not found.  Status=%x\n", st);
            }
            return st;
        }

        //
        // Get the entrypoints.  They are roughly cloned from ntos\ps\psinit.c
        // PspInitSystemDll().
        //
        st = LdrGetProcedureAddress(Wow64Handle,
                                    &Wow64LdrpInitializeProcName,
                                    0,
                                    (PVOID *)&Wow64LdrpInitialize);
        if (!NT_SUCCESS(st)) {
            if (ShowSnaps) {
                DbgPrint("LDR: Wow64LdrpInitialize not found.  Status=%x\n", st);
            }
            return st;
        }

        st = LdrGetProcedureAddress(Wow64Handle,
                                    &Wow64PrepareForExceptionProcName,
                                    0,
                                    (PVOID *)&Wow64PrepareForException);
        if (!NT_SUCCESS(st)) {
            if (ShowSnaps) {
                DbgPrint("LDR: Wow64PrepareForException not found.  Status=%x\n", st);
            }
            return st;
        }

        st = LdrGetProcedureAddress(Wow64Handle,
                                    &Wow64ApcRoutineProcName,
                                    0,
                                    (PVOID *)&Wow64ApcRoutine);
        if (!NT_SUCCESS(st)) {
            if (ShowSnaps) {
                DbgPrint("LDR: Wow64ApcRoutine not found.  Status=%x\n", st);
            }
            return st;
        }

        //
        // Now that all DLLs are loaded, if the process is being debugged,
        // signal the debugger with an exception
        //

        if ( Peb->BeingDebugged ) {
             DbgBreakPoint();
        }

        //
        // Release the loaderlock now - this thread doesn't need it any more.
        //
        RtlLeaveCriticalSection(&LdrpLoaderLock);

        //
        // Call wow64 to load and run 32-bit ntdll.dll.
        //
        (*Wow64LdrpInitialize)(Context);
        // This never returns.  It will destroy the process.
    }
#endif

    LDRP_CHECKPOINT();

    //
    // Check if image is COM+.
    //

    if (UseCOR) {
        //
        // The image is COM+ so notify the runtime that the image was loaded
        // and allow it to verify the image for correctness.
        //
        PVOID OriginalViewBase = Peb->ImageBaseAddress;

        st = LdrpCorValidateImage(&Peb->ImageBaseAddress,
                                  LdrpImageEntry->FullDllName.Buffer);
        if (!NT_SUCCESS(st)) {
            return st;
        }
        if (OriginalViewBase != Peb->ImageBaseAddress) {
            //
            // Mscoree has substituted a new image at a new base in place
            // of the original image.  Unmap the original image and use
            // the new image from now on.
            //
            NtUnmapViewOfSection(NtCurrentProcess(), OriginalViewBase);
            NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
            if (!NtHeader) {
                LdrpCorUnloadImage(Peb->ImageBaseAddress);
                return STATUS_INVALID_IMAGE_FORMAT;
            }
            // Update the exe's LDR_DATA_TABLE_ENTRY
            LdrpImageEntry->DllBase = Peb->ImageBaseAddress;
            LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
        }
        // Edit the initial instruction pointer to point into mscoree.dll
        LdrpCorReplaceStartContext(Context);
    }

    LDRP_CHECKPOINT();

    // If this is a windows subsystem app, load kernel32 so that it can handle processing
    // activation contexts found in DLLs and the .exe.

    if ((NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
        (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)) {
        UNICODE_STRING Kernel32DllName = RTL_CONSTANT_STRING(L"kernel32.dll");
        PVOID Kernel32Handle;

        st = LdrpLoadDll(
                0,                  // Flags
                NULL,               // DllPath
                NULL,               // DllCharacteristics
                &Kernel32DllName,   // DllName
                &Kernel32Handle,    // DllHandle
                TRUE);             // RunInitRoutines
        if (!NT_SUCCESS(st)) {
            if (ShowSnaps) {
                DbgPrint("LDR: Unable to load kernel32.dll.  Status=%x\n", st);
            }
            return st;
        }

        st = LdrGetProcedureAddress(Kernel32Handle, &Kernel32ProcessInitPostImportFunctionName, 0, (PVOID *) &Kernel32ProcessInitPostImportFunction);
        if (!NT_SUCCESS(st)) {
            if (ShowSnaps) {
                DbgPrint(
                    "LDR: Failed to find post-import process init function in kernel32; ntstatus 0x%08lx\n", st);
            }
            Kernel32ProcessInitPostImportFunction = NULL;

            if (st != STATUS_PROCEDURE_NOT_FOUND)
                return st;
        }
    }

    LDRP_CHECKPOINT();

    st = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
    if (!NT_SUCCESS(st))
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - call to LdrpWalkImportDescriptor failed with status %x\n",
            __FUNCTION__,
            st);

    LDRP_CHECKPOINT();

    if ((PVOID)NtHeader->OptionalHeader.ImageBase != Peb->ImageBaseAddress) {

        //
        // The executable is not at its original address.  It must be
        // relocated now.
        //

        PVOID ViewBase;
        NTSTATUS status;

        ViewBase = Peb->ImageBaseAddress;

        status = LdrpSetProtection(ViewBase, FALSE, TRUE);

        if (!NT_SUCCESS(status)) {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - call to LdrpSetProtection(%p, FALSE, TRUE) failed with status %x\n",
                __FUNCTION__,
                ViewBase,
                status);

            return status;
        }

        status = LdrRelocateImage(ViewBase,
                    "LDR",
                    STATUS_SUCCESS,
                    STATUS_CONFLICTING_ADDRESSES,
                    STATUS_INVALID_IMAGE_FORMAT
                    );

        if (!NT_SUCCESS(status)) {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - call to LdrRelocateImage failed with status %x\n",
                __FUNCTION__,
                status);

            return status;
        }

        //
        // Update the initial thread context record as per the relocation.
        //

        if (Context) {

            OldBase = NtHeader->OptionalHeader.ImageBase;
            Diff = (PCHAR)ViewBase - (PCHAR)OldBase;

            LdrpRelocateStartContext(Context, Diff);
        }

        status = LdrpSetProtection(ViewBase, TRUE, TRUE);
        if (!NT_SUCCESS(status)) {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - call to LdrpSetProtection(%p, TRUE, TRUE) failed with status %x\n",
                __FUNCTION__,
                ViewBase,
                status);

            return status;
        }
    }

    LDRP_CHECKPOINT();

    LdrpReferenceLoadedDll(LdrpImageEntry);

    //
    // Lock the loaded DLLs to prevent dlls that back link to the exe to
    // cause problems when they are unloaded.
    //

    {
        PLDR_DATA_TABLE_ENTRY Entry;
        PLIST_ENTRY Head,Next;

        Head = &Peb->Ldr->InLoadOrderModuleList;
        Next = Head->Flink;

        while ( Next != Head ) {
            Entry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
            Entry->LoadCount = 0xffff;
            Next = Next->Flink;
        }
    }

    //
    // All static DLLs are now pinned in place. No init routines have been run yet
    //

    LdrpLdrDatabaseIsSetup = TRUE;


    if (!NT_SUCCESS(st)) {
#if DBG
        DbgPrint("LDR: Initialize of image failed. Returning Error Status 0x%lx\n", st);
#endif
        return st;
    }

    LDRP_CHECKPOINT();

    if ( !NT_SUCCESS(st = LdrpInitializeTls()) ) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - failed to initialize TLS slots; status %x\n",
            __FUNCTION__,
            st);

        return st;
    }

    //
    // Register initial dll ranges with the stack tracing module.
    // This is used for getting reliable stack traces on X86.
    //

#if defined(_X86_)
    {

        PLIST_ENTRY Current, Start;
        PLDR_DATA_TABLE_ENTRY Entry;

        Start = &(NtCurrentPeb()->Ldr->InMemoryOrderModuleList);
        Current = Start->Flink;

        while (Current != Start) {

            Entry = CONTAINING_RECORD (Current,
                                       LDR_DATA_TABLE_ENTRY,
                                       InMemoryOrderLinks);

            RtlpStkMarkDllRange (Entry);
            Current = Current->Flink;
        }
    }
#endif

    //
    // Now that all DLLs are loaded, if the process is being debugged,
    // signal the debugger with an exception
    //

    if (Peb->BeingDebugged) {
         DbgBreakPoint();
         ShowSnaps = ((FLG_SHOW_LDR_SNAPS & Peb->NtGlobalFlag) != 0);
    }

    LDRP_CHECKPOINT();

#if defined (_X86_)
    if ( LdrpNumberOfProcessors > 1 ) {
        LdrpValidateImageForMp(LdrDataTableEntry);
    }
#endif

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

    //
    // Check for shimmed apps if necessary
    //
    if (pAppCompatExeData != NULL) {

        Peb->AppCompatInfo = NULL;

        //
        // The name of the engine is the first thing in the appcompat structure.
        //
        LdrpLoadShimEngine((WCHAR*)pAppCompatExeData, UnicodeImageName, pAppCompatExeData);
        }
    else {
        //
        // Get all application goo here (hacks, flags, etc.)
        //
        LdrQueryApplicationCompatibilityGoo(UnicodeImageName, ImageFileOptionsPresent);
        }

    LDRP_CHECKPOINT();

    if (Kernel32ProcessInitPostImportFunction != NULL) {
        st = (*Kernel32ProcessInitPostImportFunction)();
        if (!NT_SUCCESS(st)) {
            DbgPrintEx(
                DPFLTR_LDR_ID,
                LDR_ERROR_DPFLTR,
                "LDR: %s - Failed running kernel32 post-import function; status 0x%08lx\n",
                __FUNCTION__,
                st);

            return st;
        }
    }

    LDRP_CHECKPOINT();

    st = LdrpRunInitializeRoutines(Context);
    if (!NT_SUCCESS(st)) {
        DbgPrintEx(
            DPFLTR_LDR_ID,
            LDR_ERROR_DPFLTR,
            "LDR: %s - Failed running initialization routines; status %x\n",
            __FUNCTION__,
            st);

        return st;
    }

    //
    // Shim engine callback.
    //
    if (g_pfnSE_InstallAfterInit != NULL) {
        if (!(*g_pfnSE_InstallAfterInit)(UnicodeImageName, pAppCompatExeData)) {
            LdrpUnloadShimEngine();
        }
    }

    if ( NT_SUCCESS(st) && Peb->PostProcessInitRoutine ) {
        (Peb->PostProcessInitRoutine)();
    }

    LDRP_CHECKPOINT();

    return STATUS_SUCCESS;
}

>Инкрементируя вероятность<



Автор: Octavian
 

Members, viewing this thread

Сейчас на форуме нет ни одного пользователя.