好难好难好难。。。
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