понедельник, 28 ноября 2011 г.

Ищем код Patch-Guard

Стало интересно, можно ли найти код Patch Guard используя лишь факт того, что он каким-то образом считает хеши секций.
В итоге родился скрипт для IDA, который ищет во всех ф-циях инструкции используемые для подсчета хешей, т.е. xor/rol и прочие.

Получился такой список:

RtlpValidatePeHeaderHash2 xor count = 2 <=== данная ф-ция не интересна
RtlpValidatePeHeaderHash2 shr count = 1
RtlpValidatePeHeaderHash2 rol count = 1

sub_565580 xor count = 2
sub_565580 shr count = 1
sub_565580 rol count = 2

sub_565730 xor count = 24
sub_565730 rdtsc count = 6
sub_565730 shl count = 6
sub_565730 shr count = 4
sub_565730 ror count = 6

sub_565950 xor count = 3
sub_565950 shr count = 4
sub_565950 rol count = 2

sub_565B10 xor count = 3
sub_565B10 shr count = 5
sub_565B10 rol count = 2

sub_566090 xor count = 6
sub_566090 rdtsc count = 1
sub_566090 shl count = 1
sub_566090 shr count = 1
sub_566090 ror count = 1

sub_566140 xor count = 3
sub_566140 shr count = 3
sub_566140 rol count = 2

sub_5667D0 xor count = 4
sub_5667D0 shr count = 5
sub_5667D0 rol count = 2

sub_566A50 xor count = 3
sub_566A50 shl count = 1
sub_566A50 shr count = 2
sub_566A50 rol count = 2

sub_566BC0 xor count = 3
sub_566BC0 shl count = 1
sub_566BC0 shr count = 3
sub_566BC0 rol count = 2

sub_566D30 xor count = 13
sub_566D30 rdtsc count = 3
sub_566D30 shl count = 5
sub_566D30 shr count = 1
sub_566D30 ror count = 3

FsRtlMdlReadCompleteDevEx xor count = 12
FsRtlMdlReadCompleteDevEx rdtsc count = 2
FsRtlMdlReadCompleteDevEx shl count = 2
FsRtlMdlReadCompleteDevEx shr count = 4
FsRtlMdlReadCompleteDevEx ror count = 2

ObLogSecurityDescriptor xor count = 2 <=== данная ф-ция не интересна
ObLogSecurityDescriptor shr count = 1
ObLogSecurityDescriptor rol count = 2

KiSystemStartup xor count = 1 <=== данная ф-ция не интересна, т.к. данные инструкции используются только для инициализации security_cookie
KiSystemStartup rdtsc count = 1
KiSystemStartup shl count = 1
KiSystemStartup shr count = 2
KiSystemStartup rol count = 1
KiSystemStartup ror count = 2

SEH хендлеры IDA не нашла, поэтому используя скрипт из предыдущего поста, добавив в него вывод BeginAddress/EndAddress в RUNTIME_FUNCTION.

После отработки скрипта, запустим скрипт нахождения xor/ror/rol инструкций, выкинув лишнее(ObLogSecurityDescriptor, KiSystemStartup) получим:

sub_410820 xor count = 1 <=== Pg Seh handler
sub_410820 rol count = 1
sub_410820 ror count = 1

sub_5010D0 xor count = 1 <=== Pg Seh handler
sub_5010D0 rol count = 1
sub_5010D0 ror count = 1

sub_502360 xor count = 1 <=== Pg Seh handler
sub_502360 rol count = 1
sub_502360 ror count = 1

sub_565580 xor count = 2
sub_565580 shr count = 1
sub_565580 rol count = 2

sub_565730 xor count = 24
sub_565730 rdtsc count = 6
sub_565730 shl count = 6
sub_565730 shr count = 4
sub_565730 ror count = 6

sub_565950 xor count = 3
sub_565950 shr count = 4
sub_565950 rol count = 2

sub_565B10 xor count = 3
sub_565B10 shr count = 5
sub_565B10 rol count = 2

sub_566090 xor count = 6
sub_566090 rdtsc count = 1
sub_566090 shl count = 1
sub_566090 shr count = 1
sub_566090 ror count = 1

sub_566140 xor count = 3
sub_566140 shr count = 3
sub_566140 rol count = 2

sub_5667D0 xor count = 4
sub_5667D0 shr count = 5
sub_5667D0 rol count = 2

sub_566A50 xor count = 3
sub_566A50 shl count = 1
sub_566A50 shr count = 2
sub_566A50 rol count = 2

sub_566BC0 xor count = 3
sub_566BC0 shl count = 1
sub_566BC0 shr count = 3
sub_566BC0 rol count = 2

sub_566D30 xor count = 13
sub_566D30 rdtsc count = 3
sub_566D30 shl count = 5
sub_566D30 shr count = 1
sub_566D30 ror count = 3

FsRtlMdlReadCompleteDevEx xor count = 12
FsRtlMdlReadCompleteDevEx rdtsc count = 2
FsRtlMdlReadCompleteDevEx shl count = 2
FsRtlMdlReadCompleteDevEx shr count = 4
FsRtlMdlReadCompleteDevEx ror count = 2

Видно, что операции для всех трех SEH обработчиков одинаковые - xor, rol, ror.
Осталось определить к какой ф-ции они относятся. Для этого смотрим лог:

RuntimeFunctionAddress = 5a5bc4, beginAddress = 4107f0, endAddress = 410811, UnwindData = 531044, ExceptionHandler = 429830
Scope Handler = 410820
Scope Handler = 410820

RuntimeFunctionAddress = 5c9a8c, beginAddress = 501090, endAddress = 5010bd, UnwindData = 53101c, ExceptionHandler = 429830
Scope Handler = 5010d0

RuntimeFunctionAddress = 5b0e20, beginAddress = 43f130, endAddress = 43f1b1, UnwindData = 5312b4, ExceptionHandler = 429830
Scope Handler = 502360

Получаем DPC ф-ции используемые патчгвардом:

.text:00000000004107F0 ExpTimeZoneDpcRoutine proc near
.text:0000000000501090 ExpTimeRefreshDpcRoutine proc near
.text:000000000043F130 ExpTimerDpcRoutine proc near

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

Получим две основные цепочки, пример:

403AA2(KiFilterFiberContext) -> 403aa2 -> 8212f0 -> 804810 -> 565950

и

567450(FsRtlUninitializeSmallMcb) -> 566f00 -> 5667d0 -> 566260 -> 565ed0 -> 565b10 -> 565950 -> 565730

Очевидно, что одна из них - инициализация PG, а вторая - ф-ция проверки хешей.

Далее, построив дерево вызовов от этих 2х родительских ф-ций получим все ф-ции используемые патч гвардом.

Таким образом, статическим анализом будет найдено 95% кода патч гварда, на долю динамического анализа придется небольшая часть,
без которой полностью логику восстановить будет сложно.

p.s. Речь шла о PG первой версии.

2 комментария:

  1. Скрипт для нахождения xor/ror/rol я не стал постить, там ничего сложного нет, а загромождать пост им нехочется.

    ОтветитьУдалить