prototype:原型
CORS(Cross-Origin Resource Sharing):跨资源共享
Interceptor:拦截器
BOM:Browser Object Module(浏览器对象模型)
Ajax(Asynchronous Javascript And XML):异步的JavaScript和XML,Ajax其实就是浏览器与服务器之间的一种异步通信方式
XHR:XMLHttpRequest是创建AJAX请求的JavaScript API,它的方法提供了在浏览器和服务器之间发送请求的能力。
Referrer:推荐人
snippets:片段
canvas:油画
initiator:启动器
npm(Node Package Manager)一个JavaScript的包管理工具,用于在开发过程中安装、分享和管理代码包。
scheme:方案
href (Hypertext Reference):超文本引用
GBK:Chinese Internal Code Specification,汉字内码扩展规范
UTF-8:编码是一种可变长度的编码方式,可以表示世界上几乎所有的字符,使用1至4个字节表示一个字符。在 UTF-8 编码中,大写字母’H’ 被编码为一个字节 0x48。
UTF-16:是一种固定长度的编码方式,每个字符都使用2个字节进行编码。
ECB:(Electronic Codebook)电子密码本模式,是最简单的加密模式之一,将每个明文分割为块,然后对每个块单独进行加密处理。
模式参考网站:https://blog.csdn.net/weixin_42272869/article/details/124278342
encode和decode
字符串通过编码成为字节码,字节码通过解码成为字符串。
字符串或者字节只能同时拥有一个方法 ,要么解码要么编码
encode默认utf-8
base64.encodebytes=base64.b64encode
base64.decodebytes=base64.b64decode
将其转化为二进制存储到计算机中,这个过程我们称之为编码
UTF-8、UTF-16、UTF-32 都是 Unicode 的一种实现
Unicode是一种字符集,包含了世界上几乎所有的字符,每个字符都有一个唯一的编号,即码点。
每个MD5哈希值中的字符都代表4位二进制数字(16进制字符)。因此,32个字符(16进制数)乘以4就等于128位。在这种情况下,“202cb962ac59075b964b07152d234b70”的MD5哈希值由128位(4位 x 32个字符)组成。
https(协议)://a.xxx.com(域名):8080/file/list(路径)
XHR:显示所有AJAX异步请求
JS:显示JS文件
WS:显示websocket请求
Media:显示媒体文件,音频,视频等
Doc:显示html
Application是应用管理部分,主要是记录网站加载的所有资源信息。
包括存储数据(local Storage、Session Storage、Cookies)、缓存数据、字体、图片、脚本、样式表等。
用的最多的是Cookies,如果需要清除,右键→clear
△:辨别Cookies来源可以看httpOnly,有√来自服务端,没√来自本地生成
堆栈调试
在Network中的initiator中点击其中一个js连接,然后就可以打断点,刷新后会进入断点
监听XHR
打开console,单机sources,右侧有个XHR/fetch BreakPoints,单机+就能监听。
想URL中的signture就适合XHR段断点事件监听
找不到参数位置,但是知道触发条件,可以使用事件监听器进行段带你,在sources中有DOM Breakpoint、Global Listeners,Event Listener Breakpoints都可以进行DOM事件监听。
Hook
在Js也需要用到Hook技术,例如想分析某个cookie是如何生成时,想通过直接在代码里搜索该cookie的名称来找生成逻辑,需要审核非常多代码。这个时候,用hook document.cookie的set方法,就可以通过打印当时的调用方法堆栈或者直接下断点来定位到该cookie的生成代码位置。
在JS逆向中,把替换原函数过程称为hook,一般使用Object.defineProperty()来进行hook:
直接替换:
function a() {
console.log("I'm a.");
}
a = function b() {
console.log("I'm b.");
};
a() // I'm b.
Object.defineProperty()
Object.defineProperty(obj,prop,descriptor)
- obj:需要定义属性的当前对象
- prop:当前需要定义的属性名
- descriptor:属性描述符:get,set,value,writable,enumerable,configurable
一般hook使用get和set方法:
var people = {
name: 'Bob',
};
var count = 18;
// 定义一个 age 获取值时返回定义好的变量 count
Object.defineProperty(people, 'age', {
get: function () {
console.log('获取值!');
return count;
},
set: function (val) {
console.log('设置值!');
count = val + 1;
},
});
console.log(people.age);
people.age = 20;
console.log(people.age);
网站加载要运行HOOK代码,在运行网站自己的代码,才能成功断下,这个过程是HOOK代码的注入。
TamperMonkey注入
油猴插件,是一款免费的浏览器拓展和最为流行的用户脚本管理器。
用户可以在GreasyFork、OpenUserJS等平台直接获取别人发布的脚本,功能众多且强大,比如视频解析,去广告等。
JS逆向指的是对JavaScript代码的逆向工程,即对JavaScript代码进行分析和解密的过程。这通常涉及到反编译、动态调试、代码审计等技术手段,用于理解和破解JavaScript程序的功能和逻辑。
安卓逆向指的是对Android应用程序进行逆向工程,包括对APK文件、DEX文件、Java代码等进行分析和破解。安卓逆向通常涉及到反编译、动态调试、代码审计、破解加密算法、修改应用程序的功能等技术手段。安卓逆向可以用于破解应用的限制、修改应用的功能、分析应用的安全性等目的。
动态语言
不用事先指定变量的类型
Object类型
let person={
name:"张三",
age:20,
student:true
}
typeof person; //object
let person={
name:"张三"
}
person.age=20; //person:{name:'张三',age:20}
常见的编码有base64、unicode、urlencode编码,加密有MD5、SHA1、HMAC、DES、RSA等。
base64
base64是一种基于64个可打印ASCLL字符对任意字节数据进行编码的算法。
window.btoa():加密
window.atob():解密
MD5
消息摘要算法,广泛使用的密码散列函数,可以产出128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
所以解密一般通过暴力穷举,或者网站接口实现解密
SHA1
Secure Hash Algorithm:安全哈希算法主要适用数字签名标准里面定义的数字签名算法,SHA1比MD5安全性更强,对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。
HMAC
Hash message authentication codes:散列消息鉴别码,基于加密hash和共享密钥的消息认证协议。实现远离是用公开函数和密钥产生一个固定长度的值作为认识标识,用这个标识鉴别消息的完整性。
DES
Data Encryption Standard:数据加密标准,属于对称加密算法。
DES是一个分组加密算法,电芯的DES以64位为分组对数据加密,加密和解密用的同一个算法。它的密钥长度是56位,可以是任意的56位数
JS逆向时,DES加密的搜索关键词有DES、mode、padding等
AES
AES全称:高级加密标准,在密码学中又称Rijndael加密法。
AES也是对称加密算法,如果能够获取到密钥,那么就能对密文解密。
Js逆向时,AES加密的搜索关键词有AES、mode、padding等
RSA
Rivest-Shamir-Adleman,RSA加密算法是一种非对称加密算法,在公开密钥加密和电子商业中RSA被广泛使用,被普遍认为是目前最优秀的公钥方案之一。RSA是第一个能同时用于加密和数字签名的算法,能够抵抗目前为止已知的所有密码攻击。
注意Js代码中的RSA常见标志setPublickey
Array类型
a=[1,2,3]
b=[“a”,“b”,“c”]
a**b:幂运算
a===b:返回a是否等于b
10.25%3=1.25:整数取模,保留浮点
!!运算符
把任何值转换为boolean类型,将真值转换为true,将假值转换为false
??运算符
左侧操作数为null或undefined的时候,才会使用右侧操作数的值
把" ",false,0等值当做正常值,只有遇到null和undefined时,才设置默认值
""??10; //""
false??"no"; //false
null??100; //100
undefined??"empty";//"empty"
函数
function sayHello()
{
console.log("hello");
}
匿名函数
把函数复制给变量或常量:
const square=function(x){return x*x}
箭头函数
由参数列表、=>符号和{}包裹的函数体构成
多个参数:
const sum=(x,y)=>{return x+y;}
一个参数:
const increment=a=>{return a+1;}
const increment=a=>a+1
没有参数:
const getDefaultSize=()=>10;
可选与默认参数
function init(arg1,arg2,options)
{
if(options)
{
}
}
init("value1","value2");
init("value1","value2",{prop:"value"};
可变长度参数
隐式arguments变量,用索引:
function joinString(seperator){
let result="";
for(let i=1;i<arguments.length;i++)
{
if(i>1){
result+=seperator;
}
}
return result;
}
console.log(joinStrings(",","react","node"));
rest运算符
rest运算符用…来表示,后面加上标识符(strs),用于引用它的值。
function joinStrings(seperator,…strs)
{
return strs.join(seperator);
}
console.log(joinStrings(“,”,“react”,“node”))
回调函数
function addUser(user,callback){
console.log("保存${user.username}成功");
callback(true);
}
addUser({username:"user"},function(success)){
if(success){
console.log("添加成功!");
}
}
等同:
addUser({username:"user"},(success)=>{});
作用域
全局
用globalThis来访问全局,后来的值会覆盖掉前面的值
//chapter5/scope1.js
var x= 10;
globalThis.x; //10;
var x="Hello";
globalThis.x; //"Hello"
JavaScript的作用域属于静态作用域,称为词法作用域(Lexical Scope),它的意思是,作用域在编写代码的时候就已经确定了,而动态作用域是程序在运行的时候,才去动态地判断作用域。词法作用域可以让理解作用域变得更简单,只需看代码就能够知道某个变量的作用域了,例如在函数中定义的作用域只需看该函数的大括号在哪里结束,那么变量的作用域就会在哪里结束。
闭包
函数式变成的最终目的是只需调用一次函数,就可以完成所有业务逻辑,属于声明式编程范式(Declarative Programming Paradigm),而之前章节的代码则大部分属于命令式编程范式(Imperative Programming Paradigm),即完成一个业务所关注的步骤。
闭包(Closure)指的是一种语法形式和变量查找机制,在一系列嵌套的函数中,所有内部的函数都可以访问外部函数及全局作用域中定义的变量、对象和函数(以下简称内容)等
状态
闭包实现自增:
function increment(initialValue){
let result=initialValue;
return function by(step){
result+=step;
return result;
}
}
const incFiveBy = increment(5);
console.log(incFiveBy(2));
console.log(incFiveBy(4));
increment函数接受一个initialValue参数,指定初始值。
内部定义一个result变量用于保存自增结果,返回一个子函数by()
by()接受一个step参数,用于指定自增补偿。
可以看出incFiveBy()中的result是共享的,可以把它称为状态(state),每次调用incFiveBy都会修改状态,这是闭包用途之一。
//chapter5/closure_inc3.js
const incFiveBy= increment(5);
const incFiveByTwo=()=> incFiveBy(2);
const incFiveByFour=()=> incFiveBy(4);
//chapter5/closure_inc3.js
console.log(incFiveByTwo()); //7
console.log(incFiveByFour());//11
console.log(incFiveByFour());//15
定义私有状态
对内部状态起到保护作用
//chapter5/closure2.js
function data(){
let arr=[1,3,5,7,9];
let index=0;
return{
value(){
return arr[index];
},
next(){
index=++index%arr.length;
},
pre(){
index=(--index+arr.length)%arr.length;
},
};
}
//chapter5/closure2.js
const myData=data();
console.log(myData.value());//1
myData.next(); //index:1
myData.next(); //index:2
console.log(myData.value());//5
myData.pre(); //index:1
myData.pre(); //index:0
myData.pre(); //index:4
console.log(myData.value());//9
立即执行函数表达式(IIFE,Immediately Invoked Function Expression),把匿名函数包裹起来,并在后边使用另一对()调用它:
const myData=(function(){
let arr=[1,3,5,7,9];
//...省略内部逻辑
})();
高阶函数
如果函数满足一下两点中的任意一点或全部,则这个函数就称为高阶函数
① 接受另一个函数作为参数
② 返回一个函数
function square(f){
return (...args)=>f(...args)**2;
}
const sum=(a,b)=>a+b;
const squareOfSum=square(sum);
console.log(squareOfSum(1,2));
柯林化
Currying:指把一个接收多个参数的函数转化为一系列接收一个参数的子函数的过程。
function convertRate(rate){
return (amount)=>amount*rate;
}
const uToC=convertRate(6.78);
console.log(uToC(1)); //6.78
复杂例子:
const cToJ=convertRate(15.74)
const uToJ=(amount)=>cToJ(uToC(amount));
console.log(uToJ(1)) //106.7172
函数缓存
Memoization:对于耗时的函数,把已经执行过的函数结果保存起来作为缓存,如果再次需要使用,可判断缓存,有缓存则返回缓存的结果。一般使用函数的参数列表作为缓存的key。
function fib(n){
if(n<=1) return n;
if(fib[n]) return fib[n];
fib[n]=fib(n-1)+fib(n-2);
return fib[n];
}
const start=new Date().getTime();
console.log(fib(50));
const end=new Date().getTime();
console.log("${end-start}")
纯函数
Pure function指一个函数,每次传递相同参数能得到相同返回结果,且没副作用产生。
函数内会影响a的值
let a=5;
function sum(b){
a=10;
return a+b;
}
数组
数组是对象
创建数组
let arr=[1,2,3]
let arr=new Array(1,2,3)
let arr=new Array(5); //五个空元素的数组
let arr=Array.from([3,2,5]) //浅复制,复制的是内存地址
let arr=Array.from(new Set(["a","c","d"]));
map
let arr=[1,2,3,4];
let newArr=arr.map(v=>v+2);
filter
let arr=[8,1,3];
let filteredArr=arr.filter((v)=>v>5);
console.log(filterArr);
some&every
let test=arr.some((v)=>v);
console.log(test); //true
let test=arr.every((v)=>v>5);
console.log(test);
数组排序
sort
["apple","banana","cat"].sort(); //正排
["apple","banana","cat"].reverse(); //正排
数组连接
[1,3].concat([2,4],[5,8]);
数组裁切
[1,2,3,4,5,6].slice(2,5);//[3,4,5]
搜索元素
[1,2,3].includes(2); //true
[1,2,3].indexOf(2); //1
[1,2,3,2].lastIndexOf(2) // 3
[1,3,5,7].find(v=>v>=5); //5是元素本身
[1,3,5,7].find(v=>v>=5); //2是索引
字符串数组
["hello","world"].join(); //"hello,world"
["a","b","c"].join(","); //"a,b,c"
[1,2,3].join("+"); //"1+2+3"
["this",undefined,"is",null].join("");//"this is"
解构赋值
const point=[12,5]
const [x,y]=point
对象
getSlug是方法
update-at的-是不合法字符,所以要加双引号
const blogPost={
id:1,
title:"tur",
getSlug:function(){
return " /post/ + this.title"
},
"update-at":"2020-10-26",
};
简化属性
const title=getUserInput();
const blogPost={
title, //相当于title:title
}
计算属性名
let prop="a";
const obj={
[prop]:1,
['get$(prop.toUpperCase())'](){
return this[prop];
}
}
最终生成对象:
{
a:1,
getA(){return this[prop];}
}
访问与添加对象属性
blogPost.title;
blogPost["title"]
遍历对象属性
Object.keys()
const blogPost={
id:1,
title:"jc",
getSlug:function(){
return "/post/"+title;
}
}
Object.keys(blogPost).forEach((key)=>{
console.log("${key}:${blogPost[key]}")
})
getters和setters
//chapter7/getters_setters1.js
const cart={
items:["商品1","商品2","商品3"],
get total(){
return this.items.length;
},
};
cart.total; //3
//chapter7/getters_setters2.js
const user={
_username:"",
set username(value){
if(value.length>=5){
this._username=value;
}
},
get username(){
return this._username;
},
};
user.username="testuser";
console.log(user.username); //testuser
原型
JavaScript是基于原型的编程语言,每个对象除了本身的属性之外还有一个__proto__属性,只想一个对象,称为原型对象(Prototypical Object),每个对象都会继承原型对象中的属性和方法。
const obj={a:1}
Object.getPrototypeOf(obj);
Object.getPrototypeOf(obj)===prototype;
DOM对象
DOM,全称是"Document Object Model"(文档对象模型)
DOM操作,可以简单 理解为元素操作
操作元素时,把元素看成一个对象,然后使用对象的属性和方法来进行相关操作。
在JavaScript中,节点分为很多种类型。DOM节点有12中类型,常用的只有下面三种:
① 元素节点
② 属性节点
③ 文本节点
<div id="wrapper">绿叶学习网</div>
JaveScript会把元素、属性以及文本当做不同的节点来处理。
通过这6种方式来获取指定元素:
getElementById()
getElementsByTagName()
getElementsByClassName()
querySelector() querySelectorAll()
getElementsByName()
document.title document.body
getElementById和getElementByTagName区别
①
ByID获取的是1个元素
ByTagName获取的是多个元素
②
ByID前面只接受document
ByTagName前面可以接受document,也可以接受其他DOM对象
③
ByID不可以操作动态创建的DOM元素
ByTagName可以操作动态创建的DOM元素
getElementsByName
对于表单元素来说,有个一般元素都没有的name属性。
ByName只用于表单元素,一般只用于单选按钮和复选框
事件
var oBtn=document.getElementById("btn");
oBtn.onclick=function()
{
alert("绿叶学习网");
};
HTML绑定事件的方法:
行内绑定、动态绑定、事件监听、bind和on绑定
行内绑定:
<li>
<div onclick="xxx()">点击</div>
</li>
动态绑定:
<script>
var xx = document.getElementById("lx");
xx.onclick=function(){}
</script>
事件监听:
<script>
var xx = document.getElementById("lx");
xx.addEvenetListener("click",function(){})
</script>
bind()
$("button").bind("click",function(){$("p").slideTooggle();})
on()
$(document).ready(function(){$("p").on("click",function(){})});
参考网站:
https://blog.csdn.net/xw1680/article/details/133411112?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-133411112-blog-109348937.235v43pc_blog_bottom_relevance_base9&spm=1001.2101.3001.4242.2&utm_relevant_index=2