D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Оригинал: https://kienmanowar.wordpress.com/2023/05/22/case-study-decrypt-strings-using-dumpulator/
Исходя из предоставленной информации, я уверен, что эти строки определенно были зашифрованы. Просмотрев фрагмент кода с использованием произвольной строки, я обнаружил соответствующий ассемблерный код и псевдокод (имена функций и переменных изменены соответствующим образом):
На приведенном выше изображении легко в этом убедиться:
Побродив по различным функциям и подумав над тем, как кодить, я начал чувствовать себя все более обескураженным. Более того, изучая перекрестные ссылки на функцию mw_decrypt_str_wrap, я заметил, что она вызывается более 4000 раз для расшифровки строк... ВАТАФАК.
Код: Скопировать в буфер обмена
Результат выполнения приведенного выше кода:
Черт возьми... это именно то, что я хотел.
Далее я перепишу код в соответствии со своим замыслом следующим образом:
Код: Скопировать в буфер обмена
Результат выполнения приведенного выше скрипта:
Никаких ошибок!!! В качестве заключительного шага я добавил в этот скрипт фрагмент кода, который выведет Python-файл. Этот файл будет содержать команды idc.set_cmt для установки комментария для расшифрованных строк, приведенных выше по адресу вызова функции decrypt.
Итоговый результат выглядит следующим образом:
Не получилось на xss гифку загрузить(получился скриншот), можете перейти по ссылке в начале статьи и посмотреть
Конец.
1. Ссылки
- Dumpulator (by mrexodia Duncan Ogilvie)
- Native function and Assembly Code Invocation
- OALABS Research
- И @herrcore (спасибо за его предложение в приватном чате)
2. Анализ кода
Я получил подозрительную DLL, которую необходимо проанализировать. Эта DLL упакована(packed). После распаковки и закидывания DLL в IDA, IDA успешно проанализировала ее, найдя более 7000 функций (включая вызовы функций API и библиотек). При беглом просмотре на вкладке Strings я обнаружил множество строк следующего формата:Исходя из предоставленной информации, я уверен, что эти строки определенно были зашифрованы. Просмотрев фрагмент кода с использованием произвольной строки, я обнаружил соответствующий ассемблерный код и псевдокод (имена функций и переменных изменены соответствующим образом):
На приведенном выше изображении легко в этом убедиться:
- В регистре EAX будет храниться адрес зашифрованной строки.
- В регистре EDX будет храниться адрес строки после расшифровки.
- Функция mw_decrypt_str_wrap выполняет задачу расшифровки строки.
Побродив по различным функциям и подумав над тем, как кодить, я начал чувствовать себя все более обескураженным. Более того, изучая перекрестные ссылки на функцию mw_decrypt_str_wrap, я заметил, что она вызывается более 4000 раз для расшифровки строк... ВАТАФАК.
3. Используем dumpulator
Как видно из приведенного изображения, в функции дешифрования слишком много вызовов функций. Кроме того, переписывание этой функции расшифровки потребует много времени и отладки кода для проверки. Я считаю, что нужно найти способ эмулировать эту функцию для выполнения шага расшифровки и получения расшифрованной строки. Мне пришло в голову несколько решений, и я также спросил своего брата, который предложил использовать x или y решения. После некоторых проб и ошибок я решил попробовать использовать dumpulator. Чтобы использовать dumpulator, сначала нужно создать файл минидампа этой DLL (дамп при остановке в DllEntryPoint). Получив файл дампа, я протестировал следующий фрагмент кода:Код: Скопировать в буфер обмена
Код:
from dumpulator import Dumpulator
dec_str_fn = 0x02FE08C0
enc_str_offset = 0x02FD9988
dp = Dumpulator("mal_dll.dmp", quiet=True)
tmp_addr = dp.allocate(256)
dp.call(dec_str_fn, [], regs={'eax':enc_str_offset , 'edx': tmp_addr})
dec_str = dp.read_str(dp.read_long(tmp_addr))
print(f"Encrypted string: '{dp.read_str(enc_str_offset)}'")
print(f"Decrypted string: '{dec_str}'")
Результат выполнения приведенного выше кода:
Черт возьми... это именно то, что я хотел.
Далее я перепишу код в соответствии со своим замыслом следующим образом:
- Используем regex для поиска шаблонов(patterns) и извлечения всех закодированных строковых адресов.
- Отфильтруем адреса, соответствующие шаблону, но не являющиеся функциями дешифрования или неопределенными адресами, и добавим их в BLACK_LIST.
Код: Скопировать в буфер обмена
Код:
import re
import struct
import pefile
from dumpulator import Dumpulator
dump_image_base = 0x2F80000
dec_str_fn = 0x02FE08C0
BLACK_LIST = [0x3027520, 0x30380b6, 0x30380d0, 0x3039a08, 0x3039169, 0x303a6b6, 0x303aa0e, 0x303ab5c, 0x303bbf3, 0x3066075, 0x306661b, 0x3083e50,
0x3084373, 0x30856d1, 0x30858aa, 0x308c7ac, 0x308d02d, 0x30acbfd, 0x30cd12e, 0x30cd187, 0x30cd670, 0x30cd6d4, 0x30cfe2f, 0x30d4cc4,
0x3106da0]
FILE_PATH = 'dumped_dll.dll'
dp = Dumpulator("mal_dll.dmp", quiet=True)
file_data = open(FILE_PATH, 'rb').read()
pe = pefile.PE(data=file_data)
egg = rb'\x8D\x55.\xB8(....)\xE8....\x8b.'
tmp_addr = dp.allocate(256)
def decrypt_str(xref_addr, enc_str_offset):
print(f"Processing xref address at: {hex(xref_addr)}")
print(f"Encryped string offset: {hex(enc_str_offset)}")
dp.call(dec_str_fn, [], regs={'eax': enc_str_offset, 'edx': tmp_addr})
dec_str = dp.read_str(dp.read_long(tmp_addr))
print(f"{hex(xref_addr)}: {dec_str}\n")
return dec_str
for m in re.finditer(egg, file_data):
enc_str_offset = struct.unpack('<I', m.group(1))[0]
inst_offset = m.start()
enc_str_offset_in_dmp = enc_str_offset - 0x400000 + dump_image_base
call_fn_addr = inst_offset + 8 - 0x400 + dump_image_base + 0x1000
if call_fn_addr not in BLACK_LIST:
str_ret = decrypt_str(call_fn_addr, enc_str_offset_in_dmp)
print(f"H0lY SH1T... IT's D0NE!!!")
Результат выполнения приведенного выше скрипта:
Никаких ошибок!!! В качестве заключительного шага я добавил в этот скрипт фрагмент кода, который выведет Python-файл. Этот файл будет содержать команды idc.set_cmt для установки комментария для расшифрованных строк, приведенных выше по адресу вызова функции decrypt.
Итоговый результат выглядит следующим образом:
Не получилось на xss гифку загрузить(получился скриншот), можете перейти по ссылке в начале статьи и посмотреть


Конец.