JS逆向学习-「有道翻译」逆向详细处理过程



前言

深入学习js逆向中,这里详细记录下个人针对 有道翻译的 加解密全过程


一、定位接口

  1. 首先还是清除浏览器cookie后,刷新页面;
  2. 输入你好,查看响应的接口在这里插入图片描述
    如果无关的请求数量很多,可以先在这里插入图片描述清除,选择筛选Fetch/XHR, 再输入翻译,能最迅速定位
  3. 这里看一眼请求和响应,很显然翻译接口就是webtranslate
  4. 但是响应是一串莫名其妙的字符,显然是加密了,那就先破解加密。要是响应内容解不了密,请求再顺利也没有用

二、响应数据解密


首先还是先尝试搜索decrypt( 或decrypt,看下有没有明显的解密方法
在这里插入图片描述
确实有几个看起来可疑的,定位到对应位置,打上断点,重新输入翻译内容,再看是否断住。如果断住,看一下decrypt(相关参数和执行结果是否是我们想要的。这里可以自己试一下。这里试了下没有找到相关的方法,说明解密方法名可能不是decrypt。
或者也可能就是太多了我们不好找,都没关系,那就换个思路。借用接口名称定位

  1. 直接搜索webtranslate,找一下对应构造请求的位置在这里插入图片描述

  2. 或者用XHR断点,添加断点后,重新输入翻译就会断住在这里插入图片描述
    上述两种方法都可以。但是还是有一些区别。其中全局搜索定位到的位置,一般是构造请求的地方;XHR断点断住的地方,是send请求的地方,会更靠后。所以假设如果要通过接口名称定位请求参数加密,用全局搜索会更接近;如果要通过接口名称定位响应的解密,用XHR断点会更接近。一般还是都用XHR断点会更好

  3. 首先我们要注意下正常请求的加密响应是什么样子的在这里插入图片描述

  4. 加上XHR断点后,输入“你好”进行翻译,断住了,但是显然这里的地址是/webtranslate/key在这里插入图片描述

  5. 点击继续执行脚本到下一次断点,可以看到这次的地址是/webtranslate在这里插入图片描述

  6. 可以开始往下走了,一直点击向下执行,目的是找到返回响应,进行解密处理的地方。这里可以多注意下作用域,有没有我们关注的变量在这里插入图片描述

  7. 到这里就看到加密的响应了,继续往下走看什么时候解密出来在这里插入图片描述

  8. 很明显就能看到,在这里就是数据解出来的地方,这里decodeData方法应该就是我们要找的方法在这里插入图片描述

  9. 光标放到方法上,跳转到方法内部,左侧打个断点。因为函数已经执行过了,所以要重新刷新,输入“你好”,重新开始执行,一直跳到这个断点就行在这里插入图片描述

  10. 简单看下这个方法,很明显写了aes-128-cbc, 就是个 AES加密,CBC模式的(如果对AES什么的不熟,后面我会补充一种直接不管它什么加密,硬抠下来的方式,主要是看思路)。
    那么关键就在于秘钥key和偏移量vi,断点往后打。关键就是a,i参数在这里插入图片描述

  11. 这里a, i是Unit8Array, 用alloc方法生成的,那我们直接用nodejs的Buffer.alloc替换。再看下y()函数,就是简单的md5加密,返回二进制的值,可以直接拿下来。在这里插入图片描述

  12. y()方法传参o和n显然就是原始的秘钥和偏移量,是一串特殊的字符,全局搜索一下看一下能不能找到哪里来的。很显然是固定的字符串在这里插入图片描述

  13. 然后就是c.a.createDecipheriv方法,那就直接用node中内置的crypto加密库替换c.a。

  14. 整个解密函数就梳理完了,简单整理下,js代码如下 。执行没有问题

const crypto=require('crypto')
const o = 'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl';
const n = 'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4';

function y(e) {
    return crypto.createHash("md5").update(e).digest()
}
function decodeData(t){
        const a = Buffer.alloc(16, y(o))
      , r = Buffer.alloc(16, y(n))
      , i = crypto.createDecipheriv("aes-128-cbc", a, r);
    let s = i.update(t, "base64", "utf-8");
    return s += i.final("utf-8"),
    s
}
text='Z21kD9ZK1ke6ugku2ccWu4n6eLnvoDT0YgGi0y3g-v0B9sYqg8L9D6UERNozYOHqnYdl2efZNyM6Trc_xS-zKtfTK4hb6JP8XwCzNh0avc8qItQUiIU_4wKKXJlIpvMvfKvJaaZzaX6VEtpkr2FdkfoT_Jgbm2GRSVj3r40autIdlImENG8hC0ZH4ww7utwuTt3Oo_ZpXg0BSq9wePSAB75-ChkiGKF9HTIPeCl2bl84SBD1XDfFCZpkKQhecYSs0JLoXOqP2ltavxRrg58Hp1q5uIgZZ_Oo2-Jmd-t1r4es40drcAq5bjmS62M2VJF8D6ojtOh9JTfNwgzD3CxYn-Pd7-TgHMyNEJEkFXTAyxzpjlFqtrCYDE3SZUYlENkqsL8Wrra1hM-1nTfiB-BLcWAdRBynNpP5_54aq_-GBsq8bB_9yEX5ovzDB4_Ry_spVVuUnb39iplMHCdCnjOD3ngiIDbl9SUz-9npjBX05ZYRdPmFPAl424qdoaxeVqnVoH8jQFPZVqaHMzu4mJg0SICDWFH7GP1zqGRbXd3ESjT_iBInl3gICt2XVuhh_nubcELkTEC6xbqEDRQkPUNMpzXJHjcvsLHtcmSW0S9F0445ho9kT2qZYdMBC3Fs0OaHpUtFu77gZpQn7sGiqh8VliXIcUtfvvop-1c-Vu5QjfUbLn2-s5POR9fGYG6rt6ioe_PGmwWj-Cc00zUM7FybfarKTr4D3Rk57R72qpXN4Ja86ZsCAMmDG-m5z31RQh_V7echJ8Kna3Go3yWKCK4vtSwOWrFhiS5RTz6EkrGc3SkFKbb5vp8Wop_84myBtgnBmj4CczhTq2HcOxrJf4def6yDt2uBxyv4bTVGx9Yx3uB4Gx0iK5kYvfma6B_LnkRWk331wjuXKQtBGYIuWkR8J5QtvBmIRVaa7AA19Z4xMIEAqbcuQ5p4I9FCElthBrJd9YOcouHK4U27xxYWJJXcJjAU6hR_oB1nwjAlwdreYSrxqhhnMfxUlzwXnjkeHIQsIrXmyDqn1ecy2NyzUnoIscC4EigujhLKbuFQIzbD5YNhKxCwU1RSNRYYy_A1hktX'
console.log(decodeData(text))

这个代码也可以用python实现

import base64
from Crypto.Cipher import AES
import hashlib


def decode_data(text):
    # 偏移量
    decodeiv = "ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4"
    # 秘钥
    decodekey = "ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl"
    # 先把密匙和偏移量进行md5加密 digest()是返回二进制的值
    key = hashlib.md5(decodekey.encode(encoding='utf-8')).digest()
    iv = hashlib.md5(decodeiv.encode(encoding='utf-8')).digest()
    # AES解密 CBC模式解密
    aes_en = AES.new(key, AES.MODE_CBC, iv)
    # 将已经加密的数据放进该方法
    data_new = base64.urlsafe_b64decode(text)
    # 参数准备完毕后,进行解密
    a = aes_en.decrypt(data_new).decode('utf-8').strip()
    return a
  1. 对AEC转nodejs代码更多靠经验。最后面会讲下不管AES硬抠的方式,比较麻烦一些

三、构造请求

接下来破解请求参数加密。重头开始,还是先清除cookie 重新刷新,然后输入“你好”,定位到翻译接口/webtranslate。

首先生成cookie

首先还是将请求转成python代码执行。会发现有请求携带了cookie,并且删除cookie后无法请求成功。那就先看下cookie是什么。
搜索请求可以看到OUTFOX_SEARCH_USER_ID是某个请求set的,而OUTFOX_SEARCH_USER_ID_NCOO是在代码某处生成的。
那就先挖一下OUTFOX_SEARCH_USER_ID_NCOO。最后会发现生成OUTFOX_SEARCH_USER_ID_NCOO就是用固定数和随机数相乘得到的,那就是一串随机的数字,不重要。在这里插入图片描述
然后可以很容易发现OUTFOX_SEARCH_USER_ID好像就是某个数字加上某个ip地址。尝试手动改一下,结果发现,只要保持一定的格式就能用,最后改成下面这样完全没问题。

cookies = {
    "OUTFOX_SEARCH_USER_ID_NCOO": "",
    "OUTFOX_SEARCH_USER_ID": "1@1.1.1.1"
}

那就不管他的生成逻辑了,固定写死就行。

生成表单参数

  1. 查看请求参数,虽然参数很多,但比较明显能看出来,大部分都是固定的字符串,多试几遍也能看出来。其中真正需要的只有sign、mysticTime(比较明显就是时间戳)。 i是要翻译的内容,关键就是sign
    在这里插入图片描述
  2. 搜索一下sign:(一般这种参数加上:或者=去搜更快定位)在这里插入图片描述
  3. 在一些看起来可疑的地方都打上断点,然后重新输入、断住,看是不是我们想要的。最可疑的就是这里,很显然这几个参数的定义都是我们的请求中包含的。直接在第一行sign这里打上断点在这里插入图片描述
  4. 执行到这一行成功断住,划取选中 k(o, e)看执行结果,能看到是一串数字字母组合。不确定是不是这个,直接跳过断点执行,拿到翻译结果后,对比请求中的sign
    在这里插入图片描述
    在这里插入图片描述
    ?怎么不一样,难道不是这里吗?
    实际上我们在跳断点的时候会发现,在sign: k(o, e)这一行,断住了两次,所以我们拿第二次断住时生成的sign去对比webtranslate接口参数的sign才是一样的。第一次执行sign: k(o, e),是因为在调用webtranslate/key接口时也用到了该方法。对比第二次sign: k(o, e)的结果,可以确定sign就是这里生成的
  5. 为了方便观察全部参数,我们直接在该函数结束位置也打个断点,执行下去。然后选中k, 跳转到函数内部,这个k函数就是核心的方法在这里插入图片描述
  6. 可以看到k方法内部非常简单,就是拼接字符串,然后调用j方法进行MD5加密。参数也很简单,k(o, e)的o实际上就是上面定义的(new Date).getTime()是个时间戳。k(o, e)的e是一串奇怪的字符串‘fsdsogkndfokasodnaso’,还不知道是什么在这里插入图片描述
  7. 全局搜一下fsdsogkndfokasodnaso,发现跟前面解密时用到的AES的key和vi是一起的,也是个key,可以确定是固定的在这里插入图片描述
  8. 整个sign生成的逻辑就很清晰了:用时间戳+固定的key(可以认为变量只有时间戳)构造字符串进行md5加密生成的。简单。其中c.a还是用crypto加密库替换,key固定,保留时间戳传参(没有直接在这里生成时间戳,因为请求的表单参数里有个单独的时间戳字段mysticTime,两边保持一致)
function j(e) {
    return C.createHash("md5").update(e.toString()).digest("hex")
}
function getSign(timestamp) {
    return j(`client=fanyideskweb&mysticTime=${timestamp}&product=webfanyi&key=fsdsogkndfokasodnaso`)
}

请求加密部分的代码还是比较简单的。把写好的请求和响应内容解密的代码放一起,试一下,没有问题。
整个过程也不难,完整代码就不贴了。有兴趣的可以自行尝试下。


总结

以上方法仅用于学习参考

  • 21
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值