Взлом простых iFrame приложений на примере iГений В последнее время развелось множество приложений, основанных на простейших яваскриптах. Пример такого приложения: iГений (глючный клон приложения Pilotter, но людям нравится, т.к. они не знают о нормальной версии этой игры). Суть приложения простая: управляя белым квадратом, не дать ему столкнуться с другими фигурами. Нажав ПМК на главное окно приложения, сразу понятно что написано оно на HTML + JS. ВКонтакт позволяет делать только с помощью технологии iFrame, следовательно надо найти адрес фрейма. Строчка на яваскрипте и адрес фрейма наш: Теперь можно перейти к просмотру исходника приложения, там все страшно, и состоит из одного яваскрипт файла, который к нашему счастью не упакован. Прикладываю этот жуткий код ниже, на случай, если он изменится: Code: isNS4 = (document.layers) ? true : false; isIE4 = (document.all && !document.getElementById) ? true : false; isIE5 = (document.all && document.getElementById) ? true : false; isNS6 = (!document.all && document.getElementById) ? true : false; var curX, curY, curX2, curY2, boxX, boxY, moving=0, touch=0, tmp, tmp2; var gametime=0, started=0, speed=50, next=5; var starttime, endtime, finaltime=0; var enemyxdir = new Array(1,1,1,1); var enemyydir = new Array(1,1,1,1); var x1, y1, x2, y2, x3, y3, x4, y4, gen; var sdvigX, sdvigY; if (isNS4 || isNS6){ document.captureEvents(Event.MOUSEUP|Event.MOUSEDOWN|Event.MOUSEMOVE); } document.onmousemove = checkLocation; document.onmouseup = stop; function startclock(){var today = new Date(); starttime = today.getTime();} function endclock(){var today = new Date(); endtime = today.getTime();} function calctime(){var time = (endtime - starttime - 0)/1000; return time;} function giveposX(divname){ if (isNS4) var posLeft = document.layers[divname].left; else if (isIE4 || isIE5) var posLeft = document.all(divname).style.pixelLeft; else if (isNS6) var posLeft = parseInt(document.getElementById(divname).style.left + ""); return posLeft; } function giveposY(divname){ if (isNS4) var posTop = document.layers[divname].top; else if (isIE4 || isIE5) var posTop = document.all(divname).style.pixelTop; else if (isNS6) var posTop = parseInt(document.getElementById(divname).style.top + ""); return posTop; } function setposX(divname, xpos){ if (isNS4) document.layers[divname].left = xpos; else if (isIE4 || isIE5) document.all(divname).style.pixelLeft = xpos; else if (isNS6) document.getElementById(divname).style.left = xpos; } function setposY(divname, ypos){ if (isNS4) document.layers[divname].top = ypos; else if (isIE4 || isIE5) document.all(divname).style.pixelTop = ypos; else if (isNS6) document.getElementById(divname).style.top = ypos; } function givesize(divname, dimension){ var divsize = 0; if (dimension == 'y') { if (isNS4) divsize = document.layers[divname].clip.height; else if (isIE4 || isIE5) divsize = document.all(divname).style.pixelHeight; else if (isNS6) divsize = parseInt(document.getElementById(divname).style.height + ""); } else if (dimension == 'x') { if (isNS4) divsize = document.layers[divname].clip.width; else if (isIE4 || isIE5) divsize = document.all(divname).style.pixelWidth; else if (isNS6) divsize = parseInt(document.getElementById(divname).style.width + ""); } return divsize; } function checktouching(num) { var enemy = "enemy" + num + ""; var difX = giveposX('box') - giveposX(enemy) - 0; var difY = giveposY('box') - giveposY(enemy) - 0; if (difX > (-1 * givesize('box', 'x')) && difX < givesize(enemy, 'x') && difY > (-1 * givesize('box', 'y')) && difY < givesize(enemy, 'y')) { touch = 1; } else touch = 0; } function movenemy(num,step_x,step_y){ var enemy = "enemy" + num + ""; var enemyx = givesize(enemy, 'x'); var enemyy = givesize(enemy, 'y'); if (giveposX(enemy) >= (550 - enemyx) || giveposX(enemy) <= 0) { enemyxdir[num] = -1 * enemyxdir[num]; } if (giveposY(enemy) >= (550 - enemyy) || giveposY(enemy) <= 0) { enemyydir[num] = -1 * enemyydir[num]; } var newposx = giveposX(enemy) + (step_x*enemyxdir[num]) + 0; var newposy = giveposY(enemy) + (step_y*enemyydir[num]) + 0; setposX(enemy, newposx); setposY(enemy, newposy); checktouching(num + ""); if (touch == 1) { stop(); reset(); } } function rand(number) { return Math.ceil(Math.random()*number); } function rt() { return rand(30) - 13; } function rx(){ tmp = rt(); while (Math.abs(tmp) < 3) { tmp = rt(); } return tmp; } function movenemies() { endclock(); ptim = ((endtime - starttime - 0)/1000); if(ptim > 0){ print_t = ptim + ""; print_t = print_t.split('.'); document.getElementById("print_time_1").innerHTML = print_t[0]; document.getElementById("print_time_2").innerHTML = print_t[1]; } gametime = gametime + 1 next = next + 1; if ((next == 10)&(speed>1)) { speed = speed - 1; next = 0; } if (speed < 1){ speed = 1; } if (gen != 1) { x1 = rx(); y1 = rx(); x2 = rx(); y2 = rx(); x3 = rx(); y3 = rx(); x4 = rx(); y4 = rx(); gen = 1; } movenemy(0,x1,y1); movenemy(1,x2,y2); movenemy(2,x3,y3); movenemy(3,x4,y4); setTimeout(movenemies,speed); } function start(e) { if (started == 0) { movenemies(); startclock(); started = 1; } curX = (isNS4 || isNS6) ? e.pageX : window.event.x; curY = (isNS4 || isNS6) ? e.pageY : window.event.y; curX2 = eval(curX - 40); curY2 = eval(curY - 40); boxX = eval(curX - 20); boxY = eval(curY - 20); var boxleft = giveposX('box'); var boxtop = giveposY('box'); sdvigX = boxX - boxleft; sdvigY = boxY - boxtop; if ((curX - sdvigX) > boxleft && (curX2 - sdvigX) < boxleft && (curY - sdvigY) > boxtop && (curY2 - sdvigY) < boxtop) { moving = 1; setposX('box', boxX - sdvigX); setposY('box', boxY - sdvigY); if (isNS4 || isNS6){ document.captureEvents(Event.MOUSEMOVE); } } } function stop(e){ moving=0; if (isNS4 || isNS6){ document.releaseEvents(Event.MOUSEMOVE); } } function reset(e){ endclock(); moving=0; if (isNS4 || isNS6){ document.releaseEvents(Event.MOUSEMOVE); } if (finaltime == 0) { finaltime = calctime(); VK.api('wall.post', {message: "Мой результат: "+finaltime+" секунд! Слабо больше? Если продержишься 18 секунд - ты гений! Заходи: http://vk.com/app3103965", attachments: "photo115944705_288812188"}); setInterval('document.location.reload()', 1000); throw "stop"; } } function checkLocation(e){ curX = (isNS4 || isNS6) ? e.pageX : window.event.x; curY = (isNS4 || isNS6) ? e.pageY : window.event.y; boxX = eval(curX - 20); boxY = eval(curY - 20); checktouching('1'); if (moving == 1 && touch == 0){ setposX('box',boxX - sdvigX); setposY('box',boxY - sdvigY); if ((curY - sdvigY) > 69 && (curX - sdvigX) > 69 && (curY - sdvigY) < 481 && (curX - sdvigX) < 481) return false; else stop(); reset(); } else if (touch == 1){ stop(); reset(); } } Тут происходит множество непонятных вещей и желания вникать в них у меня совершенно нет. Нас интересует постинг на стену нашего результата. Варианты, как это можно подменить (в порядке увеличения сложности): -Подменить непосредственно вызов функции VK.API -Подменить функцию подсчета времени -Изменить скорость движения фигур Давайте разберем каждый из способов. Для каждого из них нам понадобится отладчик в браузере. В Chrome он встроен (Ctrl + Shift + J), в Opera тоже, в FF есть плагин FireBug. Для отладки кода я открывал скрипт в отладчике основной файл игры, ставил брекпоинты на первую строчку и через консоль вводил нужный мне код. 1. Подмена вызова функции VK.API. Нетрудно заметить, что конечный ответ формируется одной строчкой под номером 166-167. Эти строчки находятся в функции reset, наличие отладчика в браузере позволяет ее без проблем заменить. В конечном итоге достаточно вбить в консоль: Code: reset = function(e){ endclock(); moving=0; if (isNS4 || isNS6){ document.releaseEvents(Event.MOUSEMOVE); } if (finaltime == 0) { finaltime = calctime(); VK.api('wall.post', {message: "Мой результат: 1500.151 секунд! Слабо больше? Если продержишься 18 секунд - ты гений! Заходи: http://vk.com/app3103965", attachments: "photo115944705_288812188"}); setInterval('document.location.reload()', 1000); throw "stop"; } } и затем сыграть в игру, тут даже комментировать нечего. Получили результат: 2. Подменить функцию подсчета времени. В коде выше видно, что finaltime формируется какой-то функцией calctime(), а значит для подмены we need to go deeper. Хотя там тоже все очевидно, функция простым вычитанием генерирует float, который передается в вызов API. Я думал что тут все будет сложнее, но нет, внимательный читатель поймет, что делает код и в чем его отличие от оригинального: Code: calctime = function(){var time = (endtime - starttime - 0)/1000; return time*10000;} Играем и получаем что-то типа: 3. Изменить скорость движения фигур Из всех предложенных, это самый сложный, но самый красивый вариант. Для этого нам надо понять как устроена игра. В самом начале вызывается функция start(), которая запускает рекурсивную функцию movenemies() (по названию понятно, что она двигает другие квадраты, а нам и нужно узнать их движение). В этой функции с помощью другой функции rx() генерируются новые координаты квадратов. Теперь точно конец цепочки, нам достаточно поменять rx(), чтобы координаты не менялись: Code: rx = function() { return 0; } После этого все квадраты стоят на месте сколько угодно времени: Для конца игры нам надо специально врезаться нашим квадратом в другие фигуры. Я думаю этих способов хватит, чтобы протянуть 18 секунд, а значит поздравляю с получением статуса гения. Мораль статьи: - Используйте обфускаторы - Пишите нормальный код, не завязанный на одних функциях Бонус. Четвертый способ изменения таймера Раз уж дочитали до сюда, то вот вам бонус: играем в игру, проигрываем, постим на стену и средствами контакта редактируем запись: 22/09/2012 http://bafoed.net/post/10121/
Таки есть еще один способ, вполне себе не напряжный) Запускаем квадраты эти и сразу жмем Ctrl+Tab. После чего ждем то количество времени, какое вам необходимо и переключаемся обратно) 18 секунд наберете спокойно, пис) P.S: Но, иногда не срабатывает)