spiderdemo第四题

正文

分析

spiderdemo第四题是一道wasm的题

看到wasm,笔者知道这个流程

  1. 某个wasm文件发送请求
  2. 初始化wasm
  3. 调用wasm里面的函数

必然如此。

题目还需要使用hook反调试,直言的说,笔者不会使用hook方式,爬虫技术不行,0.0

但是并不代表过不了。

首先进入页面,打开开发者工具

T4-WASM挑战https://www.spiderdemo.cn/sec1/wasm_challenge/?challenge_type=wasm_challenge就会跳转到原神页面

那么使用ctrl+u,查看网页源代码

view-source:https://www.spiderdemo.cn/sec1/wasm_challenge/?challenge_type=wasm_challenge

发现是看得到源代码,那很好

在源代码里面可以看到关键信息

javascript 复制代码
 <script>
        /**
         * 获取指定页面数据(集成 WASM 加密验证)
         * @param {number} page - 页码
         * @param {string} type - 挑战类型 (card.json中的id)
         * @returns {Object} 页面数据
         */
        async function apiGetPageData(page, type = challengeType) {
            let url = `/sec1/api/wasm_challenge/page/${page}/?challenge_type=${encodeURIComponent(type)}`;
            let headers = { 'Content-Type': 'application/json' };
            
            // 如果 WASM 已准备好,添加加密验证
            if (window.wasmReady && window.encrypt_simple) {
                try {
                    const timestamp = Math.floor(window.get_timestamp() / 1000).toString();
                    const verifyString = `${type}_page_${page}`;
                    const wasmAuth = window.encrypt_simple(verifyString, timestamp);
                    
                    // 添加 WASM 验证参数到 URL
                    url += `&wasm_auth=${encodeURIComponent(wasmAuth)}`;
                    headers['X-WASM-Timestamp'] = timestamp;
                    headers['X-WASM-Page'] = page.toString();
                    
                } catch (error) {
                    console.warn('⚠️ WASM 加密失败,继续无验证请求:', error);
                }
            }
            try {
                const data = await $.ajax({
                    url: url,
                    method: 'GET',
                    headers: headers,
                    dataType: 'json'
                });
                return data;
            } catch (xhr) {
                const data = xhr.responseJSON || {};
                const errorMessage = data.error || `HTTP ${xhr.status}: ${xhr.statusText}`;
                throw new Error(errorMessage);
            }
        }
    </script>

分析一下,假设对第二页发送请求

首先可以确定暂时的url如下

https:://spiderdemo.cn//sec1/api/wasm_challenge/page/2/?challenge_type=${encodeURIComponent(type)}

其次,可以发现wasm里面的函数是encrypt_simple,

需要传入两个参数**,一个是verifyString,是{type}_page_{page}这个字符串,另一个是**

秒级别的时间戳,说白了10位的时间戳。

加密后的结果,变成wasm_auth对应的值,放到url里面

需要请求头的参数进行加密

javascript 复制代码
headers['X-WASM-Timestamp'] = timestamp;
headers['X-WASM-Page'] = page.toString();

这两个很好处理。

那么现在只需要获取到encrypt_simple这个算法里面的东西,就可以了。


++后面笔者又经过几个小时的分析,后面笔者又去搞的反调试,虽然成功了,但感觉没必要。++


再次分析

在源代码里面搜索wasm

笔者看到了这个东西,那问题不就解决了,后面不就从从容容、游刃有余

不需要过反调试。

直接下载这个js文件

spiderdemo.cn//static/pkg/wasm_anti.jshttps://www.spiderdemo.cn//static/pkg/wasm_anti.js新建一个a.html,和js文件在同一目录下,如下

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
                <script type="module">
                    import init, { encrypt_simple, aes_encrypt, get_timestamp } from './wasm_anti.js';
                    init().then(() => {
                    window.encrypt_simple = encrypt_simple;
                    window.aes_encrypt = aes_encrypt;
                    window.get_timestamp = get_timestamp;
                    window.wasmReady = true;
                    console.log('🔐 WASM 加密模块已就绪');
                    }).catch(err => {
                    console.error('❌ WASM 加载失败:', err);
                    window.wasmReady = false;
                    });
                </script>
<body>

</body>
</html>

在webstorm或者pycharm运行,

发现这个报错

说明,wasm文件的名字叫wasm_anti_bg.wasm

然后,对访问对应的文件

https://www.spiderdemo.cn//static/pkg/wasm_anti_bg.wasmhttps://www.spiderdemo.cn//static/pkg/wasm_anti_bg.wasm就可以获取wasm文件,放到和wasm_anti.js同一目录下

然后,运行a.html

完美。

哈哈哈哈哈哈,不需要反调试。

编写爬虫

写爬虫最麻烦的是逆向,已经完成了逆向,后面不必多言

笔者还是使用和第二题一样的操作

关于spiderdemo第二题的奇思妙想-CSDN博客https://blog.csdn.net/qq_63401240/article/details/153792789?spm=1001.2014.3001.5501修改a.html文件的内容

javascript 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
 <script type="module">
      import init, { encrypt_simple, aes_encrypt, get_timestamp } from './wasm_anti.js';
                    init().then(() => {
                    window.encrypt_simple = encrypt_simple;
                    window.aes_encrypt = aes_encrypt;
                    window.get_timestamp = get_timestamp;
                    window.wasmReady = true;
                    console.log('🔐 WASM 加密模块已就绪');
                    }).catch(err => {
                    console.error('❌ WASM 加载失败:', err);
                    window.wasmReady = false;
                    });
 </script>
 <script>
     function get_ok(){
         return window.wasmReady
     }
     function get_auth(page,timestamp){
         let type="wasm_challenge"
         let verifyString=`${type}_page_${page}`
         return window.encrypt_simple(verifyString, timestamp);
     }
 </script>
<body>
</body>
</html>

爬虫如下

javascript 复制代码
from httpx import Client
import time
from DrissionPage import ChromiumPage

html = ChromiumPage()
html.get("http://localhost:63343/..../a.html")

while True:
    ready = html.run_js('return get_ok();')
    print(ready)
    if ready is True:
        break

cookies = {
    'sessionid':'你的session_id'
}
total=0
for page_number in range(1,101):
    timestamp = str(int(time.time()))
    url=f'https://www.spiderdemo.cn/sec1/api/wasm_challenge/page/{page_number}/'
    wasm_auth = html.run_js(f'return get_auth({page_number},"{timestamp}");')
    headers = {
        'Content-Type': 'application/json',
        'X-Wasm-Page': str(page_number),
        'X-Wasm-Timestamp': str(timestamp),
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36'
    }
    params={
        'challenge_type':'wasm_challenge',
        'wasm_auth':wasm_auth
    }
    response = Client().get(url=url,params=params,cookies=cookies, headers=headers)
    total+=sum(response.json()['page_data'])
print(total)

结果如下

成功,哈哈哈哈哈哈

没有逆向js,没有逆向wasm,没有用hook。

反调试分析

还是从源代码里面入手,可以发现引入的外部js文件

可以查看四个js文件,那么显然最关键的文件就是wasm_challenge.js了。

因此,直接下载这个js文件

spiderdemo.cn/static/js/wasm_challenge.jshttps://www.spiderdemo.cn/static/js/wasm_challenge.js分析一下这个文件,笔者使用webstorm

首先经过格式化这个js文件,可以在文件的末尾,发现一些东西

这里面好像有debug的事情 笔者看到setInterveral,还有什么debuggerCheckInterval

解决反调试和混淆

解决方法

直言的说,这里笔者搞了几个小时。。。。。。。。。

笔者使用本地替换的方式解决这个跳转问题,但是,笔者删除一些代码

javascript 复制代码
if (typeof debuggerCheckInterval === "undefined" || !debuggerCheckInterval) {
}
document["addEventListener"]("DOMContentLoaded", function () {
    initializePage()
});

把那些全部删除了,还是不行,会跳转,后来笔者还去解混淆了,笔者还想看看这里是否对wasm文件发送了请求,最后没在这个wasm_challenge.js里面。

笔者就一直对跳转感到疑问,为什么??为什么?明明已经删除了

直言的说,笔者看到这篇文章

Python爬虫入门:spiderdemo题解及详细思路(入门篇) - 吾爱破解 - 52pojie.cnhttps://www.52pojie.cn/thread-2066443-1-1.html笔者明白了。

首先,在webstrom里面,首先ctrl+shift+"+"快捷键是展开全部函数,ctrl+shift+"-"是折叠全部函数

然后笔者使用全部折叠

笔者发现这个**_ÿijjji和_ÿbgbad这两个函数是执行了的,因此,把这两个去掉**

实际上笔者是看了前面文章大佬才知道这是反调试的函数,总之,直接把执行函数去掉

如下

成功

解混淆**_ÿhecih函数**

那个wasm_challenge.js里面又许多函数,其中有个关键的函数**_ÿhecih,**笔者对其解混淆过

应该怎么说?是直接给出答案,还是一步一步来,笔者还是选择一步一步来,慢慢来,不慌

首先,把需要解混淆的代码放到一个新的文件------g.js

javascript 复制代码
function _ÿhecih(_0x841bd7, _0x44fab0) {
    let _0x1f1cc1 = 3 + 1;
    for (let _0x536a0d = 0 - 0; _0x536a0d < 0 - -5; _0x536a0d++) {
        switch (_0x1f1cc1) {
            case 0 + 2: {
                return _0x3bc79e
            }
            case 1 * 1 + 2: {
                for (var _0x39d32e = 0 * 0 + 0; _0x39d32e < _0x841bd7["le" + "ngth"]; _0x39d32e++) {
                    _0x3bc79e += _ÿdijia["fromCharCod" + "e"](_0x841bd7["cha" + "rCodeAt"](_0x39d32e) ^ _0x44fab0["char" + "CodeAt"](_0x39d32e % _0x44fab0["le" + "ngth"]))
                }
                _0x1f1cc1 += -(1 - 0);
                break
            }
            case 1 - 0: {
                var _0x3bc79e = "";
                _0x1f1cc1 += 0 + 2;
                break
            }
            case 0 * 0 + 4: {
                try {
                    _0x841bd7 = _ÿgdjhd(_ÿdddej(_ÿjhbia(_0x841bd7)))
                } catch (_0x7648cb) {
                    _0x841bd7 = _ÿjhbia(_0x841bd7)
                }
                _0x1f1cc1 += -(0 * 1 + 3);
                break
            }
        }
    }
}

慢慢来

webstrom在windows上的搜索是ctrl+f,webstrom在windows上的替换是ctrl+r

  1. 在新的文件中,搜索 **_0x1f1cc1,**发现有5个,全局替换为total,或者其他名字。
  2. 计算total在不同case情况下的结果
  3. _ÿgdjhd在wasm_challenge.js中搜索,发现是decodeURIComponent,全部替换
  4. _ÿdddej在wasm_challenge.js中搜索,发现是escape,全部替换
  5. _ÿjhbia在wasm_challenge.js中搜索,发现是atob,全部替换
  6. 最外层for循环中的**_0x536a0d** 搜索并全部替换成变量**i,**计算值
  7. case 4的for循环中的**_0x39d32e** 搜索并全部替换成变量**j,**计算值
  8. 合并字符串

现在解混淆之后的结果

javascript 复制代码
function _ÿhecih(_0x841bd7, _0x44fab0) {
    let total = 4;
    for (let i = 0; i < 5; i++) {
        switch (total) {
            case 2: {
                return _0x3bc79e
            }
            case 3: {
                for (var j =  0; j < _0x841bd7["length"]; j++) {
                    _0x3bc79e += String["fromCharCode"](_0x841bd7["charCodeAt"](j) ^ _0x44fab0["charCodeAt"](j % _0x44fab0["length"]))
                }
                total += -1;
                break
            }
            case 1: {
                var _0x3bc79e = "";
                total += 2;
                break
            }
            case 4: {
                try {
                    _0x841bd7 = decodeURIComponent(escape(atob(_0x841bd7)))
                } catch (_0x7648cb) {
                    _0x841bd7 = atob(_0x841bd7)
                }
                total += -3;
                break
            }
        }
    }
}

测试一下

javascript 复制代码
let a=_ÿhecih("EBcVAQ==", "ccgh")
console.log(a)

能够解出来,是否正确就不敢确定,没报错,继续

  1. 修改函数_ÿhecih名为unmaskString
  2. 第一个参数为cipher,全局替换
  3. 第二个参数为key,全局替换
  4. total += -3;就是1,把case 1里面的内容放到case 4中,并修改_0x3bc79e名字为return_value
  5. total += 2就是3,把case 3里面的内容放到case 4中
  6. 其他同理,最后整理代码,去掉total,i,之类的中间变量

最后结果如下

javascript 复制代码
function unmaskString(cipher, key) {
       try {
            cipher = decodeURIComponent(escape(atob(cipher)))
        } catch (_0x7648cb) {
            cipher = atob(cipher)
        }
        var return_value = "";
        for (var j =  0; j < cipher.length; j++) {
            return_value += String.fromCharCode(cipher.charCodeAt(j) ^ key.charCodeAt(j % key.length))
        }
        return return_value
}

行,再次测试

没问题。

其他函数类似的,解混淆。

测试一下

对**_ÿaieic函数解一下混淆**

如下

javascript 复制代码
function _ÿaieic(_0x2e81e6) {
    var _0x31ab5c = {
        "header_check": _ÿhecih("6K6f5rCh5aWV", "hcab") + _ÿhecih("5qKm5rS45o295om6", "fslb"),
        "number_challenge": _ÿhecih("5Yud5oGl5pSI5ayl", "udxr") + _ÿhecih("5rC25ZOr5o2h5omw", "tgph"),
        "js_challenge": _ÿhecih("Pg==", "thhv") + _ÿhecih("Jea2nOa2vuimm+afpuaNuuaJoA==", "vkxx"),
        "wasm_challenge": _ÿhecih("IDEl", "wpvi") + _ÿhecih("OOaNvuaJqQ==", "uoqn")
    };
    return _0x31ab5c[_0x2e81e6] || _0x2e81e6
}

把**_ÿhecih**变成unmaskString,并执行

结果如下

修改一下变量名和函数名,结果如下

javascript 复制代码
function get_title(index) {
    let  map = {
        "header_check": "请求头检测挑战",
        "number_challenge":  "动态数字求和挑战",
        "js_challenge": "JS混淆解析挑战",
        "wasm_challenge": "WASM挑战"
    };
    return map[index] || index
}

这个**_ÿaieic函数就是笔者自定义的get_title函数。**

哈哈哈哈哈哈

就这样吧!!!!!!

相关推荐
好好好起个名真难19 小时前
爬虫 beautifulSoup 方法
爬虫·beautifulsoup
B站_计算机毕业设计之家1 天前
python舆情分析可视化系统 情感分析 微博 爬虫 scrapy爬虫技术 朴素贝叶斯分类算法大数据 计算机✅
大数据·爬虫·python·scrapy·数据分析·1024程序员节·舆情分析
B站_计算机毕业设计之家1 天前
Spark微博舆情分析系统 情感分析 爬虫 Hadoop和Hive 贴吧数据 双平台 讲解视频 大数据 Hadoop ✅
大数据·hadoop·爬虫·python·数据分析·1024程序员节·舆情分析
猫头虎1 天前
大模型训练中的关键技术与挑战:数据采集、微调与资源优化
人工智能·爬虫·数据挖掘·数据分析·网络爬虫·aigc·1024程序员节
Elieal1 天前
AJAX 知识
前端·ajax·okhttp
失败又激情的man1 天前
爬虫逆向之X音a_bogus参数分析
爬虫·1024程序员节
爬虫程序猿2 天前
用 Python 给京东商品详情做“全身 CT”——可量产、可扩展的爬虫实战
开发语言·爬虫·python
盼哥PyAI实验室2 天前
《Python爬虫 + 飞书自动化上传》全流程详细讲解
爬虫·python·飞书
小白学大数据2 天前
Java爬虫性能优化:以喜马拉雅音频元数据抓取为例
java·爬虫·性能优化