攻防世界逆向高手题之secret-string-400
继续开启全栈梦想之逆向之旅~ 这题是攻防世界逆向高手题的secret-string-400 下载附件,照例扔入exeinfope中查看信息: 一开始愣了一下,后来发现是压缩包啊,然后继续进一步解压: 一个html和配套js,看起来想我前面做的密码学,毕竟密码学和逆向是相通的嘛。 可以看出html调用了js的check函数,而check函数好像有一个machine类和一堆预定义参数,然后就执行run了。 . . 在继续跟踪途中,如第一个红框所示,machine是一个函数,然后第二个红框中的run也是一个函数,第三个红框中command调用了调用了parsecommand函数,parsecommand中文是解析命令,这里是一个中文类暗示,但是我一开始并没有看懂。parsecommand跟踪下去发现是一堆连续的调用,基本把整个js剩下的函数都串起来了,逆向起来相当麻烦。
. 下图中Loadcode函数对应一开始的check函数之一,js中只有这一个loadcode函数,就一个预先赋值和,但是这里code中文是代码的意思,一开始我还是没看出来。 . . 由于我不太懂js,所以这些线索我都没法串起来,我甚至不知道输入关键字Input在哪里。 . . (这里积累第一个经验) 没办法了,查了资料,才发现这machine是虚拟机,一开始的loadcode这预加载列表的确有意义,但不是ascii码,所以看不懂,这些是字节码,用于给后面opcodes转化的,检查输入的关键字符Input在转换字节码后的代码里,不在这里。
查看到文件时一个简单的虚拟机,需要了解到所有的opcodes的意义,并且将字节码转化为可读的代码,或者替换run函数来跟踪进我们的程序:
可以看出是个设计了个虚拟机,虚拟机的指令和数据来自 machine.loadcode() 。调试可以发现,其实现原理是根据不同的Opcodes,进行特定的操作,而这些操作是通过js下的 eval() 来执行。loadcode() 里面有不少明文
说到这里基本就可以理清了,opcodes函数把Loadcode中的预加载字符字节码转化为代码,然后才执行run,关键代码就在经过opcodes转化后的字节码中。
有两种方法获取字节码转换后的代码。
(这里积累第二个经验) 第一种方法,直接转换字节码,我也是第一次知道可以直接用bytes函数把字节码直接转换为字节串的,也是开了眼界。bytes函数是以字节序列二进制的形式表示字节串,以字节为单位。可能对得上字节码吧。
print(bytes([11, 1, 79, 98, 106, 101, 99, 116, 0, 12, 1, 120, 0, 114, 101, 116, 117, 114, 110, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 103, 101, 116, 69, 108, 101, 109, 101, 110, 116, 115, 66, 121, 84, 97, 103, 78, 97, 109, 101, 40, 39, 105, 110, 112, 117, 116, 39, 41, 91, 48, 93, 46, 118, 97, 108, 117, 101, 47, 47, 0, 15, 3, 1, 120, 0, 14, 3, 1, 117, 115, 101, 114, 105, 110, 112, 117, 116, 0, 12, 1, 121, 0, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 101, 110, 100, 32, 61, 32, 102, 117, 110, 99, 116, 105, 111, 110, 40, 41, 123, 116, 104, 105, 115, 46, 99, 111, 100, 101, 61, 91, 93, 59, 116, 104, 105, 115, 46, 80, 67, 61, 49, 55, 51, 125, 47, 47, 0, 15, 3, 1, 121, 0, 12, 1, 122, 0, 97, 108, 101, 114, 116, 40, 49, 41, 59, 47, 47, 11, 234, 79, 98, 106, 101, 99, 116, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 50, 41, 59, 47, 47, 12, 234, 120, 255, 118, 97, 114, 32, 102, 61, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 114, 101, 103, 105, 115, 116, 101, 114, 115, 91, 49, 93, 46, 117, 115, 101, 114, 105, 110, 112, 117, 116, 47, 47, 10, 118, 97, 114, 32, 105, 32, 61, 32, 102, 46, 108, 101, 110, 103, 116, 104, 47, 47, 10, 118, 97, 114, 32, 110, 111, 110, 99, 101, 32, 61, 32, 39, 103, 114, 111, 107, 101, 39, 59, 47, 47, 10, 118, 97, 114, 32, 106, 32, 61, 32, 48, 59, 47, 47, 10, 118, 97, 114, 32, 111, 117, 116, 32, 61, 32, 91, 93, 59, 47, 47, 10, 118, 97, 114, 32, 101, 113, 32, 61, 32, 116, 114, 117, 101, 59, 47, 47, 10, 119, 104, 105, 108, 101, 40, 106, 32, 60, 32, 105, 41, 123, 47, 47, 10, 111, 117, 116, 46, 112, 117, 115, 104, 40, 102, 46, 99, 104, 97, 114, 67, 111, 100, 101, 65, 116, 40, 106, 41, 32, 94, 32, 110, 111, 110, 99, 101, 46, 99, 104, 97, 114, 67, 111, 100, 101, 65, 116, 40, 106, 37, 53, 41, 41, 47, 47, 10, 106, 43, 43, 59, 47, 47, 10, 125, 47, 47, 10, 118, 97, 114, 32, 101, 120, 32, 61, 32, 32, 91, 49, 44, 32, 51, 48, 44, 32, 49, 52, 44, 32, 49, 50, 44, 32, 54, 57, 44, 32, 49, 52, 44, 32, 49, 44, 32, 56, 53, 44, 32, 55, 53, 44, 32, 53, 48, 44, 32, 52, 48, 44, 32, 51, 55, 44, 32, 52, 56, 44, 32, 50, 52, 44, 32, 49, 48, 44, 32, 53, 54, 44, 32, 53, 53, 44, 32, 52, 54, 44, 32, 53, 54, 44, 32, 54, 48, 93, 59, 47, 47, 10, 105, 102, 32, 40, 101, 120, 46, 108, 101, 110, 103, 116, 104, 32, 61, 61, 32, 111, 117, 116, 46, 108, 101, 110, 103, 116, 104, 41, 32, 123, 47, 47, 10, 106, 32, 61, 32, 48, 59, 47, 47, 10, 119, 104, 105, 108, 101, 40, 106, 32, 60, 32, 101, 120, 46, 108, 101, 110, 103, 116, 104, 41, 123, 47, 47, 10, 105, 102, 40, 101, 120, 91, 106, 93, 32, 33, 61, 32, 111, 117, 116, 91, 106, 93, 41, 47, 47, 10, 101, 113, 32, 61, 32, 102, 97, 108, 115, 101, 59, 47, 47, 10, 106, 32, 43, 61, 32, 49, 59, 47, 47, 10, 125, 47, 47, 10, 105, 102, 40, 101, 113, 41, 123, 47, 47, 10, 97, 108, 101, 114, 116, 40, 39, 89, 79, 85, 32, 87, 73, 78, 33, 39, 41, 59, 47, 47, 10, 125, 101, 108, 115, 101, 123, 10, 97, 108, 101, 114, 116, 40, 39, 78, 79, 80, 69, 33, 39, 41, 59, 10, 125, 125, 101, 108, 115, 101, 123, 97, 108, 101, 114, 116, 40, 39, 78, 79, 80, 69, 33, 39, 41, 59, 125, 47, 47, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 51, 41, 59, 47, 47, 15, 1, 234, 120, 255, 9, 255, 255, 255, 12, 10, 97, 108, 101, 114, 116, 40, 52, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 53, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 54, 41, 59, 47, 47, 10, 97, 108, 101, 114, 116, 40, 55, 41, 59, 47, 47, 0, 12, 1, 103, 0, 118, 97, 114, 32, 105, 32, 61, 48, 59, 119, 104, 105, 108, 101, 40, 105, 60, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 46, 108, 101, 110, 103, 116, 104, 41, 123, 105, 102, 40, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 91, 105, 93, 32, 61, 61, 32, 50, 53, 53, 32, 41, 32, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 99, 111, 100, 101, 91, 105, 93, 32, 61, 32, 48, 59, 105, 43, 43, 125, 47, 47, 0, 12, 1, 104, 0, 119, 105, 110, 100, 111, 119, 46, 109, 97, 99, 104, 105, 110, 101, 46, 80, 67, 61, 49, 55, 50, 47, 47, 0, 15, 0, 1, 103, 0, 15, 0, 1, 104, 0]).split(b’\x00’))
这里.split(b’\x00’)是为了分隔字符,如果没有它就会这样: 用.split(b’\x00’)分隔后就没有这些混淆符了: 依稀可以看出代码就在上面,整理后就是:(input关键字也在这里面)
[b'\x0b\x01Object',
b'\x0c\x01x',
b"return document.getElementsByTagName('input')[0].value//",
b'\x0f\x03\x01x',
b'\x0e\x03\x01userinput',
b'\x0c\x01y',
b'window.machine.end = function(){this.code=[];this.PC=173}//',
b'\x0f\x03\x01y',
b'\x0c\x01z',
b"alert(1);//\x0b\xeaObject\xff\t\xff\xff\xff\x0c\nalert(2);//\x0c\xeax\xffvar
f=window.machine.registers[1].userinput//\nvar i = f.length//\nvar nonce =
'groke';//\nvar j = 0;//\nvar out = [];//\nvar eq = true;//\nwhile(j < i)
{//\nout.push(f.charCodeAt(j) ^ nonce.charCodeAt(j%5))//\nj++;//\n}//\nvar ex =
[1, 30, 14, 12, 69, 14, 1, 85, 75, 50, 40, 37, 48, 24, 10, 56, 55, 46, 56,
60];//\nif (ex.length == out.length) {//\nj = 0;//\nwhile(j < ex.length)
{//\nif(ex[j] != out[j])//\neq = false;//\nj += 1;//\n}//\nif(eq){//\nalert('YOU
WIN!');//\n}else{\nalert('NOPE!');\n}}else{alert('NOPE!');}//\xff\t\xff\xff\xff\
x0c\nalert(3);//\x0f\x01\xeax\xff\t\xff\xff\xff\x0c\nalert(4);//\nalert(5);//\na
lert(6);//\nalert(7);//",
b'\x0c\x01g',
b'var i =0;while(i<window.machine.code.length){if(window.machine.code[i] == 255
) window.machine.code[i] = 0;i++}//',
b'\x0c\x01h',
b'window.machine.PC=172//',
b'\x0f',
b'\x01g',
b'\x0f',
b'\x01h',
b'']
f = window.machine.registers[1].userinput//
var i = f.length
var nonce = 'groke';
var j = 0;
var out = [];
var eq = true;
while (j < i) {
out.push(f.charCodeAt(j) ^ nonce.charCodeAt(j % 5))
j++;
}
var ex = [1, 30, 14, 12, 69, 14, 1, 85, 75, 50, 40, 37, 48, 24, 10, 56, 55, 46,
56, 60];
if (ex.length == out.length) {
j = 0;
while (j < ex.length) {
if (ex[j] != out[j])
eq = false;
j += 1;
}
if (eq) {
alert('YOU WIN!');
} else {
alert('NOPE!');
}
} else {
alert('NOPE!');
}
. . 逻辑很简单,直接给逆向脚本:
key1=[1, 30, 14, 12, 69, 14, 1, 85, 75, 50, 40, 37, 48, 24, 10, 56, 55, 46, 56, 60]
key2="groke"
flag=""
for i in range(len(key1)):
flag+=chr(key1[i]^ord(key2[i%5]))
print(flag)
结果:
. . 第二种方法,在调用完opcodes后(即字节码转换完代码后)把代码导出来到控制台上:(js日常控制台操作)
(这里积累第三个经验) 前面我们说check函数中Loadcode导入预加载列表后就执行run函数了,查看run函数中发现parsecommand.call函数是多层调用和嵌套函数,把所有的opcodes函数串起来执行了,也就是这个command变量接受了字节码经opcodes函数转换后的代码,然后才用下面的command.execute来执行代码。 所以我们用console.log(变量.args)导出变量内容,可以在源码中添加,也可以在浏览器F12的source中添加。(我也不知道为什么console.log(command.args)中要加args这个属性,可能变量.args才能导出变量内容吧。) 在控制台console窗口中一堆折叠数据中逐个展开,双击查看代码即可发现最长的就是字节码转换后的代码。
. . 总结:
1: (这里积累第一个经验) 没办法了,查了资料,才发现这machine是虚拟机,一开始的loadcode这预加载列表的确有意义,但不是ascii码,所以看不懂,这些是字节码,用于给后面opcodes转化的,检查输入的关键字符Input在转换字节码后的代码里,不在这里。
2: (这里积累第二个经验) 第一种方法,直接转换字节码,我也是第一次知道可以直接用bytes函数把字节码直接转换为字节串的,也是开了眼界。bytes函数是以字节序列二进制的形式表示字节串,以字节为单位。可能对得上字节码吧。
3: 第二种方法,在调用完opcodes后(即字节码转换完代码后)把代码导出来到控制台上:(js日常控制台操作)
(这里积累第三个经验) 前面我们说check函数中Loadcode导入预加载列表后就执行run函数了,查看run函数中发现parsecommand.call函数是多层调用和嵌套函数,把所有的opcodes函数串起来执行了,也就是这个command变量接受了字节码经opcodes函数转换后的代码,然后才用下面的command.execute来执行代码。 所以我们用console.log(变量.args)导出变量内容,可以在源码中添加,也可以在浏览器F12的source中添加。(我也不知道为什么console.log(command.args)中要加args这个属性,可能变量.args才能导出变量内容吧。)
解毕!敬礼!
|