接受数据:
302:重定向
set-cookies
可能返回:文本 (json xml jsonP)字节数据
this 方法谁调用就是谁
arquments 方法的全部参数数组(方法可以不带参数)
call v8引擎自带的方法 运行一个函数的 函数.call(this,参数1,参数2,参数3.··.参数N)
apply v8写引擎自带的方法 运行一个函数的 函数.apply(this,[参数1,参数2,参数3,.·参数N])
逗号表达式 语句1,语句2,语句3 js看做一句,返回是最后一个语句
对象: {} obect.assign() class new function
var a={1,2,3,4} ,a=4
Object.assign() 方法用于将一个或多个源对象的所有可枚举属性复制到目标对象中,并返回目标对象。该方法的语法如下:Object.assign(target, …sources)
按ctrl,显示方法作用域
在控制台关闭警告
找函数作用域,看变量由哪里传进来
AES 明文/密文 KEY/秘钥 IV/偏移 加密模式 (CBC,ECB)
CBC需要IV
ECB不需要IV
32位sign:md5
webpack 打包js代码
下断点方式
1.用url,截取url后一段,添加xhr断点
目标网站:
https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=
2.通过js点进去
3.在源代码,用元素断点
fiddler本地替换js代码
本地修改js文件,断点要断在前面
3.JavaScript基础
解释型语言 前后端都可以写 写游戏 也可以写wg
弱类型 类型之间的计算
基础语法
console.log(1+'1')
console.log('1'-0)
console.log(1+true)
console.log('1'+true)
a='123\
asd\
qwe'
console.log(a)
11
1
2
1true
123asdqwe
对象
console.log([1,"1",true][0] )
console.log([1,"1",true]["length"] ) 属性方式
console.log([1,"1",true].length ) 方法
1
3
3
方法 函数 语句和逻辑 的 集合
()=>{} 箭头表达式
function xx(){
}
(function(){}) //匿名函数
调用:
(()=>{})()
function xx(){
}
xx()
function xx(){
}()
(function(){})()
a=(function(){})
加上()运行函数
变量定义,作用域不同:
a=1
var b=1
let c=1,在内部有效
console.log(2^3,2|3,2&3) //异或、或、与
console.log(2**3)//阶乘
1 3 2
8
function括号前加;,不然1和function会识别到一起
var a=1
;(function (){
})()
赋值运算符
变量= !变量 值 +=
虚拟机jsvmp 是由 原子操作+栈构成
字面量 是由 原子操作 (最小操作) 构成
表达式 是由 字面量和操作符构成
语句 是由 表达式构成的
程序 是由 语句构成的
混淆的字面量
{a:1}.a 不是一个语句,想把它变成语句,用括号括起来
({a:1})['a']
({a:1}).a
var b=['a']
;({a:1})[b[0]]
var b=['YQ==']
function c(index){
return atob(b[index])
}
;({a:1})[c(0)]
let day = new Date().getDay();
let dayName;
switch (day) {
case 0:
dayName = "Sunday";
break;
case 1:
dayName = "Monday";
break;
case 2:
dayName = "Tuesday";
break;
case 3:
dayName = "Wednesday";
break;
case 4:
dayName = "Thursday";
break;
case 5:
dayName = "Friday";
break;
case 6:
dayName = "Saturday";
break;
default:
dayName = "Unknown";
}
console.log("Today is " + dayName);
typeof 并不能准确的返回类型
继承 (实现的功能)—原型链(原理)
实例 实体(最终做出的东西) 原型(设计稿)(constructor方法)对象
new 类 constructor() 类
prototype __proto__
__proto__
a.__proto__
Number {0, constructor: ƒ, toExponential: ƒ, toFixed: ƒ, toPrecision: ƒ, …}
创建对象:
function a() {
console.log(1)
}
new a();
this谁调用的就是谁 如果是在构造函数中this是实例
https://www.91q.com/song/T10063924403
网站例子
4.工具使用(编程喵插件、vscode)
F12其余功能
Web 开发技术 Web 开发技术 | MDN
hook 替换功能
FD本地替换js
funetion xx() {console.log(1)}
xx = function() {}
v8提供的API进行hook
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects
字节数组[25,45,23,65,58] uint8 0-255
[uint8,uint8,uint8,uint8] => [int32]
TextDecoder(字节数组和文本的转换)、TextEncoder、DataView(字节数组的增删改查)、wss(谷歌)
Data 时间 时区+8
TextDecoder是一个用于将二解码受一个字符编码参数,并提供了decode()方法来将二进制数据解码字符串。
以下是一个使用TextDecoder的例子:
// 创建一个Uint8Array数组,包含UTF-8编码的二进制数据
const uint8Array = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
// 创建一个TextDecoder对象,指定字符编码为UTF-8
const decoder = new TextDecoder('utf-8');
// 使用TextDecoder解码二进制数据为字符串
const decodedString = decoder.decode(uint8Array);
console.log(decodedString); // 输出: "Hello World"
在上面的例子中,我们首先创建了一个Uint8Array数组,其中包了UTF-8编码的二进制数据。然后,我们创建了一个TextDecoder对象,并指定字符编码为UTF-8。最后,我们使用TextDecoder的decode方法将二进制数据解码为字符串。
TextEncoder是TextDecoder的反向操作,它用于将字符串编码为二进制数据。它提供了一个encode()方法来将字符串编码为Uint8Array数组。
以下是一个使用TextEncoder的例子:
// 创建一个TextEncoder对象
const encoder = new TextEncoder();
// 使用TextEncoder将字符串为二进制数据
const encodedData = encoder.encode('Hello World');
console.log(encodedData); // 输出: Uint8Array [ 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100 ]
在上面的例子中,我们首先创建了一个TextEncoder对象。然后,我们使用TextEncoder的encode方法将字符串编码为二进制数据。最后,我们通过打印encodedData数组来查看编码后的二进制数据。
DataView是一个用于读取和写入二进制数据的API。它提供了一种灵活的方式来操作二进制数据,可以读取和写入不同类型的数据,如整数、浮点数等。
以下是一个使用DataView的例子:
// 创建一个ArrayBuffer对象,长度为8字节
const buffer = ArrayBuffer
// 创建一个DataView对象,关联到上面的ArrayBuffer
const view = new DataView(buffer);
//DataView写入一个32位整数ArrayBuffer的第0字节位置
view.setInt32(0, 42);
// 使用DataView读取ArrayBuffer的第0字节位置的32位整数
const value = view.getInt32(0console.log(value);
// 输出: 42
在上面的例子中,我们首先创建了一个长度为8字节的ArrayBuffer对象。然后,我们创建了一个关联到该ArrayBuffer的DataView对象。接下来,我们使用DataView的setInt32方法将一个32位整数写入ArrayBuffer的第0字节位置。最后,我们使用DataView的方法读取ArrayBuffer的第0字节位置的32位整数,并将其打印出来。
总结来说,TextDecoder制解码为字符串TextEncoder用于将字符串编码为二进制数据,而DataView用于取和写入二进制数据。这些API在处理二进制数据和文本数据之间的转换时非常有用。
eval()
函数会将传入的字符串当做 JavaScript 代码进行执行。
eval('debugger')
解决:
1.hook,替换js
eval=function(){}
2.在eval('debugger')语句前下断点,在控制台输入eval=function(){}
脚本
脚本的第一个语句,选上这个
脚本因内容安全政策而被屏蔽
子类 继承了 父类 吃饭
子类.吃饭
zhivuan方法 继承 Function 调用
hook 调用
zhiyuan方法.调用()
globalThis
Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}0:
window
Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
this
Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
self
Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
json 序列化 反序列化
JSON.parse()
JSON.stringify()
const jsonString = '{"name":"John", "age":30, "city":"New York"}';
const obj = JSON.parse(jsonString);
console.log(obj);
const obj1 = { name: "John", age: 30, city: "New York"};
const jsonString1 =JSON.stringify(obj1);
console.log(jsonString1);
{name: 'John', age: 30, city: 'New York'} 对象
{"name":"John","age":30,"city":"New York"} 文本
JSON
var a; 变量
undefined 未定义
null 引用类型值为空
NaN 非数字的值
Promdse 异步 同一个线程合理的分配运行时间到不同的任务一种技术
Proxy 做hook用 加代理 无法被检测
Reflect 解代理(配套使用)
Proxy 不能被检测
a={name:123}
var a = new Proxy(a, {
get: function(target, property, receiver) {
return 'abc'
}
});
console.log(a.name)
abc
var a = {name: 123};
var a = new Proxy(a, {
set(target, property, value, receiver) {
Reflect.set(target, property, "xhiyuam", receiver);
}
});
a.name = 1;
console.log(a.name);
xhiyuam
重要:
symbol
Object.freeze()
Object.freeze()
静态方法可以使一个对象被冻结。冻结对象可以防止扩展,并使现有的属性不可写入和不可配置。被冻结的对象不能再被更改:不能添加新的属性,不能移除现有的属性,不能更改它们的可枚举性、可配置性、可写性或值,对象的原型也不能被重新指定。freeze()
返回与传入的对象相同的对象。
var a = {name: 123};
Object.freeze(a);
a.name=1
console.log(a.name)
var a = {name: 123};
delete(a)
false
delete(a.name)
true
document.getElementById
在浏览器代替js
视频知识点
NP4 AVI 数据长度讲行分割
断点续传 范围 运行的时候干分割的事情
N3U8 hls协议 还可以用时间分割 直播 点播
ts ts ts 提前分割文件
5s 5s 5s
加密
拿到日录 bd
.ts 地址(相对 绝对)tx
sha1:40位
知道加密算法后,找加密方法的js实现,直接在网页搜索关键词,然后下断点
hook完整过程
//保存原函数
//替换原雨数
//调用原丽数
doqument.createElement2= doeument.createElement;
document.createrlement = function(tagName) {
let e=doeument.createElement2 (tagName);
if ((tagName.toLowerCase) == 'script'){
return new Proxy(e, {
set(target, property, value, receiver) {
if(value.indexof('getVideoinfo' != -1)){
debugger;
}
Reflect.set(target, property, "xhiyuam", receiver);
}
});
}
return e
}
doeument.createElement('script')
本地替换js
怎么hook:在浏览器第一次加载js的位置,在js第一行下断点,在控制台输入上面的代码
Node.prototype.insertBefore2= Node.prototype.insertBefore;
Node.prototype.insertBefore=function(t,tt){
if(t.src!=undefined)
{
if(t.src.indexof("getvideoinfo")!=-l){
debugger;
}}
return this.insertBefore2(t,tt)
}
document.createElement("script")
5.工具使用(F12 FD 城南工具)
wss协议分析websocket
直播间 IM 即时通讯
比较占服务器的资源
http 慢 不够即时 短连接 TCP
握手
发请求
返回数据
服务器主动断开链接
websockets 长连接 TCP
http握手 升级为websockets
升级协议
连接服务器wss ip:端口
等待
socket
数据接收
处理粘包
并不看数据是否全部接收完成
服务器发送 网线 电脑网卡(驱动)系统端口
1.数据缺失
2.数据多了
一个包完整+不完整包
多个包完整+不完整
3.数据正好
软件处理
1.固定长度100 YY
缓冲区 先存到缓冲区
2.头尾标识符 QQ
01 05
3.TLV QQ
标识符
数据长度
数据
protobuf 谷歌数据序列化格式 字节数组 游戏
省空间
JSON
XML
protobuf格式 代码转换
序列化 二进制
python 类 用户类 js 用户类
json json
C++格式
MQTT 消息分发 消息队列 socket
订阅消息 斗地主
升级websockets 协议:
https://www.miguvideo.com/p/live/120000456669
101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: aHdCFL8tBIh1Pi7s1sq9gg==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
FD替换js,浏览器f12打开禁止缓存
e.ws.send =function(){debugger;} 找到发送位置
或者
e.ws.send2= e.ws.send;
e.ws.send = function(a) {
console.log(a)
e.ws.send2 (a)
}
e.ws.onmessage2=e.ws.onmessage;
e.ws.onmessage=function(r){
console.log(r);
e.ws.onmessage2(r);
}
需要再new WebSocket,再输入
代码中的问题是,e.ws.send2(a)应该改为e.ws.send2.call(e.ws, a),以确保在调用原始的send方法时,正确地绑定this关键字。
e.ws.send2 = e.ws.send;
e.ws.send = function(a) {
console.log(a);
e.ws.send2.call(e.ws, a);
}
e.ws.onmessage2 = e.ws.onmessage;
e.ws.onmessage = function(r) {
console.log(typeof(r.data), r.data);
if (r.data.indexOf("compressType") !== -1) {
debugger;
}
e.ws.onmessage2(r);
}