Русский / Russian English / Английский

Сейчас на форуме:
 · Начало · Статистика · Регистрация · Поиск · ПРАВИЛА ФОРУМА · Язык · RSS ·

 eXeL@B —› Программирование —› Оптимизация циклов.
<< . 1 . 2 .
Посл.ответ Сообщение


Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 20 мая 2017 20:15 New!
Цитата · Личное сообщение · #1

Здрасте

Задача следующая, решения пока я не вижу.
Приложение взято под визор/трассировку - не суть важно, имеем каждую инструкцию его.
Исполнение цикла имеет большой тайминг, посему цикл необходимо обнаружить и скипнуть.
Как обнаружить цикл ?

Вначале нужно дать какое то чёткое определение - что такое цикл.
Серия вызовов функции(апи к примеру) очевидно это не цикл.
Можно в графе найти замыкания ветвей, но мы его построить не можем - это слишком долго, нужно всё сделать в динамике.

Ранг: 412.3 (мудрец)
Статус: Участник

Создано: 21 мая 2017 08:05 · Поправил: dosprog New!
Цитата · Личное сообщение · #2

Чуваг, найди инструкции <loop> и <jxx> и включи счётчик_инструкций и счётчик_цикла. Для каждого найденного <loop> и <jxx>.
Если при повторном проходе этого адреса (<loop> и <jxx>) счётчик_инструкций будет меньше какого-то наперёд заданного значения, а счётчик_цикла больше своего заданного значения, то это и будет цикл.

Но только что-то подсказывает, что это всё никому не нужная ерунда.
Ну зачем, к примеру, перепрыгивать цикл настройки импортов при запуске приложения?


Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 21 мая 2017 08:09 New!
Цитата · Личное сообщение · #3

dosprog

Так не получится, так как после ветвления не должно быть не повторяющихся инструкций, иначе это будет не цикл. Таким образом каждая инструкция должна помечаться в пределах цикла. Счётчик не поможет.

Ранг: 0.0 (гость)
Статус: Участник

Создано: 21 мая 2017 08:11 New!
Цитата · Личное сообщение · #4

difexacaw пишет: llvm не робит в реалтайме

Трейсер и jit вполне работают, даже умеют грузить эльфы с пе, это не говоря о хз каком числе языков использующих jit llvm в своем интерпретаторе.
Вот с этого и нужно было начинать. В таком случае бери X c Y и смотри когда сработает флаг перехода или влепи int 3 на выходе цикла или что там используешь, только убедись, что выход один, иначе может сработать не тот триггер, что ты ожидал, поскольку между двумя переходами может быть еще куча, например аварийный или выход по одному из условий, вот их адреса тоже нужно брать и на их выходе лепить останов, после выхода по одному из пути можно убирать остановы.


Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 21 мая 2017 08:11 New!
Цитата · Личное сообщение · #5

> Ну зачем, к примеру, перепрыгивать цикл настройки импортов при запуске приложения?

А зачем мне крутить цикл настройки импортов, если мне импорты не нужны, тем самым понизить значительно общий профайл

Ранг: 0.0 (гость)
Статус: Участник

Создано: 21 мая 2017 08:13 New!
Цитата · Личное сообщение · #6

difexacaw пишет: Так не получится, так как после ветвления не должно быть не повторяющихся инструкций

Декрипт в цикле перестал быть циклом из за декрипта, рили?


Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 21 мая 2017 08:18 New!
Цитата · Личное сообщение · #7

shellstorm

А что считать и зачем счётчиком, покажите на примере.

Ранг: 0.0 (гость)
Статус: Участник

Создано: 21 мая 2017 08:28 New!
Цитата · Личное сообщение · #8

difexacaw пишет: А что считать и зачем счётчиком, покажите на примере.

Раскраску, что же еще, признак цикла это замыкание, если мы ушли от X и от Y возвращаемся к X, значит X можно пометить, как посещенное, но раз ты ничего хранить не собираешься, значит и счетчик не нужен, но промежуточные переходы проверять нужно, поскольку, как уже говорил, выходов из цикла может быть больше одного.

допустим
X:
...
cmp eax,1000
jnz ...
call ... выход
cmp edx, 1
jmp ... выход
...
je X
...
выход
грубо, ну суть должна быть понятна.

Добавлено спустя 1 минуту
Причем если код под морфом, выход может и появиться во время работы, отпустил приложения и дальше что?

Ранг: 412.3 (мудрец)
Статус: Участник

Создано: 21 мая 2017 08:35 New!
Цитата · Личное сообщение · #9

difexacaw пишет:
Так не получится, так как после ветвления не должно быть не повторяющихся инструкций, иначе это будет не цикл. Таким образом каждая инструкция должна помечаться в пределах цикла. Счётчик не поможет.

Следи только за инструкциями переходов.

Ранг: 33.4 (посетитель)
Статус: Участник

Создано: 21 мая 2017 10:17 New!
Цитата · Личное сообщение · #10

исключение внутри цикла - еще один вариант выхода


Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 21 мая 2017 10:49 · Поправил: difexacaw New!
Цитата · Личное сообщение · #11

shellstorm

Нет проблемы выделить ветвления, даже конструктор не нужен. Вот собрал семпл для выделения цикла:



Трассируем апи -> находим цикл -> выделяем цикл в буфер -> выполняем буфер -> продолжаем трейсить.

{ Атач доступен только для участников форума } - Cycle2.rar

Ранг: 0.0 (гость)
Статус: Участник

Создано: 21 мая 2017 11:08 New!
Цитата · Личное сообщение · #12

difexacaw пишет: Нет проблемы выделить ветвления, даже конструктор не нужен

С этим как раз все понятного, я немного о другом, как бы проще объяснить, представь виртуальную машину или песочницу, там тоже делают подобные хаки для ускорения, отпустил цикл и сидишь ждешь на выходе, а выходов много, в итоге приложение убегает из песочницы, нужно в выделенном коде контролировать переходы, либо врубить int'ы по адресам перехода или контролировать контекст с установкой флага и нет гарантии, что ссылка постоянная, допустим jnz\JE\etc REG, внутри цикла ссылка может измениться и приложение выйдет за пределы цикла, и начнет жить своей жизнью.

Добавлено спустя 3 минуты
в ntdll простой код для тестов лучше взять что то по тяжелее, если конечно планируется делать универсальный двиг, потестить на малварке\протекторах и на тяжелом плюсовом коде, например какой нибудь реализации linq, там под капотом как раз указатели с циклами.


Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 21 мая 2017 11:13 New!
Цитата · Личное сообщение · #13

shellstorm

Да нет, если все ветвления поправить, то выйти из цикла куда то есчо невозможно, только если через системный вызов. Но такое конечно же нужно обработать. Себя в буфере изменить тоже нельзя, он RE.

Добавлено спустя 1 минуту
> лучше взять что то по тяжелее

vmprotect

Ранг: 0.0 (гость)
Статус: Участник

Создано: 21 мая 2017 11:23 New!
Цитата · Личное сообщение · #14

Теперь ясно, фикс ссылок на буфер, в целом тоже решение.

difexacaw пишет: vmprotect
Нет, в этом плане он простой, бегает только много и размазан по модулю, но ничем особо не удивляет, у него сложности в другом, за одной инструкцией портянка кода.
Что то древнее, раньше любили хаки на стеке и подобную дребедень которая так настораживает антивирусы.


Ранг: 329.6 (мудрец)
Статус: Участник

Создано: 21 мая 2017 11:53 New!
Цитата · Личное сообщение · #15

Я думаю что задача сформулирована неправильно - зачем искать цикл и кому он нужен, за один проход это не реализуемо, особенно на обфусцированном коде, а чтобы сократить время анализа нужно пройти весь код единицы трансляции (например функции) за 1 раз и ничего при этом не пропустить - такая задача решаема на любом коде за 1 проход. Если хотите могу описать по шагам как это сделать, этот алгоритм успешно работает хоть на линейном, хоть на обфусцированном коде и его реализация не так и сложна.
Если же требуется в дальнейшем построить код близкий к исходному, то это делается на втором и следующих проходах, где локализуются блоки присвоений, сравнений, вызовов функций, циклов, свичей и всей прочей более высокоуровневой реализации чем просто асм код.

Ранг: 0.0 (гость)
Статус: Участник

Создано: 21 мая 2017 12:15 New!
Цитата · Личное сообщение · #16

Vamit пишет: свичей

Я бы почитал о свитчах.


Ранг: 329.6 (мудрец)
Статус: Участник

Создано: 21 мая 2017 13:49 New!
Цитата · Личное сообщение · #17

Для начала нужно определить условие окончания единицы трансляции, начало известно - это адрес с которого начинаем анализ. А условие окончания будет зависеть от типа самой единицы трансляции.
Например, для функции будет 2 условия окончания: (ret или jmp) + признак восстановления первоначальной границы стека. Без учета границы стека и ret и jmp могут быть как вызовами вложенных функций, так и чем-то другим принадлежащим телу функции.
Для обработчика примитива ВМ тоже будет 2 окончания: переход на начало цикла ВМ (или выборка адреса следующего примитива для безцикловых вм) или выход из вм.
В общем условие конца анализа определяете сами в зависимости от того что анализируете.
До начала анализа требуется подготовка:
- Сохраняем значения всех регистров, значения не обязательно должны быть реальными, поверьте, все прекрасно работает с любыми значениями.
- Сохраняем вершину стека и как минимум 10 значений в стеке до вершины, идеальный вариант - если пройдена (разобрана) вызывающая единица трансляции, то сохраняем весь контекст переданный вызываемой единице от вызывающей.
- Готовимся к сохранению значений памяти. Это будет просто массив структур содержащих 2 члена: адрес и значение, можно сделать и сложнее, адрес, размер данных, тип данных, сами данные.
- Готовим таблицу переходов и меток (reference to jmp). Это будет простой массив, в который будут добавляться следующие структуры vXRefs по мере анализа.
Сама структура довольно проста:
Code:
  1. // Переходы и ссылки в коде
  2. struct vXRefs
  3. {
  4.          zArray<vRefNode>*         m_pRefs; // указатель на массив ссылок
  5.          vRefNode                        m_Jmp; // переход
  6.          vRefNode                        m_Direct; // прямая ветка
  7.          vCrossStatus         m_Cross; // статус пересечения (для простоты можно игнорировать)
  8.          DWORD      m_nStoreAddr; // адрес сохранения контекста
  9. };
  10.  
  11. // Узел дерева переходов и ссылок
  12. struct vRefNode
  13. {
  14.          DWORD      m_nAddr; // адрес в коде
  15.          void*               m_pData; // связанные данные, если переход не прямой а косвенный
  16. };

Эта структура обладает даже некоторой избыточностью, но это не беда, когда есть необходимое, хуже - искать то, чего нет...
Теперь можно начинать однопроходный анализ и ничего не пропустить.

shellstorm пишет:
Я бы почитал о свитчах.

Свитчи на первом проходе не реализуются, а только намечаются.

| Сообщение посчитали полезным: shellstorm



Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 21 мая 2017 14:35 New!
Цитата · Личное сообщение · #18

Vamit

Вы так же не можите свои мысли выражать, как и понимать суть. Какой есчо анализ, я что то спрашивал про декомпиль - нет. Вы нагенерили бреда как обычно, который не читабельный после первых двух предложений. Но спасибо за попытку обьяснить и понять.


Ранг: 667.6 (! !)
Статус: Участник
CyberMonk

Создано: 21 мая 2017 14:37 New!
Цитата · Личное сообщение · #19

Vamit а условие difexacaw пишет:
Код выполняется под визором в реалтайме.


Задача - задетектить полиморфный цикл в динамике с малым таймингом к примеру ..

| Сообщение посчитали полезным: difexacaw



Ранг: 329.6 (мудрец)
Статус: Участник

Создано: 21 мая 2017 15:05 New!
Цитата · Личное сообщение · #20

mak
Первоначальная задача в общем виде не решаема, можно реализовать только частные случаи. Я же хотел предложить альтернативный вариант, который работает как в динамике, так и в статике, и без разницы кто его использует- трейсер, декомпиль, анализатор или визор кода, это уже всё обработка полученного результата.
Не хотите, как хотите, Баба с возу - кобыле легче...


Ранг: 331.0 (мудрец)
Статус: Участник

Создано: 21 мая 2017 15:10 · Поправил: difexacaw New!
Цитата · Личное сообщение · #21

Vamit

Задача решена, топик клосед. Всем спасибо.

Хм, последнее сообщение можно редактировать, весьма хорошая фича.

Последняя имплементация, из темы на васме.

{ Атач доступен только для участников форума } - Cycle.zip
<< . 1 . 2 .
 eXeL@B —› Программирование —› Оптимизация циклов.
Эта тема закрыта. Ответы больше не принимаются.

Видеокурс ВЗЛОМ