Рапид-расшифровка данных из NSIS-скрипта 🗄
Когда нет времени на идентификацию алгоритма шифрования и реализацию алгоритма дешифрования, на помощь приходит отладчик. Но как быть со скриптовым языком для установщика?
В качестве примера взят загрузчик XDigo
• Для начала извлечем скрипт, расширение которого — .nsi. Воспользуемся специальной версией 7-Zip.
• После этого нам нужен компилятор .nsi-скриптов — скачаем и установим NSIS. Откроем компилятор и загрузим в него извлеченный скрипт. Базовые возможности программы ограничены: он позволяет только скомпилировать скрипт в исполняемый файл и запустить его.
• Для того чтобы расширить функциональность компилятора, нам понадобится Debug Plug-In. Набор его функций не очень широк, но их вполне хватит, чтобы динамически расшифровать данные.
• После установки плагина откроем исходный вредоносный скрипт и в конце функции дешифрования, после операции передачи расшифрованных данных в стек, добавим строку:
• В результате перекомпиляции скрипта и тестового запуска исполняемого файла каждый раз после выполнения функции дешифрования в отдельном окне будет демонстрироваться состояние стека на момент выполнения строки Debug::Stack, в данных которого и будут находиться расшифрованные данные.
#reverse #tips #malware #XDigo #TI
@ptescalator
Когда нет времени на идентификацию алгоритма шифрования и реализацию алгоритма дешифрования, на помощь приходит отладчик. Но как быть со скриптовым языком для установщика?
В качестве примера взят загрузчик XDigo
• Для начала извлечем скрипт, расширение которого — .nsi. Воспользуемся специальной версией 7-Zip.
• После этого нам нужен компилятор .nsi-скриптов — скачаем и установим NSIS. Откроем компилятор и загрузим в него извлеченный скрипт. Базовые возможности программы ограничены: он позволяет только скомпилировать скрипт в исполняемый файл и запустить его.
• Для того чтобы расширить функциональность компилятора, нам понадобится Debug Plug-In. Набор его функций не очень широк, но их вполне хватит, чтобы динамически расшифровать данные.
• После установки плагина откроем исходный вредоносный скрипт и в конце функции дешифрования, после операции передачи расшифрованных данных в стек, добавим строку:
Debug::Stack
• В результате перекомпиляции скрипта и тестового запуска исполняемого файла каждый раз после выполнения функции дешифрования в отдельном окне будет демонстрироваться состояние стека на момент выполнения строки Debug::Stack, в данных которого и будут находиться расшифрованные данные.
#reverse #tips #malware #XDigo #TI
@ptescalator
👏 Раз-два — и готово. Генерируем FLIRT-сигнатуры
А делаем это, чтобы не тратить время на распознавание библиотечного кода PureBasic, на котором написан COM-DLL-Dropper группировки ExCobalt.
Для начала нам понадобится компилятор PureBasic. Скачав его и установив или распаковав, найдем все .lib-файлы. Далее нам понадобятся входящие в состав Flair инструменты:
—
—
С их помощью мы и сгенерируем сигнатуры. Чтобы автоматизировать создание PAT-файла, будем использовать BAT-файл со следующим содержимым:
После получения PAT-файла нам нужно преобразовать его в SIG-файл. Для этого выполним следующую команду:
Так как произошли коллизии при генерации сигнатур, получаем следующий список файлов:
— PureBasic_x86.err,
— PureBasic_x86.exc,
— PureBasic_x86.pat.
При отсутствии коллизий сразу получили бы готовый SIG-файл. Для их устранения нужно отредактировать EXC-файл. Пример коллизии:
Видим, что три функции имеют одну и ту же сигнатуру, — нам необходимо выбрать, какую из них использовать.
Слева, рядом с именем нужной функции, ставим +. В этом случае коллизия коснулась функций, идентичных по назначению, и мы можем выбрать любую:
Но бывает, когда она касается функций с совершенно противоположным назначением, — можно выбрать любую, но запомнить или записать ее: это пригодится, когда будет получен результат.
Нужно также удалить строку --------- в EXC-файле, чтобы выбор учитывался при повторной генерации сигнатур:
После того как действие будет проделано для всех коллизий, нужно повторить генерацию. Если все сделано правильно, мы получим SIG-файл. Его следует положить в:
#reverse #tips #ComDllDropper #ExCobalt #APT #TI
@ptescalator
А делаем это, чтобы не тратить время на распознавание библиотечного кода PureBasic, на котором написан COM-DLL-Dropper группировки ExCobalt.
Для начала нам понадобится компилятор PureBasic. Скачав его и установив или распаковав, найдем все .lib-файлы. Далее нам понадобятся входящие в состав Flair инструменты:
—
pcf
— парсер файлов .lib и .obj, создает PAT-файл из COFF-файлов.—
sigmake
— конвертирует ранее созданный PAT-файл в SIG-файл для IDA.С их помощью мы и сгенерируем сигнатуры. Чтобы автоматизировать создание PAT-файла, будем использовать BAT-файл со следующим содержимым:
@echo off
\path\pcf.exe -a \path\Debugger.lib
\path\PureBasic_x86.pat
\path\pcf.exe -a \path\libmariadb.lib
\path\PureBasic_x86.pat
...
После получения PAT-файла нам нужно преобразовать его в SIG-файл. Для этого выполним следующую команду:
\path\sigmake.exe -n"PureBasic_Windows_X86_LTS_6.03" \path\PureBasic_x86.pat \path\PureBasic_x86.sig
Так как произошли коллизии при генерации сигнатур, получаем следующий список файлов:
— PureBasic_x86.err,
— PureBasic_x86.exc,
— PureBasic_x86.pat.
При отсутствии коллизий сразу получили бы готовый SIG-файл. Для их устранения нужно отредактировать EXC-файл. Пример коллизии:
_PB_WriteFloat@8 0B 5366........E8........85C0742D83780400
_PB_WriteInteger@8 0B 5366........E8........85C0742D83780400
_PB_WriteLong@8 0B 5366........E8........85C0742D83780400
Видим, что три функции имеют одну и ту же сигнатуру, — нам необходимо выбрать, какую из них использовать.
Слева, рядом с именем нужной функции, ставим +. В этом случае коллизия коснулась функций, идентичных по назначению, и мы можем выбрать любую:
_PB_WriteFloat@8 0B 5366........E8........85C0742D83780400
+_PB_WriteInteger@8 0B 5366........E8........85C0742D83780400
_PB_WriteLong@8 0B 5366........E8........85C0742D83780400
Но бывает, когда она касается функций с совершенно противоположным назначением, — можно выбрать любую, но запомнить или записать ее: это пригодится, когда будет получен результат.
Нужно также удалить строку --------- в EXC-файле, чтобы выбор учитывался при повторной генерации сигнатур:
;--------- (delete these lines to allow sigmake to read this fil
; add '+' at the start of a line to select a module
; add '-' if you are not sure about the selection
; do nothing if you want to exclude all modules
После того как действие будет проделано для всех коллизий, нужно повторить генерацию. Если все сделано правильно, мы получим SIG-файл. Его следует положить в:
%IDA Home%\sig\pc
#reverse #tips #ComDllDropper #ExCobalt #APT #TI
@ptescalator
В рамках ежемесячного просмотра свежезапатченных уязвимостей мы в команде ESC-VR обращаем пристальное внимание на уязвимости, помеченные как эксплуатируемые в дикой природе. Такие уязвимости становятся нашей главной целью, особенно если отсутствует какая бы то ни было информация о публичных эксплойтах.
Уязвимость CVE-2024-38178 — это повреждение памяти типа Type Confusion (CWE-843). Говоря по-простому: ситуация, когда область памяти, занимаемая объектом типа A, интерпретируется кодом как объект типа B.
Проанализировав патч, мы обнаружили, что изменения сделаны в функции, отвечающей за оптимизацию работы с массивами, в частности в функции
GlobOpt::OptArraySrc
. После исправления добавилась обработка ситуации, когда оптимизатор не замечает, что иногда тип переменной может изменяться в runtime
.Если вы следите за деятельностью
Google ProjectZero
так же активно, как и мы, то вы уже обо всем догадались 😉Функция
GlobOpt::OptArraySrc
уже фигурировала в ITW-эксплойте, а именно в посте, описывающем CVE-2022-41128. В посте есть
PoC
, который демонстрирует эксплуатацию CVE-2022–41128. Взяв из него ключевые строки, мы провели поиск в публичных и приватных источниках по файлам, загруженным недавно, используя следующие подстроки:•
6E6577204F626A656374287B0D0A20
•
206E657720496E7433324172726179
Мы нашли всего один файл. Он был загружен из
KR
, и эксплойт, вероятно, использовался в атаках в этой стране, о чем косвенно свидетельствует информация из бюллетени Microsoft. Прогнав файл в системах с патчем и без него, мы быстро поняли, что это именно то, что мы искали. В связи с большой схожестью с CVE-2022-41128 мы считаем, что и эта уязвимость была найдена через фаззинг, который проводился с использованием
PoC
для CVE-2022-41128 и CVE-2021-34480.Эксплойт создает ситуацию, когда JIT-компилятор убежден, что переменная X имеет тип
js::TypedArray<int,0>
, но на самом деле X содержит значение Y типа js::DynamicObj
. Далее эксплойт использует доступ по индексу 4, 11, 12, чтобы модифицировать внутренние поля массива js::JavaScriptNativeArray
, находящегося в одном из свойств значения Y. Модифицируемые поля хранят размер массива. В результате эксплойт дает возможность для доступа за пределы этого массива для того, чтобы получить примитивы на относительную запись и чтение. Дальнейшее описание заняло бы неприлично много места в рамках поста, поэтому stay tunned и happy hunting 🙂
YARA-правило (на файл):
rule exploit_CVE_2024_38178 {
strings:
$a = { 6E6577204F626A656374287B0D0A20 }
$b = { 206E657720496E7433324172726179 }
condition:
all of them
}
IoCs:
SHA256: 736092B71A9686FDE43D3C4ABD941A6774721B90B17D946C9D05AF19C84DF0A4
http://img[.]mobonad[.]com/images/20230912/43
#escvr #itw #jscript9 #reverse
@ptescalator
Please open Telegram to view this post
VIEW IN TELEGRAM
Когда активно занимаешься реверсом, рано или поздно возникает ситуация, когда на твоем пути появляется исполняемый файл на Delphi. Анализ объектов в Delphi требует особого подхода, и вручную это делать сложно. Однако такой анализ можно значительно ускорить с помощью автоматизации, если знать, как именно устроена структура объектов.
🕵️ Первый шаг при анализе Delphi — не забыть переключить параметр компилятора в
Options
→ Compiler Options
→ Compiler
, тогда IDA будет лучше обрабатывать вызовы функций.Классы в Delphi создаются через функцию
ClassCreate
, которая получает на вход указатель на структуру класса и вызывает в нем функцию Tobject_NewInstance
путем вычитания оффсета из указателя на VMT. 👀 Сама структура класса в Delphi выглядит следующим образом (пример на скриншоте 1):
struct DelphiClassInternal
{
DWORD* vmt;
DWORD* InterfaceTable; используется только для интерфейсов
DWORD* PAutoTable;
DWORD* PInitTable;
DWORD* TypeInfo;
DWORD* FieldTable;
DWORD* MethodTable;
DWORD* DynamicMethodTable;
}
💼 Рассмотрим содержимое полей
TypeInfo
, MethodTable
и FieldTable
подробнее, поскольку в них больше всего полезной для анализа информации.➡️ TypeInfo
В Delphi каждый тип объекта имеет свой идентификатор. Как видно на скриншоте 2, для нашего объекта выставлен идентификатор 7 — тип
Class
. В зависимости от этого типа, для объекта указывается соответствующий контекст. Для классов это информация о Property
и указатель на родительский тип. Зная имя Property
, нетрудно понять и разметить Get/Set-функции
. Восстановление этих имен позволяет сильно упростить восприятие некоторых блоков кода. Пример на скриншоте 3.➡️ MethodTable
Внимательный читатель заметит, что на скриншоте 1 присутствуют имена некоторых методов. Достать их можно, заглянув в таблицу опубликованных (Published) методов (текущего и родительского классов). Delphi не хранит информацию о других типах методов: приватных, защищенных и публичных. Помимо имени, там приводятся: возвращаемый тип, количество аргументов, их типы и имена.
Псевдоструктуру метода можно представить так (пример на скриншоте 4):
struct CMArg
{
DWORD* TypeInfo;
WORD UNK;
BYTE NameLen;
char Name[];
BYTE UNK2[3];
}
struct ClassPubMethod
{
WORD EntrySize;
DWORD* MethodPtr;
BYTE NameLen;
char Name[];
WORD W_UNK1;
DWORD* ReturnType;
WORD W_UNK2;
BYTE ArgCount;
CMArg Args[];
}
Из-за механизма наследования методов в Delphi восстановление даже части имен методов имеет большую пользу, если сделать это глобально, для всех классов. Затем это можно использовать среди прочего и для генерации структуры VMT класса с осмысленными именами. Пример — на скриншоте 5.
➡️ FieldTable
Заглянув в
Class
→ FieldTable
, можно найти большое количество информации о переменных (пример на скриншоте 6). Представлена она может быть в двух вариантах: 1. В виде имени, оффсета и номера типа переменной (из таблицы типов). Первые два байта в
FieldTable
— количество элементов в этой таблице, следующие четыре — указатель на таблицу типов.2. В виде имени, оффсета и указателя на тип переменной (таблица начинается сразу после таблицы из п. 1).
Структура переменных имеет следующий вид:
struct VarTypeTable
{
WORD Count;
DWORD* Entries[];
}
struct ClassVar
{
DWORD* TypeInfo;
WORD VarOffset;
WORD UNK;
BYTE NameLen;
char Name[];
}
struct TableClassVar
{
WORD VarOffet;
WORD UNK;
WORD TableTypeNum;
BYTE NameLen;
char Name[];
}
Исходя из полученной информации о переменных можно составить структуру класса (нужно не забыть, что переменные также наследуются из родительских классов). Пример — на скриншоте 7.
🤔 Резюме: в Delphi присутствует большое количество RTTI-информации, за счет которой можно относительно просто разметить большое количество функций или восстановить структуру классов для упрощения статического анализа.
#TI #Delphi #Reverse
@ptescalator
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Как починить CFG 🔧
В процессе реверса ВПО мы встречаемся со случаями, когда обфускация мешает понять общий алгоритм работы. Один из примеров — создание двух последовательных противоположных условных переходов в одну точку.
Схематично это выглядит так:
То есть IDA при анализе кода идет сначала по ветке
Далее, встретив противоположный условный переход, она снова идет по ветке
При живом исполнении в независимости от состояния флагов будет выполнен переход на операнд, то есть выполнение будет как на скриншоте 2, если мы подправим control flow.
Трудность при исследовании таких шеллкодов в том, что переходов может быть много и каждый раз анализ будет о них спотыкаться. Можно попробовать починить вручную, но если таких блоков будут сотни?
✍️ Чтобы справиться с этим, напишем несложный скрипт на
Сначала составим список противоположных условных переходов и положим его в функцию, которая будет сверять две последовательные инструкции со списком:
Будем последовательно проходить каждую инструкцию до тех пор, пока не встретим нужные либо не упремся в лимит.
🧐 С помощью метода
С помощью
Затем исправляем условные переходы и просим IDA проанализировать новый код. Это необходимо, чтобы можно было найти дальнейшие блоки обфускации:
🗂 Методом
Таким образом, этот скрипт позволяет из обфусцированного кода получить нормальный ASM-код, как на скриншоте 3.
Иногда после него остаются единичные нераспознанные байты, но их легко поправить. Из этого кода можно создать функцию, декомпилировать ее и проанализировать (как на скриншоте 4).
Изучайте IDAPython, пишите скрипты. Happy reversing!
#tip #reverse #idapython
@ptescalator
В процессе реверса ВПО мы встречаемся со случаями, когда обфускация мешает понять общий алгоритм работы. Один из примеров — создание двух последовательных противоположных условных переходов в одну точку.
Схематично это выглядит так:
start:
jnX labelA
jX labelA
labelA:
<bytes>
То есть IDA при анализе кода идет сначала по ветке
False
и создает код там, откладывая ветку True
на потом. Встретив инструкцию jnX
, IDA создает код сразу после текущей.Далее, встретив противоположный условный переход, она снова идет по ветке
False
и создает код на следующем адресе, построив мусорную инструкцию, после которой дизассемблировать уже нельзя. Тогда IDA возвращается к отложенной на потом очереди и берет адрес оттуда, но беда в том, что там код уже создан, а значит анализ завершается (хорошо видно на скриншоте 1).При живом исполнении в независимости от состояния флагов будет выполнен переход на операнд, то есть выполнение будет как на скриншоте 2, если мы подправим control flow.
Трудность при исследовании таких шеллкодов в том, что переходов может быть много и каждый раз анализ будет о них спотыкаться. Можно попробовать починить вручную, но если таких блоков будут сотни?
✍️ Чтобы справиться с этим, напишем несложный скрипт на
IDAPython
, который исправит проблему автоматически. Задача — найти эти блоки и пропатчить их.Сначала составим список противоположных условных переходов и положим его в функцию, которая будет сверять две последовательные инструкции со списком:
def c_jumps(addr, n_addr):
ops = [
("jz", "jnz"),
("jnz", "jz"),
("je", "jne"),
("jne", "je"),
...
]
if (ida_ua.print_insn_mnem(addr), ida_ua.print_insn_mnem(n_addr)) in ops:
return True
return False
Будем последовательно проходить каждую инструкцию до тех пор, пока не встретим нужные либо не упремся в лимит.
def deobf(start, limit=BADADDR):
while addr != BADADDR:
n_addr = ida_search.find_code(addr, ida_search.SEARCH_DOWN)
if n_addr == BADADDR:
break
if not c_jumps(addr, n_addr):
addr = n_addr
continue
🧐 С помощью метода
find_code
из модуля ida_search
находим следующий адрес, на котором есть код, а с помощью функции c_jumps
проверяем, являются ли инструкции на этом и следующем адресе противоположными прыжками. Найдя их, мы должны проверить, указывают ли эти прыжки на одну точку (то есть равны ли их операнды):
o1 = get_operand_value(addr, 0)
o2 = get_operand_value(n_addr, 0)
if o1 != o2:
addr = n_addr
continue
insn = ida_ua.insn_t()
l1 = ida_ua.decode_insn(insn, addr)
l2 = ida_ua.decode_insn(insn, n_addr)
С помощью
get_operand_value
получаем значение операндов (у jX и jXX он один) и проверяем их равенство. Чтобы определить длину отрезка, который нужно пропатчить, с помощью decode_insn
из ida_ua
находим длины инструкций.Затем исправляем условные переходы и просим IDA проанализировать новый код. Это необходимо, чтобы можно было найти дальнейшие блоки обфускации:
after_addr = n_addr + l2
ida_bytes.patch_bytes(addr, bytes([0x90] * (l1 + l2 + 1)))
ida_auto.auto_wait()
ida_bytes.del_items(after_addr, ida_bytes.DELIT_EXPAND)
ida_auto.auto_wait()
ida_ua.create_insn(o1)
addr = o1
ida_auto.auto_wait()
🗂 Методом
patch_bytes
из ida_bytes
мы патчим инструкции, с помощью auto_wait из ida_auto
просим IDA проанализировать новый код, затем, используя del_items
, удаляем мусорные инструкции, созданные при первичном анализе, и снова анализируем. С помощью create_insn
создаем валидную инструкцию там, куда указывали условные переходы, и переанализируем в последний раз.Таким образом, этот скрипт позволяет из обфусцированного кода получить нормальный ASM-код, как на скриншоте 3.
Иногда после него остаются единичные нераспознанные байты, но их легко поправить. Из этого кода можно создать функцию, декомпилировать ее и проанализировать (как на скриншоте 4).
Изучайте IDAPython, пишите скрипты. Happy reversing!
#tip #reverse #idapython
@ptescalator
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
📑 TaxOff: кажется, у вас… бэкдор
В третьем квартале специалисты TI-департамента экспертного центра безопасности Positive Technologies (PT Expert Security Center, PT ESC) обнаружили серию атак, направленных на государственные структуры России. Связей с уже известными группами, использующими такие же техники, нам установить не удалось.
😐 Основными целями киберпреступников были шпионаж и закрепление в системе для развития последующих атак. Эту группировку мы назвали TaxOff из-за использования писем на правовые и финансовые темы в качестве приманок. В своих атаках злоумышленники применяли написанный минимум на C++17 бэкдор, который мы назвали Trinper из-за артефакта, используемого при соединении с C2-сервером.
📩 Начальный вектор заражения — фишинговые письма. Мы обнаружили несколько таких: в одном была ссылка на Яндекс Диск с вредоносным содержимым, связанным с «1С», в другом — фальшивый установщик ПО для заполнения справок о доходах и расходах, которые госслужащим необходимо подавать каждый год. И ежегодно это ПО обновляется и становится целью злоумышленников, распространяющих вредоносы под видом обновлений.
Trinper — написанный на C++ многопоточный бэкдор с гибкой конфигурацией, в котором используются шаблонный метод в качестве паттерна проектирования, контейнеры STL, буферный кэш для повышения производительности.
🧐 Подробный анализ бэкдора и действий группировки TaxOff, а также индикаторы компрометации вы можете найти в отчете.
#TI #APT #IOC #Reverse
@ptescalator
В третьем квартале специалисты TI-департамента экспертного центра безопасности Positive Technologies (PT Expert Security Center, PT ESC) обнаружили серию атак, направленных на государственные структуры России. Связей с уже известными группами, использующими такие же техники, нам установить не удалось.
Trinper — написанный на C++ многопоточный бэкдор с гибкой конфигурацией, в котором используются шаблонный метод в качестве паттерна проектирования, контейнеры STL, буферный кэш для повышения производительности.
🧐 Подробный анализ бэкдора и действий группировки TaxOff, а также индикаторы компрометации вы можете найти в отчете.
#TI #APT #IOC #Reverse
@ptescalator
Please open Telegram to view this post
VIEW IN TELEGRAM
Статический резолв импортов 👨💻
Динамический резолв импортов по хеш-суммам в ВПО — тема заезженная, но для проведения статического анализа необходимо разметить имена и прототипы API. Чтобы из того, что представлено на скрине 1, получить то, что на скрине 2, и не мучаться с ручной разметкой, можно написать скрипт IDAPython.
😠 На примере DodgeBox рассмотрим резолв, который заключается в вычислении адреса API-функции и помещении его в глобальную структуру. Реализация — на скрине 3.
Алгоритм хеширования опустим, поскольку здесь он не столь важен. Перед началом необходимо подготовить словарь с именами функций WinAPI и их хеш-суммами. Для этого выберем те библиотеки, что используются в бинаре. Здесь есть имена DLL в открытом виде, но иногда — только хеш-суммы, в этом случае можно составить словарь из всех системных DLL. Наш словарь — на скрине 4.
Далее убеждаемся, что члены в структуре заполняются последовательно, чтобы автоматически извлечь из кода хеш-суммы, имена модулей. Внимание — первый член структуры пропускается. Создаем структуру нужного размера (скрин 5), чтобы она вместила все функции.
Чтобы извлечь хеш-суммы и имена библиотек, пишем функцию, которая пройдет по всем вызовам
Функция
На выходе
Функция
Функция
Однако на самом деле функция возвращает объект типа
Структура API после вызова скрипта представлена на скрине 6. Если применить ее к глобальной переменной, резолв превратится в то, что видно на скрине 7, и можно будет удобно анализировать бинарь статически, не запуская отладчик.
Есть, конечно, соблазн написать функцию
#tip #reverse #idapython
@ptescalator
Динамический резолв импортов по хеш-суммам в ВПО — тема заезженная, но для проведения статического анализа необходимо разметить имена и прототипы API. Чтобы из того, что представлено на скрине 1, получить то, что на скрине 2, и не мучаться с ручной разметкой, можно написать скрипт IDAPython.
Алгоритм хеширования опустим, поскольку здесь он не столь важен. Перед началом необходимо подготовить словарь с именами функций WinAPI и их хеш-суммами. Для этого выберем те библиотеки, что используются в бинаре. Здесь есть имена DLL в открытом виде, но иногда — только хеш-суммы, в этом случае можно составить словарь из всех системных DLL. Наш словарь — на скрине 4.
Далее убеждаемся, что члены в структуре заполняются последовательно, чтобы автоматически извлечь из кода хеш-суммы, имена модулей. Внимание — первый член структуры пропускается. Создаем структуру нужного размера (скрин 5), чтобы она вместила все функции.
Чтобы извлечь хеш-суммы и имена библиотек, пишем функцию, которая пройдет по всем вызовам
get_proc_by_hash
и извлечет ее аргументы.def get_hashes(resolve_API_addr, get_proc_by_hash_addr):
result = []
func: ida_funcs.func_t
func = ida_funcs.get_func(resolve_API_addr)
cur = func.start_ea
while cur < func.end_ea:
if get_operand_value(cur, 0) == get_proc_by_hash_addr:
result.append(get_args(cur))
cur = ida_search.find_code(cur, SEARCH_DOWN)
return result
Функция
get_args
поднимается на несколько шагов вверх от операции call
и извлекает аргументы.def get_args(call_addr):
func_name_hash = None
lib_name = None
cur = call_addr
True:
if print_insn_mnem(cur) == "mov" and print_operand(cur, 0) == "r8d":
func_name_hash = get_operand_value(cur, 1) & 0xFFFFFFFF
elif print_insn_mnem(cur) == "lea" and print_operand(cur, 0) == "rcx":
lib_name = ida_bytes.get_strlit_contents(get_operand_value(cur, 1), -1, STRTYPE_C_16).decode()
if func_name_hash and lib_name:
return lib_name, func_name_hash
cur = ida_search.find_code(cur, SEARCH_UP)
На выходе
get_hashes
получим список, который используем для заполнения структуры API. Основная функция будет выглядеть так:struc: ida_struct.struc_t = ida_struct.get_struc(ida_struct.get_struc_id("API"))
funcs = get_hashes(0x180007A90, 0x1800078E0)
for i in range(1, len(funcs) + 1):
lib_name, func_name_hash = funcs[i - 1]
member: ida_struct.member_t = struc.members[i]
func_name = get_func_name(lib_name, func_name_hash, winapi_hashes_dict)
if func_name:
ida_struct.set_member_name(struc, member.soff, func_name)
func_tinfo = get_func_tinfo(func_name)
if func_tinfo:
ida_struct.set_member_tinfo(struc, member, 0, func_tinfo, 0)
Функция
get_func_name
проста в реализации, она находит в словаре имя API по хеш-сумме. А вот get_func_tinfo
более интересна: она создает объект, содержащий прототип функции, который мы также применим к члену структуры.def get_func_tinfo(func_name):
tinfo = ida_typeinf.get_named_type(None, func_name, 0)
if tinfo:
type_s = tinfo[1]
field_s = tinfo[2]
t = ida_typeinf.tinfo_t()
t.deserialize(None, type_s, field_s)
t.create_ptr(t)
return t
else:
return None
Функция
ida_typeinf.get_named_type
получает информацию о типе, который содержится в Type Library (*.til)
. Вызов выглядит так:Python>get_func_tinfo("GetWindowsDirectoryW")
UINT (__stdcall *)(LPWSTR lpBuffer, UINT uSize)
Однако на самом деле функция возвращает объект типа
ida_typeinf.tinfo_t
.Структура API после вызова скрипта представлена на скрине 6. Если применить ее к глобальной переменной, резолв превратится в то, что видно на скрине 7, и можно будет удобно анализировать бинарь статически, не запуская отладчик.
Есть, конечно, соблазн написать функцию
make_beautifully
, которая сама вычитает офсеты, создаст структуру и члены внутри нее, но об этом в другой раз.#tip #reverse #idapython
@ptescalator
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Используете ли вы криптографию правильно? 🔓
Группе исследования сложных угроз департамента Threat Intelligence часто приходится решать интересные задачи в процессе реверса ВПО. Этот раз не стал исключением. Существует такая техника, как Execution Guardrails: Environmental Keying, — она нужна для ограничения выполнения ВПО только в конкретной целевой среде. Например, ее использует группировка Decoy Dog в своих операциях.
В попавшем к нам на исследование семпле применялась эта же техника: в качестве ключа для используемых строк использовалось имя компьютера, которого у нас не было, дополнительно семпл был обфусцирован. В случае, если ВПО запускалось не на нужном злоумышленнику устройстве, оно крашилось — отсюда и стартует наше исследование.
☠️ Выяснилось, что ВПО «падает» при попытке вызова функции
Чтобы вычислить промежуточный ключ (который формируется в результате логических операций), мы прибегнули к атаке на основе открытого текста. Возвращаясь к функции
Группа исследования сложных угроз рекомендует одну из платформ для изучения криптоанализа — cryptohack.org.
#tips #reverse #malware #cryptography #TI
@ptescalator
Группе исследования сложных угроз департамента Threat Intelligence часто приходится решать интересные задачи в процессе реверса ВПО. Этот раз не стал исключением. Существует такая техника, как Execution Guardrails: Environmental Keying, — она нужна для ограничения выполнения ВПО только в конкретной целевой среде. Например, ее использует группировка Decoy Dog в своих операциях.
В попавшем к нам на исследование семпле применялась эта же техника: в качестве ключа для используемых строк использовалось имя компьютера, которого у нас не было, дополнительно семпл был обфусцирован. В случае, если ВПО запускалось не на нужном злоумышленнику устройстве, оно крашилось — отсюда и стартует наше исследование.
LoadLibraryA
с переданным именем библиотеки в качестве неотображаемых байтов. Этот набор байтов должен представлять собой имя библиотеки, которая расшифровывается в цикле; при каждой итерации берется символ от имени компьютера, с помощью логических операций приводится в необратимый вид, а после уже гаммируется с зашифрованным текстом и его однобайтовой константой. Чтобы вычислить промежуточный ключ (который формируется в результате логических операций), мы прибегнули к атаке на основе открытого текста. Возвращаясь к функции
LoadLibraryA
: мы знаем, что имя библиотеки будет составлять 13 байт в кодировке ASCII + '\x00'
; так мы смогли восстановить треть ключа, а далее по аналогии уже с другими строками восстановили оставшуюся часть ключа.Дешифрование строки:
F(sym_comp_name) ^ sym_enc ^ cnst_enc = sym_dec
F(sym_comp_name) — логические операции
Получение промежуточного ключа:
sym_dll_name ^ sym_enc ^ cnst_enc = irr_sym_key
irr_sym_key — промежуточный байт ключа, необратимый
Группа исследования сложных угроз рекомендует одну из платформ для изучения криптоанализа — cryptohack.org.
#tips #reverse #malware #cryptography #TI
@ptescalator
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM