likes
comments
collection
share

手把手带你模拟36氪登录

作者站长头像
站长
· 阅读数 12

最近收到粉丝私信,想多学习下js逆向相关的知识和案例,应大多数粉丝要求:今日份js逆向练习,36氪登录模拟

目标地址:36kr.com/

初步探测

  1. 点击登录按钮,切换到账户密码登录 手把手带你模拟36氪登录
  2. 随便输入一个手机号码和6位数以上的密码,点击登录 手把手带你模拟36氪登录 可以看到XHR请求已经发出来了byMobilePassword
  3. 查看byMobilePassword相关的request header和payload request header中并未发现特殊加密的参数 手把手带你模拟36氪登录 很明显payload中mobileNo和password是经过加密的 手把手带你模拟36氪登录

牛刀小试

  1. 先来第一枪,根据关键字搜索mobileNoonly一个,点击文件进去试一下 手把手带你模拟36氪登录
  2. 格式化下代码 手把手带你模拟36氪登录
  3. 打上断点,点击登录按钮 手把手带你模拟36氪登录
  4. 断点成功断住,从chrome控制台可以看到o.a.get(t, "mobileNo")就是我们的明文手机号码,Object(i.b)()就是加密明文的方法,因此我们的重点任务就是破解Object(i.b)()这个方法 手把手带你模拟36氪登录

重点突破

  1. 鼠标光标放到Object(i.b)()上,点击弹出来的浮窗进入文件 手把手带你模拟36氪登录
  2. 文件定位到这段代码 手把手带你模拟36氪登录 简单分析下这段代码:
ar r = n(14)
    , o = n(4)
    ,
    i = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeiLxP4ZavN8qhI+x+whAiFpGWpY9y1AHSQC86qEMBVnmqC8vdZAfxxuQWeQaeMWG07lXhXegTjZ5wn9pHnjg15wbjRGSTfwuZxSFW6sS3GYlrg40ckqAagzIjkE+5OLPsdjVYQyhLfKxj/79oOfjl/lV3rQnk/SSczHW0PEyUbQIDAQAB"
    , a = function () {
        var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "";
        if (!Object(o.isNodeEnv)()) {
            var t = n(769)
                , r = new t.JSEncrypt;
            r.setPublicKey(i);
            var a = r.encrypt(e);
            return a
        }
    }
  1. 当我们看到r = new t.JSEncrypt;这行代码的时候,有经验的一看就应该明白这可能是标准的RSA加密; r.setPublicKey(i);是设置公钥,这里的i的值在上面也很清晰的写死了手把手带你模拟36氪登录

i = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeiLxP4ZavN8qhI+x+whAiFpGWpY9y1AHSQC86qEMBVnmqC8vdZAfxxuQWeQaeMWG07lXhXegTjZ5wn9pHnjg15wbjRGSTfwuZxSFW6sS3GYlrg40ckqAagzIjkE+5OLPsdjVYQyhLfKxj/79oOfjl/lV3rQnk/SSczHW0PEyUbQIDAQAB"

三种方式来破解登录

JSEncrypt库

这种方式最直接,也最简单,不过需要对相关加密库比较熟悉 在node.js环境中使用jsEncrypt库 首先, Node.js 环境中使用 JSEncrypt 需要先安装该库,可以通过 npm 安装: npm install jsencrypt 补一个window环境就可以直接使用了 手把手带你模拟36氪登录 代码如下:

window = global

function get_encrypt(message) {
    const JSEncrypt = require('jsencrypt');
    const encrypt = new JSEncrypt();
    p_k = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeiLxP4ZavN8qhI+x+whAiFpGWpY9y1AHSQC86qEMBVnmqC8vdZAfxxuQWeQaeMWG07lXhXegTjZ5wn9pHnjg15wbjRGSTfwuZxSFW6sS3GYlrg40ckqAagzIjkE+5OLPsdjVYQyhLfKxj/79oOfjl/lV3rQnk/SSczHW0PEyUbQIDAQAB'
    encrypt.setPublicKey(p_k)
// 使用公钥加密数据
    return encrypt.encrypt(message);
}

console.log(get_encrypt('1'));

通过python调用,看到这个结果,就已经说明我们模拟的加密已经通过了36kr服务器的验证,只是输入的账户不对,换成你们正确的账户就行 手把手带你模拟36氪登录

硬扣

如果不知道是RSA加密,也没有关系,我们用其他的方法,那就硬扣呗;

  1. 这几行代码n(**)差不多可以知道是webpack加载器n来的,在几个n处打上断点,刷新页面

手把手带你模拟36氪登录

  1. 断点成功进入,点击浮窗进入代码文件 手把手带你模拟36氪登录 成功定位到加载器 手把手带你模拟36氪登录
  2. 把runtime.****.js文件内容都拷贝下来

手把手带你模拟36氪登录

补环境

  1. 代码拷贝下来后,直接运行js文件 手把手带你模拟36氪登录 提示ReferenceError: window is not defined
  2. 补一个window = global再次运行,代码ok 手把手带你模拟36氪登录
  3. 格式化代码,缩近代码,可以看到是一个[]空数组 手把手带你模拟36氪登录 加密函数的文件看到这里的代码都是在[]数组中, 手把手带你模拟36氪登录
  4. 这里是webpack的数组方式,因此把这些function都拷贝到[]数组中 手把手带你模拟36氪登录

ReferenceError: navigator is not defined

手把手带你模拟36氪登录

  1. 导出加载器函数,加载器函数是n, 手把手带你模拟36氪登录 _ps = n后面就可以使用_ps全局对象来调用对应的函数了 手把手带你模拟36氪登录
  2. 因为加载器中是数组对象,搜索下 r = new t.JSEncrypt 我们所需要的方法是在哪个functuion 手把手带你模拟36氪登录 数组跟python中一样,也是从0开始的,所以我们需要的是第7个 _ps(7)打印出来的结果就是三个方法
{ a: [Getter], b: [Getter], c: [Getter] }

手把手带你模拟36氪登录

b方法返回的就是a对象,而a对象就是我们所需要的加密方法 手把手带你模拟36氪登录 7. 因此_ps(7).b('123345')就可以得到加密结果 构造一个函数返回加密结果给python程序调用

function get_encrypt(message) {
    return _ps(7).b(message)
}
  1. 接下来就是我们通过python程序来进行登录,看到这个结果,就已经说明我们模拟的加密已经通过了36kr服务器的验证,只是输入的账户不对,换成你们正确的账户就行; 手把手带你模拟36氪登录 附上相关的python代码,js代码因此太长了,就不附上了,有需要学习的朋友可以私信我。
import requests
import json
import time
import execjs

headers = {
    "authority""gateway.36kr.com",
    "accept""*/*",
    "accept-language""zh-CN,zh;q=0.9",
    "cache-control""no-cache",
    "content-type""application/json",
    "origin""https://www.36kr.com",
    "pragma""no-cache",
    "referer""https://www.36kr.com/",
    "sec-ch-ua"""Chromium";v="110", "Not A(Brand";v="24", "Google Chrome";v="110"",
    "sec-ch-ua-mobile""?0",
    "sec-ch-ua-platform"""macOS"",
    "sec-fetch-dest""empty",
    "sec-fetch-mode""cors",
    "sec-fetch-site""same-site",
    "user-agent""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}

url = "https://gateway.36kr.com/api/mus/login/byMobilePassword"

round(time.time() * 1000)

mobileNo = '18814378681'
password = '123456'
exjs = execjs.compile(open('36ke.js', encoding='utf-8').read())
mobileNo = exjs.call('get_encrypt', mobileNo)
password = exjs.call('get_encrypt', password)
data = {
    "krtoken""",
    "partner_id""web",
    "timestamp": round(time.time() * 1000),
    "param": {
        "countryCode""86",
        "mobileNo": mobileNo,
        "password": password
    }
}
data = json.dumps(data, separators=(','':'))
response = requests.post(url, headers=headers, data=data)

print(response.text)

Websocket方式

  1. 导出加密函数

手把手带你模拟36氪登录

  1. 启动我们的sekiro工具 手把手带你模拟36氪登录

可以看到启动日志是正常的,我这里是sekiro3,默认启动的netty端口是5612 手把手带你模拟36氪登录

  1. 在浏览器控制台注入sekiro_web_client.js和我们自己的脚本文件
function guid() {
        function S4() {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }

        return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
    }

    var client = new SekiroClient("ws://127.0.0.1:5612/business/register?group=ws-group&clientId=" + guid());

    client.registerAction("sss", function (request, resolve, reject) {
        const {param1} = request.params;
        resolve(sss(param1));
    })

控制台提示已经和服务端建立了websocket连接 手把手带你模拟36氪登录

  1. 接下来我们就可以通过python发送我们的请求获取加密的手机号和密码了

手把手带你模拟36氪登录 然后可以通过加密后的数据请求登录接口了。。 这种方式的缺点就是刷新浏览器的时候注入的脚本就消失了,需要重新注入,当然我们也可以通过Tampermonkey注入,不过这个小小的登录用这些,感觉就有点大炮轰蚊子了

总结:

js逆向根据实际情况,可以有多种方式破解方式,可以按照自己熟悉的来,前提要了解各种破解套路,才能找到对应最合适的。手把手带你模拟36氪登录

更多资源信息可关注公众号:python君