Как использовать dexlib2 для инструментовки определенных методов, особенно выделения регистров для добавления новых инструкций?

Я использую dexlib2 для программного инструментария некоторых методов в файле dex, например, если я нахожу такие инструкции:

invoke-virtual {v8, v9, v10}, Ljava/lang/Class;->getMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;

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

Однако теперь я столкнулся с некоторыми вопросами о том, как выделить регистры для использования в моей вставленной инструкции мониторинга?

Я знаю два способа, но в любом из них есть свои проблемы:

  1. Я могу использовать DexRewriter для увеличения числа регистров этого метода (например, с .register 6 до .register 9), чтобы можно было использовать дополнительные (3) регистра. Но сначала это ограничено 16 регистрами; во-вторых, когда я увеличиваю registerCount, параметры будут переданы последним, и поэтому мне приходится переписывать все инструкции в этом методе, использующие параметры, что утомительно.

  2. Или я могу повторно использовать регистры. Таким образом, я должен анализировать живучесть каждого регистра, в то время как dexlib2, похоже, не имеет существующего API для построения CFG и цепочки def-use, что означает, что я должен написать его сам. Кроме того, я сомневаюсь, что таким образом я смогу получить достаточно доступных регистров.

Я правильно понимаю эту проблему? существуют ли какие-либо существующие инструменты/алгоритмы для этого? Или какой-нибудь совет, что я могу сделать это лучше?

Спасибо.


person HankZhang    schedule 29.05.2018    source источник


Ответы (1)


Несколько моментов:

  • Вы не ограничены 16 регистрами в методе. Большинство инструкций могут обращаться только к первым 16 регистрам, но есть инструкции mov, которые можно использовать для замены значений с более высокими регистрами.

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

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

person JesusFreke    schedule 29.05.2018
comment
Большое спасибо! Я использую ваш второй пункт, и пока он кажется хорошим - person HankZhang; 30.05.2018