当前位置:   article > 正文

pdd(web)逆向分析_pdd webpack 逆向 window=global

pdd webpack 逆向 window=global

某购物网站逆向

url:'aHR0cHM6Ly93d3cucGluZHVvZHVvLmNvbS9ob21lL2JveXNoaXJ0Lw=='

目标:抓取到商品数据,难点:补环境+export时间戳

声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢!(手动狗头)

一、抓包分析

很明显,咱要的东西就是在这,然后要逆向的参数就是anti_content

二、寻找anti_content

直接搜索

发现有两个地方,很开心,分别打上断点,然后刷新页面

发现断到这里了,然后发现此时还没有找到anti_content

然后走t.next = 10,最后return Object(l.a)();

控制台打印一下Object(l.a)();

发现是个Promise对象(pending状态),那么我们就打印看看它的返回值

发现就在这里!进去l.a看看

走y这个函数,此时this指向什么?就是new y,也就是y的实例,然后怎么办呢?找y函数呗

仔细一瞧,发现y的函数就在下面

  1. function y() {
  2.            return (y = u(i.a.mark(function e() {
  3.                return i.a.wrap(function(e) {
  4.                    for (; ; )
  5.                        //前面都是乱七八糟的,不用看
  6.                        switch (e.prev = e.next) { //一开始就是0=0
  7.                        case 0:
  8.                            if (r) {
  9.                                e.next = 3;
  10.                                break
  11.                           }
  12.                            return e.next = 3, //这里敲个断点
  13.                            new Promise(function(e) {//promise对象
  14.                                c.push(e),
  15.                                f()
  16.                           }
  17.                           );
  18.                        case 3:
  19.                            return e.next = 5,
  20.                            r.messagePackSync();//这里也敲一个断点
  21.                        case 5:
  22.                            return e.abrupt("return", e.sent);
  23.                        case 6:
  24.                        case "end":
  25.                            return e.stop()//结束值
  26.                       }
  27.               }, e)
  28.           }))).apply(this, arguments)
  29.       }

仔细分析发现,先来到return e.next = 3 ,先看看这个promise的结果

很明显,不是这里,接着来到r.messagePackSync();//这里也敲一个断点

歪日,发现结果就在这,进去干

wc,混淆,不要怕,这是好消息至少位置对了,不然为啥要混淆,此地无银三百两((//̀Д/́/)),先断到promise对象这里

发现值已经生成了,很明显最后的n[r("0x15c", "S]Zj")](t, nr("0x1bb", "A3e0"))有很大问题

发现咱要的结果出来了,嘿嘿,简化一下看看,就是dt()

跳过来终于发现咱要的就是dt()函数,提前预定window.dog = dt()

三、扣代码

将所有代码扣下来拉到Notepad++里面,折叠所有层次

发现是webpack,简单~首要任务就是找调度器

先把dt()所在的层次扣下来

发现就是fbeZ这一个层次,直接弄过去,然后顺带在dt函数执行完了之后加个window.dog = dt()

那么我们之后就是要执行下fbeZ这个函数,让得到的anti_content值赋值给window.dog变量

那么想要执行webpack,第一步找调度器

3.1 寻找调度器

找到最开始的fbeZ,打印输出n函数,然后跳转到调度器

发现就在这里,那咱甭跟它客气,直接全扣,

然后再增加这两个地方用来输出r ,以及将调度器赋值给全局变量

3.2定义个函数输出anti_content

找到调用fbeZ所需要的三个参数

  1. function get_data(){
  2.    //获得三个参数
  3.    var e = {"i":"fbeZ","l":false,"exports":{}},
  4.        t = {},
  5.        n = window.loaders //就是n函数
  6.    fbeZ(e,t,n)//执行fbeZ
  7.    console.log(window.dog())
  8. }

执行结果:

又到了愉快的补环境时间~

四、补环境(一)

4.1 8oxB+ YuTi webpack

直接搜索8oxB

发现在这个文件,直接扣下来

同理可得YuTi

找到这个地方 ("0x3f", "LZ%H")in re[P];

注意:搜索的时候必须要取消空格,不然根本搜不到

4.2 补充基本环境

很明显,看到document就知道精彩的东西来了,开始一些基本的补环境,那就是windows、location、document、history、navigator

location

navigator

screen

 

在控制台分别打印输出

  1. // 一、补充window环境
  2. window = {}
  3. window = global;
  4. //二、补充 document
  5. document = {
  6.    referrer: 'https://www.pinduoduo.com'
  7. }
  8. Document = function Document() {
  9. }
  10. Object.setPrototypeOf(document, Document.prototype)
  11. Document.prototype.addEventListener = function () {
  12. }
  13. Document.prototype.cookie =  '_nano_fp=Xpmon5EoXpCqX0doXT_ubdWsBT4vZ2vjB~PCm7Pn; api_uid=rBUUO2W4rXuDCDYK0P5+Ag=='
  14. //三、补充 location
  15. location = {
  16.    'hash': "",
  17.    'host': "www.pinduoduo.com",
  18.    'hostname': "www.pinduoduo.com",
  19.    'href': "https://www.pinduoduo.com/home/girlclothes/",
  20.    'origin': "https://www.pinduoduo.com",
  21.    'pathname': "/home/girlclothes/"
  22. }
  23. Location = function Location() {
  24. }
  25. Object.setPrototypeOf(location, Location.prototype)
  26. // 四、补充 navigator
  27. navigator = {
  28.    appCodeName: "Mozilla",
  29.    appName: "Netscape",
  30.    appVersion: "5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0",
  31.    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0'
  32. }
  33. Navigator = function Navigator() {
  34. }
  35. Object.setPrototypeOf(navigator, Navigator.prototype)
  36. Navigator.prototype.hasOwnProperty = function () {
  37.    return true
  38. }
  39. // 五、补充 screen
  40. screen = {
  41.    // width: 1728,
  42. }
  43. Screen = function Screen() {
  44. }
  45. Object.setPrototypeOf(screen, Screen.prototype)
  46. // 六、补充 history对象
  47. history = {}
  48. History = function History() {
  49. }
  50. Object.setPrototypeOf(history, History.prototype)
  51. History.prototype.back = function () {
  52. }
​
​

发现此时已经出了值,但是真的那么简单吗?

那我们拿到值去试一试


很明显,没那么简单

五、补环境(二)

那么我们到底是哪里的问题呢?

第一反应是补环境没补全,可以用node-inspect 打印输出看看,到底哪些值没有弄。先配置好proxy代理(说白了就是hook)

5.1 配置代理

  1. // proxy代理声明
  2. function proxy_watch(obj) {
  3.    return new Proxy(obj, {
  4.        get(target, p, receiver) {
  5.            debugger;
  6.            let val = Reflect.get(...arguments);
  7.            console.log("get", target, "=获取属性>", p, "=值>", val);
  8.            return val;
  9.       },
  10.        set(target, p, value, receiver) {
  11.            debugger;
  12.            console.log("set", target, "=设置属性>", p, "=值>", value);
  13.            return Reflect.set(...arguments);
  14.       }
  15.   });
  16. };
  17. window = proxy_watch(window)
  18. document = proxy_watch(document)
  19. location = proxy_watch(location)
  20. navigator = proxy_watch(navigator)

5.2 删除node里的环境

随便补齐一点点,发现还是不能通过,后来我意识到这样补下去没有尽头,于是我就思考,有些浏览器不能执行,而node里可以执行,也就是检测到node

www.zhihu.com/question/584082357

  1. //在node中删去以下的东西
  2. delete global;
  3. delete Buffer;

发现还是没有获得值

六、查找其它问题

让我们先思考下,整个调用流程是什么,首先毫无疑问就是先用调度器(自执行函数)这里毫无疑问,所有的都要执行

然后将调度器赋值给全局变量window.loaders,作为参数n传递给fbeZ,问题就在于fbeZ执行过程中,绝对有哪一部分没有执行到。

先看看dt有没有执行到

执行了并赋值了,说明上面的代码都没问题,继续往下拉代码看看

分别在每一段可疑的地方插上的console输出,看看到底哪里没有执行

那么我们可以直接在网站上找到t[_("0x1d0", "&CF7")]

发现是exports,已经是说浏览器上加载了这个exports,而本地环境中没有去加载

  1. var lt = new ut;
  2. t[_("0x1d0", "&CF7")] = function() {
  3.    var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}
  4.   , t = _;
  5.    return e[j] && re && lt[t("0x1f", "@0Zy")](e[j]), //发现此时执行的lt(ut对象的实例)
  6.        lt
  7. }
  8. /*
  9. t("0x1f", "@0Zy") == "updateServerTime"
  10. e[j] == 1706758046 时间戳
  11. 很明显,咱的对象就是围绕时间,没有经过exports,我们用的都是错误的时间,导致得到的结果就是错误的,那么如何才能保持时间正确呢?
  12. 两种方法:
  13.   一、找到ut函数,去寻找跟时间有关的东西,然后把它变成动态的
  14.   二、
  15. */

6.1 查找ut函数

然后往下查找

发现该地方出现了时间戳,很可疑,打上断点然后刷新页面,此时 e[j] = undefined,t("0x135", "O3]W") = “updateServerTime”

很明显就是将一个固定的数值当作时间戳赋值过去,那么我们要做的正是替换 改成如下代码,获得动态的时间戳

this[t("0x135", "O3]W")](new Date().getTime());

此时结果出来了,看着像是我们瞎猫碰到死耗子,看着挺简单的,但实际上这东西需要思考几小时才能发现,狗

6.2执行export

  1. return e[j] && re &&  lt[t("0x1f", "@0Zy")](e[j]), //发现此时执行lt,lt[t("0x1f", "@0Zy")]作为函数
  2.    
  3. lt["updataServerTime"](e[j])
  4. //e[j]此时为固定值,所以需要持续更新的时间戳

6.3 总结pdd恶意时间戳

到此为止我们已经把恶意的时间戳给补齐,也算是个大坑,平常谁会想到这个时间竟然是个检测点,太nb了。

现在我们就去找找updataServerTime到底是怎么更新时间戳的,我们直接全局搜索servertime

分别到这两个地方打上断点,刷新页面寻找时间是如何过来的

发现此时断点断在了这里

e是从t.sent传过来的,而t.sent作为上一步的返回值,需要找的就是W(),进入到l后发现又是个控制流

从上到下执行时,很明显case2后面都是一些判断逻辑,而t.server_time是已经拿到时间戳了,真相就在我打断点的那一行,也就是o.a

  1. Object(o.a)("/api/server/_stm", "get", {}, "https://apiv2.pinduoduo.com");
  2. /*
  3. 这里我们可以知道传入参数分别为url,请求方式是get请求
  4. 然后我们就要找o.a函数
  5. */
  6. function i(e, t, n, r) {
  7.    //t == get, e、r都是一段url
  8.            "" === t && (t = "post");
  9.            var i = {
  10.                url: e,
  11.                method: t,
  12.                data: n
  13.           };
  14.    //返回的结果是一个Promise对象
  15.            return new Promise(function(e, t) {
  16.                Date.now();//猜的没错是个时间戳
  17.                o.a.create({
  18.                    headers: {
  19.                        Accept: "application/json, text/javascript",
  20.                        "Content-Type": "application/json;charset=UTF-8"
  21.                   },
  22.                    timeout: 3e3,
  23.                    baseURL: r || "https://home-api.pinduoduo.com"
  24.               })(i).then(function(t) {
  25.                    e(t)
  26.               }).catch(function(e) {
  27.                    t(e)
  28.               })
  29.           }
  30.           )
  31.   }
  32. //到这里我有点好奇baseurl + url(e+r) 发送请求后的返回值是啥

发现就是请求该接口返回到server_time的值,而promise对象就是调用接口

此时e已经是时间戳了,作为一个对象{ serverTime: e };

传递给i函数,new i是个实例,我们可以跳到i函数看看

发现这不就是export

这个t[G]就是时间戳,X = 879609302220 也是最初的值,要来到这里重新赋值

这就是恶意时间戳,我只能说一句NB

七、代码整合

歪日,干了那么久终于要结束了,都不知道以后瑞数、Akamai、航司、227该如何下手,诶,走一步看一步吧

js代码就不弄上来了,2w多行自己去扣吧,现在就扣下python代码,然后给你们看看执行结果吧

  1. import requests
  2. import subprocess
  3. from functools import partial
  4. subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
  5. import execjs
  6. headers = {
  7.    "Accept": "application/json, text/javascript",
  8.    "Accept-Language": "zh-CN,zh;q=0.9",
  9.    "Cache-Control": "no-cache",
  10.    "Connection": "keep-alive",
  11.    "Origin": "https://www.pinduoduo.com",
  12.    "Pragma": "no-cache",
  13.    "Referer": "https://www.pinduoduo.com/",
  14.    "Sec-Fetch-Dest": "empty",
  15.    "Sec-Fetch-Mode": "cors",
  16.    "Sec-Fetch-Site": "same-site",
  17.    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0",
  18.    "sec-ch-ua": "^\\^Not",
  19.    "sec-ch-ua-mobile": "?0",
  20.    "sec-ch-ua-platform": "^\\^Windows^^"
  21. }
  22. url = "https://apiv2.pinduoduo.com/api/gindex/tf/query_tf_goods_info"
  23. with open('anti_content.js', 'r', encoding='utf-8') as f:
  24.    JS = f.read()
  25. code = execjs.compile(JS)
  26. anti_content = code.call('get_data')
  27. print(anti_content)
  28. params = {
  29.    "tf_id": "TFRQ0v00000Y_13397",
  30.    "page": "1",
  31.    "size": "100",
  32.    "anti_content": anti_content
  33. }
  34. response = requests.get(url, headers=headers, params=params)
  35. print(response.text)

OK,完结撒花,记录下踩的坑,还得继续学习

提前祝各位新年快乐!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/170972
推荐阅读
相关标签
  

闽ICP备14008679号