Лучший способ внедрить функциональность в двоичный файл - PullRequest
20 голосов
/ 04 ноября 2008

Как лучше всего вставить функциональность в бинарное приложение (3d party, с закрытым исходным кодом).

Целевое приложение на OSX и, похоже, скомпилировано с использованием gcc 3+. Я вижу список функций, реализованных в двоичном коде, которые отлаживают и выделяют одну конкретную функцию, которую я хотел бы вызвать удаленно.

В частности, я хотел бы вызвать эту функцию - давайте назовем ее недействительной zoomByFactor(x,y) - когда я получу определенные данные от сложного HIDevice.

Я могу легко изменять или вставлять инструкции в сам двоичный файл (т. Е. Исправление не требуется только в ОЗУ).

Что бы вы порекомендовали как способ "красиво" сделать это?

Изменить:

Мне действительно нужно все приложение. Поэтому я не могу бросить это и использовать библиотеку. (Для тех, кому нужно этическое объяснение: это проприетарная часть программного обеспечения САПР, чей веб-сайт компании не обновлялся с 2006 года. Я заплатил за этот продукт (довольно много денег за то, что он есть на самом деле) и имею проект данные, которые я не могу с легкостью перенести из него. Продукт мне подходит просто отлично, но я хочу использовать новый HID, который я недавно получил. Я изучил внутреннюю часть приложения, и я довольно уверен что я могу вызвать правильную функцию с соответствующими данными и заставить ее работать должным образом.

Вот что я сделал до сих пор, и это довольно гетто.

Я уже модифицировал части приложения через этот процесс:

xxd -g 0 binary > binary.hex
cat binary.hex | awk 'substitute work' > modified.hex
xxd -r modified.hex > newbinary
chmod 777 newbinary

Я делаю этот вид прыжков через обручи, потому что размер двоичного файла составляет почти 100 мегабайт.

Суть того, что я думаю, заключается в том, что я буду jmp где-нибудь в главном цикле приложения, запускаю поток и возвращаюсь к основной функции.

Теперь возникают вопросы: куда я могу вставить новый код? мне нужно изменить таблицы символов? в качестве альтернативы, как я могу автоматически загрузить dylib, чтобы единственный «взлом», который мне нужно было сделать, это вставить вызов нормально загруженного dylib в основную функцию?

Ответы [ 6 ]

10 голосов
/ 09 ноября 2008

Для тех, кто интересуется тем, что я в итоге сделал, вот краткое изложение:

Я посмотрел на несколько возможностей. Они попадают в исправления во время выполнения и статические исправления двоичных файлов.

Что касается исправления файлов, я, по сути, попробовал два подхода:

  1. изменение сборки в коде сегменты (__TEXT) двоичного файла.

  2. изменение команд загрузки в заголовок Маха.

Первый метод требует наличия свободного места или методов, которые вы можете перезаписать. Это также страдает от чрезвычайно плохой ремонтопригодности. Любые новые двоичные файлы требуют ручного исправления их еще раз, особенно если их исходный код даже немного изменился.

Второй метод состоял в том, чтобы попытаться добавить запись LC_ LOAD_ DYLIB в заголовок mach. Там не так много машинных редакторов, так что это сложно, но я на самом деле изменил структуры так, чтобы моя запись была видна otool -l. Однако на самом деле это не сработало, поскольку во время выполнения было dyld: bad external relocation length. Я предполагаю, что мне нужно разобраться с таблицами импорта и т. Д. И это слишком много усилий, чтобы получить права без редактора.

Второй путь - ввод кода во время выполнения. Там не так много, чтобы сделать это. Даже для приложений, которые вы контролируете (например, дочернее приложение, которое вы запускаете). Может быть, есть способ fork() и запуск процесса инициализации, но я никогда этого не делаю.

Существует SIMBL, но для этого требуется, чтобы ваше приложение было Какао, потому что SIMBL будет представлять собой системный InputManager и выборочно загружать пакеты. Я отклонил это, потому что мое приложение не было Какао, и кроме того, я не люблю общесистемные вещи.

Следующим шагом был mach_ inject и проект mach_star. Существует также более новый проект под названием PlugSuit, размещенный на Google, который, кажется, не более чем тонкая оболочка вокруг mach_inject.

Mach_inject предоставляет API для выполнения того, что подразумевает название. Я нашел проблему в коде, хотя. На 10.5.4 метод mmap в файле mach_inject.c требует наличия MAP_ SHARED или MAP_READ, иначе mmap завершится ошибкой.

Помимо этого, все на самом деле работает как рекламируется. В итоге я использовал mach_ inject_ bundle, чтобы сделать то, что я намеревался сделать со статическим добавлением DYLIB к заголовку mach: запуск нового потока в модуле init, который ведет грязную работу.

В любом случае, я сделал это вики. Не стесняйтесь добавлять, исправлять или обновлять информацию. Практически нет информации о такой работе над OSX. Чем больше информации, тем лучше.

4 голосов
/ 04 ноября 2008

В выпусках MacOS X до 10.5 вы бы делали это с помощью расширения Input Manager. Диспетчер ввода предназначен для обработки таких вещей, как ввод для неримских языков, где расширение может всплыть в окне для ввода соответствующих глифов и затем передать завершенный текст в приложение. Приложению нужно было только убедиться, что оно чистое в Юникоде, и не нужно беспокоиться о точных деталях каждого языка и региона.

Диспетчер ввода подвергался жестокому обращению с целью добавления в приложения всевозможных несвязанных функций и часто дестабилизировал приложение. Он также становился вектором атаки для троянов, таких как «Oompa-Loompa». MacOS 10.5 ужесточает ограничения для менеджеров ввода: он не будет запускать их в процессе, принадлежащем root или wheel, или в процессе, который изменил свой uid. Наиболее важно то, что 10.5 не загружает Менеджер ввода в 64-битный процесс и указывает, что даже 32-битное использование не поддерживается и будет удалено в следующем выпуске.

Так что, если вы можете жить с ограничениями, менеджер ввода может делать то, что вы хотите. В будущих выпусках MacOS почти наверняка появится другой (более безопасный, более ограниченный) способ сделать это, поскольку функциональность действительно необходима для поддержки ввода языка.

3 голосов
/ 19 сентября 2010

Полагаю, вы также можете использовать метод DYLD_INSERT_LIBRARIES .

Этот пост также связан с тем, что вы пытались сделать;

1 голос
/ 06 мая 2014

Я недавно попробовал инъекцию / переопределение, используя mach_star источники. Я закончил тем, что написал учебник для него, так как документация для этого материала всегда очень схематична и часто устарела.

http://soundly.me/osx-injection-override-tutorial-hello-world/

0 голосов
/ 11 октября 2009

В Windows это просто сделать, на самом деле это делается очень широко и известно как DLL / внедрение кода.

Существует коммерческий SDK для OSX, который позволяет делать это: Application Enhancer (бесплатно для некоммерческого использования).

0 голосов
/ 04 ноября 2008

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

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

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

Наилучший вариант, если он доступен, - это заставить поставщика вашего приложения предоставить API плагина, который позволит вам делать это чисто и надежно поддерживаемым способом.

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

...