likes
comments
collection
share

打造一款属于自己的翻译软件

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

你也可以拥有自己专属的翻译器

声明:

本人在此郑重声明,本文章中的所有内容仅供学习交流使用,已对抓包内容、敏感网址和数据接口做了脱敏处理。请勿将这些内容用于商业和非法用途,否则将承担所有法律后果。如果本文章内容侵犯了您的权益,请立即联系我,我将及时予以删除!

目标地址

aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tL2luZGV4Lmh0bWwjLw==

对某道进行破解

开始分析:

  1. 首先打开浏览器控制台,输入输入一个词,点击翻译 可以看到请求头header中并无特殊的字段  打造一款属于自己的翻译软件
  2. 在payload载荷中可以看到我们要翻译的词协程,因此说明点了翻译按钮之后,就是调用这个接口向后台发起请求,然后获取到翻译内容;  打造一款属于自己的翻译软件
  3. 确定了对应接口之后,可以看到payload中有一个特殊的参数sign,这个参数是我们需要去逆向出来的;
  4. 点击响应,数据是一串我们看不懂的玩意  打造一款属于自己的翻译软件,我们需要对response数据进行破解;

 打造一款属于自己的翻译软件 5. 分析完之后,我们主要任务就是header中的sign和response的数据解密;

准备开始js逆向

  • 获取sign的值
  1. 第一网先撒下:先搜索sign:看看有没有出现,诶,出现了,只有3个地方  打造一款属于自己的翻译软件点击进入文件,格式化代码,我们都打上断点

 打造一款属于自己的翻译软件 2. 再次点击翻译按钮,看看断点进入到哪里了  打造一款属于自己的翻译软件

  1. 找到sign生成的位置,在app.****.js文件中, sign: b(t, e),

const t = (new Date).getTime();可以看到t是个时间戳 e的生成是f(e)的参数,查看下调用堆栈  打造一款属于自己的翻译软件Zo()方法中e的取值 Wo["a"].state.text.secretKey,我们可以测试多调用几次,发现这个值始终没有变化,是个固定,因此可以写死; 4. 然后b(t,e)函数进行处理,把鼠标光标放到b函数上,可以显示b函数的位置,点击进去,格式化代码  打造一款属于自己的翻译软件

function b(e, t) {
	return p(`client=${r}&mysticTime=${e}&product=${i}&key=${t}`)
}

函数b(e,t)中使用到的变量都是取自这块

   const r = "fanyideskweb"
              , i = "webfanyi"
              , s = "client,mysticTime,product"
              , l = "1.0.0"
              , d = "web"
              , u = "fanyi.web";

可以看到都是写死的,这就是很绝,我们直接替换掉里面的变量  打造一款属于自己的翻译软件 5. 同样进入p()方法中,明显看出这个就是传入一个参数e,然后经过md5得到结果;

function p(e) {
      return c.a.createHash("md5").update(e.toString()).digest("hex")
}
  1. 现在我们要测试下这个md5是不是正经的md5,老套路,在控制台和随便一个在线加密的网站对参数'1'进行md5加密,结果对比是一致的,说明这里用的是正经的md5算法,作者并没有改写(md5这种一般很少有人改动),因为可以用通用包crypto-js里的md5进行替换;

 打造一款属于自己的翻译软件

 打造一款属于自己的翻译软件 7. 替换后的p()就是下面这个

function p(e) {
    //return c.a.createHash("md5").update(e.toString()).digest("hex")
    return CryptoJS.MD5(e.toString()).toString()
    /**
     * c.a.createHash("md5").update('1').digest("hex")
     * 正儿八经的
     * 'c4ca4238a0b923820dcc509a6f75849b'
     * 因此可用标准算法crypto-js替换
     */

}
  1. 替换之后,就可以得到sign的值

 打造一款属于自己的翻译软件

  • 解密返回后的数据
  1. 先撒网用关键字json.parse(去撒,看看有没有结果,有7个,不多,都打上断点试下

这里为什么我们要用这个关键字去搜索呢?(因为大多数情况下,后端如果返回明文数据,一般也是json格式,前端拿到数据会有json.parse()转换成json对象,这样方便取值,如果想我们这种情况是密文的话,前端拿到密文,解密之后,接下来的动作一般也是进行json.parse()转换,所有我们搜索这个关键字,基本也就是找解密的位置)  打造一款属于自己的翻译软件

 打造一款属于自己的翻译软件 2. 重新点击翻译按钮,断点进入到textTranslate.81983bbc.js文件中  打造一款属于自己的翻译软件 3. o是后天返回的密文数据,通过下面这段代码进行对o的解密操作

const n = Jo["a"].decodeData(o, Wo["a"].state.text.decodeKey, Wo["a"]

 打造一款属于自己的翻译软件 4. 在控制输出,这两个对象是固定的值(可以多次几次,其实这两个值,decodeKey就是解密算法的密钥,decodeIv就是偏移量)

Wo["a"].state.text.decodeKey
Wo["a"].state.text.decodeIv
  1. Jo["a"].decodeData() 这个就是我们的解密方法,鼠标光标放到这里,点击进入函数
  2. 解密函数如下,可以看出,用的是aes算法
O = (t, o, n) => {
    if (!t)
        return null;
    const a = e.alloc(16, m(o))
        , r = e.alloc(16, m(n))
        , i = c.a.createDecipheriv("aes-128-cbc", a, r);
    let s = i.update(t, "base64", "utf-8");
    return s += i.final("utf-8"),
        s
}
  1. 点击进入c.a.createDecipheriv("aes-128-cbc", a, r)中,这里是文件名chunk-vendors.641ed4ef.js 打造一款属于自己的翻译软件

  2. function c(t, e, n) 中用到了模块o[t],s[t],这块模块又各种引用了其他模块,链路挺深的,所以这里我们选择全扣,(这里我已经帮你们试过了,一点一点扣太痛苦了)

    o = n("bac2")
    , s = n("0be8")

 打造一款属于自己的翻译软件 9. 把整个chunk-vendors.641ed4ef.js文件拷贝下来,放入到我们的本地的pycharm中,总共4w多行代码,还好,不多 打造一款属于自己的翻译软件 10. 把这个文件拉到第一行位置,看到关键字webpackJsonp,知道我们是由多个文件webpack打包成的,因此下一步我们要定位到webpack加载器loader

 打造一款属于自己的翻译软件 11. 随便在加载器调用的位置打一个断点,刷新页面,即可进入断点位置,点击引用出进入

 打造一款属于自己的翻译软件

  1. 这里便是我们的加载器了
    function s(t) {
        if (n[t])
            return n[t].exports;
        var o = n[t] = {
            i: t,
            l: !1,
            exports: {}
        };
        return e[t].call(o.exports, o, o.exports, s),
        o.l = !0,
        o.exports
    }

 打造一款属于自己的翻译软件 13. 找到加载器后,就基本完成了一大半了,把整个加载器文件都拷贝到本地,然后把chunk-vendors.641ed4ef.js里面的模块也粘贴到加载器里面的模块中

 打造一款属于自己的翻译软件

  1. 开始补环境,缺啥补啥,window对象补上去

 打造一款属于自己的翻译软件 15. 导出加载器对象,定义一个全局变量,名字随便取,我们这里定义var _ps

_ps=s

 打造一款属于自己的翻译软件

  1. 点击进入解密函数,这个模块的话是956a模块,
   function c(t, e, n) {
            if (t = t.toLowerCase(),
            o[t])
                return i.createDecipheriv(t, e, n);
            if (s[t])
                return new r({
                    key: e,
                    iv: n,
                    mode: t,
                    decrypt: !0
                });
            throw new TypeError("invalid suite type")
        }

 打造一款属于自己的翻译软件

17.打印下_ps('956a')模块内容,有我们需要的方法 createDecipheriv: [Function: c]

 打造一款属于自己的翻译软件 18. createDecipheriv()方法搞定了,剩下两个参数a和r的值,其实也就是上面提到的解密key和偏移iv值,这两个值也是固定的,因此我们可以在控制台把这个值打印出来,拷贝下来,不用扣这段代码了;

 const a = e.alloc(16, m(o))
                  , r = e.alloc(16, m(n))
                  , i = c.a.createDecipheriv("aes-128-cbc", a, r);

 打造一款属于自己的翻译软件 19. 输入密文,获取到明文结果  打造一款属于自己的翻译软件

到这里我们就可以结合python打造我们自己的翻译器了

 打造一款属于自己的翻译软件

文章持续更新,可以微信搜一搜「 python君 」第一时间阅读