Требуется простой Hello-World, шелл-код без нулей для Windows

Я хотел бы протестировать переполнение буфера, написав «Hello World» на консоль (используя Windows XP 32-Bit). Шелл-код должен быть без нулей, чтобы "scanf" мог передать его программе, которую я хочу переполнить. Я нашел множество руководств по сборке для Linux, но ни одного для Windows. Может ли кто-нибудь помочь мне пройти через это с помощью NASM? Thxxx!


person Daniel    schedule 09.01.2011    source источник
comment
Что ж, коды операций сборки одинаковы как для Linux, так и для Windows, вещи из этого учебника должны применяться и для Windows.   -  person BlackBear    schedule 09.01.2011
comment
Коды операций сборки такие же, но системные вызовы разные. См. Мой ответ ниже для более подробной информации. :)   -  person MarioVilas    schedule 13.01.2013


Ответы (2)


Коды операций сборки те же, поэтому обычные уловки для создания шелл-кодов без нулей все еще применимы, но способ выполнения системных вызовов другой.

В Linux вы выполняете системные вызовы с помощью инструкции "int 0x80", тогда как в Windows вы должны использовать библиотеки DLL и выполнять обычные вызовы пользовательского режима для их экспортируемых функций.

По этой причине в Windows ваш шелл-код должен:

  • Жестко закодируйте адреса функций Win32 API (скорее всего, будет работать только на вашем компьютере)
  • Используйте шеллкод преобразователя Win32 API (работает во всех версиях Windows)

Если вы только учитесь, сейчас, вероятно, проще просто жестко закодировать адреса, которые вы видите в отладчике. Чтобы сделать позицию звонка независимой, вы можете загрузить адреса в регистры. Например, вызов функции с 4 аргументами:

PUSH 4                  ; argument #4 to the function
PUSH 3                  ; argument #3 to the function
PUSH 2                  ; argument #2 to the function
PUSH 1                  ; argument #1 to the function
MOV EAX, 0xDEADBEEF     ; put the address of the function to call
CALL EAX

Обратите внимание, что аргументы помещаются в обратном порядке. После инструкции CALL EAX будет содержать возвращаемое значение, и стек будет таким же, как и раньше (т.е. функция выдает свои собственные аргументы). Регистры ECX и EDX могут содержать мусор, поэтому не полагайтесь на то, что они сохранят свои значения после вызова.

Прямая инструкция CALL не будет работать, потому что она зависит от позиции.

Чтобы избежать нулей в самом адресе, попробуйте любой из трюков без нулей для шеллкода x86, их много, но мой любимый (хотя и длинный) кодирует значения с помощью инструкций XOR:

MOV EAX, 0xDEADBEEF ^ 0xFFFFFFFF   ; your value xor'ed against an arbitrary mask
XOR EAX, 0xFFFFFFFF                ; the arbitrary mask

Вы также можете попробовать NEG EAX или NOT EAX (инверсия знака и переключение битов), чтобы проверить, работают ли они, это намного дешевле (два байта каждый).

Вы можете получить справку по различным функциям API, которые вы можете вызвать здесь: http://msdn.microsoft.com

Наиболее важные из них, вероятно, следующие:

Первая запускает команду, следующие две - для загрузки файлов DLL и получения адресов ее функций.

Вот полное руководство по написанию шелл-кодов Windows: http://www.codeproject.com/Articles/325776/The-Art-of-Win32-Shellcoding

person MarioVilas    schedule 13.01.2013

Язык ассемблера определяется вашим процессором, а синтаксис ассемблера определяется ассемблером (отсюда и синтаксис at & t и Intel). Основное различие (по крайней мере, я думаю, что раньше ...) в том, что окна работают в реальном режиме (вызов фактические прерывания для выполнения каких-либо действий, и вы можете использовать всю память, доступную для вашего компьютера, а не только вашу программу), а Linux - это защищенный режим (у вас есть доступ только к памяти в маленьком кубе памяти вашей программы, и вам нужно вызвать int 0x80 и выполнять вызовы ядра вместо вызовов оборудования и BIOS) В любом случае, материал типа hello world будет более или менее одинаковым для Linux и Windows, если они являются совместимыми процессорами.

Чтобы получить шелл-код из вашей программы, которую вы создали, просто загрузите его в отладчик вашей целевой системы (gdb для Linux и отладка для Windows) и в отладке введите d (или это было u? В любом случае, он должен сказать, если вы набираете h (help)), а между инструкциями и памятью будут коды операций. Просто скопируйте их в свой текстовый редактор в одну строку и, возможно, создайте программу, которая переводит их все в их значения ascii. Не уверен, как это сделать в GDB, хотя ...

В любом случае, чтобы превратить его в эксплойт bof, введите aaaaa ... и продолжайте добавлять, пока он не выйдет из строя из-за ошибки переполнения буфера. Но узнайте, сколько именно нужно, чтобы он сломался. Затем он должен сказать вам, какой это был адрес памяти. Обычно это должно быть указано в сообщении об ошибке. Если там написано «9797 [остальной исходный обратный адрес]», значит, вы его получили. Теперь вам нужно использовать отладчик ur, чтобы узнать, где это было. дизассемблируйте программу с помощью вашего отладчика и найдите, где был вызван scanf. Установите там точку останова, запустите и исследуйте стек. Найдите все эти 97 (которые я забыл упомянуть, это число ascii для 'a'.) И посмотрите, где они заканчиваются. Затем удалите точку останова и введите количество a, которое, как вы выяснили, потребовалось (точное количество. Если сообщение об ошибке было «переполнение буфера в '97 [остальной исходный адрес возврата]», то удалите последний a, введите адрес, который вы нашли при проверке стек и вставьте шелл-код.Если все пойдет хорошо, вы должны увидеть, как выполняется шелл-код.

Удачного взлома ...

person The_Doctor    schedule 29.12.2011
comment
С этим ответом есть несколько проблем. 1) Windows не реальный режим. 2) Код hello world для Windows и Linux сильно отличается, поскольку Windows - это не POSIX. 3) Лучше всего поискать ответ в Google, а не доверять своей памяти. 4) Объяснение того, как использовать bof, довольно запутанное, неполное и на самом деле не связано с вопросом. - person MarioVilas; 13.01.2013