термоядерный инлайн GETORIX | INT3 Спецвыпуск: Хакер, номер #066, стр. 066-068-4 Теперь при грамотном пропатчивании существующая защита перестанет мешать нормальной работе с программой. [остается написать патч] Как уже было сказано, inline-патч должен быть запущен перед переходом на OEP (Original Entry Point), но в нашем случае EP (Entry Point) = OEP. И где размещать его? Можно, конечно, поколдовать с самим файлом: добавить новую секцию (с патчем), изменить параметр AdressOfEntryPoint в PE-заголовке, указав на эту секцию, и потом из тела патча передавать управление непосредственно на начало программы в основной секции кода. В предложенном способе плохо только то, что придется вносить значительные модификации в файл (получив, как следствие, изменение размеров и смешение секций), чего как раз не хотелось бы. У меня же родилась идея заменить первый в программе BL-переход (Branch with Link) на вызов нашего inline-патча и уже из него (после того как основной код будет исправлен) передать управление функции, вызываемой в оригинале. Конечно, звучит немного нелогично и сложновато, зато интересно с точки зрения реализации. Для начала определимся с местом расположения нашего собственного кода. Видимо, после основного кода, перед секцией импорта. Для того чтобы узнать адрес последней инструкции, в листинге IDA перейдем на начало секции импорта (она находится по адресу 1E000). Смотрим выше и видим, что секция кода заканчивается адресом 1D830. Отступим немного и определим начало патча на адрес 1D840. Теперь запустим любой редактор PE, здесь в конверторе из этого RVA получим File offset. Получается, CC40. Наконец-то пришла пора разработки тела inline-патча. Здесь советую уделить большое внимание сохранению параметров функции в стеки при входе в подпрограмму (Prolog) и их восстановлению из стека (Epilog) при выходе из подпрограммы. Дело в том, что архитектура ARM поддерживает множество способов укладывания данных в стек, и если не понимать разницу между ними, быстро запутаешься и приведешь свой КПК к HardReset. В итоге, после некоторых усилий, зависящих от того самого пухленького багажа знаний, должно получиться нечто, похожее на код из листинга 4. Листинг 4. ARM-код inline-патча 0001D840 STMFD SP!, {LR} [сохраним адрес возврата в стеке] 0001D844 STMFD SP!, {R0-R3} [сохраним параметры затертой функции] 0001D848 MOV R0, #0xEA [опкод безусловного перехода] 0001D84C LDR R1, =0x18DEF [адрес перехода таймера] 0001D850 STRB R0, [R1] [замена байта в памяти] 0001D854 LDR R1, =0x11147 [адрес вызова диалога] 0001D858 STRB R0, [R1] [замена байта в памяти] 0001D85C LDMFD SP!, {R0-R3} [восстанавливаем параметры функции] 0001D860 BL _cinit [вызов затертой функции] 0001D864 LDMFD SP!, {PC} [возвращаемся обратно] Если выбросить команду «BL _cinit» или заменить ее на какой-либо другой вызов, можно скомпилировать эту программу и таким образом получить опкод. Затем вырезать его в HEX-редакторе и поместить в жертву по уже оговоренному адресу CC40. Разумеется, профессионалы обойдутся и без таких действий и запишут опкод сразу, по памяти. |