JS逆向入门案例-某花顺股票数据(hexin-v)-07

文章目录

    • 概要
    • 整体架构流程
    • 小结

概要

提示:仅供学习,不得用做商业交易,如有侵权请及时联系!

逆向:某花顺股票数据

URL:aHR0cHM6Ly9xLjEwanFrYS5jb20uY24v

目的:hexin-v(cookie)

整体架构流程

提示:分析-调试-猜想-实现-执行

一、hook进行断点

	(function () {
	  'use strict';
	  var cookieTemp = '';
	  Object.defineProperty(document, 'cookie', {
	    set: function (val) {
	      if (val.indexOf('v') != -1) {
	        debugger;
	      }
	      console.log('Hook捕获到cookie设置->', val);
	      cookieTemp = val;
	      return val;
	    },
	    get: function () {
	      return cookieTemp;
	    },
	  });
	})();

在这里插入图片描述

继续往上跟栈,找到值生成的地方:

在这里插入图片描述
二、这里我们直接补环境,直接将该js文件全部扣下到node里面,并挂上代理:

my_Proxy = function (obj_, obj_name, proxy=true) {
   function set_traverse_object(tarrget, obj, recursion_layers) {
       recursion_layers -= 1;
       console.log();
       for (let prop in obj) {
           const value = obj[prop];
           const tg_name = `${tarrget}.${prop.toString()}`;
           const value_type = get_value_type(value);
           if (value && value_type === "object" && recursion_layers >= 1) {
               set_traverse_object(tg_name, value, recursion_layers);
               continue
           }
           if (value && value.toString() !== '[object Object]') {
               console.log(`setter  hook->${tg_name};  value-> ${value};  typeof-> ${value_type}`);
               continue
           }
           console.log(`setter  hook->${tg_name};  value-> ${value};  typeof-> ${value_type}\n`)
       }
   }

   function new_handel(target_name, obj, number) {
       return new Proxy(obj, my_handler(target_name, number))
   }

   function get_value_type(value) {
       if (Array.isArray(value)) {
           return 'Array'
       }
       return typeof value;
   }

   function my_handler(target_name, number) {
       return {
           set: function (obj, prop, value) {
               const value_type = get_value_type(value);
               const tg_name = `${target_name}.${prop.toString()}`;

               if (value && value_type === "object") {
                   set_traverse_object(tg_name, value, number)
               } else {
                   console.log(`setter  hook->${tg_name};  value-> ${value};  typeof-> ${value_type}`)
               }
               return Reflect.set(obj, prop, value);
           },
           get: function (obj, prop) {
               const tg_name = `${target_name}.${prop.toString()}`;
               const value = Reflect.get(obj, prop);
               let value_type = get_value_type(value);
               if (value && value_type === 'object') {
                   return new_handel(tg_name, value, number)
               }
               console.log(`getter  hook->${tg_name};  value-> ${value};  typeof-> ${value_type}\n`);
               return value
           },
           deleteProperty(target, propKey) {
               // 没有实现链式输出
               let result = Reflect.deleteProperty(target, propKey);
               let value_type = get_value_type(result);

               console.log(`delete hook-> ${propKey}, result-> ${result};  typeof-> ${value_type}\n`);
               return result;
           }
       }
   }
   if (!(proxy === true)){
       return obj_;
   }
   return new Proxy(obj_, my_handler(obj_name, 30));
};
function monitorWindow(obj, obj_str) {
   // 设置打印字符串长度
   const MAX_VALUE_LENGTH = 70;
   /**
    截取 value 值,用于在日志中输出时限制字符串长度,避免日志过长。
    @param {Object} value - 需要被截取的值。
    @returns {Object} 返回截取后的字符串值。
    */
   function truncateValue(value) {
       if (typeof value === "string" && value.length > MAX_VALUE_LENGTH) {
           return value.substring(0, MAX_VALUE_LENGTH) + "...";
       }

       if (typeof value !== "object") {
           return value;
       }

       const keys = Object.keys(value);
       const result = {};

       if (keys.length > 2) {
           result[keys[0]] = value[keys[0]].toString().substring(0, MAX_VALUE_LENGTH) + "...";
       }

       return "{" + Object.entries(result).map(([k,v])=>`${k}: ${v}`).join(", ") + "}";
   }

   /**
    序列化 value 值,用于在日志中输出时处理对象或方法。
    @param {Object} value - 需要被序列化的值。
    @returns {Object} 返回序列化后的字符串值。
    */
   function serializeValue(value) {
       if (typeof value === "object") {
           try {
               return JSON.stringify(value);
           } catch {
               return value;
           }
       }
       return value;
   }

   /**
    * 创建代理处理程序,用于对被代理对象的属性访问、属性设置、方法调用等进行监听并打印操作日志。
    * @param {Object} name - 对象名。
    * @returns {Object} 返回代理处理程序。
    */
   function createHandler(name) {

       function shouldSkipKey(key, name) {

           if (key === 'window' || key === 'self' || key === 'global' || key === 'globalThis' || key === name || key === "_globalObject") {
               return true;
           }

           if (typeof key === 'string' && (key.startsWith('__') || key.endsWith('__'))) {
               return true;
           }

           return String(key) === "Symbol(impl)" || String(key) === "Element" || String(key) === "prototype" || truncateValue(serializeValue(name)).includes("Symbol(impl)");

       }
       return {
           get(target, key, receiver) {
               // 打印调用栈
               // console.log(new Error().stack);
               // target=Object.defineProperty(target)
               // 获取属性值

               const value = target[key];

               // 不打印toString和valueOf特定的信息
               if (key === Symbol.unscopables || key === 'toString' || key === 'valueOf') {
                   return Reflect.get(target, key, receiver);
               }

               // 内部属性
               if (shouldSkipKey(key, name)) {
                   // debugger
                   if (typeof key != 'number') {
                       console.log(`访问: "${(String(key) + "\"内部属性").padEnd(28, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
                   }
                   
                   return value;
               }

               // 处理代理函数的构造函数
               if (typeof value === 'function' && value.hasOwnProperty('prototype')) {
                   try {
                       new value
                       // console.log(`调用了构造函数: ${String(key).padEnd(22, " ")} |"参数": ${JSON.stringify(value)}`);
                       return new Proxy(value,createHandler(`${String(name)}.${String(key)}`))
                   } catch (e) {}
               }

               // 处理代理对象的属性访问和设置()
               if (typeof value === 'function' && !value.hasOwnProperty('prototype')) {
                   return function getFunc(...args) {
                       try {
                           var result = Reflect.apply(value, target, args);
                           console.log(`调用了函数: ${(String(key)).padEnd(27, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|参数= ${truncateValue(serializeValue(args))}`);
                           return result
                       } catch (e) {// return  Reflect.apply(value, target, args[1])
                       }
                   }
               }

               // 处理代理对象的属性访问和设置(递归调用)
               if (value != null && (typeof value === 'object')) {
                   if ('number' === typeof key) {
                       console.log('key:', key);
                       console.log(`访问: "${(String(key) + "\"属性").padEnd(30, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
                   }
                   
                   return new Proxy(value,createHandler(`${String(name)}.${String(key)}`));
               }

               if (typeof value === 'function') {
                   // 在Node上和windows有些差异,node有函数也有prototype,所以需要继续回调
                   return new Proxy(value,createHandler(`${String(name)}.${String(key)}`));
               } else {
                   // 不进行代理的属性或方法
                   if (key != 'toJSON') {
                       console.log(`获取: "${(String(key) + "\"属性").padEnd(30, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
                   }
                   
               }
               return value;
           },
           set(target, key, value, receiver) {
               // 打印调用栈
               // console.log(new Error().stack);
               console.log(`设置对象: "${(String(key) + "\"").padEnd(28, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|值=`, truncateValue(serializeValue(value)));
               return Reflect.set(target, key, value, receiver);
           },
           apply(target, thisArg, args) {
               // 打印调用栈
               // console.log(new Error().stack);
               console.log(`调用了函数: ${(String(name)).padEnd(27, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|参数= ${truncateValue(serializeValue(args))}`);
               return Reflect.apply(target, thisArg, args);
           },
           construct(target, args, newTarget) {
               // 打印调用栈
               // console.log(new Error().stack);
               console.log(`调用了构造函数: ${String(target.name).padEnd(23, " ")}|"${(truncateValue(serializeValue(name)) + "\"对象").padEnd(50, " ")}|参数= ${JSON.stringify(args)}`);
               return Reflect.construct(target, args, newTarget);
           },
       };
   }
   return new Proxy(obj,createHandler(obj_str));
};

直接搜索:var rt;,给它定义成全局变量

在这里插入图片描述

挂上代理,我们直接补上window、document、navigator、location

在这里插入图片描述

继续将undefined改为浏览器对应的值:

在这里插入图片描述

下面的自己慢慢补吧,直接划一波水,帖一波最后的环境值:

window = global;
addEventListener = function () { };
document = {
    head: {},
    getElementsByTagName: function (res) {
        return []
    },
    createElement: function (res) {
        if (res === 'canvas') {
            return {
                getContext: function (res) {
                    if (res === 'webgl2') {
                        return {}
                    }
                }
            }
        }
        return {}
    },
    addEventListener: function () { },
    documentElement:{}
};
navigator = {
    plugins: {
        length: 2,
        '0': {
            name:'Chromium PDF Plugin'
        },
        '1': {
            name:'Chromium PDF Viewer'
        }
    },
    userAgent: 'Mozilla/5.0 (Windows NT 10.0; JiSu) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.3.1.7 Safari/537.36',
    javaEnabled: function () {
        return false
    },
    webdriver: false,
    doNotTrack: null,
    language: 'zh-CN',
    languages: ['zh-CN', 'zh'],
    platform: 'Win32',
    vendor: 'Google Inc.',
    appVersion:'5.0 (Windows NT 10.0; JiSu) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.3.1.7 Safari/537.36'
};
location = {
    "ancestorOrigins": {},
    "href": "https://脱密处理/",
    "origin": "https://脱密处理",
    "protocol": "https:",
    "host": "脱密处理",
    "hostname": "脱密处理",
    "port": "",
    "pathname": "/",
    "search": "",
    "hash": ""
};
XMLHttpRequest = function () { }
window.hasOwnProperty_ = hasOwnProperty;
hasOwnProperty = function (res) {
    if (res === 'fetch') {
        return true
    }
    return window.hasOwnProperty_(res)
}
Window = function () {
    
}

在这里插入图片描述

三、最终就是实现python

在这里插入图片描述

小结

提示:学习交流群:v:wzwzwz0613拉进群

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值