攻防世界逆向高手题的secret-string-400

99 篇文章 33 订阅

攻防世界逆向高手题之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才能导出变量内容吧。)

解毕!敬礼!

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐一 · 林

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值