Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Регистрируясь, я даю согласие на обработку данных и условия почтовых рассылок.
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр Онлайн-РПГ в формате коллекционной карточной игры. Собери свою уникальную колоду из фэнтезийных героев и брось вызов игрокам другим в дуэлях и масштабных битвах на арене!

Повелители стихий

Карточные, Мидкорные, Ролевые

Играть

Топ прошлой недели

  • solenakrivetka solenakrivetka 7 постов
  • Animalrescueed Animalrescueed 53 поста
  • ia.panorama ia.panorama 12 постов
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая «Подписаться», я даю согласие на обработку данных и условия почтовых рассылок.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
0 просмотренных постов скрыто
506
buhanka.chan
buhanka.chan
Юмор для всех и каждого

Ответ на пост «Мы что-то такое всегда подозревали»⁠⁠2

8 месяцев назад
Перейти к видео

@ArNikich, готово.

Юмор Политика Дональд Трамп Владимир Жириновский Видео Вертикальное видео Короткие видео Нейровидео Нейронные сети Ответ на пост Реверс Повтор
17
6
5igorsk
5igorsk

Реверс русалка⁠⁠

9 месяцев назад
Реверс русалка
Показать полностью 1
Картинка с текстом Кентавр Комментарии Реверс Странный юмор Повтор
2
75
Catslikeme
Catslikeme
Кусь
Серия Котики 2

Просто очень щедрые и заботливые коты⁠⁠

9 месяцев назад
Перейти к видео
Вертикальное видео Кот Толстые котики Кошатники Пушистые Юмор Видео Короткие видео Реверс Повтор
4
2
0sadchi
0sadchi
Лига Разработчиков Видеоигр

Как создать скрипт-beautifier в Ghidra на Python?⁠⁠

9 месяцев назад

Приветствую, дорогой читатель. Хочу представить вашему вниманию пример, как можно упростить себе жизнь при исследовании кода программ, используя скриптинг в Ghidra.

Если вы уже имели опыт работы с дизассемблером, то заметили, что читать его вывод не так легко, если целью является понять более высокие абстракции, заложенные в нём. Возможно, вы даже пытались декомпилировать его в псевдокод, но работать с переменными типа local_1-999 – то ещё удовольствие. Да, можно щёлкнуть на каждую из них и присвоить имя на основе логики. А что, если у вас 2000 строк и более?

Чтобы не натереть мозоль, давайте разберёмся, как написать скрипт, который сделает большую часть работы за нас.

Все манипуляции были проделаны на версии 11.1.2. Чтобы попасть в список доступных скриптов, откройте меню Window → Script Manager и там же создайте новый скрипт, нажав в правом верхнем углу кнопку Create New Script и выбрав язык Python.

Важное ограничение: Ghidra использует внутреннюю реализацию языка Python версии 2.7.

Пишем код.

Первым делом, нужно объявить кодировку, чтобы не получить кучу ошибок о наличии не-ASCI символов

# -*- coding: utf-8 -*-

Указываем, что исходный файл сохранён в кодировке UTF-8 (поддержка Unicode символов).

from ghidra.util.task import Task

Импортируем класс Task из модуля Ghidra, который позволяет создавать задачи для выполнения операций в фоне.

from ghidra.app.decompiler import DecompInterface

Импортируем интерфейс декомпилятора, позволяющий получать C-подобный код из бинарных данных.

from ghidra.util.task import ConsoleTaskMonitor

Импортируем класс ConsoleTaskMonitor для отслеживания прогресса выполнения задач с выводом в консоль.

from ghidra.program.model.symbol import SourceType, SymbolType

Импортируем типы источников и типов символов, используемые для обозначения происхождения имен (например, USER_DEFINED) и вида символа (функция, переменная, метка).

from ghidra.program.model.pcode import HighFunctionDBUtil

Импортируем утилиты для работы с высокоуровневым представлением функции (HighFunction) в базе данных Ghidra.

from ghidra.program.model.pcode.HighFunctionDBUtil import ReturnCommitOption

Импортируем опцию фиксации (commit) изменений в базе данных при обновлении параметров функции.

from java.awt import BorderLayout

Импортируем менеджер компоновки BorderLayout для организации компонентов в окне Java.

from javax.swing import JButton, JFrame, JTextArea, JScrollPane, JPanel

Импортируем стандартные Swing-компоненты: кнопку, окно, текстовую область, панель прокрутки и панель для построения GUI.

import re

Импортируем модуль регулярных выражений для поиска и обработки строк.

class RenameDialog(JFrame):

Объявляем класс RenameDialog, наследующийся от JFrame. Он представляет окно диалога для ввода новых имён.

def __init__(self, suggestions):

Конструктор класса, принимающий список предложенных имен (suggestions) для переименования.

JFrame.__init__(self, "Advanced Renamer")

Инициализируем базовый класс JFrame, задавая заголовок окна “Advanced Renamer”.

self.setSize(800, 600)

Устанавливаем размер окна – 800 пикселей по ширине и 600 по высоте.

self.setLayout(BorderLayout())

Задаём менеджер компоновки BorderLayout для организации компонентов внутри окна.

self.text_area = JTextArea()

Создаём текстовую область, в которой пользователь сможет редактировать имена.

self.text_area.setText("# Format: old=new\n" + "\n".join(suggestions))

Заполняем текстовую область начальным текстом с примером формата и списком предложенных имён, разделённых переносами строк.

scroll_pane = JScrollPane(self.text_area)

Создаём панель прокрутки, содержащую нашу текстовую область, чтобы можно было просматривать длинный текст.

self.add(scroll_pane, BorderLayout.CENTER)

Добавляем панель прокрутки в центр окна (согласно BorderLayout).

button_panel = JPanel()

Создаём панель для размещения кнопок в окне.

self.apply_btn = JButton("Apply", actionPerformed=lambda _: self.setVisible(False))

Создаём кнопку “Apply” с обработчиком события: при нажатии окно будет скрыто (setVisible(False)).

button_panel.add(self.apply_btn)

Добавляем кнопку “Apply” на панель кнопок.

self.add(button_panel, BorderLayout.SOUTH)

Размещаем панель кнопок в нижней части окна.

class AdvancedRenamer(Task):

Объявляем класс AdvancedRenamer, наследующийся от Task. Он отвечает за логику переименования символов в Ghidra.

def __init__(self, program, function):

Конструктор класса принимает объект программы (program) и функцию (function), над которой будет производиться переименование.

super(AdvancedRenamer, self).__init__("Advanced Renamer", True, False, True)

Вызываем конструктор базового класса Task, задавая имя задачи и некоторые флаги (например, показывать прогресс, отменяемость и т.д.).

self.program = program

Сохраняем ссылку на текущую программу Ghidra.

self.function = function

Сохраняем ссылку на функцию, которую собираемся анализировать и переименовывать.

self.monitor = ConsoleTaskMonitor()

Создаем экземпляр монитора задач, который выводит статус выполнения в консоль.

self.skipped = {'int', 'char', 'void', 'return', 'break', 'float'}

Определяем множество ключевых слов, которые не будут изменяться при переименовании (например, базовые типы и управляющие конструкции).

def find_and_rename(self, old_name, new_name):

Определяем метод для поиска символа с именем old_name и его переименования в new_name.

decompiler = DecompInterface()

Создаём экземпляр интерфейса декомпилятора.

decompiler.openProgram(self.program)

Открываем текущую программу в декомпиляторе для дальнейшей работы.

results = decompiler.decompileFunction(self.function, 60, self.monitor)

Декомпилируем функцию с таймаутом 60 секунд, используя монитор для отслеживания прогресса.

if results.decompileCompleted():

Проверяем, успешно ли завершилась декомпиляция.

hfunction = results.getHighFunction()

Получаем высокоуровневое представление функции (HighFunction) из результатов декомпиляции.

signatureSrcType = self.function.getSignatureSource()

Получаем тип источника сигнатуры функции для дальнейшего обновления базы данных.

HighFunctionDBUtil.commitParamsToDatabase(hfunction, True, ReturnCommitOption.COMMIT, signatureSrcType)

Фиксируем изменения параметров функции в базе данных, используя указанные опции. Это необходимо для того, чтобы локальные имена, такие как lVar1, uVar2, pVar3, были согласованы с базой данных, потому, что они генерируются самим декомпилятором и просто выводятся на экран, без коммита в базу.

if old_name.startswith("FUN_"):

Если имя символа начинается с “FUN_”, считаем его именем функции.

return self.rename_function(old_name, new_name)

Вызываем метод для переименования функции.

elif old_name.startswith(("DAT_", "PTR_", "UNK_", "LAB_")):

Если имя начинается с “DAT_”, “PTR_”, “UNK_” или “LAB_”, обрабатываем его как метку или данные. Покаяние: У меня так и не получилось дать ума PTR_ и UNK_, хоть это и глобальные имена, как DAT_ и LAB_, они не переименовываются данной функцией, но я оставил их как есть :з

return self.rename_label(old_name, new_name)

Вызываем метод для переименования метки.

elif old_name.startswith(("local_", "param_", "uVar", "lVar")):

Если имя соответствует шаблону локальной переменной или параметра, то…

return self.rename_local_variable(old_name, new_name)

… вызываем метод для переименования локальной переменной.

else:

Если ни одно из условий не выполнено, по умолчанию обрабатываем как локальную переменную.

return self.rename_local_variable(old_name, new_name)

Вызываем метод для переименования локальной переменной.

def rename_function(self, old_name, new_name):

Определяем метод, который переименовывает функцию с именем old_name в new_name.

try:

Начинаем блок обработки исключений, чтобы избежать сбоев при ошибках.

addr_str = old_name[4:] if old_name.startswith("FUN_") else old_name

Если имя начинается с “FUN_”, удаляем этот префикс, чтобы получить строку адреса функции.

addr = toAddr("0x{}".format(addr_str))

Преобразуем строку с адресом в объект адреса Ghidra, добавляя префикс “0x”.

func = getFunctionAt(addr)

Получаем объект функции, расположенной по данному адресу.

if func and func.getName() == old_name:

Если функция найдена и её имя соответствует old_name, то…

func.setName(new_name, SourceType.USER_DEFINED)

… устанавливаем новое имя для функции, указывая, что оно задано пользователем (USER_DEFINED).

except: pass

Если возникает ошибка (например, неверный адрес), просто игнорируем её.

def rename_label(self, old_name, new_name):

Определяем метод для переименования метки или символа, представляющего данные.

try:

Начинаем блок обработки исключений.

addr_str = old_name[4:] if old_name.startswith(("LAB_", "DAT_", "PTR_", "UNK_")) else old_name

Извлекаем адрес метки, убирая префикс (например, “LAB_”) если он присутствует.

addr = toAddr(addr_str)

Преобразуем строку адреса в объект адреса Ghidra.

for sym in self.program.getSymbolTable().getSymbols(addr):

Перебираем все символы, зарегистрированные по этому адресу, из таблицы символов программы.

if sym.getName() == old_name:

Если имя символа совпадает с old_name, то…

sym.setName(new_name, SourceType.USER_DEFINED)

… устанавливаем новое имя для символа с типом источника USER_DEFINED.

return True

Возвращаем True, указывая, что переименование прошло успешно.

except: pass

При возникновении исключения игнорируем его.

def rename_local_variable(self, old_name, new_name):

Определяем метод для переименования локальной переменной или параметра.

try:

Начинаем блок обработки исключений.

if new_name.lower() in self.skipped:

Если новое имя (в нижнем регистре) содержится в списке ключевых слов для пропуска, то…

return False

… прекращаем переименование, возвращая False.

# Далее идет блок, необходимый для обработки параметров

for param in self.function.getParameters():

Перебираем все параметры текущей функции.

if param.getName() == old_name:

Если имя параметра совпадает с old_name, то…

param.setName(new_name, SourceType.USER_DEFINED)

… устанавливаем новое имя для параметра.

# Local variables (даже если наш пациент был найдет среди параметров

# необходимо пройтись и по локальным переменным,

# иначе они не переименовываются, возможно надо тут просто

# сделать коммит в базу)

decompiler = DecompInterface()

Создаём новый экземпляр декомпилятора для обработки локальных переменных.

decompiler.openProgram(self.program)

Открываем программу в декомпиляторе.

results = decompiler.decompileFunction(self.function, 60, self.monitor)

Декомпилируем функцию с таймаутом 60 секунд.

if results.decompileCompleted():

Если декомпиляция прошла успешно, то…

hfunction = results.getHighFunction()

… получаем высокоуровневое представление функции.

syms = hfunction.getLocalSymbolMap().getSymbols()

Получаем список локальных символов (переменных) из высокоуровневой функции.

for sym in syms :

Перебираем каждый локальный символ.

if sym.getName() == old_name and sym.getName() != new_name:

Если имя символа совпадает с old_name и ещё не равно new_name, то…

HighFunctionDBUtil.updateDBVariable(sym, new_name, None, SourceType.USER_DEFINED)

… обновляем имя переменной в базе данных с новым именем и источником USER_DEFINED.

return True

Возвращаем True после успешного переименования локальной переменной.

return False

Если ни один из блоков не сработал, возвращаем False – переименование не выполнено.

except Exception as e:

Ловим исключения и сохраняем их в переменной e для отладки.

print("Error: {} -> {} ({})".format(old_name, new_name, str(e)))

Выводим сообщение об ошибке с указанием старого и нового имени, а также текста ошибки. Обратите внимание на форматирование строки, т.к. это Python 2.7.

return False

Возвращаем False, сигнализируя, что произошла ошибка при переименовании.

def run(self):

Определяем метод run, который является точкой входа при выполнении задачи AdvancedRenamer.

decompiler = DecompInterface()

Создаем экземпляр декомпилятора для работы с функцией.

decompiler.openProgram(self.program)

Открываем программу в декомпиляторе.

results = decompiler.decompileFunction(self.function, 60, self.monitor)

Декомпилируем функцию с таймаутом 60 секунд.

if not results.decompileCompleted():

Если декомпиляция не завершилась успешно, то…

print("Decompilation failed!")

… выводим сообщение об ошибке декомпиляции.

return

Прерываем выполнение метода run (задача не может продолжаться без декомпиляции).

code = results.getDecompiledFunction().getC()

Получаем декомпилированный C-подобный код функции в виде строки.

entities = re.findall(r'\b([A-Za-z_][A-Za-z0-9_]*)\b', code)

С помощью регулярного выражения находим все идентификаторы (слова, начинающиеся с буквы или подчёркивания) в коде.

filtered_names = [n for n in set(entities) if n not in self.skipped]

Создаём множество уникальных идентификаторов и исключаем те, что присутствуют в self.skipped (ключевые слова).

dialog = RenameDialog(filtered_names)

Создаем диалоговое окно RenameDialog, передавая список найденных имён для потенциального переименования.

dialog.setLocationRelativeTo(None)

Устанавливаем расположение диалога по центру экрана (None означает центр относительно родительского окна).

dialog.setVisible(True)

Делаем диалог видимым – ожидаем, пока пользователь внесёт изменения и нажмёт “Apply”.

while dialog.isVisible(): pass

Активно ждём, пока окно не будет закрыто (пользователь не закончит ввод).

success = 0

Инициализируем счётчик успешно переименованных символов.

for line in dialog.text_area.getText().split('\n'):

Перебираем каждую строку из текста, введённого пользователем в текстовой области диалога.

line = line.strip()

Удаляем пробелы в начале и конце строки.

if line and '=' in line and not line.startswith('#'):

Если строка не пуста, содержит символ “=” и не является комментарием (не начинается с “#”), то…

old, new = line.split('=', 1)

Разбиваем строку на две части по первому символу “=”, где левая часть – старое имя, правая – новое.

if self.find_and_rename(old.strip(), new.strip()):

Вызываем метод find_and_rename с очищенными от пробелов старыми и новыми именами; если переименование прошло успешно, то…

success += 1

… увеличиваем счётчик успешных переименований.

print("Successfully renamed: {}/{}".format(success, len(filtered_names)))

Выводим итоговое сообщение о том, сколько из найденных идентификаторов было успешно переименовано.

if __name__ == "__main__":

Стандартная проверка: выполняется ли скрипт как главный модуль.

func = getFunctionContaining(currentAddress)

Получаем функцию, в которой находится текущий адрес курсора в Ghidra.

if func:

Если функция найдена, то…

task = AdvancedRenamer(currentProgram, func)

Создаем экземпляр задачи AdvancedRenamer, передавая текущую программу и найденную функцию.

task.run()

Запускаем выполнение задачи переименования.

else:

Если функция не найдена (курсор не находится внутри функции), то…

print("Position cursor inside function!")

… выводим сообщение с просьбой установить курсор внутри функции для корректной работы скрипта.

Подготовка.

Когда все готово, можем пойти в любую нейросеть. По-моему мнению самая лучшая на сегодняшний день для данной задачи будет DeepSeek-r1. Выверенный опытным путем промпт.

Прокомментируй каждую строку и переименнуй переменные и функции нормально. Саму структуру кода оставь, как есть, не сокращая и не меняя, то есть никаких "и так далее" - пиши код полностью! Все имена должны быть подробными, то есть не tmp и прочее, никаких сокращенных бысмысленных имен. Опиши к чему пренадлежат переменные, не просто windowStruct, а UIState как напимер. Так же переименую DAT_ как g_..новоеИмя, и LABEL_куда прыгаем {НАШ_ПСЕВДО_КОД} после кода выведи все, что переименовал в формате списка старое_имя=новое_имя\n в список включай все переменные, функции, DAT_, LAB_, param_ и прочее без исключений прям все пиши

Выбираем цель, для эксперимента

В итоге, у меня получился вот такой вот список для моей функции

param_1=hWndPointer

bVar1=isCursorConfinedDueToCapture

bVar2=isMarginApplied

cVar3=isCursorCapturedResult

local_res8=clientTopLeftPoint

local_res10=clientBottomRightPoint

local_38=confinedCursorRect

local_28=windowRect

Запускаем!!

После запуска скрипта (при условии, что курсор установлен внутри функции) откроется диалоговое окно, в котором будут выведены найденные идентификаторы. Введите список переименований в формате:

ВАЖНО!!! Переменные по типу xVarN нужно сортировать по убыванию, так как они не внесены в базу. Переименование меньшей переменной приведёт к тому, что большая займёт её место, и список станет невалидным.

После ввода нажмите кнопку Apply и дождитесь окончания выполнения.

(метод подсчета требует доработки)

В итоге должно получиться нечто подобное:

Спасибо за внимание! Скачать PDF и сам скрипт можно по ссылке – https://t.me/osiechan/62 А начать путь в реверс-инжиниринге можно на увлекательном бесплатном курсе по ботостроению для ММОРПГ – https://t.me/osiechan/41

Показать полностью 4
[моё] Программирование Python Гайд Windows Реверс Длиннопост
1
307
Pnevmopix
Pnevmopix
Дикие животные

Ответ на пост «Дом для осьминога»⁠⁠2

9 месяцев назад

Вы думали я не реверсну? Я реверсну)

Перейти к видео
Осьминог Головоногие Моллюск Морские обитатели Дикие животные Дикая природа Пляж Бутылка Пластиковые бутылки Вертикальное видео Короткие видео Реверс Видео Ответ на пост
25
4
CTEPEOCOH
CTEPEOCOH
Пакистанские технологии

Ответ на пост «Двигатель превращается в...»⁠⁠

10 месяцев назад
Перейти к видео

В комментарии видео не добавляется. @tlsandos, @DartViktor

Пакистан Пакистанские технологии Техника безопасности Изготовление Реверс Видео Ответ на пост
3
55
EgoRProG
EgoRProG
Видеохостинг на Пикабу

Хорошему танцору ничего не мешает⁠⁠

10 месяцев назад
Перейти к видео
Черный юмор Танцы Видео Вертикальное видео Короткие видео Неожиданно Реверс
20
2728
SourLemon1
SourLemon1

Маленькие динозавры⁠⁠

10 месяцев назад
Перейти к видео
Коати Носухи Гватемала Видео Вертикальное видео Короткие видео Реверс Динозавры
134
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии