Як вказував Олі вже у своїй відповіді, ви не можете отримати дуже оригінальний вихідний код виконуваного файлу.
Під час компіляції вихідного коду (компіляція призначена як типово більш широке прийняття, отже, як весь процес, який "перетворює" вихідний код у виконуваний файл), багато інформації втрачається.
Препроцесор C, наприклад, зробить наступне (серед іншого):
- Інтерпретація, виконання та видалення директив (
#
операторів) препроцесора
- Видалити коментарі
- Видаліть зайвий пробіл
З іншого боку, те, що не втрачається під час компіляції вихідного коду, технічно перетворюється на функціонально еквівалентний вихідний код.
Це відбувається тому:
- Бінарні інструкції мають відповідність 1: 1 із інструкціями щодо складання; складання вихідного коду збірки - це лише просте перетворення інструкцій складання у бінарні інструкції на основі таблиці корисних можливостей; одна двійкова інструкція завжди може бути ідентифікована і перетворювана на одну інструкцію зі складання ;
- Інструкції по збірці не мають 1: 1 відповідальності з інструкціями C; компіляція вихідного коду С зазвичай не є просто перетворенням інструкцій С до інструкцій по збірці на основі таблиці корисних можливостей, адже це часто навпаки; зазвичай інструкція C перетворюється на кілька (часто різні за залежністю від компілятора) інструкцій по збірці; однак шаблони декількох інструкцій зі складання зазвичай можна ідентифікувати та перетворювати на одну інструкцію C ;
Є інструменти, звані декомпілятори, мета яких - спробувати повернути виконуваний файл у функціонально еквівалентний вихідний код; однак результат зазвичай є чимось далеким від самого оригінального вихідного коду (і, як правило, також неможливий);
Розглянемо цю програму:
#include <stdio.h>
#define MESSAGE "Literal strings will be recovered" // This preprocessor directive won't be recovered
/*
This comment and the comment above won't be recovered
*/
int main(int argc, char* argv[]) {
printf(MESSAGE);
return 0;
}
Скомпілювавши його у виконуваний файл і повторно розклавши його у вихідний код, це більш-менш те, що ви зазвичай отримуєте назад (у цьому конкретному випадку я використовував gcc
/ Бумеранг ):
// address: 0x80483fb
int main(int argc, char **argv, char **envp) {
printf("Literal strings will be recovered");
return 0;
}
Як і передбачалося:
- Директиви щодо препроцесора відсутні
- Коментарі відсутні (крім того
// address: 0x80483fb
, який додав декомпілятор)
- Не вистачає непотрібного простору (окрім нових рядків і таблиць, доданих декомпілятором)
Це також досить непоганий результат; не рідко можна отримати в код вбудовані інструкції зі складання:
asm("assembly_instruction");
__asm__("assembly_instruction");
Підсумковий рядок (як уже вказувалося в інших відповідях): ви не можете отримати саме оригінальне джерело виконуваного файлу *.
* Тим НЕ менше, в залежності від виконуваного файлу і від вашої удачі, ви могли б бути в змозі отримати що - то з допомогою декомпілятори.
strings
програма фільтра може бути дуже корисною для визначення того, що конкретна бінарна програма чи робить, оскільки вона буде друкувати всі вбудовані текстові рядки довше вказаної довжини в двійковий файл і перегляд повідомлень у програмі іноді багато що розповідає про те, що це і що робиться.