З мовами віртуальної машини на основі байт-кодів, таких як Java, VB.NET, C #, ActionScript 3.0 тощо, ви іноді чуєте про те, як легко просто завантажити декомпілятор з Інтернету, запустити байт-код через нього один раз і Часто придумай щось не надто далеко від початкового вихідного коду за лічені секунди. Імовірно, така мова є особливо вразливою до цього.
Нещодавно я почав цікавитись, чому ви більше не чуєте про це щодо рідного двійкового коду, коли ви принаймні знаєте, на якій мові він був написаний оригінально (і, таким чином, на яку мову спробувати декомпілювати). Довгий час я вважав, що це просто тому, що рідна машина машини настільки шаленіша і складніша, ніж типовий байт-код.
Але як виглядає байт-код? Це виглядає приблизно так:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
А як виглядає нативний машинний код (у шістнадцятковій формі)? Це, звичайно, виглядає приблизно так:
1000: 2A 40 F0 14
1001: 2A 50 F1 27
1002: 4F 00 F0 F1
1003: C9 00 00 F2
І інструкції виходять із дещо схожого настрою:
1000: mov EAX, 20
1001: mov EBX, loc1
1002: mul EAX, EBX
1003: push ECX
Отже, з огляду на мову, щоб спробувати декомпілювати якийсь рідний бінарний код, скажімо, на C ++, що так важко в цьому? Єдині дві ідеї, які одразу приходять до тями, - це 1) це насправді набагато складніше, ніж байт-код, або 2) щось про те, що операційні системи, як правило, пакутують програми та розкидають їх частини, викликає занадто багато проблем. Якщо одна з цих можливостей правильна, поясніть, будь ласка. Але так чи інакше, чому ви ніколи не чуєте про це в основному?
ПРИМІТКА
Я збираюся прийняти одну з відповідей, але хочу спочатку щось згадати. Практично всі посилаються на те, що різні фрагменти вихідного вихідного коду можуть відображати один і той же машинний код; локальні назви змінних втрачаються, ви не знаєте, який тип циклу спочатку використовувався тощо.
Однак приклади на кшталт двох, що були згадані, в моїх очах начебто тривіальні. Деякі відповіді хоч і стверджують, що різниця між машинним кодом та оригінальним джерелом суттєво значно більша, ніж щось таке тривіальне.
Але, наприклад, коли мова йде про такі речі, як імена локальних змінних і типи циклів, байткод також втрачає цю інформацію (принаймні, для ActionScript 3.0). Я вже витягував цей матеріал назад через декомпілятор, і мені було зовсім неважливо, чи називалася змінна strMyLocalString:String
чи loc1
. Я все ще міг заглянути в той невеликий локальний обсяг і побачити, як він використовується без особливих проблем. І for
цикл - це майже те саме, що і awhile
петля, якщо ви подумаєте про це. Крім того, навіть коли я би запускав джерело через irrFuscator (який, на відміну від secureSWF, не робить багато більше, ніж просто рандомізувати змінну члена та імена функцій), все одно виглядало так, що ви можете просто почати ізолювати певні змінні та функції в менших класах, малюнок дізнайтеся, як вони використовуються, призначте їм власні імена та працюйте звідти.
Для того, щоб це було великою справою, машинному коду потрібно було б втратити набагато більше інформації, ніж це, і деякі відповіді все ж впадають у це.