Главная страница
Навигация по странице:

  • Рисунок 8 Окно «Сегменты»

  • Рисунок 9 Встроенный редактор скриптов auto a; for (a=0x116;a Пояснение

  • Рисунок 10 IDAC: Создание нового сегмента Подробнее о значении каждого из полей рассказано в главе «Сегменты и селекторы», а здесь не рассматривается. Пояснение

  • Описание функций встроенного языка


    Скачать 2.86 Mb.
    НазваниеОписание функций встроенного языка
    Анкорobraz_mihlenia_-_dizassembler_IDA
    Дата29.09.2022
    Размер2.86 Mb.
    Формат файлаpdf
    Имя файлаobraz_mihlenia_-_dizassembler_IDA.pdf
    ТипСправочник
    #704305
    страница3 из 39
    1   2   3   4   5   6   7   8   9   ...   39
    Base Type Cls 32es ss ds ▲
    ║ seg000 00000100 0000013C byte 1000 pub CODE N FFFF FFFF 1000 00010100 0001013C ▓
    ║ ▓
    ║ ▼

    17
    ╚1/1 ═════════════════◄■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒►─┘
    Рисунок 8 Окно «Сегменты»
    Искомый адрес находится в столбце “Base” и для наглядности на приведенной копии экрана выделен жирным шрифтом. Обратится к любой ячейке сегмента поможет конструкция “[segment:offset]”, а для чтения и модификации ячеек предусмотрены функции
    Byte и PatchByte соответственно. Их вызов может выглядеть, например, так: a=Byte([0x1000,0x100]) – читает ячейку, расположенную по смещению 0x100 в сегменте с базовым адресом 0x1000; PatchByte([0x1000,0x100],0x27) – присваивает значение 0x27 ячейке памяти, расположенной по смещению 0x100 в сегменте с базовым адресом 0x1000.
    Как следует из названия функций, они манипулируют с ячейками размером в один байт.
    Существуют так же функции, манипулирующие целыми словами, подробнее о них можно прочесть в главе «Виртуальная память».
    Знания этих двух функций вполне достаточно для написания скрипта - расшифровщика при условии, что читатель знаком с языком Си. Реализация IDA-Си не полностью поддерживается стандарта – подробнее об этом рассказывается в главе «Язык скриптов IDA-Си», здесь же достаточно заметить, что IDA не позволяет разработчику задавать тип переменной и определяет его автоматически по ее первому использованию, а объявление осуществляется ключевым словом “auto”. Например, “auto MyVar, s0” объявляет две переменных – MyVar и s0.
    Для создания скрипта необходимо нажать комбинацию клавиш или выбрать в меню “File” пункт “IDC Command” и в появившемся окне диалога ввести исходный текст программы:
    ╔═[■]════════════════ Notepad ═════════════════════╗
    ║ Enter IDC statement(s) ║
    ║ auto a; ▲ ║
    ║ for (a=0x116;a<0x12E;a++) ▓ ║
    ║ PatchByte([0x1000,a], ▓ OK ▄ ║
    ║ Byte([0x1000,a])^0x66); ▓ ▀▀▀▀▀▀▀▀ ║
    ║ ▓ ║
    ║ ▓ ║
    ║ ▓ Cancel ▄ ║
    ║ ▓ ▀▀▀▀▀▀▀▀ ║
    ║ ▓ ║
    ║ ▓ ║
    ║ ▓ Help ▄ ║
    ║ ▼ ▀▀▀▀▀▀▀▀ ║
    ║☼═════ 5:1 ═══◄■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒► ║
    ╚══════════════════════════════════════════════════╝
    Рисунок 9 Встроенный редактор скриптов
    auto a; for (a=0x116;a<0x12E;a++)
    PatchByte([0x1000,a],Byte([0x1000,a])^0x66); a) исходный текст скрипта - расшифровщика
    Пояснение:
    как было показано выше алгоритм расшифровщика сводится к последовательному преобразованию каждой ячейки зашифрованного фрагмента операцией XOR 0x66, (см. ниже – выделено жирным шрифтом) seg000:010C xor byte ptr [si], 66h
    seg000:010F inc si

    18
    seg000:0110 loop loc_0_10C
    Сам же зашифрованный фрагмент начинается с адреса seg000:0x116 и продолжается вплоть до seg000:0x12E. Отсюда – цикл расшифровки на языке Си выглядит так: for (a=0x116;a<0x12E;a++)
    PatchByte([0x1000,a],Byte([0x1000,a])^0x66);
    В зависимости от версии IDA для выполнения скрипта необходимо нажать либо
    (версия 3.8x и старше), либо в более ранних версиях. Если все сделано правильно, после выполнения скрипта экран дизассемблера должен выглядеть так (b).
    Возможные ошибки – несоблюдение регистра символов (IDA к этому чувствительна), синтаксические ошибки, базовый адрес вашего сегмента отличается от
    0x1000 (еще раз вызовете окно «Сегменты» чтобы узнать его значение). В противном случае необходимо подвести курсор к строке “seg000:0116”, нажать клавишу для удаления результатов предыдущего дизассемблирования зашифрованного фрагмента и затем клавишу для повторного дизассемблирования расшифрованного кода. seg000:0116 loc_0_116: ; CODE XREF: seg000:013Bu seg000:0116 mov ah, 9 seg000:0118 mov dx, 108h seg000:011B int 21h ; DOS - PRINT STRING seg000:011B ; DS:DX -> string terminated by "$" seg000:011D retn seg000:011D ; ─────────────────────────────────────────────────────────────────────────── seg000:011E db 48h ; H seg000:011F db 65h ; e seg000:0120 db 6Ch ; l seg000:0121 db 6Ch ; l seg000:0122 db 6Fh ; o seg000:0123 db 2Ch ; , seg000:0124 db 53h ; S seg000:0125 db 61h ; a seg000:0126 db 69h ; i seg000:0127 db 6Ch ; l seg000:0128 db 6Fh ; o seg000:0129 db 72h ; r seg000:012A db 21h ; ! seg000:012B db 0Dh ; seg000:012C db 0Ah ; seg000:012D db 24h ; $ seg000:012E ; ─────────────────────────────────────────────────────────────────────────── b) результат работы скрипта расшифровщика
    Цепочку символов, расположенную начиная с адреса “seg000:011E” можно преобразовать в удобочитаемый вид, подведя к ней курсор и нажав клавишу “”. Теперь экран дизассемблера будет выглядеть так: seg000:0116 loc_0_116: ; CODE XREF: seg000:013Bu seg000:0116 mov ah, 9 seg000:0118 mov dx, 108h seg000:011B int 21h ; DOS - PRINT STRING seg000:011B ; DS:DX -> string terminated by "$" seg000:011D retn seg000:011D ; ─────────────────────────────────────────────────────────────────────────── seg000:011E aHelloSailor db 'Hello,Sailor!',0Dh,0Ah,'$' seg000:012E ; ─────────────────────────────────────────────────────────────────────────── с) создание ASCII-строки
    Команда “MOV AH,9” в строке :0116 подготавливает регистр AH перед вызовом прерывания 0x21, выбирая функцию вывода строки на экран, смещение которой заносится следующей командой в регистр DX. Т.е. для успешного ассемблирования листинга необходимо заменить константу 0x108 соответствующим смещением. Но ведь выводимая строка на этапе ассемблирования (до перемещения кода) расположена совсем в другом месте! Одно из возможных решений этой проблемы заключается в создании нового

    19
    сегмента с последующим копированием в него расшифрованного кода – в результате чего достигается эмуляции перемещения кода работающей программы.
    Для создания нового сегмента можно выбрать в меню «View» пункт «Segments» и в раскрывшемся окне нажать клавишу . Появится диалог следующего вида (см. рис.
    10):
    ╔═[■]════════════ Create a new segment ════════════════╗
    ║ ║
    ║ Start address and end address should be valid. ║
    ║ End address > Start address ║
    ║ ║
    ║ Segment name MySeg ▐↓▌ ║
    ║ Start address 0x20100 ▐↓▌ C-notation: ║
    ║ End address 0x20125 ▐↓▌ hex is 0x... ║
    ║ Base 0x2000 ▐↓▌ in paragraphs ║
    ║ Class ▐↓▌ (class is any text)║
    ║ ║
    ║ [ ] 32-bit segment ║
    ║ ║
    ║ OK ▄ Cancel ▄ F1 - Help ▄ ║
    ║ ▀▀▀▀ ▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ║
    ╚══════════════════════════════════════════════════════╝
    Рисунок 10 IDAC: Создание нового сегмента
    Подробнее о значении каждого из полей рассказано в главе «Сегменты и селекторы», а здесь не рассматривается.
    Пояснение:
    Базовый адрес сегмента может быть любым если при этом не происходит
    перекрытия сегментов seg000 и MySeg;
    начальный адрес сегмента задается так, чтобы смещение
    первого байта было равно 0x100; разница между конечным и начальным адресом равна длине
    сегмента, вычислить которую можно вычитанием смещения начала расшифрованного фрагмента
    от смещения его конца – 0x13B – 0x116 = 0x25.
    Скопировать требуемый фрагмент в только что созданный сегмент можно скриптом следующего содержания. auto a; for (a=0x0;a<0x25;a++) PatchByte([0x2000,a+0x100],Byte([0x1000,a+0x116])); a) исходный текст скрипта - копировщика
    Для его ввода необходимо вновь нажать , при этом предыдущий скрипт будет утерян (IDA позволяет работать не более чем с один скриптом одновременно).
    После завершения его работы экран дизассемблера будет выглядеть так:
    MySeg:0100 MySeg segment byte public '' use16
    MySeg:0100 assume cs:MySeg
    MySeg:0100 ;org 100h
    MySeg:0100 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
    MySeg:0100 db 0B4h ; ┤
    MySeg:0101 db 9 ;
    MySeg:0102 db 0BAh ; ║
    MySeg:0103 db 8 ;
    MySeg:0104 db 1 ;
    MySeg:0105 db 0CDh ; ═
    MySeg:0106 db 21h ; !
    MySeg:0107 db 0C3h ; ├
    MySeg:0108 db 48h ; H
    MySeg:0109 db 65h ; e

    20
    MySeg:010A db 6Ch ; l
    MySeg:010B db 6Ch ; l
    MySeg:010C db 6Fh ; o
    MySeg:010D db 2Ch ; ,
    MySeg:010E db 53h ; S
    MySeg:010F db 61h ; a
    MySeg:0110 db 69h ; i
    MySeg:0111 db 6Ch ; l
    MySeg:0112 db 6Fh ; o
    MySeg:0113 db 72h ; r
    MySeg:0114 db 21h ; !
    MySeg:0115 db 0Dh ;
    MySeg:0116 db 0Ah ;
    MySeg:0117 db 24h ; $
    MySeg:0117 MySeg ends b) результат работы скрипта-копировщика
    Теперь необходимо создать перекрестную ссылку “from:seg000:013B; to:MySeg:0x100”, преобразовать цепочку символов в удобочитаемую строку, подведя курсор к строке MySeg:0108 и нажав клавишу . Экран дизассемблера должен выглядеть так:
    MySeg:0100 loc_1000_100: ; CODE XREF: seg000:013Bu
    MySeg:0100 mov ah, 9
    MySeg:0102 mov dx, 108h
    MySeg:0105 int 21h ; DOS - PRINT STRING
    MySeg:0105 ; DS:DX -> string terminated by "$"
    MySeg:0107 retn
    MySeg:0107 ; ───────────────────────────────────────────────────────────────────────────
    MySeg:0108 aHelloSailorS db 'Hello,Sailor!',0Dh,0Ah
    MySeg:0108 db '$'
    MySeg:0118 MySeg ends с) результат дизассемблирования скопированного фрагмента
    Результатом всех этих операций стало совпадение смещения строки со значением, загружаемым в регистр DX (в тексте они выделены жирным шрифтом). Если подвести курсор к константе “108h” и нажать клавишу она будет преобразована в смещение:
    MySeg:0102 mov dx, offset aHelloSailorS ; "Hello,Sailor!\r\n$ш"
    MySeg:0105 int 21h ; DOS - PRINT STRING
    MySeg:0105 ; DS:DX -> string terminated by "$"
    MySeg:0107 retn
    MySeg:0107 ; ───────────────────────────────────────────────────────────────────────────
    MySeg:0108 aHelloSailorS db 'Hello,Sailor!',0Dh,0Ah ; DATA XREF: MySeg:0102o d) преобразование константы в смещение
    Полученный листинг удобен для анализа, но все еще не
    готов к ассемблированию, хотя бы уже потому, что никакой ассемблер не в состоянии зашифровать требуемый код.
    Конечно, эту операцию можно выполнить вручную, после компиляции, но IDA позволит проделать то же самое не выходя из нее и не прибегая к помощи стороннего инструментария.
    Демонстрация получится намного нагляднее, если в исследуемый файл внести некоторые изменения, например, добавить ожидание клавиши на выходе. Для этого можно прибегнуть к интегрированному в IDA ассемблеру, но прежде, разумеется, необходимо несколько «раздвинуть» границы сегмента MySeg, дабы было к чему дописывать новый код.
    Выберете в меню “View” пункт “Segments” и в открывшемся окне подведите курсор к стоке “MySeg”. Нажатие открывает диалог свойств сегмента, содержащий среди прочих полей конечный адрес, который и требуется изменить. Не обязательно указывать точное значение – можно «растянуть» сегмент с небольшим запасом от предполагаемых изменений.
    Если попытаться добавить к программе код “XOR AX,AX; INT 16h” он неминуемо

    21
    затрет начало строки “Hello, Sailor!”, поэтому, ее необходимо заблаговременно передвинуть немного «вниз» (т.е. в область более старших адресов), например, с помощью скрипта следующего содержания «
    for(a=0x108;a<0x11A;a++) PatchByte([0x2000,a+0x20],Byte([0x2000,a]);
    ».
    Пояснение:
    объявление переменной a для краткости опущено (сами должны понимать, не
    маленькие :-), длина строки, как водится, берется с запасом, чтобы не утомлять себя лишними
    вычислениями и перемещение происходит справа налево, поскольку исходный и целевой фрагменты
    заведомо не пересекаются.
    Подведя к курсор к строке :0128 нажатием преобразуем цепочку символов к удобно-читаемому виду; подведем курсор к строке :0102 и, выбрав в меню “Edir” пункт “Path program”, “Assembler”, введем команду “MOV DX,128h”, где «128h» - новое смещение строки, и тут же преобразуем его в смещение нажатием .
    Вот теперь можно вводить новый текст – переместив курсор на инструкцию “ret”, вновь вызовем ассемблер и введем “
    XOR AX,AXINT 16hRET
    ”. На последок рекомендуется произвести «косметическую» чистку – уменьшить размер сегмента до необходимого и переместить строку “Hello, Sailor” вверх, прижав ее вплотную к коду.
    Пояснение:
    удалить адреса, оставшиеся при уменьшении размеров сегмента за его концом
    можно взводом флажка “Disable Address” в окне свойств сегмента, вызываемом нажатием
    Если все было сделано правильно конечный результат должен выглядеть как показано ниже: seg000:0100 ; File Name : F:\IDAN\SRC\Crypt.com seg000:0100 ; Format : MS-DOS COM-file seg000:0100 ; Base Address: 1000h Range: 10100h-1013Ch Loaded length: 3Ch seg000:0100 seg000:0100 seg000:0100 ; =========================================================================== seg000:0100 seg000:0100 ; Segment type: Pure code seg000:0100 seg000 segment byte public 'CODE' use16 seg000:0100 assume cs:seg000 seg000:0100 org 100h seg000:0100 assume es:nothing, ss:nothing, ds:seg000, fs:nothing, gs:nothing seg000:0100 seg000:0100 ; --------------- S U B R O U T I N E --------------------------------------- seg000:0100 seg000:0100 seg000:0100 public start seg000:0100 start proc near seg000:0100 add si, 6 seg000:0103 jmp si ; Ïåðåõîä ïî àäðåñó 0106 seg000:0103 start endp seg000:0103 seg000:0103 ; --------------------------------------------------------------------------- seg000:0105 db 0B9h ; ¦ seg000:0106 ; --------------------------------------------------------------------------- seg000:0106 mov si, offset BytesToDecrypt seg000:0109 lodsw seg000:010A xchg ax, cx seg000:010B push si seg000:010C seg000:010C loc_0_10C: ; CODE XREF: seg000:0110j seg000:010C xor byte ptr [si], 66h seg000:010F inc si seg000:0110 loop loc_0_10C seg000:0112 seg000:0112 BreakHere: ; Ïåðåõîä ïî àäðåñó 012E seg000:0112 jmp si seg000:0112 ; --------------------------------------------------------------------------- seg000:0114 BytesToDecrypt dw 18h ; DATA XREF: seg000:0106o seg000:0116 ; ---------------------------------------------------------------------------

    22
    seg000:0116 seg000:0116 loc_0_116: ; CODE XREF: seg000:013Bu seg000:0116 mov ah, 9 seg000:0118 mov dx, 108h ; "Hello,Sailor!\r\n$" seg000:011B int 21h ; DOS - PRINT STRING seg000:011B ; DS:DX -> string terminated by "$" seg000:011D retn seg000:011D ; --------------------------------------------------------------------------- seg000:011E aHelloSailor db 'Hello,Sailor!',0Dh,0Ah,'$' ; DATA XREF: seg000:0118o seg000:012E ; --------------------------------------------------------------------------- seg000:012E seg000:012E loc_0_12E: ; CODE XREF: seg000:0112u seg000:012E call $+3 seg000:0131 pop cx seg000:0132 pop si seg000:0133 mov di, 100h seg000:0136 push di seg000:0137 sub cx, si seg000:0139 repe movsb seg000:013B retn seg000:013B seg000 ends seg000:013B
    MySeg:0100 ; ---------------------------------------------------------------------------
    MySeg:0100 ; ===========================================================================
    MySeg:0100
    MySeg:0100 ; Segment type: Regular
    MySeg:0100 MySeg segment byte public '' use16
    MySeg:0100 assume cs:MySeg
    MySeg:0100 ;org 100h
    MySeg:0100 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing
    MySeg:0100
    MySeg:0100 loc_1000_100: ; CODE XREF: seg000:013Bu
    MySeg:0100 mov ah, 9
    MySeg:0102 mov dx, offset aHelloSailor_0 ; "Hello,Sailor!\r\n$"
    MySeg:0105 int 21h ; DOS - PRINT STRING
    MySeg:0105 ; DS:DX -> string terminated by "$"
    MySeg:0107 xor ax, ax
    MySeg:0109 int 16h ; KEYBOARD - READ CHAR FROM BUFFER, WAIT IF EMPTY
    MySeg:0109 ; Return: AH = scan code, AL = character
    MySeg:010B retn
    MySeg:010B ; ---------------------------------------------------------------------------
    MySeg:010C aHelloSailor_0 db 'Hello,Sailor!',0Dh,0Ah,'$' ; DATA XREF: MySeg:0102o
    MySeg:010C MySeg ends
    MySeg:010C
    MySeg:010C
    MySeg:010C end start a) окончательно дизассемблированный текст
    Структурно программа состоит из следующих частей – расшифровщика, занимающего адреса seg000:0x100 – seg000:0x113, переменной размером в слово, содержащей количество расшифровываемых байт, занимающей адреса seg000:0x114- seg000:0x116,
    исполняемого кода программы, занимающего целиком сегмент MySeg и загрузчика, занимающего адреса seg000:0x12E-seg000:0x13B. Все эти части должны быть в перечисленном порядке скопированы в целевой файл, причем исполняемый код программы необходимо предварительно зашифровать, произведя над каждым его байтом операцию XOR 0x66.
    Ниже приведен пример скрипта, автоматически выполняющего указанные действия. Для его загрузки достаточно нажать или выбрать в меню “File” пункт “Load file”, “IDC file”.
    // Компилятор для файла Crypt
    // static main()
    { auto a,f;
    // Открывается файл Crtypt2.com для записи в двоичном режиме

    23
    f=fopen("crypt2.com","wb");
    // В файл Crypt2 копируется расшифровщик for (a=0x100;a<0x114;a++) fputc(Byte([0x1000,a]),f);
    // Определяется и копируется в файл слово, содержащее число
    // байтов для расшифровки fputc( SegEnd([0x2000,0x100]) - SegStart([0x2000,0x100]),f); fputc(0,f);
    // Копируется и налету шифруется расшифрованный фрагмент for(a=SegStart([0x2000,0x100]);a!=SegEnd([0x2000,0x100]);a++) fputc(Byte(a) ^ 0x66,f);
    // Дописывается загрузчик for(a=0x12E;a<0x13C;a++) fputc(Byte([0x1000,a]),f);
    // Закрывается файл. fclose(f);
    } a) исходный код скрипта-компилятора
    Подробное объяснение каждой функции, встретившийся в скрипте, можно найти в главах «Сегменты и селекторы», «Файловый ввод-вывод» и т.д.
    Выполнение скрипта приведет к созданию файла “Crypt2.com”, запустив который можно убедиться в его работоспособности – он выводит строку на экран и, дождавшись нажатия любой клавиши, завершает свою работу.
    Огромным преимуществом такого подхода является «сквозная» компиляция файла, т.е. дизассемблированный листинг в действительности не ассемблировался! Вместо этого из виртуальной памяти байт-за-байтом читалось оригинальное содержимое, которое за исключением модифицированных строк доподлинно идентично исходному файлу.
    Напротив, повторное ассемблирование практически никогда не позволяет добиться полного сходства с дизассемблируемым файлом.
    IDA – очень удобный инструмент для модификации файлов, исходные тексты которых утеряны или отсутствуют; она практически единственный дизассемблер, способный анализировать зашифрованные программы, не прибегая к сторонним средствам; она обладает развитым пользовательским интерфейсом и удобной системой навигации по исследуемому тексту; она дает может справится с любой мыслимой и немыслимой задачей…
    …но эти, и многие другие возможности, невозможно реализовать в полной мере, без владения языком скриптов, что и подтвердил приведенный выше пример.
    1   2   3   4   5   6   7   8   9   ...   39


    написать администратору сайта