• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Защищаем код с помощью VEH и INT3

Пожалуйста, обратите внимание, что пользователь заблокирован
Ты посмотри на реалии, чувак пишет про то как любил фортики в просак 4 мес и в ветке активность
Любая тема про локеры дает такой эффект, потому что людям интереснее флудить ни о чем. Создай тему с заголовком "ревил" и текстом 123, и (если ее не удалят модеры), там напишут 20 страниц за ночь разной хуеты. Проблема в том, что из-за хайпов прошлого года образовалась прослойка людей, которым не интересны знания. Это флудеры, аверы (в плохом смысле слова), вайтхеты и прочий мусор, которому лишь бы пообсуждать , как бабкам на лавочке. Потому техническая тема всегда наберет меньше активности, чем флудильня.
з.ы. кстати не пойму, тебе не нравится вообще концепция этого "визора" или конкретная реализация от ТС? Потому как Инди делал это для реверса , т.е. чтобы "крутить семплы", как он выражался.

По теме - давно интересен этот концепт, не как защита от реверсеров , а как защита от мемдетектов. Но надо тестировать на каких-то более серьезных вещах, скажем как оно будет себя вести в многопоточном софте и т.д.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
з.ы. кстати не пойму, тебе не нравится вообще концепция этого "визора" или конкретная реализация от ТС? Потому как Инди делал это для реверса , т.е. чтобы "крутить семплы", как он выражался
Ну у Индия там реализация другая, типа того, что мы обсуждали тут, но на эльфийском. VEH - это просто механизм через который я показал, как реализовать концепт "софтварных анклавов". Не самый эффективный скажем, но все же механизм, через который это можно сделать.

Но надо тестировать на каких-то более серьезных вещах, скажем как оно будет себя вести в многопоточном софте и т.д.
Это будет сложно, как бы отказаться от глобальных переменных в пользу тред локал переменных - это просто. Но надо учитывать возможный рейс кондишн, когда два потока будут одну и ту же инструкцию расшифровывать и заливать обратно INT3. Синхронизировать потоки на запись тоже такой себе вариант в плане производительности, помимо VEH еще наложется постоянная синхронизация для каждой инструкции.
 
Решил малость проверить это дело.
Original 0.006259441375732422s
With Antidump: 0.04061150550842285s
Python:
import subprocess
import time

def measure(cmdx):
    start = time.time()
    subprocess.run(cmdx)
    end = time.time()
    time_e = end - start
    print("Program:{0}  Time:{1}s".format(cmdx, time_e))

measure("calc.exe")
measure("calc_a.exe")
C++:
#include <windows.h>

const int LOOPVARIABLE = 100000;
const long double FLOOPVARIABLE = 100000;

static HANDLE _stdout = INVALID_HANDLE_VALUE;

VOID init_std_handles(){
    _stdout = GetStdHandle(STD_OUTPUT_HANDLE); }

VOID write_line(LPCSTR line){
    DWORD written = 0; INT length = lstrlenA(line);
    WriteConsoleA(_stdout, line, length, &written, NULL);
    WriteConsoleA(_stdout, "\n", 1, &written, NULL); }

void calculateFLOPS(){
    double a= 124.23525, b = 21.2412, c = 2342.23432, d = 23.324, e= 2.3412, f = 123.21, g = 1231.12, h =567.4, j = 34.4, k =24, l =342.24,
     m= 324.23525, n = 51.2412, o = 242.23432, p = 254.324, q= 112.3412, r = 853.21, s = 31.12, t =67.4, u = 34.4, v =4, w =3.24, x =89.131, y =123.23, z =123.123,
     v1 =12.3, v2 = 3, v3 = 56.5, v4 = 88.56, v5 = 787.43, v6 = 0, v7 = 0, v8 =0, v9 = 0, v10 = 1, v11 = 54, v12 = 12, v13= 45, v14 = 5.66, v15 = 123.12, v16 =1 ,
     v17 =1, v18 = 12, v19 =12, v20 = 12.1, v21 = 1.1, v22 = 12;
    
    for(double i = 0; i < FLOOPVARIABLE; i++)    {
        a = a + b;
        c = d + e;
        f = g * h;
        m = m + n;
        j = k * l;
        q = o + p;
        s = r + s;
        v = t * u;
        m = k + n;
        j = w * l;
        x = x * y;
        v6 = v1 + v2;
        v7 = v3 * v4;
        v8 = v5 * v5;
        v9 = g * k;       } }

void calculateIOPS() {
    int a= 124, b = 21, c = 23, d = 23, e= 2.3412, f = 123, g = 1231, h =567, j = 34, k =24, l =342,
     m= 324, n = 51, o = 242, p = 254, q= 112, r = 853, s = 31, t =67, u = 34, v =4, w =3.24, x =89, y =123, z =123,
     v1 =12, v2 = 3, v3 = 56, v4 = 88, v5 = 787.43, v6 = 0, v7 = 0, v8 =0, v9 = 0, v10 = 1, v11 = 54, v12 = 12, v13= 45, v14 = 5, v15 = 123, v16 =1,
     v17 =1, v18 = 12, v19 =12, v20 = 12, v21 = 1, v22 = 12;

    for(int i = 0; i < LOOPVARIABLE; i++)    {
        a = a + b;
        c = d + e;
        f = g * h;
        m = m + n;
        j = k * l;
        q = o + p;
        s = r + s;
        v = t * u;
        m = k + n;
        j = w * l;
        x = x * y;
        v6 = v1 + v2;
        v7 = v3 * v4;
        v8 = v5 * v5;
        v9 = g * k;    }   }

extern "C" void entry_point() {
    init_std_handles();
    calculateFLOPS();
    calculateIOPS();
    write_line("Done"); }

но аверы - они же такие аверы, они могут влепить сигнатуру вообще куда угодно. Я утрирую, конечно, но все же.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Original 0.006259441375732422s
With Antidump: 0.04061150550842285s
Ну не так плохо, всего то в 6.6 раз медленнее))
 
Решил малость проверить это дело.
Original 0.006259441375732422s
With Antidump: 0.04061150550842285s
Что-то здесь не то. 2 переключения контекста (вызов ядра через шлюз + возврат в VEH) и сброс конвейера при перезаписи исполняемого кода. В первом приближении должно быть на пару порядков медленее.
Python:
def measure(cmdx):
    start = time.time()
    subprocess.run(cmdx)
    end = time.time()
    time_e = end - start
    print("Program:{0}  Time:{1}s".format(cmdx, time_e))
Тут измеряется время создания процесса, а не только исполнение кода.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Что-то здесь не то. 2 переключения контекста (вызов ядра через шлюз + возврат в VEH) и сброс конвейера при перезаписи исполняемого кода. В первом приближении должно быть на пару порядков медленее.
Ну если время создания и завершения процесса составляет в этом тесте, допустим, 0.005, то получится уже разница в 35 раз. По хорошему можно замер времени вставить в сам пейлоад, или же проделать в полезной нагрузке этот тест несколько десятков тысяч раз, чтобы нивелировать влияние времени создания и завершения процесса на время исполнения.
 
Что-то здесь не то. 2 переключения контекста (вызов ядра через шлюз + возврат в VEH) и сброс конвейера при перезаписи исполняемого кода. В первом приближении должно быть на пару порядков медленее.

Тут измеряется время создания процесса, а не только исполнение кода.
Измеряется именно время исполнения. https://docs.python.org/3/library/subprocess.html#subprocess.run
Run the command described by args. Wait for command to complete, then return a CompletedProcess instance.

Если собрать пейлоад с -O0 и выключенным -Os то итоговая версия будет исполнятся около 10сек, но я посчитал, что это немного нечестно. Хотя я не дизассемблировал итоговый бинарь, хз что там происходит на самом деле.
 
Измеряется именно время исполнения. https://docs.python.org/3/library/subprocess.html#subprocess.run
Время исполнения кода и время исполнения "экзешника" это две большие разницы. В последнем случае ОС создаёт адресное пространство процесса, объект "секция", отображает в ОЗУ содержимое PE image... Потом в этой кухне доходит дело до кода из того исходника.
 
Привет!
"Во-вторых, с точки зрения злых реверсеров есть несколько способов упростить себе жизнь. Например, как показала практика достаточно неплохой идеей оказалось занопить код, который заливал предыдущую инструкцию, и таким образом получить в открытом виде все инструкции, которые были исполнены. Одним из вариантов противодействия этому является использования хеша кода обработчика VEH при расшифровке инструкций, таким образом реверсер не сможет его пропатчить каким-то образом."....
Я не воткнул , каким образом хеш обработчика вех поможет ? Где и как это нудно применить ?
Сорян за возможно тупой вопрос, но надо же учиться :)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Я не воткнул , каким образом хеш обработчика вех поможет ? Где и как это нудно применить ?
Ну я имел ввиду, что мы можем взять хеш от инструкций функции обработчика VEH в памяти текущего процесса, и использовать этот хеш в качестве ключа для дешифрования инструкций. Если реверсер пропатчит обработчик VEH, то инструкции не расшифруются корректно, так как хеш будет другой, в секцию текст попадет рандомный мусор и после нескольких инструкций процесс упадет.
 
Примерно пол года назад писал реализацию такой же штуковины, только вместо int3 ставил аппаратные в DR регистры, получалась пошаговая отладка самого себя через EXCEPTION_SINGLE_STEP, а для отлова обращений в секции данных помечал ее как запрещенную для чтения\записи, отсеивал размер считываемых данных и выдавал на чтение уже расшифрованный вариант данных. Код тоже по одной инструкции расшифровывался, но это медленно очень, пустой цикл на 50000 итераций занимает уже весомое количество времени в пару секунд, а то и больше, я думаю что вариант, как в протекторе Armadillo, выглядит в этом плане более приемлемо, когда код расшифровывается постранично по 4096 байт
Обработка была тоже через VEH исключения, пришлось наставить еще много хуков на разные функции, даже банально на установку еще одного VEH, что бы мой не сместился ниже уровнем
А так же очень важно - многопоточность, два или более потоков могут залезть в одно и то же место исполняться одновременно, соответственно расшифровка байт кода\данных должна синхронизироваться, ох и намучался я с этим делом, но зато это все было оформлено как протектор и покрывало достаточно большое количество приложений без особых извратов, но скажу я так, все это защита гораздо хуже чем качественная виртуализация, софт анклав это идет как антидамп\скрытие кода\данных\сигнатур, но тем не менее пропатчив немного код, можно заставить его не шифроваться обратно и после того как программа отработает некоторое количество времени она будет полностью расшифрована.

Ну я имел ввиду, что мы можем взять хеш от инструкций функции обработчика VEH в памяти текущего процесса, и использовать этот хеш в качестве ключа для дешифрования инструкций. Если реверсер пропатчит обработчик VEH, то инструкции не расшифруются корректно, так как хеш будет другой, в секцию текст попадет рандомный мусор и после нескольких инструкций процесс упадет.
Это не поможет, ты можешь узнать сначала хеш этот, а потом сделать патч с учетом поправок, дабы всегда получался нужный хеш, независимо от патча (mov reg, hash например, после вычисления настоящего перетирать его заранее рассчитанным)
Вриантов усложнить систему масса, ровно так же как и вариантов, которые будут придуманы, что бы ее обойти
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх