Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #94, ОКТЯБРЬ 2006 г.

Сношения с Идой

Крис Касперски

Хакер, номер #094, стр. 094-120-5


1260: dd offset loc_401311

Хм, выглядит вполне обычно, и все метки без исключения обнаруживаются простым контекстным поиском:

$NORMAL_STATE$1535: mov ecx, dword_406428

…

loc_4012AA: or [ebp+var_10], 0FFFFFFFFh

…

loc_4012C5: movsx eax, bl

Почему же тогда ассемблерный транслятор их не видит?! Все дело в том, что IDA Pro неверно определила границы функции, поместив обращения к меткам за границы функции, в которой они упоминаются!!! А метки вообще-то локальны. Вот потому-то транслятор их и не находит!

$NORMAL_STATE$1535:

…

loc_4012AA:

…

loc_4012C5:

…

loc_401311:

…

__output endp ; <-- конец функции

off_401956 dd offset $NORMAL_STATE$1535

dd offset loc_4012AA

dd offset loc_4012C5

dd offset loc_401311

Чтобы исправить ситуацию, необходимо переместить директиву «__output endp» за конец обращений к меткам. Так, чтобы они стали частью функции __output. После чего ассемблерный код будет выглядеть так:

off_401956 dd offset $NORMAL_STATE$1535

dd offset loc_4012AA

dd offset loc_4012C5

__output endp

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

demo_3.asm(70) : error A2015: segment attributes cannot change : Alignment

demo_3.asm(8064) : error A2189: invalid combination with segment alignment : 2048

demo_3.asm(12005) : error A2015: segment attributes cannot change : Alignment

…

demo_3.asm(2925) : error A2006: undefined symbol : loc_402480

demo_3.asm(3640) : error A2001: immediate operand not allowed

demo_3.asm(4159) : error A2006: undefined symbol : loc_402D11

В глаза бросается пара уже известных нам ошибок типа «undefined symbol», первую из которых исправить достаточно легко:

__NLG_Notify1:

push ebx

push ecx

mov ebx, offset unk_406364

jmp short loc_402480

__NLG_Notify proc near

push ebx

push ecx

mov ebx, offset unk_406364

mov ecx, [ebp+8]

loc_402480:

mov [ebx+8], ecx

mov [ebx+4], eax

mov [ebx+0Ch], ebp

__NLG_Dispatch:

pop ecx

pop ebx

retn 4

__NLG_Notify endp

Достаточно «завести» подпрограмму __NLG_Notify1 под «retn 4» процедуры __NLG_Notyfy, но перед директивой __NLG_Notify endp, тогда метка будет распознаваться как надо!

__NLG_Notify proc near

push ebx

push ecx

mov ebx, offset unk_406364

mov ecx, [ebp+8]

loc_402480:

mov [ebx+8], ecx

mov [ebx+4], eax

mov [ebx+0Ch], ebp

__NLG_Dispatch:

pop ecx

pop ebx

retn 4

__NLG_Notify1:

push ebx

push ecx

mov ebx, offset unk_406364

jmp short loc_402480

__NLG_Notify endp

А вот со следующей ошибкой справиться уже сложнее, поскольку функция strcpy совершает прыжок в середину функции strcat:

_strcpy proc near

arg_0 = dword ptr 8

push edi

mov edi, [esp+arg_0]

jmp loc_402D11

_strcpy endp

_strcat proc near

arg_0 = dword ptr 4

arg_4 = dword ptr 8

mov ecx, [esp+arg_0]

…

loc_402D11:

mov ecx, [esp+4+arg_4]

test ecx, 3

jz loc_402D36

…

retn

_strcat endp

Никакими ухищрениями у нас не получится перетасовать код так, чтобы метка loc_402D11 оказалась в границах видимости, но ведь как-то же это было запрограммировано?! Обратившись к исходным текстам библиотеки LIBC.LIB (они поставляются вместе с компилятором) мы обнаружим волшебный ключик. Чтобы метка была видна отовсюду, после нее должен стоят не один знак «:», а целых два — «::».

Назад на стр. 094-120-4  Содержание  Вперед на стр. 094-120-6