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

Статья Мета-программирование Nim и обфускация

Пожалуйста, обратите внимание, что пользователь заблокирован
Тут один чел написал морфер на Си для Си сорцов. И в одном посту писал, что морфер со своей задачей справляется.
А вот и не справляется. И морфером это сложно назвать, обфускатор. Всё было построено на Control Flow Flattening, как предикат использовались мат. выражения. В зависимости от результата мат. выражения выполнялся нужный блок кода.
Исходная функция:
C:
HMODULE pLoadLibraryA(LPSTR lpFileName)
{
    typedef HMODULE(WINAPI* T_LoadLibraryA)(LPSTR lpFileName);

    HMODULE hLib = NULL;
    LPVOID ptrLoadLibraryA = NULL;
    if (!ptrLoadLibraryA)
    {
        UINT hash_LoadLibraryA = 0x0aadf0f1;
        ptrLoadLibraryA = GetApiAddr(hKernel32, hash_LoadLibraryA);
    }

    if (ptrLoadLibraryA)
    {
        hLib = ((T_LoadLibraryA)ptrLoadLibraryA)(lpFileName);
    }

    if (hLib)
    {
        return hLib;
    }

    return NULL;
}
Обработанная функция:

C:
HMODULE pLoadLibraryA(LPSTR lpFileName)
{
    typedef HMODULE(WINAPI* T_LoadLibraryA)(LPSTR lpFileName);

    HMODULE hLib = NULL;
    LPVOID ptrLoadLibraryA = NULL;
    if (!ptrLoadLibraryA)
    {
        UINT hash_LoadLibraryA = 0x0aadf0f1;
    int tqpbwncwlv = (((n633+n699)+(n981*n621)+(n854+n4)+(n296*n694)+(n630*n586)+(n541-n890)+(n597+n552)+(n4-n169)+(n88*n501)+(n85*n649)+(n183+n401)+(n582-n622)+(n128-n610)+(n378*n697)+(n178*n608)+(n307-n105)+(n954*n252)+(n244+n697)+(n63*n642)+(n336-n805)+(n913+n835)+(n450*n405)+(-2123161)));
    while ((((n750-n768)+(n46*n166)+(n857*n945)+(n61*n378)+(n442-n516)+(n754+n630)+(n319*n102)+(n97-n1)+(n962-n930)+(n11+n618)+(n610+n619)+(n754-n785)+(n404*n927)+(n622-n157)+(n340-n249)+(n573-n756)+(n170+n729)+(n719*n261)+(n583-n320)+(n733-n324)+(n832+n375)+(n145-n874)+(n831*n596)+(-1936208)))) {
        if (tqpbwncwlv == (((n276+n56)+(n781-n57)+(n736+n149)+(n236+n45)+(n165+n975)+(n127*n96)+(n13*n979)+(n402-n749)+(n975-n239)+(n745-n422)+(n204+n424)+(n721+n43)+(-30386)))) {
            break;
        }
        switch (tqpbwncwlv) {
        case 1:
            tqpbwncwlv = tqpbwncwlv + (((n448-n153)+(n379-n933)+(n527-n325)+(n909-n898)+(n363+n818)+(n373+n181)+(n80*n304)+(n388*n602)+(n588+n739)+(n529*n229)+(n18+n621)+(n519*n137)+(n935*n442)+(n80+n849)+(n827-n58)+(n822+n890)+(n138*n922)+(n29-n452)+(-997287)));
            break;
        case 8:
            tqpbwncwlv = tqpbwncwlv + (((n150-n136)+(n954-n223)+(n777*n279)+(n883*n9)+(n958+n110)+(n319-n126)+(n652*n390)+(n672*n545)+(n271+n83)+(n42+n255)+(n551*n47)+(n9-n333)+(n222+n558)+(n9-n399)+(n800*n312)+(n335*n905)+(n903*n828)+(n218-n509)+(n252+n91)+(n617-n59)+(n335*n753)+(n13*n674)+(n71*n650)+(-2482105)));
            break;
        case 9:
            tqpbwncwlv = tqpbwncwlv + (((n66*n769)+(n932+n104)+(n964+n17)+(n3+n84)+(n385-n672)+(n121+n436)+(n312+n266)+(n632-n248)+(n260-n707)+(n189-n329)+(n202+n437)+(n250-n56)+(n151-n36)+(n484+n898)+(n759+n222)+(n438-n402)+(n612-n755)+(n482+n717)+(n795-n604)+(n863*n903)+(n958-n185)+(n182+n504)+(n996+n10)+(n141*n216)+(-870306)));
            break;
        case 11:
            tqpbwncwlv = tqpbwncwlv + (((n827+n247)+(n913+n324)+(n697*n923)+(n989*n442)+(n479-n5)+(n597*n535)+(n492*n235)+(n636-n154)+(n545*n386)+(n129+n236)+(n324-n4)+(n689*n290)+(n665*n805)+(n736*n984)+(n448+n354)+(n529-n240)+(n707*n583)+(n260*n31)+(n225-n827)+(n238+n528)+(n200*n932)+(n65-n447)+(n533*n645)+(-4140463)));
            break;
        case 6:
            tqpbwncwlv = tqpbwncwlv + (((n390*n642)+(n600*n327)+(n209+n844)+(n648+n484)+(n682*n959)+(n698+n796)+(n892*n586)+(n690-n636)+(n591+n5)+(n343*n701)+(n75*n990)+(n257+n880)+(n429+n228)+(-1944145)));
            break;
        case 12:
            tqpbwncwlv = tqpbwncwlv + (((n901-n126)+(n457-n160)+(n467+n288)+(n967*n459)+(n302+n212)+(n736-n714)+(n912+n363)+(n189*n838)+(n989-n223)+(n440-n432)+(n447*n488)+(n693-n703)+(n725*n810)+(n556-n455)+(n97-n250)+(n395*n167)+(-1477935)));
            break;
        case 4:
            tqpbwncwlv = tqpbwncwlv + (((n683-n949)+(n916+n389)+(n228-n323)+(n146*n471)+(n795+n663)+(n30+n924)+(n73+n515)+(n570-n109)+(n58-n566)+(n546-n647)+(n46-n535)+(n75-n608)+(n351+n55)+(n684-n899)+(n602-n474)+(n822*n455)+(n617+n544)+(-447029)));
            break;
        case 7:
            tqpbwncwlv = tqpbwncwlv + (((n695+n417)+(n19+n548)+(n773*n283)+(n351+n269)+(n24+n655)+(n801+n314)+(n787+n37)+(n80-n81)+(n317+n790)+(n61*n793)+(n574*n918)+(n416*n432)+(n31-n82)+(n873-n112)+(n282*n383)+(n186-n239)+(n141-n345)+(n264-n904)+(-1087617)));
            break;
        case 10:
            ptrLoadLibraryA = GetApiAddr(hKernel32, hash_LoadLibraryA);
            tqpbwncwlv = (((n965-n411)+(n467+n75)+(n360+n912)+(n321*n538)+(n976+n262)+(n552*n958)+(n117+n226)+(n607-n685)+(n221+n720)+(n739-n978)+(n386*n208)+(n247*n644)+(n835+n613)+(n307-n733)+(n282*n227)+(-1010480)));
            break;
        case 3:
            tqpbwncwlv = tqpbwncwlv + (((n406-n320)+(n364+n454)+(n596*n682)+(n99+n734)+(n287+n993)+(n271*n882)+(n621*n344)+(n843+n310)+(n901*n241)+(n397*n868)+(n18*n508)+(n981+n588)+(-1435737)));
            break;
        case 2:
            tqpbwncwlv = tqpbwncwlv + (((n190-n929)+(n92*n77)+(n816+n80)+(n538+n360)+(n745-n781)+(n449-n702)+(n69+n338)+(n724*n958)+(n265+n843)+(n142*n398)+(n560+n56)+(n313*n350)+(n635-n273)+(n856+n690)+(n832-n312)+(n955-n323)+(n504*n696)+(n720*n967)+(n429-n481)+(n630-n419)+(-1919881)));
            break;
        case 13:
            tqpbwncwlv = tqpbwncwlv + (((n188+n197)+(n182+n26)+(n325-n18)+(n209+n254)+(n705*n554)+(n990*n946)+(n33+n401)+(n43-n328)+(n455-n11)+(n516-n551)+(n889-n70)+(n660-n104)+(n673-n269)+(n92-n356)+(n630*n506)+(n219-n916)+(-1648628)));
            break;
        case 5:
            tqpbwncwlv = tqpbwncwlv + (((n408*n809)+(n274+n346)+(n840+n459)+(n455+n559)+(n528*n4)+(n171*n981)+(n621*n785)+(n837-n952)+(n105+n71)+(n867+n143)+(n637-n213)+(n222-n814)+(n815+n572)+(n890-n231)+(n750*n514)+(n452+n129)+(n420+n727)+(n816+n621)+(n515*n845)+(n784*n111)+(n866+n198)+(n315*n654)+(-2111239)));
            break;
        case 0:
            tqpbwncwlv = tqpbwncwlv + (((n481-n100)+(n603*n58)+(n268+n574)+(n767*n574)+(n751*n656)+(n528*n746)+(n681+n525)+(n514-n308)+(n16*n357)+(n183*n690)+(n843-n65)+(n872*n222)+(-1690754)));
            break;
        }
    }
    }

    if (ptrLoadLibraryA)
    {
    int klbijlnjrj = (((n873+n881)+(n377-n350)+(n772*n697)+(n40-n406)+(n705-n966)+(n608*n200)+(n630-n755)+(n56-n949)+(n379+n193)+(n810+n309)+(n578-n899)+(n250*n384)+(n783-n955)+(n539+n446)+(n630*n248)+(n296-n79)+(n70*n419)+(n629-n330)+(n611+n383)+(-945083)));
    while ((((n445+n626)+(n593+n753)+(n97*n7)+(n863+n841)+(n689+n743)+(n894+n671)+(n601*n554)+(n78+n3)+(n218+n799)+(n419+n90)+(n942*n185)+(n915*n320)+(n706+n212)+(n633*n671)+(n770*n320)+(n544-n230)+(n195*n316)+(-1543422)))) {
        if (klbijlnjrj == (((n284-n88)+(n72+n168)+(n903+n61)+(n973+n460)+(n317-n641)+(n303*n243)+(n388+n532)+(n460+n835)+(n688*n101)+(n557-n694)+(n982-n190)+(n894*n294)+(n146+n877)+(n910-n726)+(n436-n994)+(n490+n353)+(n795+n193)+(n635+n880)+(n731*n67)+(n297-n697)+(n485-n867)+(n945-n306)+(n31*n940)+(-493302)))) {
            break;
        }
        switch (klbijlnjrj) {
        case 2:
            klbijlnjrj = klbijlnjrj + (((n17-n708)+(n745+n188)+(n487*n390)+(n695-n542)+(n694+n566)+(n30+n710)+(n735*n4)+(n407*n166)+(n395*n397)+(n113-n58)+(n176-n321)+(n931+n603)+(n618+n798)+(-422501)));
            break;
        case 6:
            klbijlnjrj = klbijlnjrj + (((n865+n990)+(n741*n968)+(n99-n439)+(n628*n732)+(n326*n653)+(n858+n738)+(n588+n311)+(n164+n652)+(n62+n746)+(n784+n462)+(n80+n414)+(n553-n946)+(n734+n120)+(n892+n422)+(n254*n467)+(n496-n261)+(n453-n204)+(n161-n360)+(n957+n169)+(n768+n824)+(-1520631)));
            break;
        case 1:
            klbijlnjrj = klbijlnjrj + (((n24*n957)+(n85*n906)+(n97*n75)+(n985*n551)+(n133-n13)+(n866-n492)+(n79+n896)+(n422*n283)+(n855+n400)+(n881*n841)+(n595+n328)+(n501+n285)+(n199-n240)+(n795*n291)+(n996*n419)+(n847-n539)+(n821-n802)+(-2163722)));
            break;
        case 4:
            klbijlnjrj = klbijlnjrj + (((n881+n177)+(n36+n365)+(n112+n576)+(n433*n641)+(n236-n328)+(n238*n603)+(n537-n631)+(n857+n839)+(n981+n119)+(n646-n295)+(n849+n11)+(n772-n738)+(n660-n964)+(n266+n225)+(n273-n897)+(n177*n324)+(n716*n574)+(-894963)));
            break;
        case 3:
            klbijlnjrj = klbijlnjrj + (((n591*n434)+(n389+n848)+(n414*n115)+(n119-n294)+(n614-n780)+(n349*n579)+(n422*n113)+(n530-n539)+(n894-n715)+(n763+n162)+(n406+n206)+(n192-n74)+(-556581)));
            break;
        case 5:
            hLib = ((T_LoadLibraryA)ptrLoadLibraryA)(lpFileName);
            klbijlnjrj = (((n850-n36)+(n821*n377)+(n21+n192)+(n322+n725)+(n323*n171)+(n731-n416)+(n286*n818)+(n51-n301)+(n701+n382)+(n727-n502)+(n822*n712)+(n488-n778)+(n334-n277)+(n784-n126)+(n965-n169)+(-1188631)));
            break;
        case 0:
            klbijlnjrj = klbijlnjrj + (((n547+n550)+(n895*n82)+(n348+n781)+(n267-n432)+(n559-n413)+(n624-n787)+(n611+n184)+(n428*n466)+(n464+n75)+(n880-n566)+(n451*n636)+(n792-n762)+(n407*n929)+(n186+n933)+(n973-n94)+(n605-n298)+(n607-n901)+(-943509)));
            break;
        }
    }
    }

    if (hLib)
    {
        return hLib;
    }

    return NULL;
}
Накинуть сигнатуру на подобный треш - проще простого, вырезается так же просто. Практического смысла в этом нет. Нужно действовать по другому.

Есть у нас в функции pLoadLibrary статичное значение:
UINT hash_LoadLibraryA = 0x0aadf0f1;
Напишем функцию, которая будет возвращать нужное нам значение:
C:
UINT Trash1()
{
    UINT ret = 0;
    int predikat = 4; // первым делом идём в 4-ый блок
    while (predikat > 0)
    {
        swith (predikat)
        {
            case 0: // блок с мусором
            {
                ret = 66546546;
                predikat = 4;
                break;
            }
            case 1: // тру-блок
            {
                ret = 43243434; // нужный нам хэш
                predikat = -1;
                break;
            }
            case 2: // блок с мусором
            {
                ret = 66546546;
                predikat = 1;
                break;
            }
            case 3: // блок с мусором
            {
                ret = 78678678;
                predikat = 6;
                break;
            }
            case 4: // блок с мусором
            {
                ret = 1364646;
                predikat = 2;
                break;
            }
        }
    }
}

UINT hash_LoadLibraryA = Trash1;
Каждое фейк-значение можно так же обработать, и каждое фейк-фейк значение можно обработать, и каждое фейк-фейк-фейк ...
В кач-ве предикатов не стоит использовать только мат. выражения. Работа со строками/апи/дёргаем значение из сети. Но опять же, эту лесенку из swith-case'ов можно так же сигнатурно задетектить.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Jeffs

Начнем с мат выражений.

имеем переменную int var = 28371;
Что можно сделать, каждое число выводим на новую переменную с мат вычислением

int a1 = (0,5 + 0,5) * 2 // 2
и так с последующими. Но тут есть трабл, если не оптимизируешь прогу, то это дело сделает авер с радостью
Нужно идти еще глубже.
int iu = (0,25 + ....) // 0,5

После int a1 = (iu + iu) * 2 ; // 2

Ток нужно каждую переменную разбавить еще на десятки, пока не выйдет unsigned double. Получится около 100 строк кода с мат вычисленями, при каждой генерации новые мат выражения, новое кол-во строк и глубины, вот тогда это норм наверное.

На счет циклов. Как я заметил, в while у тебя лишь двойная глубина, if и switch, как вариант на каждом операторе switch создавать новый тршген циклов + еще пару услов операторов. И эти услов операторы не просто int var = 424; или var += 33; а в свою очередь поделены на мат выражения со ста переменными. + тут можно по хешу вызывать вин апи функции, выделять память, заполнять, делать сверку и т.д. Создаваемое кол-во должно регулироваться с рандомом, т.е. не просто switch 1, 2, 3, 4, 5. А рандом кол-во switch с проверкой на рандом значения в пределах вышестоящего цикла.

А вообще, удивляюсь как ты написал морфер не зная регулярки, не работая с llvm, и на чистом Си

p.s. трешген я не вижу как просто объявить переменную, провести мат выражение и т.д. Вижу его как часть процесса, которая косвенно влияет на цикл каждый раз по другому, но общий цикл будет сводиться к тому, что вернет правильное значение.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
как Вы смотртите на такой код?

C:
int max_value1 = 10;
int max_value2 = 5;

char *xss = "dajcks";

int tryed = 0;

while(1) {
     if( RandomGenInt1(max_value1 ) == RandomGenInt2(max_value2 ) {
              DecodeString(xss, tryed);
               break;
      }
      tryed++;

}

RandomGenInt1 - генерирует рандом число из параметра по одному методу, а RandomGenInt2 по другому

А собственно в DecodeString() из полученного значения int мы после операции получаем детерминированное число. Т.е. не знаем что на входе, но знаем что на выходе. Тут простой пример, но подумав, посидев можно написать функцию еще глубже.

Via Morfer - там была примерное такое, и вообще, сделать из любого числа определенное после мат выражений не так сложно. Тут убиваем антиэмуль (если авер спрыгнет, то не получит дешифрованную строку), дешифроваем строку, + ключ у нас к дешифровке пока не понятен, но получаем из любого числа точный ключ
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Jeffs

Начнем с мат выражений.

имеем переменную int var = 28371;
Что можно сделать, каждое число выводим на новую переменную с мат вычислением

int a1 = (0,5 + 0,5) * 2 // 2
и так с последующими. Но тут есть трабл, если не оптимизируешь прогу, то это дело сделает авер с радостью
Нужно идти еще глубже.
int iu = (0,25 + ....) // 0,5

После int a1 = (iu + iu) * 2 ; // 2

Ток нужно каждую переменную разбавить еще на десятки, пока не выйдет unsigned double. Получится около 100 строк кода с мат вычисленями, при каждой генерации новые мат выражения, новое кол-во строк и глубины, вот тогда это норм наверное.

На счет циклов. Как я заметил, в while у тебя лишь двойная глубина, if и switch, как вариант на каждом операторе switch создавать новый тршген циклов + еще пару услов операторов. И эти услов операторы не просто int var = 424; или var += 33; а в свою очередь поделены на мат выражения со ста переменными. + тут можно по хешу вызывать вин апи функции, выделять память, заполнять, делать сверку и т.д. Создаваемое кол-во должно регулироваться с рандомом, т.е. не просто switch 1, 2, 3, 4, 5. А рандом кол-во switch с проверкой на рандом значения в пределах вышестоящего цикла.

А вообще, удивляюсь как ты написал морфер не зная регулярки, не работая с llvm, и на чистом Си

p.s. трешген я не вижу как просто объявить переменную, провести мат выражение и т.д. Вижу его как часть процесса, которая косвенно влияет на цикл каждый раз по другому, но общий цикл будет сводиться к тому, что вернет правильное значение.
В этой статье очень хорошо расписана тема генерации мат. выражений, у меня на си около 50 строк кода вышло.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
В этой статье очень хорошо расписана тема генерации мат. выражений, у меня на си около 50 строк кода вышло.
как раз я на хаунта ссылался. Но не достаточно глубоко имхо. Все это дело съест оптимизатор. Возьмем переменную 4. Каждый раз будем делить его 200 раз. Все данные полученные после деления будут выделены отдельные переменные. Скажем последняя переменная будет иметь значение:
int a200 = 0,000002;
int a199...

int sum = ((a200 * 2) / 3) * (a199/ 2) * 19.... ; // Итоговое значение - 2


оставить 0.000002 глупо, тут делаем глубинку мат вычисления как у Хаунта ток с глубиной генератора в 100. Вот это не съест оптимизатор и авер
 
Пожалуйста, обратите внимание, что пользователь заблокирован
как раз я на хаунта ссылался. Но не достаточно глубоко имхо. Все это дело съест оптимизатор. Возьмем переменную 4. Каждый раз будем делить его 200 раз. Все данные полученные после деления будут выделены отдельные переменные. Скажем последняя переменная будет иметь значение:
int a200 = 0,000002;
int a199...

int sum = ((a200 * 2) / 3) * (a199/ 2) * 19.... ; // Итоговое значение - 2


оставить 0.000002 глупо, тут делаем глубинку мат вычисления как у Хаунта ток с глубиной генератора в 100. Вот это не съест оптимизатор и авер
Это мат. выражение подсчитается на этапе компиляции, если включена оптимизация
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Это мат. выражение подсчитается на этапе компиляции, если включена оптимизация
Да, не сообразил с ходу...
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Или как вариант, написать стилак на асме, как пони когда-то был написан. Там морфить легче, опкоды и т.д. Но я щас почитываю masm32, но уровень еще для меня высокий
Писать на асме не имеет никакого смысла. Тут на форуме 99 процентов людей на плюсах не умеют писать, чтобы при этом себе не отстрелить обе ноги, а ты асм предлагаешь. Если так хочется морфить на уровне ассемблера, бери любой компилируемый в нативный код язык програмирования, я почти уверен, что его компилятор может в том или ином виде выводит ассемблерный листинг, морфишь его и собираешь тамошним ассемблером.


просто посмотри масс малвари, покупают крот, который задрочили уже 800 чел, покупали пердатор, на которую подрочили еще 900 чел, покупают оски, на которую дрочат 800 чел, и у них отстук с криптом за 10$ составляет больше 70%. Тут думаю, выводы можно сделать самому. А морфер на уровне сорцов, с криптом должно сохраняться долго
Ну смотря какие масштабы. Если пробили достаточно много людей, то это скорее вопрос к аверам, почему так медленно и лажово работают.


Запас шаблонов должен быть именно в нами написанных функциях. Пример: есть функция, которая декоидурет base64. Написать 6 вариантов.
Ну это не особо хорошее решение, тк количество вариантов ограничено, рано или поздно все алгоритмы попадут в детекты. Тут еще нужно помнить, что сам морфинг должен быть достаточно рандомным. Скажем я с ходу могу назвать два алгоритма control flow flattening (через цикл+switch и через цикл+jumptable), если для всех семплов и для всех функций каждого семпла использовать их, в скором времени будет уже детектиться ни твой бейс64, а твой морфер.
 
как Вы смотртите на такой код?
Лучше тогда поставить метки времени, тем самым вы будете контролировать время исполнения кода, это я называю атаки на ресурсы эмулятора, тут можно как минимум два варианта:

1. Какие-то тяжелые мат. операции, т.е. эмулятор не справится, т.к. иначе будут тормоза сильные при проверки.
2. Долгое ожидание исполнения кода.

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

Поэтому я и рекомендую, если выбрали такой способ, сделайте специальную универсальную функцию, где в параметрах указывайте время ожидания, а в качестве ожидания можно использовать разницу меток времени, причем метки времени можно получать ассемблерной инструкцией, считывая циклы процессора, т.е. регистр rdtsc.

Вот для понимания ссылки:



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

C:
//Получение регистра rdtsc
inline ull rdtsc() {
    unsigned int lo, hi;
    asm volatile ( "rdtsc\n" : "=a" (lo), "=d" (hi) );
    return ((ull)hi << 32) | lo;
}

//Задержка при помощи rdtsc
long long Sleep_mks(long long time)
{
  long long clock0 = 0;
  long long clock = 0;

//Получение частоты
long long frequency = 0;
QueryPerformanceFrequency((LARGE_INTEGER *)&frequency);

long long FcpuMHz = frequency/1000/1000 //частота процессора в МГц

  __asm rdtsc;                        //получаем текущий такт процессора (в eax)
  __asm mov [clock0], eax;            //переписываем eax в clock0
  do
  {
    __asm rdtsc;                      //получаем текущий такт процессора (в eax)
    __asm sub eax, [clock0];          //eax = eax - clock0
    __asm mov [clock], eax;           //переписываем eax в clock
  }
  while (clock < (FcpuMHz * time));
  return clock;
}

//Сам код получения ключа (wait - секунды)
long long wait_and_get_pass (long long wait) {
 
    long long ret_code = 0;
    long long clock = 0;

    long long t1 = rdtsc();
    long long clock = Sleep_mks(wait/1000000);
    long long t2 = rdtsc();
    ret_code = t2 - t1;

  return ret_code + clock;
}

Далее зная что значение, которое вернет wait_and_get_pass будет не меньше чем 2*FcpuMHz*(wait/1000000) микросекунд в целой части, можно расчитать уже на этом пароль, или что еще, минуя эмулятор.

Код чисто как пример, я не стал инкапсулировать ассемблер, да и скорей-всего нерабочий, чисто как пример, непроверял.
Возможно даже заморочно, поток мысли...)))
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Код чисто как пример, я не стал инкапсулировать ассемблер, да и скорей-всего нерабочий, чисто как пример, непроверял.
Для rdtsc в GCC/MinGW должна быть интринсика, так что можно и без асм вставок обойтись.


Поэтому я и рекомендую, если выбрали такой способ, сделайте специальную универсальную функцию, где в параметрах указывайте время ожидания, а в качестве ожидания можно использовать разницу меток времени, причем метки времени можно получать ассемблерной инструкцией, считывая циклы процессора, т.е. регистр rdtsc.
Мне кажется, что rdtsc вполне можно эмулировать без проблем, пропуская все ваши кулхацкерские ждуны.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Писать на асме не имеет никакого смысла. Тут на форуме 99 процентов людей на плюсах не умеют писать, чтобы при этом себе не отстрелить обе ноги, а ты асм предлагаешь. Если так хочется морфить на уровне ассемблера, бери любой компилируемый в нативный код язык програмирования, я почти уверен, что его компилятор может в том или ином виде выводит ассемблерный листинг, морфишь его и собираешь тамошним ассемблером.



Ну смотря какие масштабы. Если пробили достаточно много людей, то это скорее вопрос к аверам, почему так медленно и лажово работают.



Ну это не особо хорошее решение, тк количество вариантов ограничено, рано или поздно все алгоритмы попадут в детекты. Тут еще нужно помнить, что сам морфинг должен быть достаточно рандомным. Скажем я с ходу могу назвать два алгоритма control flow flattening (через цикл+switch и через цикл+jumptable), если для всех семплов и для всех функций каждого семпла использовать их, в скором времени будет уже детектиться ни твой бейс64, а твой морфер.
1. В вижуал студио можно смотреть асм код, мб таким и образом можно опкодить, морфить асм код и как ты сказал местным асмом собрать все это дело

2. Да, я буду применять принцип морфинга на абсолютном рандоме. Каждая генерация циклов, операторов будет только по рандому. Тот же самый свитч кейс (т.е. кол-во) будет сгенерировано в рандоме. Нужно показать питоновскому скрипту, какие операторы есть, как вставялть, куда вставлять, что вставялть, что морфить. Кол-во глубины морфинга переменных (мат выражений) будет создано через рандом. И да, морфиться будет не все, только некоторая часть. Если я сделаю также как Jeffs т.е. возьму цикл while и туда вставлю switch'ы, то будет детект, согласен. А что если по рандому поместить цикл в условный оператор или еще один цикл, а в самом цикле создать не только switch, но if (кста if'ом можно сбить CFF?). И в каждой функции будет вызван по рандому любой вин апи. Т.е. каждый раз когда прога компилится, будет вызван другая апи функция, в другой последовательности. И глубина логики морфинга будет контролироваться так же рандомом. Где-то глубоко (в цикле цикл, оператор в switch, тут еще один свитч и т.д.). Но главное избежать стек оверфлоу, избыточное создание операций мб вызовет и прога упадет. Что не есть гуд. Тема в общем сложная и спорная. Но в 2020 году вижу только морфинг кода как эффективную чистку и долгое служение малвари. Да, морфер приедтся изменять/поддерживать, но это намного лучше нежели в ручную эту же работу делать каждый месяц. Рано или поздно детекты будут, этого не избеажть, мб только крутой морфер спасет. Но морфер, например по шаблону, намного может увеличить срок службы
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Лучше тогда поставить метки времени, тем самым вы будете контролировать время исполнения кода, это я называю атаки на ресурсы эмулятора, тут можно как минимум два варианта:

1. Какие-то тяжелые мат. операции, т.е. эмулятор не справится, т.к. иначе будут тормоза сильные при проверки.
2. Долгое ожидание исполнения кода.

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

Поэтому я и рекомендую, если выбрали такой способ, сделайте специальную универсальную функцию, где в параметрах указывайте время ожидания, а в качестве ожидания можно использовать разницу меток времени, причем метки времени можно получать ассемблерной инструкцией, считывая циклы процессора, т.е. регистр rdtsc.

Вот для понимания ссылки:



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

C:
//Получение регистра rdtsc
inline ull rdtsc() {
    unsigned int lo, hi;
    asm volatile ( "rdtsc\n" : "=a" (lo), "=d" (hi) );
    return ((ull)hi << 32) | lo;
}

//Задержка при помощи rdtsc
long long Sleep_mks(long long time)
{
  long long clock0 = 0;
  long long clock = 0;

//Получение частоты
long long frequency = 0;
QueryPerformanceFrequency((LARGE_INTEGER *)&frequency);

long long FcpuMHz = frequency/1000/1000 //частота процессора в МГц

  __asm rdtsc;                        //получаем текущий такт процессора (в eax)
  __asm mov [clock0], eax;            //переписываем eax в clock0
  do
  {
    __asm rdtsc;                      //получаем текущий такт процессора (в eax)
    __asm sub eax, [clock0];          //eax = eax - clock0
    __asm mov [clock], eax;           //переписываем eax в clock
  }
  while (clock < (FcpuMHz * time));
  return clock;
}

//Сам код получения ключа (wait - секунды)
long long wait_and_get_pass (long long wait) {

    long long ret_code = 0;
    long long clock = 0;

    long long t1 = rdtsc();
    long long clock = Sleep_mks(wait/1000000);
    long long t2 = rdtsc();
    ret_code = t2 - t1;

  return ret_code + clock;
}

Далее зная что значение, которое вернет wait_and_get_pass будет не меньше чем 2*FcpuMHz*(wait/1000000) микросекунд в целой части, можно расчитать уже на этом пароль, или что еще, минуя эмулятор.

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

Благодарю =D
 
Мне кажется, что rdtsc вполне можно эмулировать без проблем, пропуская все ваши кулхацкерские ждуны.
Можно, но для этого нужно писать специальный драйвер, что может и непраблема для аверов, но как они узнают нужное значение которое должно получиться ?
Тут-же не просто задержка, а еще и получение нужно числа для формирования ключа расшифровки, или еще чего-то там.
Да можно конечно и проще делать, это просто пример для размышления.

Да можно без асма все это сделать.)))
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Но главное избежать стек оверфлоу, избыточное создание операций мб вызовет и прога упадет.
Ну не только, еще можно разделить на ноль, получить NaN, если работаешь с float/double, разименовать невалидный указатель и тд.


Можно, но для этого нужно писать специальный драйвер, что может и непраблема для аверов, но как они узнают нужное значение которое должно получиться ?
Зачем драйвер, в подавляющем большинстве аверов эмуляторы софтварные. Узнают они нужное число очень просто - посчитают количество выполненных инструкций между вызовами rdtsc и прикинут примерно, сколько должно было пройти времени на реальном железе.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Можно, но для этого нужно писать специальный драйвер, что может и непраблема для аверов, но как они узнают нужное значение которое должно получиться ?
Тут-же не просто задержка, а еще и получение нужно числа для формирования ключа расшифровки, или еще чего-то там.
Да можно конечно и проще делать, это просто пример для размышления.

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

Твой варик +/- если доработать то гуд будет
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ну не только, еще можно разделить на ноль, получить NaN, если работаешь с float/double, разименовать невалидный указатель и тд.
Само с собой :D
 
Ну обойти эмуляторы, это несложная задача и неважно даже, что многие эмули даже эмулируют слипы, даже на них можно придумать обходы, как показали мои тесты...)

Основные сложности обойти проактивную защиту, т.е. детекты после запуска и уменьшить детекты в облаке, вот это уже проблемы.)))

Поэтому смысл обсуждать такой обход, ну-да скан не будет детектить, но при запуске например из под нода будет детект в памяти, если вы делаете криптор, вот это уже проблема.)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
но при запуске например из под нода будет детект в памяти, если вы делаете криптор, вот это уже проблема.)
Intel SGX в помощь)). А так да, есть некие варианты, типа отладки собственного процесса и расшифровка по одной инструкции, но это, сам понимаешь, как сильно влияет на производительность.


А вообще, я рад что хоть где-то подымается тема морфинга сорцов на крестах и Си
Чисто формально эта тема про Ним, а не про Си, и про обфускацию, а не про морфинг. Но почему бы и на эту тему не потереть.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Ну обойти эмуляторы, это несложная задача и неважно даже, что многие эмули даже эмулируют слипы, даже на них можно придумать обходы, как показали мои тесты...)

Основные сложности обойти проактивную защиту, т.е. детекты после запуска и уменьшить детекты в облаке, вот это уже проблемы.)))

Поэтому смысл обсуждать такой обход, ну-да скан не будет детектить, но при запуске например из под нода будет детект в памяти, если вы делаете криптор, вот это уже проблема.)
Кста, а как вообще обходится проактивка? Это же чисто палево по действиям тип малварь создает файл с таким-то именем, туда записывает по такому-то пути. В этом случае можно каждый раз менять названия файл, расположение создания файла, задержку делать + менять алгоритм и порядок действий самой проги по рандому. Тогда каждый раз прога будет вести себя по другому, и еще разбавленный код морфером с добавляением трешгена вовсе должен сохранять фуд долгое время, не? Думаю, нужно создать отдельный топик и обсудить этот вопрос. И да, как обойти скан памяти?
 


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