Как выгрузить программу из памяти

Обновлено: 06.07.2024

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

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

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

Нюансы при выгрузке памяти

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



Рисунок 1: Назначение некоторых пинов у внешней флеш-памяти

Кроме того, мы ознакомились с набором инструкций и можем взаимодействовать с микросхемой при помощи любого устройства, которое умеет «общаться» с шиной SPI.

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

Нужен демонтаж флеш-памяти? (теория)

Самый лучший способ остановить коммуникацию между Ralink и флеш-памятью – демонтаж и полная изоляция микросхемы от остальной цепи. Данный метод позволяет нам полностью управлять ситуацией и исключает все возможные источники конфликтов, но, к сожалению, требует дополнительное оборудование, опыт и время. Мы попробуем пойти более простым путем.

Второй способ – перевод Ralink в неактивный режим, в то время как все остальные элементы вокруг находятся в режиме ожидания. Зачастую у микроконтроллеров есть пин Reset, который, при подаче логического нуля, перезагружает микросхему без отключения питания на плате. Но у нас нет полной версии даташита (возможно, эта документация распространяется только среди покупателей на основе соглашения о неразглашении информации). Внешний вид микросхемы и сложность окружающей цепи серьезно затрудняю задачу по самостоятельному поиску нужного пина.

Третий способ – подача напряжения только на внешнюю флеш-память вместо включения всей цепи. Подача питания на плату недокументированным способом может привести к конфликтам. Мы могли бы изучить цепь питания, но поскольку роутер дешевый и распространенный, попробуем обойтись без дополнительных исследований. Согласно даташиту необходимое напряжение – 3 В. Я буду запитывать внешнюю флеш-память напрямую.



Рисунок 2: Схема прямого запитывания внешней-флеш памяти

Мы будем напрямую подавать питание и ожидать данные из UART порта микроконтроллера Ralink. После подачи напряжения на задней стороне платы загорелись светоизлучающие диоды, трафик на порте отсутствует, и, предположительно, Ralink находится в неактивном режиме. Однако даже в этом случае, соединение микроконтроллера с флеш-памятью может препятствовать передаче информации вследствие нюансов проектирования цепи питания и чипа. Важно не забывать об этих деталях, если мы в дальнейшем столкнемся с чем-нибудь странным. Если произойдет нечто подобное, нам нужно физически отпаять флеш-память (или, по крайней мере, пины, отвечающие за передачу информации).

Светоизлучающие диоды и другие статические компоненты не могут взаимодействовать с флеш-памятью и, соответственно, не могут стать причиной проблем, если мы подаем достаточный ток. Я использую ступенчатый источник питания, где предусмотрена подача различных токов на все случаи жизни. Если у вас нет подобного источника питания, можете попробовать воспользоваться системой питания внешнего (ведущего) устройства или каким-либо USB-адаптером питания в случае, если необходимы токи большего размера.

Теперь пришло время подключить внешнее устройство к шине SPI.

Соединение с флеш-памятью

После того как мы убедились в отсутствии необходимости демонтажа, то можем подсоединить устройство, которое умеет общаться с шиной SPI, и начать поблочное чтение памяти. Для решения этой задачи подойдет любой микроконтроллер, но намного удобнее воспользоваться специальным переходником SPI-USB. Я воспользуюсь моделью FT232H, которая поддерживает как протокол шины SPI, так и другие низкоуровневые протоколы.

Теперь, когда мы знаем назначения пинов флеш-памяти и переходника USB-SPI, пробуем подсоединиться.



Рисунок 3: Схема подключение переходника к флеш-памяти

После подготовки и настройки аппаратной части переходим к выгрузке данных.

Выгрузка информации

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

Flashrom – старое и нестабильное приложение, однако поддерживает модель FT232H (переходник) в качестве ведущего устройства, и модель FL064PIF (флеш-память) – в качестве ведомого. У меня возникли проблемы при работе в OSX и виртуальной машине с Ubuntu, но в конечном итоге все заработало в системе Raspberry Pi (ОС Raspbian):



Рисунок 4: Выгрузка данных из флеш-памяти при помощи flashrom

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

Разделение бинарного файла

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

Примечание: binwalk – очень полезная утилита для анализа бинарных файлов, созданная командой /dev/ttyS0; Если вы занимаетесь исследованиями аппаратной части, вам определенно нужно познакомиться с ребятами из этой группы.



Рисунок 5: Базовая информация о бинарном файле, полученная при помощи утилиты bindwalk



Рисунок 6: Карта флеш-памяти

При наличии нужных адресов мы можем разделить бинарный файл на 4 базовых сегмента. Утилита dd принимает на входе 3 параметра в десятичном формате: размер блока (bs, в байтах), смещение (skip, количество блоков) и размер (count, количество блоков); Для преобразования из шестнадцатеричной системы в десятичную мы можем воспользоваться либо калькулятором, либо средствами шелла и командой $(()):

$ dd if=spidump.bin of=bootloader.bin bs=1 count=$((0x020000))
131072+0 records in
131072+0 records out
131072 bytes transferred in 0.215768 secs (607467 bytes/sec)
$ dd if=spidump.bin of=mainkernel.bin bs=1 count=$((0x13D000-0x020000)) skip=$((0x020000))
1167360+0 records in
1167360+0 records out
1167360 bytes transferred in 1.900925 secs (614101 bytes/sec)
$ dd if=spidump.bin of=mainrootfs.bin bs=1 count=$((0x660000-0x13D000)) skip=$((0x13D000))
5386240+0 records in
5386240+0 records out
5386240 bytes transferred in 9.163635 secs (587784 bytes/sec)
$ dd if=spidump.bin of=protect.bin bs=1 count=$((0x800000-0x660000)) skip=$((0x660000))
1703936+0 records in
1703936+0 records out
1703936 bytes transferred in 2.743594 secs (621060 bytes/sec)

Мы создали 4 бинарных файла:

  1. bootloader.bin: загрузчик U-boot. Файл несжатый, поскольку микроконтроллер Ralink не умеет распаковывать эту информацию.
  2. mainkernel.bin: ядро в Linux. Базовая прошивка, управляющая системой bare metal. Упакована алгоритмом lzma.
  3. mainrootfs.bin: Файловая система. Содержит все важные бинарные и конфигурационные файлы. Упакована как squashfs при помощи алгоритма lzma.
  4. protect.bin: различные данные, упомянутые в третьей статье. Упаковка отсутствует.

Анализ отдельных частей бинарного файла

После разделения бинарного файла на 4 части рассмотрим подробнее каждый из этих сегментов.

Загрузчик



Рисунок 7: Информация о бинарном файле, имеющем отношение к загрузчику

Утилита binwalk нашла и декодировала заголовок uImage. Загрузчик U-Boot использует данные заголовки для идентификации важных областей памяти. Это та же самая информация, которая отображается командой file в случае с полным дампом памяти, поскольку вначале идет тот же самый заголовок.

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

Ядро



Рисунок 8: Информация о бинарном файле, имеющем отношение к ядру

Перед извлечением полезной информации необходима распаковка. После анализа через binwalk мы еще раз убедились (как и во второй статье), что ядро упаковано алгоритмом lzma, который является очень популярным среди встроенных систем. Быстрая проверка при помощи команды strings mainkernel.bin | less подтверждает, что информации, пригодной для анализа, в файле нет.

Существует множество утилит для распаковки алгоритма lzma, например, 7z или xz, однако ни одна из этих утилит не смогла распаковать файл mainkernel.bin:

$ xz --decompress mainkernel.bin
xz: mainkernel.bin: File format not recognized

Скорее всего, дело в заголовке uImage, который нужно вычленить из файла. Мы знаем, что информация, упакованная lzma, начинается с байта 0x40. То есть нам необходимо скопировать все, кроме первых 64 байт.



Рисунок 9: Копирование части файла при помощи утилиты dd

Пробуем распаковать еще раз:

$ xz --decompress mainkernel_noheader.lzma
xz: mainkernel_noheader.lzma: Compressed data is corrupt

Утилите xz удалось распознать алгоритм lzma, но не запакованные данные. Мы пытаемся распаковать весь файл mainkernel, имеющий отношение к флеш-памяти, однако хранимая информация навряд ли занимается 100% сегмента. Попробуем удалить неиспользуемую память в конце файла и распаковать вновь:



Рисунок 10: Удаление ненужной части файла и повторная распаковка

Как видно из рисунка выше, распаковка завершилась удачно, что можно проверить при помощи команды strings, которая ищет строки в формате ASCII в бинарных файлах. Попробуем поискать что-нибудь полезное:



Рисунок 11: Поиск полезной информации в распакованном файле при помощи команды strings

Строка Wi-Fi Easy and Secure Key Derivation выглядит многообещающе, но впоследствии выяснилось, что данная строка определена в спецификации Wi-Fi Protected Setup spec. Ничего интересного, имеющего отношения к алгоритму генерации паролей.

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

Файловая система



Рисунок 12: Информация о бинарном файле, имеющем отношение к файловой системе

Сегмент памяти mainrootfs не имеет заголовка uImage поскольку относится к ядру, а не к загрузчику U-Boot.

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



Рисунок 13: Пример сигнатуры файловой системы

Поскольку данная файловая система популярна, и поиск нужной конфигурации – довольно скучное и утомительное занятие, кто-то уже должен был написать скрипт, упрощающий решение этой задачи. Я нашел версию Firmware Modification Kit заточенную под операционную систему OSX, которая содержит скомпилированные версии unsquashfs и включает в себя скрипт unsquashfs_all.sh.



Рисунок 14: Поиск и распаковка нужной версии файловой системы

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



Рисунок 15: Некоторые элементы дерева файловой системы

В полной версии дерева можно найти все остальные файлы, используемые системой (а не только из папки /var/).

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



Рисунок 16: Некоторые бинарные файлы, представляющие для нас интерес

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

Защищенная область



Рисунок 17: Информация о бинарном файле, имеющем отношение к защищенной области памяти

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



Рисунок 18: Содержимое части файла protect.bin

Содержимое файла protect.bin, скорее всего, совпадает с файлом curcfg.xml: логи и некоторые строки, показанные на рисунке выше. Эту информацию мы уже проанализировали в третьей части и не нашли ничего нового.

Что дальше

На данный момент исследование аппаратной части Ralink закончено, и мы получили все, что находится во флеш-памяти. Теперь вы можете найти, что вам необходимо. Например, мы хотим управлять роутером через отладочный UART порт, найденный в первой статье, но при попытке получить доступ к оболочке ATP CLI, мы не можем подобрать учетную запись. После выгрузки информации из внешней флеш-памяти находим XML файл в защищенной области, в котором находится учетная запись.

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

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

В любом смартфоне на Android предустановлено большое количество приложений, многими из которых мы никогда не пользуемся. Изначально они не занимают место в памяти приложений, но после автоматического обновления иногда доходит даже до того, что обновления предустановленных приложений забивают всю память и не дают установить какие-либо новые приложения. Кроме того, у большинства предустановленных приложений есть постоянно работающая резидентная часть, которая замедляет работу смартфона и потребляет энергию аккумулятора.

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

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

Итак, заходим в "Настройки-Приложения" и ищем кандидатов на удаление. Во вкладке "загруженные" будут те из предустановленных приложений, для которых Андроид установил обновления.

Нажимаем на приложение. Первым делом нажимаем кнопку "удалить обновления".

Соглашаемся на предложение заменить обновлённое приложение исходной версией.

Затем нажимаем "Выключить" и подтверждаем своё действие.

Нажимаем "Остановить", чтобы выгрузить приложение из памяти (если этого не сделать, оно будет работать до перезагрузки).

Так делаем со всеми ненужными приложениями. Далее переходим на вкладку "Все".

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

Я всегда отключаю следующие приложения:

Разумеется, если вы пользуетесь какими-либо приложениями из этого списка, отключать их не надо.

Для того, чтобы Андроид не устанавливал обновления на всё подряд, автообновление лучше выключить: запускаем "Play Маркет" и нажимаем на три полоски в левом верхнем углу.

Чтобы выгрузить резидентную программу из памяти, необходимо сделать три вещи: закрыть открытые программой файлы и устройства, восстановить все перехваченные векторы прерываний, и наконец, освободить всю занятую программой память. Трудность может вызвать второй шаг, так как после нашего резидента могли быть загружены другие программы, перехватившие те же прерывания. Если в такой ситуации восстановить вектор прерывания в значение, которое он имел до загрузки нашего резидента, программы, загруженные позже, не будут получать управление. Более того, они не будут получать управление только по тем прерываниям, которые у них совпали с прерываниями, перехваченными нашей программой, в то время как другие векторы прерываний будут все еще указывать на их обработчики, что почти наверняка приведет к ошибкам. Поэтому, если хоть один вектор прерывания не указывает на наш обработчик, выгружать резидентную программу нельзя. Это всегда было главным вопросом, и спецификации AMIS и IBM ISP (см. предыдущую главу) являются возможным решением этой проблемы. Если вектор прерывания не указывает на нас, имеет смысл проверить, не указывает ли он на ISP-блок (первые два байта должны быть EBh 10h, а байты 6 и 7 — «K» и «B»), и, если это так, взять в качестве вектора значение из этого блока и т.д. Кроме того, программы могут изменять порядок, в котором обработчики одного и того же прерывания вызывают друг друга.

Последний шаг в выгрузке программы — освобождение памяти — можно выполнить вручную, вызывая функцию DOS 49h на каждый блок памяти, который программа выделяла через функцию 48h, на блок с окружением DOS, если он не освобождался при загрузке, и наконец, на саму программу. Однако есть способ заставить DOS сделать все это (а также закрыть открытые файлы и вернуть код возврата) автоматически, вызвав функцию 4Ch, объявив резидент текущим процессом. Посмотрим, как это делается на примере резидентной программы, занимающей много места в памяти. Кроме того, этот пример реализует все приемы, использующиеся для вызова функций DOS из обработчиков аппаратных прерываний, о которых рассказано в главе 5.8.3.

В этом примере, достаточно сложном из-за необходимости избегать всех возможностей повторного вызова прерываний DOS и BIOS, добавилась еще одна мера предосторожности — сохранение состояния EMS-памяти перед работой с ней и восстановление в исходное состояние. Действительно, если наш резидент активируется в тот момент, когда какая-то программа работает с EMS, и не выполнит это требование, программа будет читать/писать уже не в свои EMS-страницы, а в наши. Аналогичные предосторожности следует предпринимать всякий раз, когда вызываются функции, затрагивающие какие-нибудь глобальные структуры данных. Например: функции поиска файлов используют буфер DTA, адрес которого надо сохранить (функция DOS 2Fh), затем создать собственный (функция DOS 1Ah) и в конце восстановить DTA прерванного процесса по сохраненному адресу (функция 1Ah). Таким образом надо сохранять/восстанавливать состояние адресной линии А20 (функции XMS 07h и 03h), если резидентная программа хранит часть своих данных или кода в области HMA, сохранять состояние драйвера мыши (INT 33h, функции 17h и 18h), сохранять информацию о последней ошибке DOS (функции DOS 59h и 5D0Ah), и так с каждым ресурсом, который затрагивает резидентная программа. Писать полноценные резидентные программы в DOS сложнее всего, но, если не выходить за рамки реального режима, это — самое эффективное средство управления системой и реализации всего, что только можно реализовать в DOS.

Чтобы приложения, используемые на Android-устройстве, не оставались запущенными в фоне и не занимали оперативную память смартфона, нужно их закрывать. Существует пара вариантов, которые помогают пользователям устройств на базе Андроид правильно осуществить данную процедуру. Если на персональном компьютере достаточно нажать на стандартный «крестик» в углу, то с телефонами и планшетами не все так однозначно.

Стандартный способ закрытия приложений

Чтобы выйти из программы или игры, необходимо воспользоваться кнопкой «назад» или «домой». В первом случае может возникнуть необходимость нажать «назад» дважды, чтобы вернуться туда, откуда осуществлялся вход в андроид приложение.


Опция «домой» вернет пользователя на главный экран, свернув любую андроид программу за одно нажатие.

Но не всегда этого стандартного метода достаточно, чтобы осуществить полный выход из андроид приложений, освободив от нагрузки ОЗУ и ЦПУ. Большинство используемых программ все еще остаются работать в фоновом режиме, если пользователь нажал на кнопку «назад» или «домой».

Выгрузка из памяти

Данный метод позволяет в кратчайшие сроки принудительно закрыть любой запущенный на телефоне или планшете процесс. В дальнейшем запуск выгруженной программы может занять больше времени и системных ресурсов. Однако метод помогает освободить ОЗУ и снизить нагрузку на ЦПУ, поэтому считается простым и распространённым среди пользователей Андроид-устройств.


Чтобы осуществить выгрузку ненужных приложений на андроид из памяти, необходимо открыть окошко «многозадачности» (список всех используемых недавно программ) и смахнуть их в сторону. У большинства девайсов (например, телефонов Самсунг) имеется универсальная кнопка «очистить все», с помощью которой за одно нажатие закрыть и выгрузить из памяти сразу все недавно используемые приложения на андроид, а не какое-нибудь одно.

Помните, что на большинстве телефонов закрытие андроид приложений и их выгрузка из ОЗУ не приносят ощутимого прироста производительности. Эти опции скорее помогают снизить расход батареи и уменьшить нагрузку на стандартные системные процессы ОС Андроид 9.

Принудительная остановка

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

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


В открывшемся списке найдите андроид приложение, которое нужно закрыть, нажмите на него и воспользуйтесь кнопкой «остановить». Система запросит подтверждение, после чего программа будет остановлена.

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

Читайте также: