Пишу тему, скорее не для какого-либо ответа, а скорее поделиться очередным неудачным опытом. Проходил уроки по реверсу IdaPro сделанные yashechka и тут, как мне показалось, у меня возникла "блестящая" идея, а почему бы не менять необходимую мне информацию прямо в памяти программы. Поразбиравшись в этой теме, начал писать свой сканер сигнатур. Сначала начал делать вывод информации на основе ListView, но он оказался не подходящим для этого дела. Я это понял, когда уже написал пару тысяч строк. Ну что же, мне в первой, переписывать. Сел и хорошенько всё обдумал, решил что подходящим для вывода информации будет контрол TreeView. Опять начал писать программу и вот когда уже набралось три тысячи строк(почему я пишу про количество строк, для того что бы было понятно, что первая неудачная часть программы заняла не одну неделю усилий и вторая часть также), пришёл к печальному выводу: если ты знаешь сигнатуру, то это еще не значит, что ты сможешь узнать в какую ячейку памяти, последовательность инструкций запишет данные. К примеру, возьмём всем известную программу CheatEngine, она сканируя память находит адрес с необходимым значением, после этого, каким то чудесным образом устанавливает инструкции которые пишут в эту ячейку памяти и читают из неё. Но вот обратный вариант, если ты знаешь инструкции, найти ячейку памяти в которую пишут эти инструкции (по моему мнению) уже невозможно, потому что одни и те же инструкции могут записывать кучу разных данных не имеющих к друг другу ни какого отношения. Например: Код (Text): mov ecx,[rdx] mov [rax],ecx Тему это пишу, потому что вроде бы надо продолжать писать программу, но смысла она уже не имеет даже для "внутреннего использования". Вообщем очередной кризис, делал, делал, что-то а оказалось впустую.
На то, что ты привел, делать сигнатуру неразумно. Сигнатура должна цепляться за уникальную последовательность/константы. Какой толк от десятков тысяч попаданий в последовательность из двух мувов? Интел не очень подходит для всех этих фокусов: из-за sib-байта и нескольких вариантов как можно закодировать одну и ту же инструкцию, а также причуд компилеров, если просто обрубать последовательность конъюнкцией с маской и сравнивать, выхлоп будет слабоват. Опять же выбирать последовательность для сигнатуры надо так, чтобы было можно из найденного достать нужный адрес/смещение. Вообще идасигнатуры делаются по распространенным либам с отладочной информацией в надежде, что именно эта версия либы будет подключена. Сигнатурные движки даже не оперируют с битами, максимум - с ниблами. Единственное по-моему исключение - yara, но сигнатуры на регулярках полная дичь. Мой колхоз-стайл для не-интелов выглядит так: и работает пугающе хорошо. Но это все от простоты компилера и самого набора инструкций зависит. Для интела это все надо серьезно усложнять. То есть первый этап например брать последовательность одних только опкодов, а далее - взаимосвязь источников-приемников и так, чтобы порядок был необязательно таким и возможно даже с разрывами. По сути граф получится.
Во-первых скорость, во-вторых яра оперирует с нех-строками например "CE 20 00 50", если тебе нужно взять 7 бит из 8 ты делаешь 2 кейса, 6 из 8 - 4 кейса. Регулярки в принципе для этого не подходят, это удобное средство работы блин с текстами. Ее автор похоже просто хотел как бы попроще намутить что-то более-менее пригодное, не особенно напрягаясь. А комьюнитям предлагается это жрать и нахваливать.
Предлагаете нахваливаеть какой-нибудь OSSIM ? А если серьезно, то каким алгоритмом это было бы делать правильнее всего?
Именно Yara это и делает правильно. RegExp там просто надстройка над автоматом поиска константных сигнатур. В сущности, это тот же движок, что у ClamAV (модифицированный Aho-Corasic).
Я и про константные сигнатуры упомянул и почему яра не лучше, хотя могёт немного больше их. Нравится - пользуйтесь. Если пользуетесь.
Код (Text): for (every character in the virus signature) { if(the character is a hexadecimal digit) { make a child of t corresponding to this fixed nibble; t = this child; } else if(the character is ?) create a child of t labeled ?; t = this child; /* there may be several marked ? if two signatures have a common prefix including a ? */ } else if(the next two characters are of the form %d) create a child of t labeled %; t = this child; /* there may be several marked % similarly */ } Это обработка "константных сигнатур", дискретная единица - нибл (4 бита, 1 символ в нех-представлении). Это в пользу яры был аргумент или рандомные пдфки? Не открою америку, если сообщу, что у интелов номера регистров кодируются в 0-2 и 3-5 битах байта (3 бита, карл), что не очень кратно 4. Есть например архитектура PowerPC, где опкод почти любой инструкции - 6 бит младшего байта и чаще всего оставшиеся два бита относятся к номеру регистра. И ярой, которая "делает это правильно" отсечь эти два оставшихся бита можно только 4мя возможными комбинациями статического опкода и произвольных двух оставшихся бит. Потому что в яре применены передовые технологии обработки поэзии и прозы.
f13nd, чет может туплю, но не пойму, причем тут адреса регистров? ты же не байт с байтом сигнатуры и регистров сравниваешь. Зарядил один массив, зарядил второй. По любому, до сравнения они много раз где будут перемещаться и копироваться, что бы учитывать такую мелочь. Возможно, глуп и не прав, поэтому прошу, объясни еще раз схему потерь "на тактах". Что б даже ребенку было понятно.
Просто по наблюдениям, регистры это первое что будет отличаться в другой сборке того же алгоритма. Максимум что можно выдавить из битовых масок - оставить в них одни опкоды и характерные константы, относящиеся к алгоритму, а не к адресации локальных/глобальных переменных например. Для PE-файлов windows, повторюсь, всё это, в том числе регулярки на хексотекст работают очень условно. Считай не работают. Компилеры далеко не только регистры на свое усмотрение крутят. Даже объяснил в первом посте откуда в иде сигнатуры берутся и почему так. --- Сообщение объединено, 24 янв 2019 --- Если совсем "на кошках", то вот GetKeyState windows 8.1: Код (Text): .text:6BA8BBD0 8B FF mov edi, edi .text:6BA8BBD2 55 push ebp .text:6BA8BBD3 8B EC mov ebp, esp .text:6BA8BBD5 64 A1 18 00 00 00 mov eax, large fs:18h .text:6BA8BBDB 53 push ebx .text:6BA8BBDC 8B 80 70 0F 00 00 mov eax, [eax+0F70h] .text:6BA8BBE2 83 78 78 00 cmp dword ptr [eax+78h], 0 .text:6BA8BBE6 0F 84 28 7F 03 00 jz loc_6BAC3B14 .text:6BA8BBEC loc_6BA8BBEC: ; CODE XREF: GetKeyState(x)+37F4D↓j .text:6BA8BBEC 8B 5D 08 mov ebx, [ebp+nVirtKey] .text:6BA8BBEF 83 FB 20 cmp ebx, 20h .text:6BA8BBF2 0F 83 43 0F 00 00 jnb loc_6BA8CB3B .text:6BA8BBF8 64 A1 18 00 00 00 mov eax, large fs:18h .text:6BA8BBFE 8B 0D F0 40 B0 6B mov ecx, _gpsi .text:6BA8BC04 8B 80 70 0F 00 00 mov eax, [eax+0F70h] .text:6BA8BC0A 8B 90 70 08 00 00 mov edx, [eax+870h] .text:6BA8BC10 3B 91 08 0F 00 00 cmp edx, [ecx+0F08h] .text:6BA8BC16 0F 85 1F 0F 00 00 jnz loc_6BA8CB3B .text:6BA8BC1C 0F B6 CB movzx ecx, bl .text:6BA8BC1F BA 01 00 00 00 mov edx, 1 .text:6BA8BC24 56 push esi .text:6BA8BC25 8B F1 mov esi, ecx .text:6BA8BC27 C1 E9 02 shr ecx, 2 .text:6BA8BC2A 83 E6 03 and esi, 3 .text:6BA8BC2D 57 push edi .text:6BA8BC2E 33 FF xor edi, edi .text:6BA8BC30 0F B6 9C 01 74 08 00 00 movzx ebx, byte ptr [ecx+eax+874h] .text:6BA8BC38 8B C2 mov eax, edx .text:6BA8BC3A 8D 0C 75 01 00 00 00 lea ecx, ds:1[esi*2] .text:6BA8BC41 D3 E0 shl eax, cl .text:6BA8BC43 85 C3 test ebx, eax .text:6BA8BC45 0F 85 7A FF 00 00 jnz loc_6BA9BBC5 ... GetKeyState XP SP3 Код (Text): .text:7E379ED9 8B FF mov edi, edi .text:7E379EDB 55 push ebp .text:7E379EDC 8B EC mov ebp, esp .text:7E379EDE 57 push edi .text:7E379EDF 64 A1 18 00 00 00 mov eax, large fs:18h .text:7E379EE5 33 FF xor edi, edi .text:7E379EE7 39 78 40 cmp [eax+40h], edi .text:7E379EEA 0F 84 D2 4C FF FF jz loc_7E36EBC2 .text:7E379EF0 loc_7E379EF0: ; CODE XREF: GetKeyState(x)-B30E↑j .text:7E379EF0 83 7D 08 20 cmp [ebp+nVirtKey], 20h .text:7E379EF4 73 56 jnb short loc_7E379F4C .text:7E379EF6 64 A1 18 00 00 00 mov eax, large fs:18h .text:7E379EFC 8B 88 10 07 00 00 mov ecx, [eax+710h] .text:7E379F02 8B 15 80 10 3C 7E mov edx, _gpsi .text:7E379F08 3B 8A 24 09 00 00 cmp ecx, [edx+924h] .text:7E379F0E 75 3C jnz short loc_7E379F4C .text:7E379F10 0F B6 4D 08 movzx ecx, byte ptr [ebp+nVirtKey] .text:7E379F14 56 push esi .text:7E379F15 8B F1 mov esi, ecx .text:7E379F17 C1 E9 02 shr ecx, 2 .text:7E379F1A 0F B6 94 01 14 07 00 00 movzx edx, byte ptr [ecx+eax+714h] .text:7E379F22 33 C0 xor eax, eax .text:7E379F24 83 E6 03 and esi, 3 .text:7E379F27 40 inc eax .text:7E379F28 8D 4C 36 01 lea ecx, [esi+esi+1] .text:7E379F2C D3 E0 shl eax, cl .text:7E379F2E 85 C2 test edx, eax .text:7E379F30 75 15 jnz short loc_7E379F47 .text:7E379F32 loc_7E379F32: ; CODE XREF: GetKeyState(x)+71↓j .text:7E379F32 33 C0 xor eax, eax .text:7E379F34 8D 0C 36 lea ecx, [esi+esi] .text:7E379F37 40 inc eax .text:7E379F38 D3 E0 shl eax, cl .text:7E379F3A 5E pop esi .text:7E379F3B 85 C2 test edx, eax ... Как бы корелляции видны, но что насчет сигнатуры на обе функции? Алгоритм-то один и вряд ли вообще исходник менялся с тех пор. В принципе для винды, у которой конечное число официальных сборок, можно обойтись конечным числом сигнатур. Но через битовые маски эта задача только так и решается. Если у нас есть библиотека функций X в составе программы Y, то даже регулярки не помогут. Можно хоть зачитаться пдфами об антивирусах дос-эпохи. --- Сообщение объединено, 24 янв 2019 --- Щас перечитываю, будто марсианин с марса вещает. В общем случае т.н. сигнатура выглядит так: 05B8FFFFEB278A4606B4008BD8B8....8EC0 или так: 05B8FFFFEB278A4606B4008BD8B8????8EC0 Или как-нибудь еще. Маска может отдельно задаваться и прочее. yara-сигнатуры выглядят как регулярные выражения. То же самое, по в синтаксисе RegEx. Смысл этих буквоцифр сводится к к тому, что мы получаем из этого паттерна: 05 B8 FF FF EB 27 8A 46 06 B4 00 8B D8 B8 .. .. 8E C0 маску: FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 FF FF и значение: 05 B8 FF FF EB 27 8A 46 06 B4 00 8B D8 B8 00 00 8E C0 Маску применяем логическим "И" на наши данные, обнулив незначащие биты (2 байта вон там в конце), и сравниваем со значением. У яры обработка чуть сложней, там всё колдунство над текстом происходит. Если знаете что такое регулярные выражения, должно быть понятно как. Потери происходят там, где в очередных 4 битах есть как значащие биты, так и те, которые не мешало бы выкинуть. Это происходит либо в сторону большего числа возможных ложных срабатываний или меньшего числа правильных срабатываний. Если приходится лавировать между разными факторами и хочется сделать экстремально короткую сигнатуру, но с максимальным выхлопом, эта 4битность так себе союзник. Если в короткой форме inc reg: 01000rrr, где rrr - номер регистра то мы вынуждены либо взять оба нибла 01000000 inc eax либо один нибл 0100.... inc/dec rn И это практически по каждому формату инструкции так. Чаще всего выбором занимается машина на усмотрение разработчика утилиты, сгенерировавшей сигнатуру. А результатом пользоваться предстоит тебе.
f13nd, ну, это я понял. Если бы мы говорили про железно-аппаратный фильтр, куда сигнатуры заливались бы, допустим по выделенному каналу, тогда имело бы смысл об этом думать. А так, это не большая плата за удобство для оператора, потому как ярой много чего ищется. Например, можно сделать правило по стрингам, вдруг там где-то домен прописан. С ярой изначально надо понимать, что будет временной лаг, между замеченным дампом и созданием правил. Но зато это возможно практически в любой организации рядовым сисадмином. ИМХО, яра - это инструмент ответа команды реагирования, а не превентивный антивирус на входном потоке. Вместе с rasm2 (от radare2) как инструмент, имеет не то что право на жизнь, а даже кое какие плюсы. Ведь существует как tshark, так и wireshark. Тут просто задачи разные. Ну такое мое мнение. Я думал он текстом ищет, в правила же "558BEC" текстом забиваются, а не байтовым потоком.
Я не заметил в какой момент речь пошла об антивирусах Мне просто этот движок кажется странным и категорически не подходит, это не значит, что он совсем не работает и пользоваться им нельзя.
Признаю, был не прав. Но и сравнивать задачу ТС поиска байтов в рантайме, с текстовым поиском по файлам - это тоже перебор. Кажется мне, что postgresql + jsonb такие задачи отработает быстрее яры.