开发者工具使用

settings的Network里勾选preserve logdisable cache,Console里勾选Log XMLHttpRequests

有的网页,直接查看源码里有的标签元素,通过爬虫直接去获取的时候反而不存在,可能是由于该元素是由js代码去动态生成的,初始的页面源码里并没有

如果想查看按钮绑定的事件,在Elements里面右侧的Event listeners里,可以取消勾选Ancestors,这个选项是监听祖先节点的事件的,对于按钮来说不需要,然后可以找到该按钮对应的事件代码在哪里

搜索和普通断点

点击右上角三个点,把show console drawer打开,然后在下面控制台框的左上角三个点选search,可以搜索url或者参数

https://cj.eloancn.com/网站的登录为例

全局搜索url,找到对应代码,跳转过去

找到定义login_url_: "/pcgway/login/v1/02",继续搜索login_url_,找到dosubmit函数

this.$fech处打上断点,点击登录之后成功断在该行代码

此时查看变量值发现password还是被加密的状态,所以加密函数不在这里,应该在上层函数,查看右侧函数栈,往上回溯函数,一直找到login函数,这里很可能是加密逻辑的代码,对象e存储password,现在找对象e在哪里生成的,用正则表达式搜索e,代表只匹配e这个单词,\be\b,当然这里用这个方法是多此一举

password: r.PUBLIC.encryptByDES(this.checkPwd.password.trim(), r.PUBLIC.DESkey)打断点即可,或者直接鼠标选中this.checkPwd.password.trim(),会显示计算出来的值,从而知道该行代码就是加密的代码

还有一种方法是搜变量,比如password,还可以衍生出很多种搜索方法

1
2
3
4
5
6
7
password=
password =
password:
password :
['password']=
["password"]=
...

或者搜其他参数、搜码表、搜S盒、K表

xhr和callstack

当登录请求是xhr请求的时候,可以进行xhr断点,在source面板右侧有xhr/fetch breakpoints

点击加号可以添加字符串,当xhr请求的url中有这个字符串的时候会断下来

Initiator和callstack

Network面板里会显示发起请求的时候的js代码所在位置

事件断点

事件触发,比如按钮点击事件,不一定是在按钮元素上绑定事件,也可能是在祖先元素上绑定事件,也可以触发(事件委派)

右键按钮元素,检查,右侧可以找到Event Listener,进而找到代码

此外还有全局事件断点,在source面板中的右侧Event Listener Breakpoints里有各种全局事件

debugger和条件断点

什么是条件断点,比如一个for循环,循环500次,我希望其在第400次的时候断下来,肯定不希望执行400次,就需要设置一个条件,在达到这个条件的时候断下来,在webstorm里就是在断点处右键即可,浏览器中设置条件断点的方式也是一样的

debugger的作用就是,在js代码中,正常执行的时候,debugger的位置不会断下来,但是调试的时候就断在这里了

js Hook

一般不去在局部代码内去hook,比如

1
2
3
!function(){
...
}();

因为内部代码块里很难知道哪个函数是关键函数,都是被混淆了的代码

大部分时候js hook用来去hook全局变量、全局对象下的一些方法

能够在全局作用域下访问的东西,很适合做js hook

比如在canvas创建的时候,hook drawImage函数,要想hook一个函数,首先要知道这个函数是在哪个对象下面的,一般是在原型对象下面定义的,hook的时候是先保存原来的方法,再去覆盖该方法

以某宁为例,打开全局事件canvas create断点,会断在canvas被初始化的地方,这个地方有时候离drawImage的代码还很远,这个时候可以用hook去获取该方法的参数,在控制台可以运行t.call(e, u, y).__proto__查看原型对象

控制台输入如下代码,然后会在调用drawImage的时候输出参数

1
2
3
4
5
6
7
8
9
10
11
const __drawImage = CanvasRenderingContext2D.prototype.drawImage;
// 函数名随意
CanvasRenderingContext2D.prototype.drawImage = function CanvasRenderingContext2D(...arg){
console.log(arg);
return __drawImage.call(this,...arg);
}
// 不建议用这种方式定义函数,可能被检测
CanvasRenderingContext2D.prototype.drawImage = function(...arg){
console.log(arg);
return __drawImage.call(this,...arg);
}

hook和debug结合,会在调用drawImage的时候断下来,然后通过回溯函数栈,可以定位到触发drawImage函数的位置

1
2
3
4
5
6
const __drawImage = CanvasRenderingContext2D.prototype.drawImage;
CanvasRenderingContext2D.prototype.drawImage = function newFuncName(...arg){
debugger;
console.log(arg);
return __drawImage.call(this,...arg);
}