测试地址。可以看到需要分析的为sign和password,password我试过了是md5。那么sign就从启动器那里断点。从这里下断,因为是异步的。然后找w的数组分别定义的元素。发现sign信息,从这里断点,发现走了后面那段,也就是h.c(e)。h.c跳转到w函数,通过w函数经过后续分析,f函数其实是md5,后续就很好解决了,总之就是这样。
假设列表[4,5,2,1,3],按从小到大排序。外层for循环是定义比较轮数,内层for循环指的是交换次数。那么就会两层for循环例如A(外)和B(内)且 A<len(列表长度)-1,因为五个元素,只需要比较四次。B<len(列表长度)-1-i(当前A循环的次数i),因为每轮最后一个元素都会变成最大的,于是后续就不需要进行重复比较。例如第一次循环,外层为0(下标),内层是0,然后通过判断元素下标来交换元素。第二次循环,外层下标为1,内层要额外除去第一轮排序的最后一个元素(因为已经有最大值在最后了,不需要比较)Y = [4,5,2,1,3]len = length(Y) // 假设 len 是获取列表长度的函数// 外层循环:控制比较的轮数// n个元素需要 n-1 轮比较for(var i = 0; i < len - 1; i++){// 内层循环:控制每轮比较的次数 // 每轮将当前未排序部分的最大元素“冒泡”到末尾 // 每次外层循环结束后,都会有一个元素(最大的)排到正确位置 for(var j = 0; j < len - 1 - i; j++){
java中的继承代表实例化一个子类,子类依旧可以调用父类的方法和属性,可以省去子类单独编写一些重复代码,例如eat、sleep这种,还有一些通用方法啊,在父类设置后直接子类继承,很方便。多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。下面是关于继承与多态相关的代码:public class Main { public static void main(String[] args) { Person p = new Student(); System.out.println(p.num); //返回 1 p.run(); //返回 Student.run 不论加不加 override 只要是父类声明的非static方法,子类也有的同名方法,都会调用子类的方法。 System.out.println(p.name); //返回 jack // System.out.println(p.type); // 报错 因为引用了不在引用类型中的变量。 // p
下面的代码中,字符串其实并没有变,变的只是s的指向。// 字符串不可变 public class Main { public static void main(String[] args) { String s = "hello"; System.out.println(s); // 显示 hello s = "world"; System.out.println(s); // 显示 world } }以及这段代码中,输出的是hello,因为从s = "hello" 开辟了hello这个字符串的空间,还有s指向了hello这个字符串;t=s,s是个指针指向的是字符串,所以t也指向hello,那么当s被赋值为world时,s的指针指向了world字符串,并不影响原先的t指针,所以打印t依旧是hello。// 字符串不可变 public class Main { public static void main(String[] args) { St
网址:aHR0cHM6Ly9mdXd1Lm5oc2EuZ292LmNuLw==/(ㄒoㄒ)/~~哎呀这个老烦人了,我明明参数都解决了,就是不给通过,我寻思着算法应该没问题啊。等大佬来解惑。可以看到需要分析 x-tif-signature、signData、encData1.x-tif-signature的话直接就能搞定了。测试过了是原生的sha256.2.signData也在这个f函数内部被赋值,往下断点。这是未进入 t.data.signData 函数内部的t值{ "transformRequest": {}, "transformResponse": {}, "timeout": 30000, "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN", "maxContentLength": -1,
使用fabric来批量控制VPS运行脚本:from fabric import Connection, Config from loguru import logger # 服务器列表(包含密码) servers = [ {"host": "1223:3333:103:218::32", "user": "root", "port": 22, "password": "your_password_1"}, # {"host": "192.168.1.102", "user": "root", "port": 2222, "password": "your_password_2"} ] comm = input('请输入命令(回车跳过):') comm = comm if comm else &q
有这么一种网站,访问请求会发送三次,第三次才能返回响应结果,并且前两次返回521状态码,那么这个网站就是采用了加速乐Cookie反爬。首先看第一次请求,响应的是一段js代码,这段js代码执行后是设置cookie的。然后是第二次请求,响应的也是段js,这段js是设置第二次的cookie的(__jsluid_s由第一次访问url后服务器那边返回设置的)。第二次的请求需要携带第一次请求返回js执行后设置的cookie。即__jsl_clearance_s为第一次返回内容js执行后的结果。第三次请求,变的只有__jsl_clearance_s,也就是第二次返回的js执行的一些操作导致cookie的更变。所以我们要逆向的目标就是第二次返回的js内容。把js复制下来然后贴到控制台代码段那里分析因为该代码更改的是cookie,所以我们提前控制台输入hook cookie代码,然后提前下断点。// hook cookie代码 (function () { 'use strict'; var org = document.cookie.__lookupSetter__('cookie')
补环境主要是补DOM和BOM,一些nodejs没有的属性啊之类。关于 Proxy 对象用来补环境是很方便的,例如监听了window对象,那么运行一些混淆的代码,就能判断该方法做了什么改变。当混淆的js想要获取window的某个属性,就可以通过拦截然后输出到控制台,然后我们可以补下来。 const proxy = new Proxy(obj, { get(target, prop) { console.log("方法:Get ||","对象", name, '属性', prop, '值:', target[prop]); return target[prop]; }, set(target, prop, value) { console.log("方法:Set ||","对象", name, '属性', prop, '修改值:',
这是原始请求包:这是处理的json,可以看到默认python处理的会添加空格,我们要保持和原始请求包一样。毕竟有的时候反爬虫可能会检测这些。
本次測試網址。如圖所示,本次分析K參數,先去啓動器找到發送的地方下斷點。發現k值已經生成,那麽就往前調,從堆棧那裏。定位到異步方法,跟進去這個m,進攔截器裏面找request下斷點。發現此時沒有k值生成,因爲t方法還沒有執行。控制臺輸入HOOK代碼,把 e.data hook住。Object.defineProperty(e, 'data', { set(){ debugger } })然後發現hook成功,繼續往上跟於是便找到了k的生成邏輯。跟y.a函數,進入内部把整個函數複製本地,然後運行,修修補補最終發現y.b,然後跟,就會發現是個aes128加密,即對稱加密算法。然後用gpt生成相同邏輯的加密代碼,運行。最終結果對比:aes的參數在login頁面有。const crypto = require('crypto'); /** * AES-128-CBC 解密函数 (对应原 h 函数) * @param {string} e - 要解密的hex字符串 * @param {string} n - 密钥(utf8字符串) * @param {s
地址請求頭的X-sign需要逆向,斷點后找到 r["x-sign"] = s(e, t)e和t參數直接從瀏覽器複製,進入s函數發現返回md5加密值,分析是否為標準md5,上面的if條件為true,所以else語句不用複製到本地。最終測試結果:var crypto = require('crypto'); function md5(password) { var md5 = crypto.createHash('md5'); return md5.update(password).digest('hex'); } function r(e, t) { if (!e.headers || !e.headers["x-platform"]) return t.cid; var n = t.headerEncryptKeys.find(function (t) { return t.name == e.headers["x-platform"] }); return n
跟進去這個u,再跟P發現這個是返回好幾層的函數,例如下面這種找到最外層代碼發現是自執行函數,將其複製到本地運行發現G未定義,把G也複製過去。最終代碼window = global e = window var G = "undefined" !== typeof e ? e : "undefined" !== typeof window ? window : "undefined" !== typeof self ? self : void 0 , Y = function(e) { return e && "undefined" != typeof Symbol && e.constructor === Symbol ? "symbol" : typeof e }; (function() { var e = function(e, t,
測試網址:https://www.megabit.vip/在請求頭中有個Sign參數需要逆向分析,搜索關鍵詞定位。定位到這裏分析,三元表達式,即 true ? 條件成功的分支:條件失敗的分支。這裏最終走的是Object(y.a)((new Date).getTime())const l = (null === (t = e.url) || void 0 === t ? void 0 : t.includes("/pro/u/withdraw/create")) ? C((new Date).getTime()) : Object(y.a)((new Date).getTime())跳轉過去找把這些有用到的複製到本地,這個是webpack形式,那麽就先在n那裏斷點后刷新頁面然後跳進函數把加載器摳出來這個就是加載器,然後本地寫一個自執行函數把加載器放進去,外部生成一個變量用於接收自執行函數内部的加載器函。通過打印輸出分析加載進去的模塊,然後通過瀏覽器扣就好了,用到哪個就將其放到模塊列表即可。 var uu !function (e) { function f(f
当spider发起一个请求时,request会先经过中间件1的process_request进行处理,然后到达中间件2的此方法进行处理,当经过所有的中间件的此方法处理之后,最后到达下载器进行网站请求,然后返回响应内容。process_response就是逆序处理,先到达中间件2的此方法,再到达中间件1,最后响应返回spider中,由开发者处理。
我的理解:首先Spider把請求對象發送到引擎,引擎又發送給調度器,調度器中的過濾器負責(URL去重)然後放入請求隊列。然後調度器返回給引擎,引擎發送到下載器,下載器從互聯網請求資源,后返回給引擎。引擎返回給Spider返回内容,Spider解析數據后再次提交給引擎,引擎把解析數據交給管道用於持久化存儲數據。