Когда вы пишете свой первый компилятор для C, вы пишете на другом языке. Теперь у вас есть компилятор для C, скажем, на ассемблере. В конце концов, вы придете к тому месту, где вам придется анализировать строки, особенно экранирующие последовательности. Вы напишите код для преобразования \n
в символ с десятичным кодом 10 (и \r
в 13 и т. Д.).
После того, как этот компилятор готов, вы начнете переопределять его в C. Этот процесс называется " bootstrapping ".
Код разбора строки станет:
...
if (c == 92) { // backslash
c = getc();
if (c == 110) { // n
return 10;
} else if (c == 92) { // another backslash
return 92;
} else {
...
}
}
...
Когда это компилируется, у вас есть двоичный файл, который понимает '\ n'. Это означает, что вы можете изменить исходный код:
...
if (c == '\\') {
c = getc();
if (c == 'n') {
return '\n';
} else if (c == '\\') {
return '\\';
} else {
...
}
}
...
Так где же информация о том, что \ n - это код для 13? Это в двоичном коде! Это похоже на ДНК: компиляция исходного кода C с этим двоичным файлом унаследует эту информацию. Если компилятор сам компилируется, он передает эти знания своим потомкам. С этого момента нет никакого способа увидеть из одного источника, что будет делать компилятор.
Если вы хотите спрятать вирус в исходном коде какой-либо программы, вы можете сделать это следующим образом: получить исходный код компилятора, найти функцию, которая компилирует функции, и заменить ее следующим:
void compileFunction(char * name, char * filename, char * code) {
if (strcmp("compileFunction", name) == 0 && strcmp("compile.c", filename) == 0) {
code = A;
} else if (strcmp("xxx", name) == 0 && strcmp("yyy.c", filename) == 0) {
code = B;
}
... code to compile the function body from the string in "code" ...
}
Интересными частями являются A и B. A является исходным кодом для compileFunction
, включая вирус, вероятно, каким-то образом зашифрованным, так что это не очевидно из поиска в полученном двоичном файле. Это гарантирует, что компиляция с самим компилятором сохранит код внедрения вируса.
B - то же самое для функции, которую мы хотим заменить нашим вирусом. Например, это может быть функция «login» в исходном файле «login.c», которая, вероятно, из ядра Linux. Мы могли бы заменить его версией, которая будет принимать пароль «joshua» для учетной записи root в дополнение к обычному паролю.
Если вы скомпилируете это и распространите в виде бинарного файла, вы не сможете найти вирус, посмотрев на источник.
Первоначальный источник идеи: http://cm.bell -labs.com / who / ken / trust.html