好难好难好难。。。
Misc
签到
其实应该是个Web题来着,打开网页容器,如下图。
是个游戏题,那么既然是签到,自然不会太难,所以要么是传分数返回flag,要么是js里就有flag。咱们看一下源码。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <title>拼</title> <link rel="stylesheet" href="style.css"> </head> <body> <div id="photo"> <img src="games/img/geek0/geek.png" class="selected" /> </div> <div class="btn-group"> <input type="button" value="开始游戏" /> </div> <div class="g-box" id="J_layoutBox"> <ul id="box"></ul> </div> <script> var config = { imgPath:'games/' } </script> <script src="game.js"></script> </body> </html>
有一个js,那么看一下js。
/* 拼图小游戏 */ var zIndex = 1; window.onload = function() { var oPhoto = document.getElementById("photo"); var aThumb = oPhoto.getElementsByTagName("img"); var oBox = document.getElementById("box"); var oLayoutBox = document.getElementById("J_layoutBox"); var aLi = oBox.getElementsByTagName("li"); var oInput = document.getElementsByTagName("input")[0]; var i = 0; var imgPath = 0; var oDateStart = null; var aPos = []; var aData = []; for (i = 0; i < 15; i++) aData.push(i + 1); //缩略图 for (i = 0; i < aThumb.length; i++) { aThumb[i].index = i; aThumb[i].onmouseover = function() { this.className += " hover" }; aThumb[i].onmouseout = function() { this.className = this.className.replace(/\shover/, "") }; aThumb[i].onclick = function() { for (i = 0; i < aThumb.length; i++) aThumb[i].className = ""; this.className = "selected"; imgPath = this.index; oBox.innerHTML = ""; oInput.value = "开始游戏"; createMask(); aData.sort(function(a, b) { return a - b }); GAME(false) } } //创建遮罩层 function createMask() { if (document.getElementById('mask')) { return false; } var oMask = document.createElement("div"); oMask.id = "mask"; oMask.style.zIndex = zIndex; oLayoutBox.appendChild(oMask) } createMask(); //游戏处理函数 function GAME(ran) { //随机排列数组 ran && aData.sort(function(a, b) { return Math.random() > 0.5 ? -1 : 1 }); //插入结构 var oFragment = document.createDocumentFragment(); var oLi, row, col; for (i = 0; i < aData.length; i++) { oLi = document.createElement("li"); //使用background方式以减少http请求和减去图片切割步骤 // var oImg = document.createElement("img"); // oImg.src = config.imgPath + "img/geek" + imgPath + "/" + aData[i] + ".png"; // oLi.appendChild(oImg); row = parseInt((aData[i] - 1) / 5); col = parseInt((aData[i] - 1) % 5); oLi.style.backgroundImage = 'url(' + config.imgPath + 'img/geek' + imgPath + '/geek.png)'; oLi.style.backgroundPosition = '-' + col * 82 + 'px -' + row * 190 + 'px'; oLi.setAttribute('data-index', aData[i]); oFragment.appendChild(oLi) } oBox.appendChild(oFragment); oBox.style.background = "url(" + config.imgPath + "img/geek" + imgPath + "/back.png) no-repeat"; //布局转换 for (i = 0; i < aLi.length; i++) { aLi[i].index = i; aLi[i].style.top = aLi[i].offsetTop + "px"; aLi[i].style.left = aLi[i].offsetLeft + "px"; aPos.push({ "left": aLi[i].offsetLeft, "top": aLi[i].offsetTop }) } for (i = 0; i < aLi.length; i++) { aLi[i].style.position = "absolute"; aLi[i].style.margin = "0"; drag(aLi[i]) } //拖拽函数 function drag(obj, handle) { var handle = handle || obj; handle.style.cursor = "move"; handle.onmousedown = function(event) { var event = event || window.event; var disX = event.clientX - this.offsetLeft; var disY = event.clientY - this.offsetTop; var oNear = null; obj.style.zIndex = zIndex++; document.onmousemove = function(event) { var event = event || window.event; var iL = event.clientX - disX; var iT = event.clientY - disY; var maxL = obj.parentNode.clientWidth - obj.offsetWidth; var maxT = obj.parentNode.clientHeight - obj.offsetHeight; iL < 0 && (iL = 0); iT < 0 && (iT = 0); iL > maxL && (iL = maxL); iT > maxT && (iT = maxT); obj.style.left = iL + "px"; obj.style.top = iT + "px"; for (i = 0; i < aLi.length; i++) aLi[i].className = ""; oNear = findNearest(obj); oNear && (oNear.className = "hig"); return false }; document.onmouseup = function() { document.onmousemove = null; document.onmouseup = null; if (oNear) { var tIndex = obj.index; obj.index = oNear.index; oNear.index = tIndex; startMove(obj, aPos[obj.index]); startMove(oNear, aPos[oNear.index], function() { if (finish()) { var iHour = iMin = iSec = 0; var oDateNow = new Date(); var iRemain = parseInt((oDateNow.getTime() - oDateStart.getTime()) / 1000); iHour = parseInt(iRemain / 3600); iRemain %= 3600; iMin = parseInt(iRemain / 60); iRemain %= 60; iSec = iRemain; alert("flag{ed6033f8-8e9a-47c2-87aa-3c2c18abdc6b}\n\n\u7528\u65f6\uff1a" + iHour + "\u5c0f\u65f6" + iMin + "\u5206" + iSec + "\u79d2"); createMask(); } }); oNear.className = ""; } else { startMove(obj, aPos[obj.index]) } handle.releaseCapture && handle.releaseCapture() }; this.setCapture && this.setCapture(); return false } } //找出相遇点中最近的元素 function findNearest(obj) { var filterLi = []; var aDistance = []; for (i = 0; i < aLi.length; i++) aLi[i] != obj && (isButt(obj, aLi[i]) && (aDistance.push(getDistance(obj, aLi[i])), filterLi.push(aLi[i]))); var minNum = Number.MAX_VALUE; var minLi = null; for (i = 0; i < aDistance.length; i++) aDistance[i] < minNum && (minNum = aDistance[i], minLi = filterLi[i]); return minLi } } GAME(); //开始游戏 oInput.onclick = function() { document.getElementById('mask') && oLayoutBox.removeChild(document.getElementById('mask')); oDateStart = new Date(); oBox.innerHTML = ""; this.value = "\u91cd\u65b0\u5f00\u59cb"; GAME(true) }; //判断是否完成 function finish() { var aTemp = []; var success = true; aTemp.length = 0; for (i = 0; i < aLi.length; i++) { for (var j = 0; j < aLi.length; j++) { if (i == aLi[j]["index"]) { // aTemp.push(aLi[j].getElementsByTagName("img")[0].src.match(/(\d+)\./)[1]); aTemp.push(parseInt(aLi[j].getAttribute('data-index'))); } } } for (i = 1; i <= aTemp.length; i++) { if (i != aTemp[i - 1]) { success = false; break } } return success } }; //求两点之间的距离 function getDistance(obj1, obj2) { var a = (obj1.offsetLeft + obj1.offsetWidth / 2) - (obj2.offsetLeft + obj2.offsetWidth / 2); var b = (obj1.offsetTop + obj1.offsetHeight / 2) - (obj2.offsetTop + obj2.offsetHeight / 2); return Math.sqrt(a * a + b * b) } //碰撞检测 function isButt(obj1, obj2) { var l1 = obj1.offsetLeft; var t1 = obj1.offsetTop; var r1 = obj1.offsetLeft + obj1.offsetWidth; var b1 = obj1.offsetTop + obj1.offsetHeight; var l2 = obj2.offsetLeft; var t2 = obj2.offsetTop; var r2 = obj2.offsetLeft + obj2.offsetWidth; var b2 = obj2.offsetTop + obj2.offsetHeight; return !(r1 < l2 || b1 < t2 || r2 < l1 || b2 < t1) } //获取最终样式 function getStyle(obj, attr) { return parseFloat(obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj, null)[attr]) } //运动框架 function startMove(obj, pos, onEnd) { clearInterval(obj.timer); obj.timer = setInterval(function() { doMove(obj, pos, onEnd) }, 30) } function doMove(obj, pos, onEnd) { var iCurL = getStyle(obj, "left"); var iCurT = getStyle(obj, "top"); var iSpeedL = (pos.left - iCurL) / 5; var iSpeedT = (pos.top - iCurT) / 5; iSpeedL = iSpeedL > 0 ? Math.ceil(iSpeedL) : Math.floor(iSpeedL); iSpeedT = iSpeedT > 0 ? Math.ceil(iSpeedT) : Math.floor(iSpeedT); if (pos.left == iCurL && pos.top == iCurT) { clearInterval(obj.timer); onEnd && onEnd() } else { obj.style.left = iCurL + iSpeedL + "px"; obj.style.top = iCurT + iSpeedT + "px"; } }
直接全文搜索一下flag
,就能找到flag。
flag:
flag{ed6033f8-8e9a-47c2-87aa-3c2c18abdc6b}
Reverse
virus
下载得到一个exe, 在ida里打开。
可以发现输入的数据就是最后的flag。
第一次for循环是在分割输入的数据。
for ( i = 0; i < v12; ++i ) { if ( flag[i] == '-' ) { v3 = v14++; *(&v6 + v3) = i; } if ( !v14 ) { *(&v5 + i) = flag[i] - '0'; if ( *(&v5 + i) > 9 || *(&v5 + i) < 0 ) return 0; } }
其中v6数组记录了-
的位置,v14记录了-
的个数,v5数组记录了还没出现-
时的每一个数字。
然后循环结束后,有如下语句:
if ( v14 != 4 ) return 0;
那么说明有4个-
。
然后第二次for循环如下:
for ( i = 1; i <= v14; ++i ) { v11 = *(&v6 + i) - *(&v6 + i - 1) - 1; if ( step[i] != v11 ) return 0; strncpy(&road[200 * i], &flag[*(&v6 + i - 1) + 1], v11); }
循环4次,每次算出v6数组数据前后的差值,然后和step数组进行匹配,最后将-
直接的字符串存到road数组里。其中int step[6] = {0, 19, 25, 26, 28, 0}
。
也就是说flag格式为:flag{一串数字-19个字符-25个字符-26个字符-28个字符}
然后road[200]
/road[400]
/road[600]
/road[800]
分别为19个字符
/25个字符
/26个字符
/28个字符
。
然后接着看下个for循环。
for ( i = 0; i <= 3; ++i ) { if ( check_flag((int)&global_map + 200 * *(&v5 + i), *(&v5 + i), &road[200 * (i + 1)]) ) { puts("How about try again?"); return 0; } if ( i == 3 ) printf("Great! We will defeat it!!! your flag is flag{%s}", flag); }
可见需要验证四个road数组数据,全部通过后即为flag,check_flag
传入的参数分别为global_map[200*v5[0/1/2/3]]
,v5[0/1/2/3]
,road[200/400/600/800]
,其中v5数组即为之前存储的一串数字
,查看一下global_map数组,可以发现存在global_map[0:199/200:399/400:599/600:799/800:999],然后global_map[0:199]又为空数据,所以猜测一串数字
应当以1234
构成,且有四位。
所以check_flag
传入的参数分别为global_map[200/400/600/800]
,1/2/3/4
,road[200/400/600/800]
。
然后观察check_flag
函数。
可以发现处理a3传入的是个switch
分支,所以合法传入应该是[wsad]
,所以猜测可能是个走路游戏,然后ws
是上下走,改动v6,ad
是左右走,改动v5,然后配合下面的20*v6+v5
,猜测v6是行,v5是列,然后地图大小应该是20w10h,所以上面初始化v6、v5用的start数组和dword_403444数组,就是起始位置,v6[]={3,1,1,8}
,v5[]={2,2,11,3}
。
然后又因为下面是与a1核对,所以a1传入的global_map数组就是地图数据,去看一下global_map数组,以20w10h分割,得到如下地图。
global_map[200] 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 73 2E 2E 2E 2E 2E 2E 2E 2E 2E 7C 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 7C 00 00 00 00 00 7C 7C 64 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 7C 00 00 00 00 00 7C 7C 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 7C 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 global_map[400] 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 7C 7C 73 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 64 7C 7C 00 7C 7C 2E 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 2E 2E 7C 7C 00 7C 7C 7C 2E 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 2E 2E 7C 7C 7C 00 7C 7C 7C 7C 2E 2E 7C 7C 7C 7C 7C 7C 7C 2E 2E 7C 7C 7C 7C 00 7C 7C 7C 7C 7C 2E 2E 7C 7C 7C 7C 7C 2E 2E 7C 7C 7C 7C 7C 00 7C 7C 7C 7C 7C 7C 2E 2E 7C 7C 7C 2E 2E 7C 7C 7C 7C 7C 7C 00 7C 7C 7C 7C 7C 7C 7C 2E 2E 7C 2E 2E 7C 7C 7C 7C 7C 7C 7C 00 7C 7C 7C 7C 7C 7C 7C 7C 2E 2E 2E 7C 7C 7C 7C 7C 7C 7C 7C 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 global_map[600] 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 2E 2E 2E 2E 2E 2E 2E 2E 2E 73 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 2E 2E 2E 2E 2E 2E 2E 2E 2E 64 7C 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 global_map[800] 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00 7C 7C 7C 2E 2E 2E 2E 2E 2E 2E 2E 2E 2E 7C 7C 00 00 00 00 00 7C 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 00 00 00 00 00 7C 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 00 00 00 00 00 7C 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 00 00 00 00 00 7C 7C 7C 2E 7C 7C 7C 7C 7C 7C 7C 7C 2E 7C 7C 00 00 00 00 00 7C 7C 7C 73 7C 7C 7C 7C 7C 7C 7C 7C 64 7C 7C 00 00 00 00 00 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 7C 00 00 00 00 00
根据上面的分析,0x73就是起始位置,0x64就是终点位置,然后结合一下以下语句:
if ( *(_BYTE *)(a1 + 20 * v6 + v5) != 0x2E ) return 1;
可以知道0x2E就是路径,所以四张地图的路径分别是dddddddddsssssaaaaaaaaawww
,sdsdsdsdsdsdsddwdwdwdwdwdwdw
,aaaaaaaaasssssssddddddddd
,wwwwwdddddddddsssss
。
又因为flag中的四个路径都有长度要求,所以按照19, 25, 26, 28
的长度来排,就是4312
,那么由于a2传入的就是之前的v5,也就是flag的首段数字,所以为了和地图一一对应,首段即为4312
。
最终拼接即可得到flag。
flag:
flag{4312-wwwwwdddddddddsssss-aaaaaaaaasssssssddddddddd-dddddddddsssssaaaaaaaaawww-sdsdsdsdsdsdsddwdwdwdwdwdwdw}
Comments NOTHING