Путеводитель по написанию вирусов Win32

Тема в разделе "29a", создана пользователем psh3nka, 31 янв 2017.

Метки:
Статус темы:
Закрыта.
  1. psh3nka

    psh3nka Active Member

    Публикаций:
    0
    Регистрация:
    21 янв 2017
    Сообщения:
    104
    Путеводитель по написанию вирусов под Win32: 1. Введение /09.10.2002/ — архив WASM.RU

    Дисклеймер переводчика
    Серия туториалов "Путеводитель по написанию вирусов под Win32" предназначена для сугубо образовательных целей. По крайней мере именно это было целью перевода: предоставить людям информацию о формате PE-файла, работе операционной системы, таких полезных технологиях, как полиморфизм и многом другом, что может потребоваться кодеру в его нелегком пути к постижению дао программирования. То, как читатели используют эту информацию, остается на их совести.

    Дисклеймер автора
    Автор этого документа не ответственен за какой бы то ни было ущерб, который может повлечь неправильное использование данной информации. Цель данного туториала ― это научить людей как создавать и побеждать ламерские YAM-вирусы :). Этот туториал предназначается только для образовательных целей. Поэтому, законники, я не заплачу и ломанного гроша, если какой-то ламер использует данную информацию, чтобы сделать деструктивный вирус. И если в этом документе вы увидите, что я призываю разрушать или портить чужие данные, идите и купите себе очки.

    Несколько вводных слов
    Привет, дорогие друзья,
    вы помните "Путеводитель Billy Belcebu по написанию вирусов"? Это был большой туториал об устаревших в настоящее время вирусах под MS-DOS. В нем я рассказал о большинстве известных вирусных техник под DOS. Туториал был написан для начинающих, чтобы они стали чуть более продвинутыми. И вот я снова здесь и пишу еще один классный (я надеюсь) туториал, но в этот раз я буду говорить о новой угрозе нашего времени, вирусах под Win32, и, конечно, обо всем, что связано с этой темой. Я заметил отсутствие полноценного пособия и спросил себя, почему бы мне не написать его самому? Сказано ― сделано :). Пионером в области Win32-вирусов была группа VLAD, а пионером в области туториалов на эту тему стал Lord Julus. Я не забыл о парне, который написал интересные туториалы и зарелизил их до Lord Julus'а, конечно, я говорю о JHB. Интересные техники были разработаны Murkry, а затем Jacky Qwerty... Я надеюсь, что не забыл никого, кто сыграл еще важную роль в короткой истории создания вирусов под Win32. Обратите внимания, что я не забыл о родоначальниках всего этого.
    Как обычно, я хочу поблагодарить несколько музыкальных групп, таких как Blind Guardian, HammerFall, Stratovarius, Rhapsody, Marilyn Manson, Iron Maiden, Metallica, Iced Earth, RAMMS+EIN, Mago De Oz, Avalanch, Fear Factory, Korn, Hamlet и Def Con Dos. Их музыка создала прекрасную атмосферу для написания огромных туториалов и кода.
    Структура этго туториала отличается от моих прежних пособий, теперь я поместил в начало краткое содержание, а весь приведенный код написан мной или основывается на чужом, но адаптирован. В очень редких случаях он попросту рипнут ;). Шучу. Но я действительно постарался избежать ошибок, допущенных мной в моих туториалах о вирусах под почти исчезнувший в наше время MS-DOS (RIP).
    Я должен поблагодарить Super/29A, который помог мне при создании данного туториала, он был одним из моих бета-тестеров, а также пожертвовал кое-что для данного проекта.
    ОБРАТИТЕ ВНИМАНИЕ: Английский не является моих родным языком, поэтому прошу извинить меня за возможные ошибки (вероятно, их довольно много) и сообщить мне о них, чтобы я мог учесть это при обновлениях данного документа (я помещу ник того, кто укажет мне на ошибки, наряду с благодарностью).
    (Примечание переводчика: обратите внимание, что документ, который вы читаете, является переводом на РУССКИЙ. Информацию об ошибках в переводе следует слать переводчику, а не Billy Belcebu.)
    ― Вот мои контактные данные (но не спрашивайте у меня всякую ерунду, у меня не так много времени)
    E-mailbilly_belcebu@mixmail.com
    Personal web pagehttp://members.xoom.com/billy_bel
    http://www.cryogen.com/billy_belcebu
    Sweet dreams are made of this...
    © 1999 Billy Belcebu/iKX

    Содержание
    Кто-то (привет, Qozah!) сказал мне после чтения бета-версии этого туториала, что оно несколько хаотично, поэтому очень легко потеряться между главами. Я попытался реорганизовать туториал, хотя, возможно, мне это и не слишко удалось.
    • Дисклеймер
    • Несколько вводных слов
    • Содержание
    • Что потребуется для написания вируса
    • Краткое введение
    • Заголовок PE
    • Ring-3, кодинг на уровне пользователя
    • Ring-0, кодинг на уровне бога
    • Резидентность
    • Оптимизация в Win32
    • Антиотладка в Win32
    • Полиморфизм в Win32
    • Продвинутые Win32-техники
    • Приложение 1: полезная нагрузка
    • Приложение 2: об авторе
    • Заключение
      Что потребуется для написания вирусов
      Вот несколько программ, которые я хочу вам порекомендовать (если у вас нет денег, чтобы купить их... СКАЧАЙТЕ!) :)
      • Windows 95 или Windows NT или Windows 98 или Windows 3.x + Win32s :)
      • Пакет TASM 5.0 (который включает TASM32 и TLINK32)
      • SoftICE 3.23+ (или новее) для Win9X и для WinNT
      • Справочник по Win32 API
      • Win95 DDK, Win98 DDK, Win2000 DDK... короче все M$ DDK и SDK
      • Очень рекомендуется статья Мэтта Питрека о заголовке PE
      • Утилита Jacky Qwerty PEWRSEC
      • Несколько журналов, таких как 29A(#2+), Xine(#2+), VLAD($6), DDT(#1)...
      • Несколько вирусов под Windows, таких как Win32.Cabanas, Win95.Padania, Win32.Legacy...
      • Несколько эвристических антивирусов под Windows
      • "Нейромантик" Вильяма Гибсона, это священная книга
      • И это пособие, разумеется!
      Я надеюсь, что не забыл ничего важного.
    © Billy Belcebu, пер. Aquila
     
    Последнее редактирование модератором: 16 июл 2019
    rococo795 и Mikl___ нравится это.
  2. psh3nka

    psh3nka Active Member

    Публикаций:
    0
    Регистрация:
    21 янв 2017
    Сообщения:
    104
    Путеводитель по написанию вирусов под Win32: 2. Базовая информация /22.10.2002/

    Хорошо, начнем очищение вашей головы от концепций MS-DOS'овского программирования: чарующих 16-ти битных смещений, способов, как стать резидентными... все, что мы использовали годами, теперь стало абсолютно бесполезным. Да, теперь все это бесполезно. В данном пособии, когда я говорю о Win32, я подразумеваю Windows 95 (обычные, OSR1, OSR2), Windows 98, Windows NT или Windows 3.x + Win32s. Наиболее главное изменение, на мой взгляд, заключается в том, что прерывания были заменены функциями API, а 16-ти битные регистры и смещения были заменены 32-х битными. Да, Windows открыла двери другим языками программирования, кроме ассемблера (таким как C), но я останусь с ассемблером навсегда: в большинстве случаев он более понятен и удобен для оптимизирования (привет, Super!). Как я сказал несколькими строчками выше, вы должны использовать функции API. Вы должны знать, что параметры должны быть в стеке, а функции API вызываются с помощью call.
    PS: Также я должен сказать, что называю Win95 (и все ее версии) и Win98 как Win9X, а Win2000 как Win2k. Учтите это.

    Изменения между 16-ти и 32-х битным программированием
    Как правило мы будем работать с двойными словами вместо слов, и это открывает перед нами новые возможности. У нас есть на два сегмента больше, кроме уже известных CS, DS, ES и SS: FS и GS. И у нас есть новые 32-х битные регистры: EAX, EBX, ECX, EDX, ESI, EDI, EBP и ESP. Давайте посмотрим, как играть с регистрами: представьте, что у нас есть доступ к нижнему слову EAX. Что мы можем сделать? До этой части можно добраться с помощью AX, который и является нижним словом EAX. Например, EAX = 00000000, а мы хотим поместить 1234h в его нижнее слово. Мы просто должны сделать "mov ax, 1234h" и все. Но что, если нам нужен доступ к верхнему слову EAX? Для этих целей мы не можем использовать регистр: мы должны прибегнуть к какой-нибудь из инструкций вроде ROL (или SHL, если значение нижнего слова для нас неважно).
    Давайте продолжим и рассмотрим типичную программу, которую пишет кодер, изучая новый язык: "Hello, world!" :).

    "Hello, World" под Win32

    Это очень легко. Мы должны использовать функцию API "MessageBoxA", поэтому мы определяем ее с помощью команды "extrn", а затем помещаем параметры в стек и вызываем эту функцию. Обратите внимание, что строки должны быть в формате ASCIIZ (ASCII, 0). Помните, что параметры должны помещаться в стек в перевернутом порядке.
    Код (ASM):
    1.  
    2.  
    3.                 .386                            ; Процессор (386+)
    4.                 .model flat                     ; Использует 32-х битные
    5.                                                 ; регистры
    6.  
    7.  extrn          ExitProcess:proc                ; Функции API, которые
    8.  extrn          MessageBoxA:proc                ; использует программа
    9.  
    10.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    11.  ; С помощью директивы "extrn" мы указываем, какие API мы будем использовать;
    12.  ; ExitProcess возвращает контроль операционной системе, а MessageBoxA      ;
    13.  ; показывает классическое виндовозное сообщение.                           ;
    14.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    15.  
    16.  .data
    17.  szMessage       db      "Hello World!",0       ; Message for MsgBox
    18.  szTitle         db      "Win32 rocks!",0       ; Title of that MsgBox
    19.  
    20.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    21.  ; Здесь мы не будем помещать данные настоящего вируса. Фактически, только  ;
    22.  ; из-за того, что TASM отказывается ассемблировать код, если мы не поместим;
    23.  ; здесь какие-нибудь данные. Как бы то ни было... Помещайте здесь данные   ;
    24.  ; 1-го поколения носителя вашего вируса.                                   ;
    25.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    26.  
    27.                 .code                           ; Поехали!
    28.  
    29.  HelloWorld:
    30.                 push    00000000h               ; Стиль MessageBox
    31.                 push    offset szTitle          ; Заголовок MessageBox
    32.                 push    offset szMessage        ; Само сообщение
    33.                 push    00000000h               ; Хэндл владельца
    34.  
    35.                 call    MessageBoxA             ; Вызов функции
    36.  
    37.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    38.  ; int MessageBox(                                                          ;
    39.  ;   HWND hWnd,          // хэндл окна-владельца                            ;
    40.  ;   LPCTSTR lpText,     // адрес текста сообщения                          ;
    41.  ;   LPCTSTR lpCaption,  // адрес заголовка MessageBox'а                    ;
    42.  ;   UINT uType          // стиль MessageBox'а                              ;
    43.  ;  );                                                                      ;
    44.  ;                                                                          ;
    45.  ; Мы помещаем параметры в стек до вызова самой API-функции, и если вы      ;
    46.  ; помните, стек построен согласно принципу LIFO (Last In First Out),       ;
    47.  ; поэтому мы должны помещать параметры в перевернутом порядке (при всем    ;
    48.  ; уважении к автору данного туториала, я должен сказать, что он не прав    ;
    49.  ; вовсе не поэтому мы должны помещать данные в перевернутом порядке - прим.;
    50.  ; пер.). Давайте посмотрим на краткое описание каждого из параметров этой  ;
    51.  ; функции:                                                                 ;
    52.  ;                                                                          ;
    53.  ; ¦ hWnd: идентифицирует окно-владельца messagebox'а, который должен быть  ;
    54.  ;   создан. Если этот параметр равняется NULL, у окна с сообщением не будет;
    55.  ;   владельца.                                                             ;
    56.  ; ¦ lpText: указывает на ASCIIZ-строку, содержащую сообщение, которое нужно;
    57.  ;   отобразить.                                                            ;
    58.  ; ¦ lpCaption: указывает на ASCIIZ-строку, содержащую заголовок окна       ;
    59.  ;   сообщения. Если этот параметр равен NULL, будет использован заголовок  ;
    60.  ;   по умолчанию.                                                          ;
    61.  ; ¦ uType: задает флаги, которые определяют содержимое и поведение         ;
    62.  ;   диалогового окна. Это параметр может быть комбинацией флагов.          ;
    63.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    64.  
    65.                 push    00000000h
    66.                 call    ExitProcess
    67.  
    68.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    69.  ; VOID ExitProcess(                                                        ;
    70.  ;   UINT uExitCode      // код выхода для всех ветвей                      ;
    71.  ;  );                                                                      ;
    72.  ;                                                                          ;
    73.  ; Эта функция эквивалентна хорошо известному Int 20h или функциям 00, 4С   ;
    74.  ; Int 21h. Она просто завершает выполнение текущего процесса. У нее только ;
    75.  ; один параметр:                                                           ;
    76.  ;                                                                          ;
    77.  ; ¦ uExitcode: задает код выхода для процесса и всех ветвей, выполнение    ;
    78.  ;   которых будет прервано вызовом данной функции. Используйте функцию     ;
    79.  ;   GetExitCodeProcess, чтобы получить код возврата процесса, а функцию    ;
    80.  ;   GetExitCodeThread, чтобы получить код возврата треда.                  ;
    81.  ;-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·;
    82.  
    83.  end HelloWorld
    84.  
    Как вы можете видеть, это все очень просто программируется. а теперь, когда вы знаете, как сделать "Hello, world!", вы можете заразить весь мир ;).
     
    rococo795 и Mikl___ нравится это.
  3. psh3nka

    psh3nka Active Member

    Публикаций:
    0
    Регистрация:
    21 янв 2017
    Сообщения:
    104
    Кольца
    Я знаю, что все вы очень боитесь того, что сейчас последует, но, как продемонстирую, все это на самом деле несложно. Вы должны уяснить: у процессора четыре уровня привилегий: Ring-0, Ring-1, Ring-2 и Ring-3, причем последний имеет больше всего ограничений, а первый подобен Валгалле для кодеров, почти полная свобода действий. Вспомните DOS, где мы всегда программировали в Ring-0... А теперь подумайте, что вы сможете делать то же самое под платформами Win32... Ладно, прекратим мечтать и начнем работать.
    Ring-3 ― это т.н. "пользовательский" уровень, на котором у нас множество ограничений. Кодеры Microsoft сделали ошибку, когда зарелизили Win95 и сказали, что она "незаражаема". Это было продемонстрировано еще до начала продаж системы Bizatch (которых еще неверно называли Boza, но это другая история). Программисты Microsoft думали, что вирус не сможет добраться до API. Но они не подумали об интеллектуальном превосходстве вирмейкеров... Конечно, мы можем писать вирус и на пользовательском уровне. Достаточно взглянуть на массу новых Win32 вирусов времени выполнения, которые релизятся в настоящее время, они все сделаны под Ring-3... Не поймите меня неверно, я не говорю, что это плохо, и между прочим, только Ring-3 вирусы могут работать под всеми версиями Win32. Они ― будущее... в основном из-за того, что скоро будет релиз Windows NT 5.0 (или Windows 2000). Для успешной жизни вируса мы должны найти функции API (то, что написали Bizatch, размножалось плохо, потому что они "захардкодили" адреса API-функций, а они отличаются от версии к версии Windows), что мы можем сделать несколькими способами, о которых я расскажу позже.
    Ring-0 ― это другая история, очень отличная от Ring-3. Это уровень, на котором работает ядро. Разве это не прекрасно? Мы можем иметь доступ к портам, к местам, о которых не могли мечтать раньше... это почти что оргазм. Мы не можем выйти в Ring-0 без использования одного из специальных способов, таких как модификация IDT, техника "Call Gate", показанная SoPinKy/29A в 29A#3 или вставки в VMM, техника, продемонстрированная в вирусах Padania или Fuck Harry. Нам не нужны API-функции, так как мы работает напрямую с сервисами VxD и похоже, что их адреса одни и те же во всех версиях Win9x, поэтому мы можем их указывать явно. Я расскажу об этом подробнее во главе, посвященной Ring-0.

    Важные сведения
    Я думаю, что должен рассказать об этом вначале данного пособия, как бы то ни было, лучше об этом знать, чем не знать :). Хорошо, давайте поговорим о внутренностях наших Win32-операционных систем.
    Во-первых, вы должны уяснить несколько концепций. Давайте начнем с селекторов. Что такое селектор? Это очень просто. Это очень большой сегмент, и эта форма Win32-памяти также называется плоской памятью. Мы можем напрямую обращаться к 4 гигабайтам памяти (4.294.967.295 байтов) используя только 32-х битные смещения. И как организованна эта память? Давайте взглянем на одну из диаграмм, которые я так люблю делать:
    [​IMG]
    Обратите внимание на одну вещь: у WinNT последние две секции находятся отдельно от первых двух. Ладно, теперь я помещу определения, которые вы должны знать. В остальной части туториала я буду исходить из того, что вы о них помните.

    ¤ VA:
    VA расшифровывается как Virtual Address (виртуальный адрес). Это адрес чего-нибудь, но в памяти (помните, что в Windowz вещи на диске и в памяти не обязательно эквиваленты).

    ¤ RVA:
    RVA расшифровывается как Relative Virtual Address. Очень важно четко это понять. RVA ― это смещение на что-то, относительно того места, куда промэппирован файл (вами или системой).

    ¤ RAW-данные:
    RAW-данные ― это имя, которое мы используем для обозначения данных так, как они есть физически на диске (данные на диске ≠ данные в памяти).

    ¤ Виртуальные данные:
    Виртуальные данные ― это имя, которым мы называем данные, когда они загруженны системой в память.

    ¤ Файловый мэппинг:
    Техника, реализованная во всех операционных системах Win32, которая позволяет производить различные действия с файлом быстрее и затрачивать при этом меньше памяти, а также она более удобна, чем способы, практиковавшиеся в DOS. Все, что мы изменяем в памяти, также изменяется на диске. Файловый мэппинг ― это единственный способ обмениваться информацией между различными процессами, который работает во всех Win32-операционных системах.

    Как компилировать программы

    Черт, я почти забыл об этом :). Используются обычные параметры для компиляции ассемблерной программы под Win32. Все примеры в данном туториале компилируются со следующими параметрами (где 'program' ― это имя файла .asm, но без какого-либо расширения):
    tasm32 /m3 /ml program,,;
    tlink32 /Tpe /aa program,program,,import32.lib
    pewrsec prog
    Я надеюсь, что это достаточно ясно. Вы также можете использовать make-файлы или написать .bat, который будет делать все автоматически (как сделал я!).

    © Billy Belcebu, пер. Aquila
     
    Последнее редактирование модератором: 16 июл 2019
    rococo795 и Mikl___ нравится это.
  4. psh3nka

    psh3nka Active Member

    Публикаций:
    0
    Регистрация:
    21 янв 2017
    Сообщения:
    104
    Путеводитель по написанию вирусов под Win32: 3. Заголовок PE /23.10.2002/

    Вероятно, это одна из самых важных глав данного пособия. Прочитайте его!

    Введение

    Очень важно хорошо представлять себе структуру заголока PE-файла, чтобы писать наши виндовозные вирусы. В этой главе я перечислю все, что считаю наиболее важным, но здесь не вся информация о PE-файле, поэтому рекомендую взглянуть на документы, упомянутые в разделе "Что потребуется...".
    [​IMG]
    Давайте рассмотрим каждую из этих частей поподробнее. Вот диаграмма в стиле Micheal J. O'Leary.
    [​IMG]
    Теперь, когда вы получили общее представление о заголовке PE, эта чудесная (но несколько усложненная) вещь станет нашей новой целью. Хорошо-хорошо, у вас есть уже общее представление, но вам нужно знать внутреннюю структуру заголовка PE. Приготовьтесь!
    IMAGE_FILE_HEADER
    [​IMG]
    Я дам краткое описание (резюме того, что сказал в своем прекрасном документе о формате PE-файла Мэтт Питрек) полей IMAGE_FILE_HEADER.

    ¤ PE\0\0:
    Это метка, которая есть у каждого PE-файла. Просто проверяйте ее существование при заражении файла. Если метки нет, то это не PE-файл, ок?

    ¤ Машина:
    Так как компьютером, который мы используем может быть несовместим с PC (теоретически), а PE-файлы могут быть и на таких компьютерах, в этом поле указывается тип машины, для которой предназначается приложение. Может быть одно из следующих значений:
    IMAGE_FILE_MACHINE_I38614ChIntel 386
    IMAGE_FILE_MACHINE_R3000162hMIPS little-endian,160h big-endian
    IMAGE_FILE_MACHINE_R4000166hMIPS little-endian
    IMAGE_FILE_MACHINE_R10000168hMIPS little-endian
    IMAGE_FILE_MACHINE_ALPHA184hAlpha_AXP
    IMAGE_FILE_MACHINE_POWERPC1F0hIBM PowerPC Little-Endian

    ¤ Количество секций:
    Это поле играет важную роль при заражении. Оно сообщает, сколько секций в файле.

    ¤ Временной штамп:
    Содержит количество секунд, которое прошло с декабря 31-ого 1969 года с 4:00 до того момента, когда файл был слинкован.

    ¤ Указатель на таблицу символов
    Не интересно, поскольку используется только в OBJ-файлах.

    ¤ Количество символов:
    Не интересно, поскольку используется только в OBJ-файлах.

    ¤ Размер опционального заголовка:
    Содержит количество байтов, которое занимает IMAGE_OPTIONAL_HEADER (смотри описание

    ¤ Характеристики:
    Флаг дает нам еще кое-какую информацию о файле. Нам это не интересно.

    IMAGE_OPTIONAL_HEADER

    [​IMG]

    ¤ Magic:
    Так как это поле всегда равно 010Bh, похоже, что это какая-то сигнатура. Не интересно.

    ¤ Старшая и младшая версии линкера:
    Версия линкера, который создал файл. Не интересно.

    ¤ Размер кода:
    Количество байт (округленное) во всех секциях, содержащих исполняемый код.

    ¤ Размер инициализированных данных:
    Предполагается, что здесь должен указываться общий размер всех секций с инициализированными данными.

    ¤ Размер неинициализированных данных:
    Неинициализированные данные не занимают места на винте, но когда система загружает файл, она выделяет ему некоторое количество памяти (виртуальную память).

    ¤ Адрес точки входа:
    Где загрузчик начнет выполнение кода. Это RVA относительно базы образа, когда система загружает файл. Очень интересно.

    ¤ База кода:
    RVA, откуда начинаются секции файла с кодом. Секции с кодом обычно идут до секций с данными и после PE-заголовка. Для файлов, произведенных с помощью микрософтовских линкеров, этот RVA обычно равен 0x1000. TLINK32, похоже, добавляет к этому RVA базу образа и сохраняет результат в данном поле.

    ¤ База данных
    RVA, откуда начинаются секции с данными. Они обычно идут последними после PE-заголовка и секций с кодом.

    ¤ База образа:
    Когда линкер создает экзешник, он предполагает, что файл будет промэппирован в определенное место в памяти. Этот адрес и хранится в данном поле, делая возможным определенную оптимизацию со стороны линкера. Если файл действительно промэппирован по этому адресу, код не нуждается в каком-либо патчении перед запуском. В экзешниках, компилируемых для Windows NT, база образа по умолчанию равна 0x10000, а для DLL он по умолчанию равен 0x400000. В Win9x адрес 0x10000 не может использоваться при загрузке 32-х битных EXE, так как он находится внутри региона, разделяемого всеми процессами. Из-за этого Микрософт изменил адрес базы по умолчанию на 0x400000.

    ¤ Выравнивание секций:
    При мэппировании секции выравниваются таким образом, чтобы они начинались с виртуального адреса, кратного данному значению. Выравнивание секций по умолчанию равно 0x1000.

    ¤ Файловое выравнивание:
    В PE-файле raw-данные, представляющие каждую из секций, начинаются со значения, кратного данному параметру. По умолчанию он равен 0x200, вероятно, потому что тогда секции будут начинаться с начала сектора диска (который также равен 0x200 байтам). Это поле эквивалентно размеру выравнивания сегментов/ресурсов в NE-файлах. В отличии от NE-файлов, PE-файлы не имеют сотен секций, поэтому на файловое выравнивание уходит очень мало место.

    ¤ Старшая и младшая версии операционной системы:
    Минимальная версия операционной системы, которая требуется для использования данной программы. Назначение данного поля не совсем ясно, так как поля подсистемы служат, похоже, той же самой цели. Это поле по умолчанию равно 1.0.

    ¤ Младшая и старшая версии образа:
    Задаваемое пользователем поле. Оно позволяет вам иметь разные версии EXE или DLL. Вы можете установить значения этих полей с помощью опции линкера /VERSION. Например LINK /VERSION:2.0 myobj.obj

    ¤ Старшая и младшая версии подсистемы:
    Содержат минимальную версию подсистемы, которая требуется для запуска данной программы. Типичное значение этого поля ― 3.10 (что означает Windows NT 3.1).

    ¤ Зарезервировано:
    Похоже, что оно всегда равно 0 (идеально для метки заражения).

    ¤ Размер образа:
    Похоже, что это полный размер всех частей образа, о которых должен позаботиться загрузчик. Это размер региона, начинающегося от базы образа до конца последней секции, который округляется до ближайшего числа, кратного выравниванию секций.

    ¤ Размер заголовков:
    Размер PE-заголовка и таблицы секций (объектов). Raw-данные секций начинаются непосредственно после всех компонентов заголовка.

    ¤ Чексумма:
    Предположительно CRC файла. Как и в других микрософтовских форматах исполняемых файлов, это поле игнорируется и устанавливается в 0. Есть одно исключение из этого правила: в доверенных (trusted) сервисах и EXE это поле должно содержать верную чексумму.

    ¤ Подсистема:
    Тип подсистемы, используемой приложением для пользовательского интерфейса.
    NATIVE1 Не требует подсистемы (например драйвер устройства)
    WINDOWS_GUI2Выполняется в подсистеме Windows GUI
    WINDOWS_CUI3Выполняется в символьной подсистеме Windows
    (консольное приложение)
    OS2_CUI5Выполняется в символьной подсистеме OS/2 (только OS/2 1.x)
    POSIX_CUI7Выполняется в символьной подсистеме Posix

    ¤ Характеристики DLL:
    Набор флагов, задающий при каких условиях будет вызываться функция инициализации DLL (например DLLMain). Похоже, что это значение всегда равно 0, тем не менее операционная система вызывает инициализацию DLL для всех 4-х событий.
    1Вызывать инициализацию, когда DLL впервые загружается в адресное пространство процесса
    2Вызывать инициализацию, когда тред завершает работу
    4Вызывать инициализацию, когда тред начинает работу
    8Вызывать инициализацию, когда DLL завершает свою работу

    ¤ Размер зарезервированного стека:
    Количество виртуальной памяти, резервируемой для начального стека треда. Тем не менее, не вся эта память выделяется (смотри следующее поле). Это поле по умолчанию равно 0x100000. Если вы укажете 0 в качестве размера стека при создании треда функцией CreateThread, именно столько будет занимать стек нового треда.

    ¤ Размер выделенного стека:
    Количество памяти, выделяемой для начального стека треда. Это поле по умолчанию равно 0x1000 (1 страница) у Microsoft Linker, в то время как TLINK32 делает это поле равным двум страницам.

    ¤ Размер зарезервированной кучи:
    Количество виртуальной памяти, которое необходимо зарезервировать для начальной кучи процесса. Этот хэндл кучи можно получить, вызвав GetProcessHeap. Нет вся эта память выделяется (смотри следующее поле).

    ¤ Размер выделенной кучи:
    Количество памяти, изначально выделяемой для кучи процесса. По умолчанию ― одна страница.

    ¤ Флаги загрузчика:
    Согласно WINNT.H эти поля относятся к поддержке отладки. Я никогда не видел экзешника с установленными битами этого поля, да и как заставить линкер их установить не совсем понятно.
    1. Вызвать инструкцию точки прерывания перед запуском процесса
    2. Вызвать отладчик после того, как процесс будет загружен в память

    ¤ Number Of Rva And Sizes:
    Количество элементов в массиве DataDirectory (ниже). Современные компиляторы всегда устанавливает это поле равным 16.
     
    Последнее редактирование модератором: 16 июл 2019
    rococo795 нравится это.
  5. psh3nka

    psh3nka Active Member

    Публикаций:
    0
    Регистрация:
    21 янв 2017
    Сообщения:
    104
    IMAGE_SECTION_HEADER
    [​IMG]

    ¤ Имя секции:
    Это 8-ми байтовое имя в формате ANSI (UNICODE), которая задает имя секции. Большая часть имен секций начинается с "." (например ".text"), но это не обязательное требование как утверждают некоторые руководства по формату PE. Вы можете назвать вашу секцию как хотите с помощью специальной директивы ассемблера или с помощью "#pragma data_seg" и "#pragma code_seg" в Microsoft C/C++ компиляторе. Важно учитывать, что если имя секции занимает 8 байт, то в конце не будет NULL-байта. Вы можете использовать %.8s с функцией printf, чтобы скопировать строку в другой буфер и добавить NULL в конце.

    ¤ Виртуальный размер:
    Значение этого файла отличается в EXE и OBJ. В EXE он содержит реальный размер код или данных. Это размер до округления до ближайшего числа, кратного файловому выравниванию. Поле SizeOfRawData 'размер raw-данных' (похоже, названное не совсем верно) содержит округленное значение. Линкер Borland'а меняет значения этих двух полей и похоже, что он прав. Для OBJ файлов этой поле означает физический адрес секции. Первая секция начинается с адреса 0. Чтобы найти физический адрес следующей секции в OBJ-файле, добавьте значение SizeOfRawData к физическому адресу текущих секции.

    ¤ Виртуальный адрес:
    В EXE это поле содержит RVA на то место, куда загрузчику следует промэппировать секцию. Чтобы посчитать реальный стартовый адрес данной секции в памяти и добавьте базовый адрес образа к виртуальному адресу (поле VirtualAddress). Микрософтовские инструменты по умолчанию указывают на RVA 0x1000. В OBJ'ах это поле не имеет значения и установлено в 0.

    ¤ Размер raw-данных:
    В EXE это поле содержит округленный до кратного файловому выравниванию числа размер секции. Например, предположим, что файловое выравнивание равно 0x200. Если поле VirtualSize содержит значение 0x35A, в этом поле будет находиться 0x400. В OBJ'ах это поле содержит точный размер секции, созданной компилятором или ассемблером. Другими словами для OBJ это поле играет ту же роль, что и виртуальный размер в EXE.

    ¤ Указатель на raw-данные:
    Это смещение на raw-данные, которое меняется от файла к файлу. Если ваша программа самостоятельно загружает файл PE или COFF в память (вместо того, чтобы позволить сделать это операционной системе), это поле более важно, чем VirtualAddress ― по этому смещению вы найдете данные секций, а не по RVA, указанном в поле виртуального адреса.

    ¤ Указатель на релокейшены:
    В OBJ'ах это смещение на информацию о релокейшенах данной секции. Информация о релокейшенах каждой секции OBJ следует непосредственно за raw-данными этой секции. В EXE это поле не имеет значения (как и следующее поле) и установлено в ноль. Когда линкер создает EXE, он устанавливает большую часть адресных записей (fixups), и только релокейшены адреса базы и импортируемых функций устанавливаются во время загрузки. Информация о релокейшенах базы и импортируемых функций находится в специальных секциях, поэтому в EXE нет необходимости держать информацию о релокейшенах после каждой секции raw-данных.

    ¤ Указатель на номера строк:
    Это смещение на таблице номеров строк. Эта таблица соотносит номера строк исходного кода со сгенерированным кодом для каждой конкретной строки. В современных отладочных форматах, таких как формат CodeView, информация о номерах строк хранится как часть отладочной информации. В отладочном формате COFF, тем не менее, информация о номерах строк хранится отдельно от символьной информации о именах/типах. Обычно только секциим кода (такие как .text) требуется данная информация. В EXE-файлах номера строк собираются ближе к концу файла после raw-данных секций. В OBJ-файлах таблица номеров строк для секций находится после секции данных и таблицы релокейшенов для этой секции.

    ¤ Количество релокейшенов:
    Количество релокейшенов в соответствующей таблице для данной секции (поле PointerToRelocations ― 'указатель на релокейшены'). Похоже, что данное поле содержит верные данные только в OBJ'ах.

    ¤ Количество номеров строк:
    Количество номеров строк в соответствующей таблице для данной секции.

    ¤ Характеристики:
    То, что большинство программистов называет флагами, формат COFF/PE называет характеристиками. Это поле является множеством флагов, которые задают атрибуты секции (такие как код/данные, доступно ли для чтения или для записи). Чтобы получить полный список всех возможных атрибутов секций, смотрите IMAGE_SCN_XXX_XXX #defin'ы в WINNT.H. Некоторые из важных флагов приведены ниже:
    0x00000020Эта секция содержит код. Обычно устанавливается вместе с флагом выполняемого кода (0x80000000).
    0x00000040Эта секция содержит инициализированные данные. Этот флаг есть почти у всех секций кроме секции выполняемого кода и .bss.
    0x00000080Эта секция содержит неинициализированные данные (например секция .bss).
    0x00000200Эта секция содержит комментарии или другой тип информации. Типичное использование данной секции ― это секция .drectve, добавляемая компилятором и содержащая команды для линкера.
    0x00000800Содержимое этой секции не должно помещаться в конечный EXE-файл. Эти секции используются компилятором/ассемблером, чтобы передать информацию линкеру.
    0x02000000Эту секция можно выгрузить из памяти после загрузки (например секция с релокейшенами ― .reloc).
    0x10000000Эта секция является разделяемой. Если используется вместе с DLL, данные в этой секции будут разделяться всеми процессами, ее использующими. По умолчанию секции данных являются неразделяемыми, и это означает, что каждый процесс, использующий DLL получает свою собственную копию этой секции данных. Если использовать техническую терминологию, флаг разделяемости говорит менеджеру загрузки, чтобы тот установил мэппинги страниц таким образом, чтобы все процессы, использующие DL ссылались на одну и ту же физическую страницу в памяти. Чтобы сделать секцию разделяемой, используйте атрибут SHARED во время линковки. Например:
    LINK /SECTION:MYDATA,RWS ...
    говорит линкеру, что секция под названием MYDATA должна быть доступной для чтения и записи, а также быть разделяемой.
    0x20000000Эта секция является исполняемой. Этот флаг обычно устанавливается везде, где установлен флаг кода (0x00000020).
    0x40000000Эта секция доступна для чтения. Этот флаг установлен почти для всех секций EXE-файла.
    0x80000000Эта секция доступна для записи. Если этот флаг не установлен в секции EXE, загрузчик должен пометить промэппированные страницы как доступные только для чтения или выполнения. Обычно такой атрибут есть у секций .data и .bss. Что интересно, у секции .idata этот атрибут тоже установлен.
    Необходимые изменения
    Хорошо, здесь я объясню вам изменения, которые необходимо выполнить при заражении PE. Я предполагаю, что вы делаете вирус, который увеличивает размер последней секции PE-файла. Эта техника получила наибольшее распространение среди нас, да и она, между прочим, гораздо проще, чем добавление другой секции. Давайте посмотрим, как вирус может изменить заголовок исполняемого файла. Для этого мы используем программу INFO-PE Lord'а Julus'а [SLAM]

    + DOS-информация +
    Код (Bash):
    1.  
    2. Анализируемый файл: GOAT002.EXE
    3.  
    4.  DOS-отчеты:
    5.               ¦ Размер файла          - 2000H      (08192d)
    6.               ¦ Время создания файла  - 17:19:46   (hh:mm:ss)
    7.               ¦ Дата создания файла   - 11/06/1999 (dd/mm/yy)
    8.               ¦ Аттрибуты : архивный
    9.  
    10.  [...]
    11.  
    + PE Header +
    [​IMG]
    + Опциональный заголовок PE +
    [​IMG]
    + Заголоки PE-секции +
    [​IMG]


    Это был нормальный незараженный файл. Ниже идет тот же самый файл, но зараженный моим Aztec'ом (Вирус-пример для Ring-3, смотри ниже).


    + DOS INFORMATION +
    Анализируемый файл: GOAT002.EXE
    Код (Bash):
    1.  
    2.  DOS-отчеты:
    3.              ¦ Размер файла  - 2600H      (09728d)
    4.              ¦ Время создания файла  - 23:20:58   (hh:mm:ss)
    5.              ¦ Дата создания файла  - 22/06/1999 (dd/mm/yy)
    6.              ¦ Аттрибуты : архивный
    7.  
    8.  [...]
    9.  
    + Заголовок PE +
    [​IMG]
    + Опциональный PE-заголовок +
    [​IMG]
    + Заголовки PE-секций +
    [​IMG]


    Я надеюсь, что это помогло вам понять, что мы делаем, когда заражаем PE, увеличивая его последнюю секцию. Чтобы вам не сравнивать каждую из этих таблиц друг с другом, я составил для вас следующим маленький список:
    [​IMG]
    Код очень прост. Для тех, кто не понимает ничего без кода, взгляните на Win32.Aztec, который полностью объяснен в следующей главе.
    © Billy Belcebu, пер. Aquila
     
    Последнее редактирование модератором: 16 июл 2019
    rococo795 и Mikl___ нравится это.
Статус темы:
Закрыта.