воскресенье, 15 мая 2011 г.

Про статический анализ бинарного кода

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

Пример:

открываем notepad.exe в IDA, находим кусок высокоуровнего seh'а(scopetable entry):

.text:01001898 stru_1001898    _msEH <0FFFFFFFFh, offset loc_100752A, offset loc_100753E>

Смотрим сами обработчики - ссылок из кода на них нет, но(!) есть data xref:

.text:01007528                 jmp     short loc_1007557
.text:0100752A
.text:0100752A loc_100752A:                            ; DATA XREF: .text:stru_1001898
.text:0100752A                 mov     eax, [ebp+ms_exc.exc_ptr]
.text:0100752D                 mov     ecx, [eax]
.text:0100752F                 mov     ecx, [ecx]
.text:01007531                 mov     [ebp+var_28], ecx
.text:01007534                 push    eax
.text:01007535                 push    ecx
.text:01007536                 call    _XcptFilter
.text:0100753B                 pop     ecx
.text:0100753C                 pop     ecx
.text:0100753D                 retn
.text:0100753E
.text:0100753E loc_100753E:                            ; DATA XREF: .text:stru_1001898
.text:0100753E                 mov     esp, [ebp+ms_exc.old_esp]
.text:01007541                 mov     esi, [ebp+var_28]
.text:01007544                 cmp     [ebp+var_1C], 0
.text:01007548                 jnz     short loc_1007551
.text:0100754A                 push    esi             ; int
.text:0100754B                 call    ds:_exit
.text:01007551 ; ---------------------------------------------------------------------------

IDA прекрасно все находит и резолвит, т.к. есть:

.text:0100739D                 push    70h
.text:0100739F                 push    offset stru_1001898
.text:010073A4                 call    __SEH_prolog

А теперь идем в тот же notepad.exe, делаем поиск по ф-ции GetSystemTimeAsFileTime, по xref прыгаем на место вызова её и видим:

.text:010070CC sub_10070B1     endp
.text:010070CC
.text:010070CC ; ---------------------------------------------------------------------------
.text:010070CF                 db 5 dup(0CCh)
.text:010070D4 ; ---------------------------------------------------------------------------
.text:010070D4                 mov     edi, edi
.text:010070D6                 push    ebp
.text:010070D7                 mov     ebp, esp
.text:010070D9                 sub     esp, 10h
.text:010070DC                 mov     eax, dword_1009604
.text:010070E1                 test    eax, eax
.text:010070E3                 jz      short loc_10070EC
.text:010070E5                 cmp     eax, 0BB40h
.text:010070EA                 jnz     short loc_1007139
.text:010070EC
.text:010070EC loc_10070EC:                            ; CODE XREF: .text:010070E3
.text:010070EC                 push    esi
.text:010070ED                 lea     eax, [ebp-8]
.text:010070F0                 push    eax
.text:010070F1                 call    ds:GetSystemTimeAsFileTime
.text:010070F7                 mov     esi, [ebp-4]

Опачки, ф-ция не распозналась IDA'ой. Превратим принудительно её в ф-цию нажав p, после чего видно, что на ф-цию нет перекрестных ссылок, её никто не вызывает из данного модуля. То есть в графе, если им описать данный модуль по xref'aм, эта ф-ция будет отсутствовать.

На логичный вопрос - зачем она тогда нужна в коде, если ее никто не вызывает? Ответ прост - раз есть, то скорее всего кто-то вызывает( или в микрософте любят компилировать с выключенной оптимизацией =] ), и этот кто-то - просто другой модуль ( CRT ) и делается это динамически:

notepad зовет _initterm, который находится в рантаймовской либе msvcrt.dll:

msvcrt!_initterm+0xb:
77c39d72 8b06            mov     eax,dword ptr [esi]
77c39d74 85c0            test    eax,eax
77c39d76 7402            je      msvcrt!_initterm+0x13 (77c39d7a)
77c39d78 ffd0            call    eax <= вызов нашей ф-ции (0x010070D4)

Можно конечно эвристически определить, что по такому-то адресу находится код, на который никто не ссылается, собс-но так IDA и поступает, но, если представить на секунду, что код может быть в принципе каким угодно ( обфусцированным, зашифрованным и т.д.), то эвристика не поможет, а ссылок нa него нет - итог: fail.

В принципе это все достаточно очевидно, но видимо не для всех(надеюсь данный пример поможет).

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

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