猿人学第二届第三题(vmp混淆)

觉得文章还不错的请点点赞!!! 磕头了!!!


声明:

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

逆向目标:

逆向过程:

打开 F12 调试窗口,刷新页面,看到请求参数需要 page 和 token。  

在源面板打下 xhr 断点,成功断在第 646 行。可以看到我们 token 值已经出现,同时观察右边值发现出现了 SM3 等关键词,我们不妨推断 token 就是通过 SM3 加密得到的。

在网上使用标准 SM3 加密和浏览器 SM3 加密对比,可以判断浏览器在标准的 SM3 加密进行了魔改。

在 645 行进行日志断点(记录点),Fe 就是调用函数是所有传入的参数,we[1] 则是调用的函数名。

再此刷新页面,等待日志输出完毕,向上查找 sm3Digest 函数观察传入参数发现,此参数就是时间戳 + 页数

接下来就是对照日志找不同了,先找一个标准的 SM3 算法,这里我用的是这篇文章的,直接复制即可 。

在 645 行打下条件断点,对比标准 SM3 算法发现 reset 函数的 reg 初始值不一样,将其修改成浏览器的值。

再此观察日志定位 strToBytes 函数,此函数是将字符串转发换成 Unicode 编码形式。将本地的值和浏览器的值多次对比可知,偶数的值都相同,奇数的值都减一。

只需在值入列表时添加一个 if 判断就行 。

观察_t 函数和返回值,这里它将函数的返回值魔改了,将本地的值替换成浏览器的值。

再定位 _compress 函数,将这三个值分别修改成 424463564742949672904289724415。因为这三个是日志输出没有,需要单步调试比较麻烦,这里不过多说明。

/**
 * 国密SM3加密{JS实现}
 *
 * 参考 https://blog.csdn.net/Shen_yuanjia/article/details/111879819
 *
 * @returns
 */
function SM3() {
	if (!(this instanceof SM3)) {
		return new SM3();
	}

	this.reg = new Array(8);
	this.chunk = [];
	this.size = 0;

	this.reset();
}

SM3.prototype.reset = function() {
	this.reg[0] = 1937770108;
	this.reg[1] = 1983173321;
	this.reg[2] = 385893078;
	this.reg[3] = 3666375988;
	this.reg[4] = 2701930684;
	this.reg[5] = 353449901;
	this.reg[6] = 3816598093;
	this.reg[7] = 4008382286;
	this.chunk = [];
	this.size = 0;
};

/**
 * 字符串转byte数组
 */
SM3.prototype.strToBytes= function (s) {
  var ch, st, re = [];
  for (var i = 0; i < s.length; i++ ) {
    ch = s.charCodeAt(i);
	if ((ch % 2) != 0){
		 ch -= 1
	 }
    st = [];
    do {
      st.push( ch & 0xFF );
      ch = ch >> 8;
    }
    while ( ch );
    re = re.concat( st.reverse() );
  }
  return re;
};

SM3.prototype.write = function(msg) {
	var m = (typeof msg === 'string') ? this.strToBytes(msg) : msg;
	this.size += m.length;
	var i = 64 - this.chunk.length;
	if (m.length < i) {
		this.chunk = this.chunk.concat(m);
		return;
	}

	this.chunk = this.chunk.concat(m.slice(0, i));
	while (this.chunk.length >= 64) {
		this._compress(this.chunk);
		if (i < m.length) {
			this.chunk = m.slice(i, Math.min(i + 64, m.length));
		} else {
			this.chunk = [];
		}
		i += 64;
	}
};

/**
 * 计算hash值
 */
SM3.prototype.sum = function(msg, enc) {
	if (msg) {
		this.reset();
		this.write(msg);
	}

	this._fill();
	for (var i = 0; i < this.chunk.length; i += 64) {
		this._compress(this.chunk.slice(i, i + 64));
	}

	var digest = null;
	if (enc == 'hex') {
		digest = "";
		for (var i = 0; i < 8; i++) {
			digest += this.reg[i].toString(16);
		}
	} else {
		var digest = new Array(32);
		for (var i = 0; i < 8; i++) {
			var h;
			h = this.reg[i];
			digest[i * 4 + 3] = (h & 0xff) >>> 0;
			h >>>= 8;
			digest[i * 4 + 2] = (h & 0xff) >>> 0;
			h >>>= 8;
			digest[i * 4 + 1] = (h & 0xff) >>> 0;
			h >>>= 8;
			digest[i * 4] = (h & 0xff) >>> 0;
		}
	}

	this.reset();
	return digest;
};

SM3.prototype._compress = function(m) {
	if (m < 64) {
		console.error("compress error: not enough data");
		return;
	}
	var w = this._expand(m);
	var r = this.reg.slice(0);
	for (var j = 0; j < 64; j++) {
		var ss1 = this._rotl(r[0], 12) + r[4] + this._rotl(this._t(j), j)
		ss1 = (ss1 & 4244635647) >>> 0;
		ss1 = this._rotl(ss1, 7);
		var ss2 = (ss1 ^ this._rotl(r[0], 12)) >>> 0;
		var tt1 = this._ff(j, r[0], r[1], r[2]);
		tt1 = tt1 + r[3] + ss2 + w[j + 68];
		tt1 = (tt1 & 4294967290) >>> 0;
		var tt2 = this._gg(j, r[4], r[5], r[6]);
		tt2 = tt2 + r[7] + ss1 + w[j];
		tt2 = (tt2 & 4289724415) >>> 0;
		r[3] = r[2];
		r[2] = this._rotl(r[1], 9);
		r[1] = r[0];
		r[0] = tt1;
		r[7] = r[6]
		r[6] = this._rotl(r[5], 19);
		r[5] = r[4];
		r[4] = (tt2 ^ this._rotl(tt2, 9) ^ this._rotl(tt2, 17)) >>> 0;
	}
	for (var i = 0; i < 8; i++) {
		this.reg[i] = (this.reg[i] ^ r[i]) >>> 0;
	}
};

SM3.prototype._fill = function() {
	var l = this.size * 8;
	var len = this.chunk.push(0x80) % 64;
	if (64 - len < 8) {
		len -= 64;
	}
	for (; len < 56; len++) {
		this.chunk.push(0x00);
	}

	for (var i = 0; i < 4; i++) {
		var hi = Math.floor(l / 0x100000000);
		this.chunk.push((hi >>> ((3 - i) * 8)) & 0xff);
	}
	for (var i = 0; i < 4; i++) {
		this.chunk.push((l >>> ((3 - i) * 8)) & 0xff);
	}
};

SM3.prototype._expand = function(b) {
	var w = new Array(132);
	for (var i = 0; i < 16; i++) {
		w[i] = b[i * 4] << 24;
		w[i] |= b[i * 4 + 1] << 16;
		w[i] |= b[i * 4 + 2] << 8;
		w[i] |= b[i * 4 + 3];
		w[i] >>>= 0;
	}

	for (var j = 16; j < 68; j++) {
		var x;
		x = w[j - 16] ^ w[j - 9] ^ this._rotl(w[j - 3], 15);
		x = x ^ this._rotl(x, 15) ^ this._rotl(x, 23);
		w[j] = (x ^ this._rotl(w[j - 13], 7) ^ w[j - 6]) >>> 0;
	}

	for (var j = 0; j < 64; j++) {
		w[j + 68] = (w[j] ^ w[j + 4]) >>> 0;
	}

	return w;
};

SM3.prototype._rotl = function(x, n) {
	n %= 32;
	return ((x << n) | (x >>> (32 - n))) >>> 0;
};

SM3.prototype._t = function(j) {
	if (0 <= j && j < 16) {
		return 2044544281;
	} else if (16 <= j && j < 64) {
		return 2081922442;
	} else {
		console.error("invalid j for constant Tj");
	}
};

SM3.prototype._ff = function(j, x, y, z) {
	if (0 <= j && j < 16) {
		return (x ^ y ^ z) >>> 0;
	} else if (16 <= j && j < 64) {
		return ((x & y) | (x & z) | (y & z)) >>> 0;
	} else {
		console.error("invalid j for bool function FF");
		return 0;
	}
};

SM3.prototype._gg = function(j, x, y, z) {
	if (0 <= j && j < 16) {
		return (x ^ y ^ z) >>> 0;
	} else if (16 <= j && j < 64) {
		return ((x & y) | (~x & z)) >>> 0;
	} else {
		console.error("invalid j for bool function GG");
		return 0;
	}
};

/**
 * 等效于Array.from目的是做浏览器兼容处理 Array.from IE浏览器不支持
 */
SM3.prototype.toArray = function(s, f){
	var a = [];
	for(var i=0; i<s.length; i++){
		var t  = s[i];
		if(f){
			t = f(t);
		}
		a.push(t);
	}
	return a;
};

/**
 * SM3加密主函数
 *
 * @param msg
 * @returns
 */
function sm3Digest(msg){
	var _sm3 = new SM3();
    var digest = _sm3.sum(msg);
    var hashHex = _sm3.toArray(digest, function(byte) {return ('0' + (byte & 0xFF).toString(16)).slice(-2);}).join('');
    return hashHex;
}

注意:在请求时需要加上 headers 中的 accept-time 参数用于校验,此参数需和生成 token 的时间戳保持一致。

结果:

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值