本文仅供学习交流使用,如有侵权,联系我删除。
由于篇幅过长,本篇分析wasm的网页加载流程,下一篇分析如何执行wasm2c翻译出来的c代码
一般来说对于webassmebly的逆向,有两种选择,一个是扣js在nodejs等含有wasm运行时的环境中运行(缺点需要wasm运行时),另一种就是分析算法,自己写算法(缺点是耗时时间长)。那么有没有一种不用分析算法且可以脱离wasm运行时的快速逆向方法呢?当然是有的。即执行wasm2c翻译出来的c代码,快速wasm逆向,c/c++/c#/python可调用,
我们打开高德地图,
看到如图所示的url,即矢量瓦片:[Asm] 纯文本查看 复制代码 1 | https://vdata04.amap.com/nebula/v3 ? key=bfe31f4e0fb231d29e1d3ce951e2c780&msg=7188355d0c44c5dabfd17b014f888bbf2321f2116e4354556cf52a9d7782368fadbd71091671a8ef05353af85941de664fc42793f4791a5029cb4a2342f3f7a3dc4b4432685cb09c6504dd1bd958c96d8f61f1098710c56cea2a50cac26c1a58&p=2
|
经过跟踪可以看到关键点:
[JavaScript] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 | b.prototype.bw = function (g, A, I, t, B, i, Q, C, e, o, E, h, a) {
a = A.join( ";" ),
a = this .parent.PW.transform( '["' + a + '","' + E + '"]' ),
g = g + ( "?key=" + this .parent.key) + "&msg=" + a,
return g += "&p=2" ,
makeFetchRequest( this .parent.Uh, g, function (A, i) {
A ? h(A) : setTimeout( function () {
l.pQ(i, B, I, C, e, Q, t, o, h, g)
}, 10)
})
}
|
关键的句子是his.parent.PW.transform('["' + a + '","' + E + '"]'),即把经纬度坐标经过加密,然后访问url。跟进去
就可以发现他是如何初始化wasm以及调用wasm的。
首先把那一大串base64编码的的字符串解码成buffer,然后调用
[JavaScript] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | function initSync(A) {
var i = {
wbg: {}
};
return i.wbg.__wbg_new_59cb74e423758ede = function () {
return addHeapObject( new Error)
}
,
i.wbg.__wbg_stack_558ba5917b466edd = function (A, i) {
var g = passStringToWasm0(getObject(i).stack, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc)
, i = WASM_VECTOR_LEN;
getInt32Memory0()[A / 4 + 1] = i,
getInt32Memory0()[A / 4 + 0] = g
}
,
i.wbg.__wbg_error_4bb6c2a97407129a = function (A, i) {
try {
console.error(getStringFromWasm0(A, i))
} finally {
wasm.__wbindgen_free(A, i)
}
}
,
i.wbg.__wbindgen_object_drop_ref = function (A) {
takeObject(A)
}
,
i.wbg.__wbindgen_throw = function (A, i) {
throw new Error(getStringFromWasm0(A, i))
}
,
i = loadSync(A, i).instance,
wasm = i.exports
}
|
来加载wasm。其中i是wasm的导入函数,直接扣即可。
加载wasm之后调用了RSAPublicKeyPair函数,跟进去可以发现调用了wasm里面的rsapublickeypair_new函数
紧接着执行了this.instance.init(),即调用了wasm里面的$rsapublickeypair_init函数
这上面均是RSA算法初始化的过程,即-加载wasm同时加载导入函数-初始化-加载RSA公钥
分析过RSA算法初始化的过程之后。我们来看看他是如何加密的‘
[JavaScript] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 | function passStringToWasm0(A, i, g) {
if (void 0 === g) {
var I = cachedTextEncoder.encode(A)
, t = i(I.length);
return getUint8Memory0().subarray(t, t + I.length).set(I),
WASM_VECTOR_LEN = I.length,
t
}
for ( var B = A.length, Q = i(B), C = getUint8Memory0(), e = 0; e < B; e++) {
var o = A.charCodeAt(e);
if (127 < o)
break ;
C[Q + e] = o
}
|
首先他把字符串变成了ascll格式,然后调用了i函数__wbindgen_malloc:
从函数名字__wbindgen_malloc就可以看出,为待加密的字符串分配内存空间
然后C[Q + e] = o直接把加密的字符串写入内存。
之后调用了wasm.rsapublickeypair_encode(8, this.UW, i, g)函数进行加密。参数 this.UW是前面rsapublickeypair_new函数返回的内存地址,i是待加密的字符串分配内存空间的地址,g是加密的字符串长度
[JavaScript] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 | up.prototype.encode = function (A) {
try {
var i = passStringToWasm0(A, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc)
, g = WASM_VECTOR_LEN;
return wasm.rsapublickeypair_encode(8, this .UW, i, g),
getStringFromWasm0(I = getInt32Memory0()[2], t = getInt32Memory0()[3])
} finally {
var I = getInt32Memory0()[2]
, t = getInt32Memory0()[3];
wasm.__wbindgen_free(I, t)
}
}
|
加密之后取了uint8array内存地址为8和12处(对应 I=getInt32Memory0()[2], t = getInt32Memory0()[3]))的数,然后跟踪可以发现I,也就是内存地址8处的数即为加密后字符串的内存地址,内存12处即为加密后字符串的长度,有地址和长度,加密的字符串就出来了。。
接下来的流程可以不要,如果你是扣代码或者分析算法可以走,便于分析,如果执行wasm2c翻译出来的c代码,就不需要。
没有什么好说的,直接扣就行了。
如上图,扣完之后写了一个html,输入待价密字符串,点击按钮,就会在页面上写出加密的内容,为了便于调试,我们在wasm加载完成之后直接注入一些脚本
这样在wasm的调试页面就直接可以搜索了,非常方便(这里感谢@jixun66)大神在我上个帖子评论区https://www.52pojie.cn/forum.php ... 379690&pid=37592798指出
|