Всех приветствую. В данной статье хочу рассказать вам об одной малваре (как выяснилось позже разработанной хакерской группировкой - Ocean Lotus) с необычным способом обфускации своего кода. Думаю, что данный материал должен быть интересен как любителям различных малварей, так и кодерам, которые ищут новые (ну или не совсем) техники обфускации.
Дисклеймер: автор не претендует на адекватное знание ассемблера и реверса, поэтому возможны неточности. Цель статьи - описание интересной идеи обфускации кода.
Ну отлично! Малварь нашли. Откуда она взялась тоже выяснили. Денег вроде не потеряли. В чем проблема? А проблема в том, что ИБешники не смогли разобрать как она работает. Это нужно для того, чтобы написать соответствующие правила на IDS и SIEM, которые располагались в инфраструктуре, да и к тому же при расследовании компьютерных инцидентов важно знать на что способна малварь, чтобы оценить бизнес риски и понять например, какие дырки оно могло оставить в системе. Тут разыгрался мой интерес ковырять неизведанное, тем более в случае успеха мне пообещали хорошую бутылку виски. Я принялся за работу (позже об этом пожалел).
DLL hijacking - это техника атаки, при которой легитимную библиотеку подменяют вредоносной с таким же названием. Суть в том, что DLL это тоже PE файл, который отличается от EXE по факту только заголовком, поэтому в них присутствует свой Entry Point под названием "DllMain", в которую входит программа, при вызове C++ функции типа "LoadLibrary". При этом как правило EXE файл является легитимным и подписанным. Поэтому при импортировании вредоносной библиотеки такое поведение считается достаточно "нормальным".
Убедимся в этом. Воспользуемся утилитой "sigcheck" из пакета "SysinternalsSuite" и проверим файлы "sep_NE.exe" и "WINMM.dll":
Далее стал интересен третий файл во вложении: "sep_NE.slf". Под каким "углом" я на него не смотрел, это был всего лишь мусорный файл. Особый интерес вызывало то, что он весит 148 кб. Первая мысль в голове была примерно такая: "наверняка он просто зашифрован каким-нибудь AES. Щас использую утилиту "strings", вытащу все строки с библиотеки и получу ключ". На деле оказалось, что строк то в библиотеке почти нет. Только несколько имен функций, которые скорее всего используются как аргумент функции GetProcAddress, чтобы получить адрес нужной функции. Ниже приведена небольшая часть вывода утилиты:
Далее с помощью утилиты "Dependency Walker" посмотрел таблицу экспорта. Видим, что у библиотеки присутствует 0 экспортируемых функций. Значит основной код находится в DllMain:
Осознав, что такими темпами я буду ковыряться очень долго, решил сразу перейти к динамическому анализу. Обычно я использую такие тулзы как: Process Hacker, ProcMon, Api Monitor плюс песочницу "Cuckoo Sandbox", но на тот момент виртуалки с ней у меня не было, поэтому пришлось обходиться малым.
Для выявления функционала малвари первым делом запустил «Api Monitor» от имени администратора. Как понятно из названия, она мониторит API вызовы процессов. После запуска «sep_Ne.exe» утилита предложит нам два процесса для мониторинга: «sep_NE.exe» и «msiexec.exe»:
Открыв «Process Hacker» увидим, что у «msiexec.exe» есть процесс-родитель «svchost.exe»:
При попытке завершить работу «msiexec.exe», «svchost.exe» снова его запускает. Если завершить работу «svchost.exe», то малварь не запустится, пока операционная система не будет перезагружена. После загрузки системы, автоматически запустится служба «svchost.exe», которая запустит «msiexe.exe». Это говорит о том, что оно записало себя в сервисы Windows.
Убедимся в этом использовав утилиту «autoruns.exe» из пакета "SysinternalsSuite". В записи журнала реестра, отвечающую за инициализацию сервисов при загрузке операционной системы появился сервис «Intel Capability Licensing Service» и путь к нему "C:\programdata\intel capability licensing service\sep_ne.exe".
Перейдем в новую созданную директорию "C:\programdata\intel capability licensing service" и посмотрим что там лежит. Отмечу, что она скрытая, а все файлы помечены как системные.
Заметим, что по сравнению с директорий откуда была запущенна малварь, появился новый файл – «Trend2013.dat». Открыв его через любой текстовый редактор видим, что часть функционала это - кейлогер, который фиксирует не только то что печатается на клавиатуре, но и запуск приложений:
При просмотре перехваченных вызовов, Api Monitor ничего интересного и значимого не было, ровно как и в ProcMon. Кроме создания скрытой директории практически ноль информации, что очень странно с учетом того, что вредонос работает в юзерспейсе и не может скрывать API вызовы. Было принято решение пойти дальше и попробовать посмотреть что там происходит в памяти. Воспользовался старой, доброй проверенной утилитой для снятия дампов "FTK Imager". Далее с помощью фреймворка "Volatility" начал анализ. Для начала спомощью плагина "pstree" вывел список процессов, нашел нужный и посмотрел его PID. Далее с помощью плагина "dlllist" просмотрел список импортируемых библиотек:
Видим, что никаких интересных библиотек нет и даже "WINMM.dll", которая шла в комплекте. Все это наводит на мысли, что малварь хранит данные в памяти. Для того, чтобы в этом убедиться, воспользуемся плагином "malfind", который просканирует процесс на наличие исполняемых страниц в которых есть вредоносный код:
Было найдено несколько таких страниц. Значит все самое сладкое лежит где-то в шаристой памяти. Т.к. dll была полупустой при анализе, то значит полезная нагрузка находится в файле "sep_NE.slf". Придется разреверсить библиотеку, чтобы понять как расшифровывается данный файл.
Я пользуюсь дизассемблером IDA PRO 7.0 с замечательным плагином Hex Rays. Ниже будет приведена первая часть кода:
Сначала, с помощью функции «VirtualAlloc» выделяется участок памяти размером 256 страниц, с типом доступа на чтение, запись и выполнение. Далее с помощью функции «GetModuleFileNameW» и работой в цикле программа получает путь к файлу «sep_NE.slf», который находится в одной папке с программой и с помощью функции «CreateFileW» открывает его.
Ниже приведена вторая часть кода:
С помощью функции «CreateFileMappingW» создается отображение файла «sep_NE.slf» в памяти и получается указатель на него с помощью «MapViewOfFile».
Все эти манипуляции с файлом производились для того, чтобы обратиться к указателю на память и запустить выполнение файла в памяти. После этого производится приостановка выполнения программы, для того, чтобы она не завершила свою работу.
В итоге мусорный файл был полностью загружен в шаристую память и там его по указателю вызвали как функцию.
Но странно, ведь когда я смотрел его в hex-редакторе, то там не было каких-либо заголовков или что-то похожее на исполняемый файл. При этом если просто закинуть его в дизассемблер, то он не сможет его распарсить.
Погуглив, я не нашел никаких ответов и единственным решением стало подрубить отладчик и посмотреть, что за ад там происходит...
Первым делом я начал отлаживать легитимный файл "sep_NE.exe" до нужного вызова функции "LoadLibrary":
Проваливаемся внутрь. Попадаем в библиотеку "WINMM.dll". Вот, например, часть кода, отвечающего за проецирование файла в разделяемую память:
Идем в конец функции, где происходит обращение к указателю в памяти на этот файл:
Видно, что последний CALL это вызов функции «Sleep» с параметром «INFINITIE» равным числу 0FFFFFFFFh в шестнадцатеричном виде. Поэтому нам нужен предпоследний CALL. Провалимся в него и попадем в файл «sep_NE.slf», который находится в разделяемой памяти:
Видим кучу мусорного кода на ассемблере при этом файл размером 148кб. На этом моменте мое лицо выглядело примерно так:
Я начал спускаться по этому коду дальше. Спустя минуту потраченной жизни, решил поставить точку останова куда-нибудь в середину файла, посмотреть что там. И... меня выкинуло, а малварь запустилась. Далее я заного провалился в эту память, чтобы понять что происходит. Во время отладки я понял, что по всему мусорному коду расставлены различные jmp, jz, jnz и т.п. на абсолютно рандомные адреса в этой шаристой памяти. Сначала может кинуть в конец файла, потом середину, потом опять конец и т.д. При этом в какой-то момент начинается недорасшифровка самого себя. Например сначала происходит jmp на рандомный адрес. Потом мусорный код следующей команды ксорится с магическим числом и получается новая команда. При этом все они абсолютно бессмысленны и если попытатся прыгнуть на другой адрес в памяти, то с большой вероятностью отладчик вылетит, а малварь запустится, потому что программа туда не заходит вовсе. Дизассемлер такое распарсить не сможет, т.к. мусорный код использует указатель стека, но при этом не меняет условные флаги. Из-за этого все переходы делаются в пределах одной ветки и возникают проблемы с дизассемблированием из-за положительных значений указателя стека.
В итоге ничего лучше в голову мне не пришло, как смиренно двигаться дальше и внимательно смотреть на команды, чтобы не пропустить первый CALL. При этом одна ошибка и нужно все начинать сначала.
Спустя 40 минут я дошел до первого вызова CALL:
Происходит получение адреса, по которому загружена программа. Выполняется CALL на следующую команду, при этом в стеке оказывается адрес этой самой команды.
С помощью структуры «PEB», которая находится по адресу fs:30h происходит получение адреса системной библиотеки «Kernel32.dll».
В этой библиотеке производится поиск адреса функции «GetProcAdress».
Ну и далее уже стандартная схема получения адреса функции "LoadLibrary" c помощью "GetProcAddress" и дальнейшее получение адресов всех нужных функций. Отмечу что в процессе отладки по коду везде расставлены функции GetTickCount как антиотладочный метод. Поэтому нужно внимательно следить за их вызовами и обнулять регист EAX, т.к. туда возвращается значение в миллисекундах этой функции. Один раз забудешь и целый час придется добираться снова до этого кода.
Дальше я понял, что голый ассемблер мне не потянуть в таком объеме и решил сдампить память чтобы попробовать распарсить её с помощью дизассемблера. И опять неудача из-за того, что после получения адресов всех нужных функций, вредонос зашифровывает часть своего кода и расшифровывает его соотвественно кусками при необходимости. При этом используется непонятный блочный алгоритм, шифрующий разные куски кода на разных ключах.
Далее этот код уже стало невозможно анализировать как минимум потому что я не знаю ассемблера на должном уровне, да и реверс не моя специализация, но примерно по импортированным функциям, смог понять основной функционал:
Очень интересно узнать ваше мнение как бы вы попробовали проанализировать данный файл. Спасибо за внимание!
P.S. Если статья была хоть немного интересна, то могу продолжить. Есть ещё необычные сэмплы которые могут быть интересны сообществу.

Автор: Temchi
Специально для https://xss.pro
Дисклеймер: автор не претендует на адекватное знание ассемблера и реверса, поэтому возможны неточности. Цель статьи - описание интересной идеи обфускации кода.
ПРЕДЫСТОРИЯ
История из жизни. Несколько лет назад, воскресенье, примерно 11 утра. Пью чай, ничего не предвещает беды. Звонит знакомый. На тот момент он работал в относительно крупной компании, отдел по информационной безопасности. Срочно просит помощи и объясняет ситуацию. Вкратце, на одной из машин, где хранились доки по бухгалтерии изменились счета для перевода средств на несколько сотен тысяч рублей, плюс SIEM ещё в субботу вечером создал событие об отключении антивируса на этой машине, но никто не обратил на это внимание. Руководство поставило задачу срочно в течении суток ему и ещё одному сотруднику, которого вызвали на работу расследовать этот инцидент и составить отчет о том каким образом это произошло, кто это сделал и какие инциденты могут произойти ещё. Сняли они дампы жесткого диска и оперативки. Нашли малварь и то, каким способом она попала на ПК. Это был максимально стандартный способ доставки - фишинговое письмо. Отправитель был якобы разработчик, который высылает срочно обновление для тулзы из-за критической ошибки безопасности. Не помню что за тулза, вроде что-то связанное с DNS, но вот скринсшот вложений:
БАЗОВЫЙ СТАТИЧЕСКИЙ И ДИНАМИЧЕСКИЙ АНАЛИЗ
Как правило при анализе вредоносов мне хватает базовых статических и динамических инструментов для анализа ПО. Под базовыми методами анализа по факту подразумевается все кроме реверса. Сразу замечаем, что есть exe файл и к нему прилагается либа "WINMM.dll". Обычно так поступают, когда используют технику - DLL hijacking. Уверен, большинство знает что это такое, но все же кратко опишу суть атаки для возможных новичков.
DLL hijacking - это техника атаки, при которой легитимную библиотеку подменяют вредоносной с таким же названием. Суть в том, что DLL это тоже PE файл, который отличается от EXE по факту только заголовком, поэтому в них присутствует свой Entry Point под названием "DllMain", в которую входит программа, при вызове C++ функции типа "LoadLibrary". При этом как правило EXE файл является легитимным и подписанным. Поэтому при импортировании вредоносной библиотеки такое поведение считается достаточно "нормальным".
Убедимся в этом. Воспользуемся утилитой "sigcheck" из пакета "SysinternalsSuite" и проверим файлы "sep_NE.exe" и "WINMM.dll":
Для выявления функционала малвари первым делом запустил «Api Monitor» от имени администратора. Как понятно из названия, она мониторит API вызовы процессов. После запуска «sep_Ne.exe» утилита предложит нам два процесса для мониторинга: «sep_NE.exe» и «msiexec.exe»:
Открыв «Process Hacker» увидим, что у «msiexec.exe» есть процесс-родитель «svchost.exe»:
При попытке завершить работу «msiexec.exe», «svchost.exe» снова его запускает. Если завершить работу «svchost.exe», то малварь не запустится, пока операционная система не будет перезагружена. После загрузки системы, автоматически запустится служба «svchost.exe», которая запустит «msiexe.exe». Это говорит о том, что оно записало себя в сервисы Windows.
Убедимся в этом использовав утилиту «autoruns.exe» из пакета "SysinternalsSuite". В записи журнала реестра, отвечающую за инициализацию сервисов при загрузке операционной системы появился сервис «Intel Capability Licensing Service» и путь к нему "C:\programdata\intel capability licensing service\sep_ne.exe".
Заметим, что по сравнению с директорий откуда была запущенна малварь, появился новый файл – «Trend2013.dat». Открыв его через любой текстовый редактор видим, что часть функционала это - кейлогер, который фиксирует не только то что печатается на клавиатуре, но и запуск приложений:
При просмотре перехваченных вызовов, Api Monitor ничего интересного и значимого не было, ровно как и в ProcMon. Кроме создания скрытой директории практически ноль информации, что очень странно с учетом того, что вредонос работает в юзерспейсе и не может скрывать API вызовы. Было принято решение пойти дальше и попробовать посмотреть что там происходит в памяти. Воспользовался старой, доброй проверенной утилитой для снятия дампов "FTK Imager". Далее с помощью фреймворка "Volatility" начал анализ. Для начала спомощью плагина "pstree" вывел список процессов, нашел нужный и посмотрел его PID. Далее с помощью плагина "dlllist" просмотрел список импортируемых библиотек:
Реверс, реверс и ещё раз реверс
Я пользуюсь дизассемблером IDA PRO 7.0 с замечательным плагином Hex Rays. Ниже будет приведена первая часть кода:
Ниже приведена вторая часть кода:
С помощью функции «CreateFileMappingW» создается отображение файла «sep_NE.slf» в памяти и получается указатель на него с помощью «MapViewOfFile».
Все эти манипуляции с файлом производились для того, чтобы обратиться к указателю на память и запустить выполнение файла в памяти. После этого производится приостановка выполнения программы, для того, чтобы она не завершила свою работу.
В итоге мусорный файл был полностью загружен в шаристую память и там его по указателю вызвали как функцию.
Но странно, ведь когда я смотрел его в hex-редакторе, то там не было каких-либо заголовков или что-то похожее на исполняемый файл. При этом если просто закинуть его в дизассемблер, то он не сможет его распарсить.
Погуглив, я не нашел никаких ответов и единственным решением стало подрубить отладчик и посмотреть, что за ад там происходит...
Первым делом я начал отлаживать легитимный файл "sep_NE.exe" до нужного вызова функции "LoadLibrary":
Проваливаемся внутрь. Попадаем в библиотеку "WINMM.dll". Вот, например, часть кода, отвечающего за проецирование файла в разделяемую память:
Видим кучу мусорного кода на ассемблере при этом файл размером 148кб. На этом моменте мое лицо выглядело примерно так:
Я начал спускаться по этому коду дальше. Спустя минуту потраченной жизни, решил поставить точку останова куда-нибудь в середину файла, посмотреть что там. И... меня выкинуло, а малварь запустилась. Далее я заного провалился в эту память, чтобы понять что происходит. Во время отладки я понял, что по всему мусорному коду расставлены различные jmp, jz, jnz и т.п. на абсолютно рандомные адреса в этой шаристой памяти. Сначала может кинуть в конец файла, потом середину, потом опять конец и т.д. При этом в какой-то момент начинается недорасшифровка самого себя. Например сначала происходит jmp на рандомный адрес. Потом мусорный код следующей команды ксорится с магическим числом и получается новая команда. При этом все они абсолютно бессмысленны и если попытатся прыгнуть на другой адрес в памяти, то с большой вероятностью отладчик вылетит, а малварь запустится, потому что программа туда не заходит вовсе. Дизассемлер такое распарсить не сможет, т.к. мусорный код использует указатель стека, но при этом не меняет условные флаги. Из-за этого все переходы делаются в пределах одной ветки и возникают проблемы с дизассемблированием из-за положительных значений указателя стека.
В итоге ничего лучше в голову мне не пришло, как смиренно двигаться дальше и внимательно смотреть на команды, чтобы не пропустить первый CALL. При этом одна ошибка и нужно все начинать сначала.
Спустя 40 минут я дошел до первого вызова CALL:
С помощью структуры «PEB», которая находится по адресу fs:30h происходит получение адреса системной библиотеки «Kernel32.dll».
Дальше я понял, что голый ассемблер мне не потянуть в таком объеме и решил сдампить память чтобы попробовать распарсить её с помощью дизассемблера. И опять неудача из-за того, что после получения адресов всех нужных функций, вредонос зашифровывает часть своего кода и расшифровывает его соотвественно кусками при необходимости. При этом используется непонятный блочный алгоритм, шифрующий разные куски кода на разных ключах.
Далее этот код уже стало невозможно анализировать как минимум потому что я не знаю ассемблера на должном уровне, да и реверс не моя специализация, но примерно по импортированным функциям, смог понять основной функционал:
- Кейлогер
- Удаленное управление
- Скринсшоты
- Загрузка файлов
- Работа с реестром
- Управление камерой
ЗАКЛЮЧЕНИЕ
Подарок от знакомого получил. Кучу нервов потратил. Ocean Lotus придумали интересный метод обфускации, который заставит задуматься даже классного специалиста по реверсу. Хочу отметить, что из-за того, что код выполнялся в шаристой памяти, то по каким-то причинам, утилиты перехватывающие API вызовы ничего не поймали. Это и есть отправная точка сложности разбора данной вирусни.
Очень интересно узнать ваше мнение как бы вы попробовали проанализировать данный файл. Спасибо за внимание!
P.S. Если статья была хоть немного интересна, то могу продолжить. Есть ещё необычные сэмплы которые могут быть интересны сообществу.

Автор: Temchi
Специально для https://xss.pro
Последнее редактирование модератором: