Метапрограммирование — создание программ, которые создают другие программы как результат своей работы (либо — частный случай — изменяющие или дополняющие себя во время выполнения).
Квайн — программа выдающая на выходе точную копию своего исходного текста.
var a='alert("var a="+String.fromCharCode(39)+a+String.fromCharCode(39)+";eval(a);")';eval(a);
В окошке alert получим свой исходник. Существуют и другие возможности распечатать свой исходник с помощью особенностей реализации конкретного языка, но в виду неуниверсальности, мы их не рассматриваем.
Самомодифицирующийся код.
Получен путем нехитрых манипуляций с предыдущим квайном. Версия каждой последующей копии будет на единицу больше версии «родителя».
var a='alert("Версия: 1");alert("var a="+String.fromCharCode(39)+a.substring(0,15) +(parseFloat(a.charAt(15))+1)+a.substring(16) +String.fromCharCode(39)+";eval(a);")';eval(a);
В зависимости от поставленной задачи можно изменять свойства и логику поведения создаваемых программ, применять обфускацию или шифрование, а так же полиморфизм.
Полиморфный код
После запуска, он выведет в окно браузера рабочую зашифрованную копию себя. Копия каждый раз будет полностью отличной от предыдущей.
z100 = '\
\
/* Инициализация счетчика для имен */\
var nc = Math.floor(Math.random()*10);\
\
/* Создание случайного имени (случайная буква[a-z] + счетчик) */\
function rv() {\
nc++;\
return String.fromCharCode(Math.floor(Math.random()*26)+97)+nc.toString();\
}\
\
/* Загружаем в `a` свой собственный код */\
var a = z100;\
\
/* Генерим имя переменной, которая окажется в eval`е потомка */\
var sn = rv();\
\
/* Подменяем в коде потомка имя переменной для eval`a на новое */\
a = a.replace(/var a = .+?;/, "var a = "+sn+";");\
\
/* Шифрование потомка. \
Исходный код разбивается на строки случайной длины, \
которые затем сохраняются в случайные переменные и \
конкатенируются. В финале мы должны получить код в \
переменной, которая попадет в eval\
*/\
var s = "";\
var vars = new Array();\
var slen;\
var tn;\
var ss;\
var ft = 1;\
while (a) {\
slen = Math.floor(Math.random()*3)+1;\
if (a.length < slen) slen = a.length;\
ss = String.fromCharCode(39)+a.substring(0,slen)+String.fromCharCode(39);\
if (Math.random() > 0.5) {\
if (vars.length > 0) {\
tn = vars.pop();\
s+=tn+"+="+ss+";";\
vars.push(tn);\
s+=sn+(ft?"":"+")+"="+vars.shift();\
} else {\
s+=sn+(ft?"":"+")+"="+ss;\
}\
ft = 0;\
} else {\
tn = rv();\
vars.push(tn);\
s+=tn+"="+ss;\
}\
s+=";";\
a = a.substring(slen);\
}\
while (vars.length) {\
s+=sn+(ft?"":"+")+"="+vars.shift()+";";\
ft = 0;\
}\
\
/* Выводим потомка в окно браузера, не забывая подменить переменную в eval`e */\
document.write(s+"eval("+sn+");");\
';
// Точка входа :-)
eval(z100);