Предполагая, что компилятор не пропускает мертвые функции полностью, что он не включает функцию и что вызов не будет проходить через PLT, после компиляции исполняемого файла вы можете просто отредактировать инструкцию вызова.
Обратите внимание, что эти две функции должны быть "совместимыми", где понятие совместимости нечетко, это означает, что "новая должна удовлетворять по крайней мере тем же предположениям, которые компилятор сделал при вызове старой".
ABIконечно, одно из таких предположений, но оно может быть не единственным.
Если ваш компилятор пропустил мертвую функцию, вы не можете переключить функцию (одна отсутствует).
Если ваш компилятор встроил вызов, вы не можете переключить функцию (нет вызова).Вы можете работать против компилятора и переписать код на сайте вызова (в исходном коде C), это называется исправлением.
Если ваш компилятор использовал PLT, вам нужно изменить запись GOT, используемую заглушкой PLT.Возможно, вам придется немного документировать себя, но изменение связанной процедуры на самом деле является особенностью механизма PLT.
Если ваш компилятор ничего не сделал, это должно быть в случае такого простого источника, когда оптимизация не включена, вы можете использовать objdump -d <file>
, чтобы найти сайт вызова и адрес новой функции:
000000000040051d <hello>:
40051d: 55 push %rbp
40051e: 48 89 e5 mov %rsp,%rbp
400521: bf f0 05 40 00 mov $0x4005f0,%edi
400526: b8 00 00 00 00 mov $0x0,%eax
40052b: e8 d0 fe ff ff callq 400400 <printf@plt>
400530: 5d pop %rbp
400531: c3 retq
0000000000400532 <investigate>:
400532: 55 push %rbp
400533: 48 89 e5 mov %rsp,%rbp
400536: bf fd 05 40 00 mov $0x4005fd,%edi
40053b: b8 00 00 00 00 mov $0x0,%eax
400540: e8 bb fe ff ff callq 400400 <printf@plt>
400545: 5d pop %rbp
400546: c3 retq
0000000000400547 <main>:
400547: 55 push %rbp
400548: 48 89 e5 mov %rsp,%rbp
40054b: b8 00 00 00 00 mov $0x0,%eax
400550: e8 c8 ff ff ff callq 40051d <hello>
400555: b8 00 00 00 00 mov $0x0,%eax
40055a: 5d pop %rbp
40055b: c3 retq
40055c: 0f 1f 40 00 nopl 0x0(%rax)
Затем измените непосредственное значение инструкции call
с разницей между целевым адресом и адресом после окончания инструкции call
(не имеет значения, где длина источникакак это одинаково для обоих адресов).
Target = 400532
After the end of call = 400555
Difference = 400532 - 400555 = -23 = 0xFFFFFFDD
Change from:
400550: e8 c8 ff ff ff
to:
400550: e8 dd ff ff ff
Обратите внимание, что непосредственные значения являются младшими знаками конца.
Вы можете использовать гекседитор для редактирования кода, чтобы найти смещение в файле, вы можете использовать эльф-ридер и немного по математике.Вы сами или можете просто искать байты инструкции вызова (проверьте также байты вокруг вызова).
После редактирования был исправлен бинарный файл:
0000000000400532 <investigate>:
400532: 55 push %rbp
400533: 48 89 e5 mov %rsp,%rbp
400536: bf fd 05 40 00 mov $0x4005fd,%edi
40053b: b8 00 00 00 00 mov $0x0,%eax
400540: e8 bb fe ff ff callq 400400 <printf@plt>
400545: 5d pop %rbp
400546: c3 retq
0000000000400547 <main>:
400547: 55 push %rbp
400548: 48 89 e5 mov %rsp,%rbp
40054b: b8 00 00 00 00 mov $0x0,%eax
400550: e8 dd ff ff ff callq 400532 <investigate>
400555: b8 00 00 00 00 mov $0x0,%eax
40055a: 5d pop %rbp
40055b: c3 retq