Что делает LdrSetDllManifestProber ?

Тема в разделе "WASM.WIN32", создана пользователем Flasher, 25 янв 2009.

  1. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Гугл молчит, ида вот что выдает:

    Код (Text):
    1. .text:77F5CD7E LdrSetDllManifestProber proc near
    2. .text:77F5CD7E
    3. .text:77F5CD7E arg_0           = dword ptr  4
    4. .text:77F5CD7E
    5. .text:77F5CD7E                 mov     eax, [esp+arg_0]
    6. .text:77F5CD82                 mov     dword_77FC4390, eax
    7. .text:77F5CD87                 retn    4
    8. .text:77F5CD87 LdrSetDllManifestProber endp
    Это как-то связано с LdrLoadDll.
    Могет кто в курсе, что это за функция?
     
  2. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    LdrpManifestProberRoutine equ dword_77FC4390
    LdrLoadDll->LdrpWalkImportDescriptor->LdrpManifestProberRoutine
     
  3. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Спасибо большое.
    Классная штука :)
     
  4. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Странно, локально когда указываю на свой диспетчер, потом загружаю либу - норм сработывает. А когда делаю аналогичное удалённо, показывает только kernel32.dll и всё.

    Код (Text):
    1. .686
    2. .model flat, stdcall
    3. option casemap :none
    4. include \masm32\include\ntdll.inc
    5. includelib \masm32\lib\ntdll.lib
    6. include \masm32\include\kernel32.inc
    7. includelib \masm32\lib\kernel32.lib
    8. include \masm32\include\user32.inc
    9. includelib \masm32\lib\user32.lib
    10.  
    11. .code
    12. LdrpManifestProberRoutine proc param1,param2,param3:dword
    13.      push ebx
    14.      push edi
    15.      push esi
    16.      call @F
    17.   @@:
    18.      pop ebx
    19.      sub ebx,offset @B
    20.      mov esi,esp
    21.      assume fs:nothing
    22.      lea edx,[offset ShlSehNext + ebx]
    23.      lea ecx,[offset RemoteSehHandler + ebx]
    24.      push ebp
    25.      push esp
    26.      push edx
    27.      push ecx
    28.      push FS:[0]
    29.      mov FS:[0],esp
    30.  
    31.      mov ebx,[esi+24h]
    32.      mov edi,UNICODE_STRING.Buffer[ebx]
    33.      push OptionOk;NoWait
    34.      push ebx
    35.      call Breake
    36.  
    37.      clc
    38. ShlSehNext:
    39.      pop FS:[0]
    40.      add esp,16
    41.      pop esi
    42.      pop edi
    43.      pop ebx
    44.      xor eax,eax
    45.      ret
    46. LdrpManifestProberRoutine endp
    47.  
    48. RemoteSehHandler proc uses edx pExcept:DWORD,pFrame:DWORD,pContext:DWORD,pDispatch:DWORD
    49.      mov edx,pFrame
    50.      assume edx:ptr SEH
    51.      mov eax,pContext
    52.      assume eax:ptr CONTEXT
    53.      push [edx].SafeOffset
    54.      pop [eax].regEip
    55.      push [edx].PrevEsp
    56.      sub dword ptr [esp],16
    57.      pop [eax].regEsp
    58.      push [edx].PrevEbp
    59.      pop [eax].regEbp
    60.      mov [eax].regEax,STATUS_INVALID_PARAMETER    
    61.      or [eax].regEFlags,1
    62.      xor eax,eax
    63.      ret
    64. RemoteSehHandler endp
    65.  
    66. Breake proc uses eax unString:PSTR,ResponceOption:dword
    67.    Local HardErrorPointer:PVOID
    68.    Local Response:dword
    69.      mov eax,unString
    70.     mov HardErrorPointer,eax
    71.     lea eax,Response
    72.     push eax
    73.     push ResponceOption
    74.     lea eax,HardErrorPointer
    75.     push eax
    76.     push 1
    77.     push 1
    78.     push STATUS_FATAL_APP_EXIT
    79.      mov eax,00b6h ;ZwRaiseHardError
    80.      mov edx,esp
    81.      int 2Eh
    82.      lea esp,[esp+6*4]
    83.     ret
    84. Breake endp
    85. EndCode:
    86.        
    87. FULLCODESIZE equ (offset EndCode - offset LdrpManifestProberRoutine)
    88.  
    89. Start proc
    90.      local LdrSetDllManifestProberProc[13]:byte
    91.      local CodeBuffer[FULLCODESIZE]:byte
    92.      local CodeAddress:dword
    93.      local CodeSize:dword
    94.      local su:STARTUPINFO
    95.      local pi:PROCESS_INFORMATION
    96.  
    97. ; Запускаем процесс суспенденным
    98.        invoke GetStartupInfo,addr su
    99.        invoke CreateProcessA,0,$CTA0("process.exe"),0,0,0,CREATE_SUSPENDED,0,0,addr su,addr pi
    100.  
    101. ; Записываем код обработчика в тело удалённого процесса
    102.        lea esi,LdrpManifestProberRoutine
    103.        lea edi,CodeBuffer
    104.        mov ecx,FULLCODESIZE
    105.        cld
    106.        rep movsb
    107.        mov CodeAddress,0
    108.        mov CodeSize,FULLCODESIZE
    109.        invoke ZwAllocateVirtualMemory,pi.ProcessHandle,addr CodeAddress,0,addr CodeSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE
    110.        invoke ZwWriteVirtualMemory,pi.ProcessHandle,CodeAddress,addr CodeBuffer,FULLCODESIZE,0
    111.  
    112. ; Найти dword_7C97C30C и записать туда указатель на наш обработчик
    113.        invoke GetModuleHandle,$CTA0("ntdll.dll")
    114.        invoke GetProcAddress,eax,$CTA0("LdrSetDllManifestProber")
    115.        mov ebx,eax
    116.        invoke ZwReadVirtualMemory,pi.ProcessHandle,ebx,addr LdrSetDllManifestProberProc,13,0
    117.        lea ebx,LdrSetDllManifestProberProc
    118.        mov ebx,dword ptr [ebx+9]
    119.        invoke ZwWriteVirtualMemory,pi.ProcessHandle,ebx,addr CodeAddress,4,0
    120.  
    121.        invoke ZwResumeThread,pi.ThreadHandle,0
    122.        invoke CloseHandle,pi.ProcessHandle
    123.        invoke CloseHandle,pi.ThreadHandle
    124.        
    125.        invoke ExitProcess,0
    126. Start endp
    127. end Start
    А код удалённого процесса выглядит так:
    Код (Text):
    1. .data
    2. Buffer db 1024 dup(0)
    3. hTest1 dd 0
    4. hTest2 dd 0
    5.  
    6. .code
    7. start proc
    8.        CCOUNTED_UNICODE_STRING "dbghelp.dll",szTest1,4
    9.        invoke LdrLoadDll,0,0,addr szTest1,addr hTest1
    10.  
    11.        CCOUNTED_UNICODE_STRING "dimap.dll",szTest2,4
    12.        invoke LdrLoadDll,0,0,addr szTest2,addr hTest2
    13.        
    14.        invoke wsprintfA,offset Buffer,$CTA0("0%08xh"),eax
    15.        invoke MessageBox,0,offset Buffer,offset Buffer,0
    16.  
    17.        invoke ExitProcess,0
    18. start endp
    19. end start
    LdrpManifestProberRoutine вить корректно собран ?
     
  5. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    - LdrpManifestProberRoutine апгрейтится при инициализации kernel32.dll
    Так как у тебя регистрация обработчика до инициализации этого модуля, то после тока как поток начнёт исполнять инициализацию kernel32 указатель на твой обработчик будет удалён(затёрт).
    - Необходимо чтоб общий размер стекового фрейма(локальных переменных) был кратен 4, в частном случае необходимо добавлять выравнивание на 4 байта к переменным, макро нужно переписать с учётом выравнивания:
    Код (Text):
    1. FULLCODESIZE equ (offset EndCode - offset LdrpManifestProberRoutine)
    2. FULLCODESIZEALIGN equ ((FULLCODESIZE + 3) And Not(3))
    И юзать FULLCODESIZEALIGN.
    - Так обработчик может быть зарегистрирован, необходимо считать указатель и вызывать его после отработки кода перехватчика.
    - Не верная модель вызова. Процедура имеет 3 параметра:
    Код (Text):
    1. NTSYSAPI
    2. VOID
    3. NTAPI
    4. LdrSetDllManifestProber(
    5.    IN PLDR_MANIFEST_PROBER_ROUTINE ManifestProberRoutine
    6.    );
    7.  
    8. typedef
    9. NTSTATUS
    10. (NTAPI * PLDR_MANIFEST_PROBER_ROUTINE) (
    11.    IN PVOID DllBase,
    12.    IN PCWSTR FullDllPath,
    13.    OUT PVOID *ActivationContext
    14.    );
    - Соответственно неверно извлекается имя модуля.
     
  6. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Хотя нет, с параметрами всё верно, извеняюсь.
     
  7. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Видимо придётся поток создать который после затирания вернёт обратно указатель на мой диспетчер да?
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Учитывая что регистрация выполняется при событии DLL_PROCESS_ATTACH, тоесть при загрузке модуля, можно подменить InitRoutine. Хэндлер будет подменять адрес возврата в стеке на код, который восстановит ManifestProberRoutine, вызывать оригинальный хэндлер и выполнить возврат. Либо из обработчика InitRoutine вызвать оригинальный хэндлер, что в принице тоже, пример для текущего процесса:
    Код (Text):
    1. PEB_CALLOUT_OFFSET  equ (PAGE_SIZE - 10*4)
    2.  
    3. Gl_LdrpManifestProberRoutineReference   PVOID ?
    4. Gl_LdrpManifestProberRoutine        PVOID ?
    5.  
    6. RegisterKernel32Callout proc uses ebx Handler:PVOID
    7.     assume fs:nothing
    8.     mov ebx,fs:[TEB.Peb]
    9.     mov eax,Handler
    10.     mov edx,PEB.Ldr[ebx]
    11.     mov edx,PEB_LDR_DATA.InLoadOrderModuleList[edx]
    12.     assume edx:PLDR_DATA_TABLE_ENTRY
    13.     mov edx,[edx].InLoadOrderModuleList.Flink   ;ntdll.dll
    14.     mov edx,[edx].InLoadOrderModuleList.Flink   ;kernel32.dll
    15.     lock xchg [edx].EntryPoint,eax
    16.     mov dword ptr [ebx + PEB_CALLOUT_OFFSET],eax
    17.     ret
    18. RegisterKernel32Callout endp
    19.  
    20. $LOAD macro Reg32, Variable
    21. Local dt_
    22.     Call dt_
    23. dt_:
    24.     pop Reg32
    25.     mov Reg32,dword ptr [Reg32 + (offset Variable - offset dt_)]
    26. endm
    27.  
    28. CalloutRoutine proc DllHandle:PVOID, Reason:ULONG, Context:PCONTEXT
    29.     assume fs:nothing
    30.     mov eax,fs:[TEB.Peb]
    31.     push Context
    32.     push Reason
    33.     push DllHandle
    34.     Call dword ptr [eax + PEB_CALLOUT_OFFSET]
    35.     .if Reason == DLL_PROCESS_ATTACH
    36.     $LOAD Ecx, Gl_LdrpManifestProberRoutineReference
    37.     $LOAD Edx, Gl_LdrpManifestProberRoutine
    38.     mov dword ptr [ecx],edx
    39.     .endif
    40.     ret
    41. CalloutRoutine endp
    Тоесть захват InitRoutine из RegisterKernel32Callout(), адрес оригинального хэндлера сохраняется в пеб.
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Забыл:
    Код (Text):
    1. $GET_REF macro Reg32, Variable
    2. Local dt_
    3.     Call dt_
    4. dt_:
    5.     pop Reg32
    6.     lea Reg32,dword ptr [Reg32 + (offset Variable - offset dt_)]
    7. endm
    8.  
    9.     $GET_REF Eax, CalloutRoutine
    10.     invoke RegisterKernel32Callout, Eax
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Ну или сразу LdrSetDllManifestProber() вызвать..
     
  11. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Спасибо, попробую соединить.
     
  12. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    269
    Апну старого мамонта на память.

    Вот краткое описание работы с активационными контекстами в коде загрузчика Windows (ntdll.dll):
    1. При загрузке каждой DLL ntdll вызывает функцию LdrpManifestProberRoutine, передавая ей базовый адрес загружаемой DLL и ее имя. Эта функция ищет манифест зависимостей в ресурсах DLL и создает активационный контекст на его основе.
    2. Указатель на созданный активационный контекст сохраняется в поле EntryPointActivationContext структуры LDR_DATA_TABLE_ENTRY, описывающей загруженную DLL.
    3. При вызове импортируемых функций из DLL, ntdll активирует ее активационный контекст при помощи RtlActivateActivationContextUnsafeFast. Это позволяет разрешать зависимости во время выполнения.
    4. После вызова функций активационный контекст деактивируется через RtlDeactivateActivationContextUnsafeFast.
    5. При выгрузке DLL ее активационный контекст освобождается.
    Таким образом активационные контексты в ntdll используются для разрешения зависимостей импортируемых DLL на этапе выполнения программы. Это позволяет поддерживать изоляцию компонентов и side-by-side сборки в Windows.
     
  13. vitokop

    vitokop Member

    Публикаций:
    0
    Регистрация:
    20 май 2006
    Сообщения:
    40
    --- Сообщение объединено, 7 ноя 2023 ---
    добавляю для удобства список всех вызовов и список оригинальных подпрограмм
     

    Вложения:

  14. galenkane

    galenkane Active Member

    Публикаций:
    0
    Регистрация:
    13 янв 2017
    Сообщения:
    269
    Дополню инфу

    Функция LdrSetDllManifestProber используется для установки функции-обработчика, которая будет вызываться загрузчиком DLL при загрузке каждого DLL-модуля.
    Этот обработчик может анализировать ресурсы DLL-модуля и извлекать оттуда различную информацию, например манифест приложения.
    Подробнее:
    1. Функция принимает один параметр - указатель на функцию-обработчик типа PLDR_MANIFEST_PROBER_ROUTINE.
    2. Этот указатель сохраняется в глобальной переменной LdrpManifestProberRoutine.
    3. При загрузке каждого DLL-модуля загрузчик проверяет, установлен ли этот обработчик.
    4. Если обработчик установлен, загрузчик вызывает его, передавая базовый адрес загружаемого модуля и имя модуля.
    5. Обработчик анализирует ресурсы модуля, возможно извлекает какие-то данные (например, манифест).
    6. Обработчик может устанавливать для модуля контекст активации (activation context) в переменную EntryPointActivationContext.
    7. Также обработчик может возвращать статус ошибки, если произошла ошибка при анализе модуля.
    Таким образом эта функция позволяет подключить к загрузчику DLL дополнительную логику для анализа загружаемых модулей.