Простой "Hello-World", необходим нулевой шелл-код для Windows - PullRequest
0 голосов
/ 09 января 2011

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

Ответы [ 2 ]

2 голосов
/ 13 января 2013

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

В 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 и получения адресов ее функций.

Вот полный учебник по написанию Winшелл-коды dows: http://www.codeproject.com/Articles/325776/The-Art-of-Win32-Shellcoding

0 голосов
/ 29 декабря 2011

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

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

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

Счастливого взлома ...

...