вторник, 19 апреля 2011 г.

К вопросу о поиске неэкспортируемых символов

Традиционные способы поиска неэкспортируемых символов основываются на интеллектуальном или полуинтеллектуальном поиске с использованием дизассемблера длин или полноценного дизассемблера, вплоть до построения графа базовых блоков для кода, что приводит к проблеме отделения кода от данных ( не решаемой в общем случае статическим анализом ).

А если отказаться от построения графа кода, то к примеру поиск ф-ции в ntdll.dll может быть полным кошмаром, изза его размазанности по всему модулю и дроблению на chunks.

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

Однако, как ни странно, на помощь приходит самый дубовый и примитивный подход - поиск по сигнатуре. А все потому, что она изза своих особенностей реализована не в С коде, а в ассемблере(win2k\private\ntos\dll\i386\ldrthunk.asm):

;++
;
; VOID
; LdrpCallInitRoutine(
;    IN PDLL_INIT_ROUTINE InitRoutine,
;    IN PVOID DllHandle,
;    IN ULONG Reason,
;    IN PCONTEXT Context OPTIONAL
;    )
;
; Routine Description:
;
;    This function calls an x86 DLL init routine. It is robust against DLLs that don't preserve EBX or fail to clean up enough stack.
;    The only register that the DLL init routine cannot trash is ESI.
;
; Arguments:
;
;    InitRoutine - Address of init routine to call
;    DllHandle - Handle of DLL to call
;    Reason - one of the DLL_PROCESS_... or DLL_THREAD... values
;    Context - context pointer or NULL
;
; Return Value:
;
;    FALSE if the init routine fails, TRUE for success.
;
;--

cPublicProc _LdrpCallInitRoutine , 4

InitRoutine     equ [ebp + 8]
DllHandle       equ [ebp + 12]
Reason          equ [ebp + 16]
Context         equ [ebp + 20]

stdENDP _LdrpCallInitRoutine
        push    ebp
        mov     ebp, esp
        push    esi         ; save esi across the call
        push    edi         ; save edi across the call
        push    ebx         ; save ebx on the stack across the call
        mov     esi,esp     ; save the stack pointer in esi across the call
        push    Context
        push    Reason
        push    DllHandle
        call    InitRoutine
        mov     esp,esi     ; restore the stack pointer in case callee forgot to clean up
        pop     ebx         ; restore ebx
        pop     edi         ; restore edi
        pop     esi         ; restore esi
        pop     ebp
        stdRET  _LdrpCallInitRoutine

_TEXT   ends
        end

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

Конечно это скорее исключение, чем правило, но тем не менее, лично мне это сэкономило массу времени.

Комментариев нет:

Отправить комментарий