Новости из Блогов Взлом простых iFrame приложений на примере iГений

Discussion in 'Мировые новости. Обсуждения.' started by Suicide, 26 Sep 2012.

  1. Suicide

    Suicide Super Moderator
    Staff Member

    Joined:
    24 Apr 2009
    Messages:
    2,483
    Likes Received:
    7,072
    Reputations:
    693
    Взлом простых iFrame приложений на примере iГений


    В последнее время развелось множество приложений, основанных на простейших яваскриптах. Пример такого приложения: iГений (глючный клон приложения Pilotter, но людям нравится, т.к. они не знают о нормальной версии этой игры).

    Суть приложения простая: управляя белым квадратом, не дать ему столкнуться с другими фигурами. Нажав ПМК на главное окно приложения, сразу понятно что написано оно на HTML + JS. ВКонтакт позволяет делать только с помощью технологии iFrame, следовательно надо найти адрес фрейма.

    Строчка на яваскрипте и адрес фрейма наш:

    [​IMG]

    Теперь можно перейти к просмотру исходника приложения, там все страшно, и состоит из одного яваскрипт файла, который к нашему счастью не упакован. Прикладываю этот жуткий код ниже, на случай, если он изменится:
    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";
    	}
    }
    и затем сыграть в игру, тут даже комментировать нечего. Получили результат:

    [​IMG]

    2. Подменить функцию подсчета времени.
    В коде выше видно, что finaltime формируется какой-то функцией calctime(), а значит для подмены we need to go deeper. Хотя там тоже все очевидно, функция простым вычитанием генерирует float, который передается в вызов API.
    Я думал что тут все будет сложнее, но нет, внимательный читатель поймет, что делает код и в чем его отличие от оригинального:
    Code:
    calctime = function(){var time = (endtime - starttime - 0)/1000; return time*10000;}
    Играем и получаем что-то типа:

    [​IMG]

    3. Изменить скорость движения фигур
    Из всех предложенных, это самый сложный, но самый красивый вариант. Для этого нам надо понять как устроена игра.
    В самом начале вызывается функция start(), которая запускает рекурсивную функцию movenemies() (по названию понятно, что она двигает другие квадраты, а нам и нужно узнать их движение).
    В этой функции с помощью другой функции rx() генерируются новые координаты квадратов. Теперь точно конец цепочки, нам достаточно поменять rx(), чтобы координаты не менялись:
    Code:
    rx = function() { return 0; }
    После этого все квадраты стоят на месте сколько угодно времени:

    [​IMG]

    Для конца игры нам надо специально врезаться нашим квадратом в другие фигуры.

    Я думаю этих способов хватит, чтобы протянуть 18 секунд, а значит поздравляю с получением статуса гения. :D
    Мораль статьи:

    - Используйте обфускаторы
    - Пишите нормальный код, не завязанный на одних функциях

    Бонус. Четвертый способ изменения таймера
    Раз уж дочитали до сюда, то вот вам бонус: играем в игру, проигрываем, постим на стену и средствами контакта редактируем запись:

    [​IMG]

    22/09/2012
    http://bafoed.net/post/10121/
     
    _________________________
  2. noisees

    noisees New Member

    Joined:
    25 Sep 2012
    Messages:
    3
    Likes Received:
    0
    Reputations:
    0
    Таки есть еще один способ, вполне себе не напряжный)

    Запускаем квадраты эти и сразу жмем Ctrl+Tab.
    После чего ждем то количество времени, какое вам необходимо и переключаемся обратно)
    18 секунд наберете спокойно, пис)

    P.S: Но, иногда не срабатывает)
     
Loading...