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

Статья HVNC часть 2: Internal Hooks, IDA, Sigmaker

unbalance

(L3) cache
Пользователь
Регистрация
28.06.2021
Сообщения
151
Решения
1
Реакции
175
http://xssforum7mmh3n56inuf2h73hvhnzobi7h2ytb3gvklrfqm7ut3xdnyd.onion/attachments/24824/Доброго вечерочка!

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

В прошлой части: [https://xss.pro/threads/54114/] [http://xssforum7mmh3n56inuf2h73hvhnzobi7h2ytb3gvklrfqm7ut3xdnyd.onion/threads/54114/]
Мы разобрались как сделать дллку для изменения функционала программ, а именно как искать уязвимости для (dll-hijacking) в приложениях, как самостоятельно заколотить проксирование экспортируемых функций в вашей дллке (export forwarding), для того что бы не было вылетов и ваша дллка правильно себя вела в GetProcAddress. А уж как мы разобрались с хуками, это вообще класс — мы познакомились с замечательной и самое главное простой библиотекой - Minhook. А так же мы собрали себе простой ратник из обычного VNC клиента и сервера.

В этой части:
Мы разберемся с тем как шпионить за тем что делает приложение с помощью простого софта - ApiMonitor, поймем в том что реверс-инженерия это не так уж и сложно, научимся добывать сигнатуры из атакуемого приложения, а так же использовать их в наших целях, для изменения (подмены) функций прямо внутри атакуемого приложения, а не экспортируемых функций из библиотек, причем патчить ничего не придется, чем мы сохраним цифровые подписи и убережем от лишних детектов антивирусов. Я постараюсь дать вам кратчайшие сведения по IDA PRO (да не отпугнет начинающих это название!) для того что бы вы побежали уже делать что то своё, или хотя бы учиться новому.
  • исследования вызова WinApi функций
  • простая работа в IDA PRO
  • внутрение хуки (Internal Hooks)
  • выводы и цели на следующую статью
ИССЛЕДОВАНИЕ ВЫЗОВОВ WINAPI ФУНКЦИЙ [0.4]

По настоящему самый лучший и гениальный инструментарий нам подарила компания Майкрософт — такой как Windows Vista, новое меню Пуск в Windows 8, а как мы радовались запуску Bing, я до сих пор утираю слёзы умиления когда вижу как IE просит меня поставить его по-умолчанию... Но если отбросить в сторону все эти по-настоящему замечательные и эмоциональные моменты, то многое ребята сделали хорошо, например свою документацию, наш верный помощник и союзник на все времена — её сайт docs.microsoft.com. Если по какой то причине вы еще не выучили WINAPI хотя вам хочется, то добро пожаловать на его просторы. Что бы стать нормальным (индуистом/виндовс)-программистом, нужно столкнуться с этим испытанием, хотя если честно, это совершенно не страшно. Вам просто нужно открыть гугл — ввести имя необходимой функции которая вам лично не будет ясна и вы конечно же найдете документацию по ней на этом замечательном ресурсе. Все функции так или иначе делятся на группы, например для работы с чтением или записью в файлы у нас набор CreateFile/WriteFile/ReadFile/SetFilePointer/CloseHandle и тому подобное (я бы мог перечислять очень долго), а для работы с интернетом у нас больше трех библиотек аж… чем не раздолье если вспомнить что в gnu/linux из коробки у нас только сокеты? (хотя и их с головой достаточно для всего).

Для начала нам нужно понять что эти функции легко детектируются, это во первых. Во вторых даже если вы привыкли работать с fopen в си — то внутри него всегда идет вызов CreateFile, а уж внутри CreateFile само собой будет вызываться — NtCreateFile, который уйдет куда то еще. Так что вы без информации никогда не останетесь — все похукано уже до вас! Вам просто нужно научиться пользоваться различными инструментами для получения разведывательных данных. Первым разведчиком у нас будет ApiMonitor — который покажет нам рантайм нашей программы — какие функции вызывает приложение во время своей работы, естественно оно само хучит ваше приложение и получает из него всю информацию.

Обязательно смотрите пожалуйста разрядность вашего приложения. А то были уникумы которые пытались подгрузить 64 битную dll в 32 битный процесс, а потом у меня спрашивали почему я не компилирую всё в 64 — так как это будущее и очень современно, и удивлялись почему же в итоге у них всё равно ничего не работает. Кстати, вы так же не сможете подгрузить 32 битную дллку в 64 битный процесс. Это просто к слову — я вас ничему не обязываю. Для простой проверки на версию компилятора, на разрядность и тому подобное удобно пользоваться комбайном - Detect It Easy, вот ссылка, вот ссылка на видео если вы не понимаете где посмотреть разрядность аттакуемого приложения
Смотрим какой разрядности ваше приложение, запускаем соответственно ему версию ApiMontor - запускаем наше приложение, инжектируемся в наш запущенный процесс.


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

Как лучше всего поступать для добычи информации о том, что происходит в момент когда ты нажимаешь кнопку? Ставим на паузу — стираем длинный лог, запускаем монитор и тыкаем на кнопку — что то происходит — мы ставим мониторинг снова на паузу. Это похоже на бред в том плане что лог действительно будет огромным, действительно придется покопаться, что бы получить хоть какую то информацию, но если быть упорным (или упоротым) то мы добудем примерный рантайм происходящего внутри приложения, и мы будем знать куда копать — например на какие функции (ох, ну сейчас то я просто тычу наугад, так как знаю что они делают) будут вызываться, если вам какая либо из них будет незнакома просто гуглите ее и смотрите что она делает — если натолкнетесь на свой вариант — поздравляю!

Ищем не просто отдельные winapi функции а их сочетания. Самое простое — для записи и чтения файлов я уже упоминал чуть выше в статье — CreateFile/WriteFile/ReadFile/SetFilePointer/CloseHandle… А вот например сочетание функций для создания скрытого рабочего стола будет примерно выглядеть так: OpenDesktop, CreateDesktop. Для проверки на каком рабочем столе находится приложение — GetCurrentThreadId, GetThreadDesktop, OpenInputDesktop и GetUserObjectInformation.

Для простого примера в этой статье я создал программу которая будет просто копировать файл из одного места в другое. Она будет иметь графический интерфейс, а так как у нас тематика HVNC — я полностью повторю фишку с проверкой рабочих столов как она реализована в ultravnc — но с некоторым изменениями, например простая операция копирования у нас не будет выполняться на рабочем столе по-умолчанию, да я совершенно осознанно решил что программа будет изначально — не работать! И будет крайне простой для реверсинга, давайте попробуем разобраться что обычно происходит внутри самых простых winapi приложений.

Вот видео с примером программы которая не будет правильно работать на Дефолтном рабочем столе, и только подменив функцию внутри Exe мы сможем обойти это препятствие

Что бы разобраться в работе любой программы, нужно понимать как эти программы хотя бы создаются в простых их вариантах. Для обучения по реверсу вам конечно подойдет такой вариант — написали простую прогу самостоятельно — начали реверсить. Это тоже самое что кататься на скейте — тысячу раз упал — на тысячу первый уже поехал. Даже если вы используете любую графическую библиотеку для создания интерфейсов то все равно под капотом у вас будет Winapi каркас, это абсолютно естественно. Вот этот каркас:

C:
LRESULT CALLBACK winproc(
    ...
)
{
    switch (wm)
    {
        case WM_CREATE:
        {
           ...
           break;
        }
        case WM_CLOSE:
            DestroyWindow(hwnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, wm, wp, lp);
    }
    return 0;
}

int WINAPI WinMain(
    ...
)
{
    CHAR CLASS[] = "WINDOWCLASS";
    HINSTANCE hInst = hInstance;
    WNDCLASSEXA wc = { };
    wc.cbSize = sizeof(wc);
    wc.lpfnWndProc = winproc;
    RegisterClassExA(&wc);
    HWND window_hwnd = CreateWindowExA(WS_EX_LEFT,....);
    ShowWindow(window_hwnd, 1);
    UpdateWindow(window_hwnd);

    MSG Msg;
    while (GetMessageA(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessageA(&Msg);
    }
    return Msg.wParam;
}

Скачать проект

Точка входа любого графического приложения — это функция WinMain, внутри нее я заполняю структуру окна WNDCLASSEXA wc — это не с++ класс в обычном понимании, просто так называется, в нем обычно хранятся какие либо данные о используемых иконках, важный момент указать ему winproc — функцию которая будет принимать действия пользователя — это наиболее важный компонент вашей программы, регистрируем класс с помощью RegisterClassExA и создаем CreateWindowExA, теперь нам нужно будет его показать на рабочем столе наше окно с функцией ShowWindow — второй параметр отвечает за ПОКАЗЫВАТЬ/НЕПОКАЗЫВАТЬ. А UpdateWindow за обновления окна при каких либо действиях пользователя, а далее следует цикл в котором у нас посылаются сообщения нашей основной функции winproc. Вообщем по WinMain у нас всё, но есть то что я добавил от себя - LoadLibraryA("fucker.dll") — уязвимая подгруздка плохой дллки, делать будем всё как в прошлой части.

Теперь самое интересное — winproc — в ней происходит получение сообщений, от того что вы нажали кнопкой мыши где то в окне, от изменения различного текста в Edit-полях, вообще всё обрабатывается именно в ней. Ее как оказалось тоже очень удобно перехватывать. Как мы видим в ней идет стандартная проверка получаемых параметров UINT wm и WPARAM wp. Сначала делается более глобальная провека Wm, что бы понять какой тип сигнала нам поступил, а потом конкретно идет проверка wp, что бы понять что нужно делать.

C:
LRESULT CALLBACK winproc(
    HWND hwnd,
    UINT wm,
    WPARAM wp,
    LPARAM lp
)
{
    switch (wm)
    {
        case WM_CREATE:
        {
            TextBox1 = CreateWindowA("EDIT",
                "",
                WS_VISIBLE | WS_CHILD,
                10, 10, 465, 18,
                hwnd, (HMENU)2, NULL, NULL);

                ...

            break;
        }

    
        case WM_COMMAND:
        {
            switch (wp)
            {
                case 16777218:
                {
                     ...

Screenshot_1.png
При проверке wm это самый важный то при первом запуске получаемый сигнал - WM_CREATE — в нем вы обрисовываете все элементы окна — каждый элемент окна, будь то кнопка в winapi тоже является окном, в него тоже поступают сигналы и он создается с помощью CreateWindowA, с небольшими оговорками — например в него передается HWND его родителя — окна на котором он будет обрисовываться. Я создам три элемента — два текстовых поля и одну кнопку. Замечу что кнопке передается еще один важный параметр который пригодится в итоге — HMENU — этот параметр является числом которое мы назначим нашей кнопке что бы когда мы на нее нажали — мы могли получить это же число в wp — что бы узнать какая кнопка была нажата. Вот таким вот бесхитростным способом устроены ваши окошки. Что бы понять как регистрируются сообщения рекомендую в VS поставить брейкпоинты и самостоятельно посмотреть какие сообщения приходят, и что в них содержится, можете тыкать по окну в разные места и смотреть что поступает к вам в winproc.

Теперь по функции которая будет копировать файл из одного места в другое — в ней и содержится ебучая проверка которую нам будет важно обойти. Давайте разберемся как она работает! При логине в каждую сессию пользователя у нас по умолчанию созданы уже два рабочих стола — основной на котором мы работаем Default и еще Winlogon — он будет работать когда у вас вылезает окошко уака.…

C:
BOOL PROVERKA_BLYAD()
{
    DWORD dw;
    char name[MAX_PATH]{};
    HDESK currentdesk = GetThreadDesktop(GetCurrentThreadId());
    GetUserObjectInformationA(currentdesk, UOI_NAME, &name, MAX_PATH, &dw);
    if (strcmp(name, "Default") == 0)
    {
        MessageBoxA(0, "FUCKOFF", "FUCKOFF", MB_OK);
        return FALSE;
    }
    return TRUE;
}

VOID COPY_FUNC_FILE(char* text1, char* text2)
{
    if (PROVERKA_BLYAD() == TRUE)
        CopyFileA(text1, text2, 0);
    return;
}

Для получения дескриптора рабочего стола который запущен в треде — мы вызываем функи: GetCurrentThreadId с ней мы получаем id нашего потока и передаем его в функцию GetThreadDesktop, которая возращает нам HDESK рабочего стола, который по идее является Default. Теперь следующий шаг получить имя рабочего стола — GetUserObjectInformation, получив его сравниваем со строкой «Default» и если это основной рабочий стол — то завершаем работу функции проверки и посылаем сигнал FALSE — который скажет что операция копирования не будет производится!

Точно так же реализовано все и в ultravnc, но об этом чуть позже. Теперь нам нужно познакомиться с героем этой статьи по настоящему вечно живущей программулиной, которая поглотила ночи множества людей, многих свела с ума и отпугнула на ранних этапах — IDA.

ПРОСТАЯ РАБОТА В IDA PRO [0.5]

По у
photo_2021-01-06_15-03-58 (2).jpg
становке вкратце, нам потребуется установить Иду и расширение которое позволит получать сигнатуры функций. Скачиваем IDA PRO с рутрекера 7.0, устанавливаем, вводим пароль, и потом крякаем! Поздравляю! Скачиваем по ссылке дллки расширения SigMaker, заходим в папку C:\Program Files\IDA 7.0\plugins и сбрасываем туда их, они и будут нашим помощником для получения сигнатур функций внутри нашего исследуемого «пациента».

Пожалуйста если вы смотрите ролик ставьте его на минимальную скорость на ютубе и включайте субтитры — я писал старался. Но так же и стоит описать все что происходит на экране в текстовом варианте тем кто хотел бы больше читать. Так же рекомендую начать реверсить программы которые вы создаете — с нуля, что бы понимать что хотя бы происходит и набивать глаз. За пару разных разобранных программ вы уже поймете что требуется от вас. Всё приходит с опытом — работать в IDA значительно проще чем писать эту статью.

Когда вы закидываете ваш исследуемый файл в IDA вы должны дождаться появления блоков — которое сигнализирует нам о том, что проект полностью обработан. Тогда у вас три пути для начала работы — это открыть список строк нажав Shift+f12, посмотреть список импортируемых Winapi функций во вкладке Imports, или самый сложный для новичка искать оригинальную функцию WinMain (точку входа приложения) и исследовать уже отталкиваясь от нее. Но всё выбирают самые легкие варианты которые уже стали мемами...

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


Видео с комментариями как найти проверочную функцию внутри UltraVnc

ВНУТРЕНИЕ ХУКИ [0.6]

Видео без комментариев, о том как найти проверочную функцию внутри нашего проекта и хукнуть её:

Расширение Sigmaker позволяет нам получить сигнатуру необходимой функции, а по этой сигнатуре вы всегда сможете найти ее оффсет, и поставить на неё хук. Достаточно просто выделить текст как показано в видео, выбрать в выпадающем списке расширение "Edit" -> "Plugins" -> "Create Code Patterm from Selection", не забудьте перед этим открыть Output Window, как я показал, что бы скопировать оттуда сигнатуру функции.

Screenshot_1.png
Screenshot_2.png
Screenshot_3.png


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

C:
 DWORD AddressOfFunc = FindPattern((char*)"\x55\x8B\xEC...\x00\x00\x00\x00",
                                        (char*)"xxxxx????....x????");

А так же мы не забудем создать typedef для реальной функции которую будем хукать
Код:
typedef BOOL(*_Real_Func)();

И создать функцию которая будет на замену реальной, и всегда возращает TRUE
Код:
BOOL Fake_Func()
{
    return TRUE;
}

Далее самое простое действие из всех что вы видели - просто хукаем это дело с помощью Minhook и готово:

C:
        case DLL_PROCESS_ATTACH:
        {
          
            if (MH_Initialize() == MH_OK)
            {
                if (MH_CreateHook((LPVOID)AddressOfFunc, &Fake_Func, reinterpret_cast<LPVOID*>(&Func)) == MH_OK)
                {

                }
                MH_EnableHook(MH_ALL_HOOKS);
            }


ВЫВОДЫ И ЦЕЛИ НА СЛЕДУЮЩУЮ СТАТЬЮ
Все рано или поздно заканчивается, считайте эта статья промежуточная и необходимая перед завершающей, я дописываю свой Magnum Opus... В этой статье мы научились хукать по новому, подменять внутри приложения необходимые нам функции. Но самое интересное нас ждет еще впереди - например, не глупые проверки, а победа над реальными ограничениями приложения. Например над тем, что из коробки UltraVnc не может получать скриншоты с виртуального рабочего стола, и с помощью внутренних хуков мы это подправим, те уже в следующей статье разговор пойдет конкретно о HVNC. Спасибо, что читали. Задавайте вопросы лучше в комментариях, так проще на них будет отвечать. Пока!
 
Последнее редактирование:
В продаже такого рода хвнц есть? Или пока только статьи?
Только в пределах статьи, мне хвнц сам по себе мало интересен.
по продажам не знаю, не смотрел. но подобного точно нет
 
Последнее редактирование:
А почему ApiMonitor а не Procmon sysinternals, вроде бы логичнее его использовать, есть какое-то принципиально важное отличие или просто дело вкуса ?
 
А почему ApiMonitor а не Procmon sysinternals, вроде бы логичнее его использовать, есть какое-то принципиально важное отличие или просто дело вкуса ?
хотелось рассмотреть всё что может когда нибудь пригодится читателю
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Хорошая статья, теперь ждем статью про то как обойти такую защиту у хрома), я не много смотрел, он короче запускается только на рабочем столе под именем default
 
Пожалуйста, обратите внимание, что пользователь заблокирован
отличная работа, продолжение будет?
 


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