js逆向中很多工作需要使用浏览器中的开发者工具,所以这里以chrome为例,先把开发者工具的使用总结一下,后面用到的时候可以回来查询。
Google Chrome浏览器的开发者工具是前端开发者的利器,它不仅提供了丰富的功能用于开发、调试和优化网页,还以其用户友好的接口而受到广泛欢迎。
打开一个网页,比如www.baidu.com,按下Ctrl+Shift+i 可以看到页面右半部分出现了如下的画面:
右边这部分就是开发者工具页面
这一排就是开发者工具的面板菜单,我们主要用到其中的4个面板:Elements(元素) Console(控制台)Sources(源代码) Network(网络),下面挨个来说
1、Elements(元素)面板
这里显示的是网页对应的HTML代码,一些静态网站的数据直接在这里就可以得到。
在这里我们可以修改Dom 和 Css 来调整我们网站的布局和设计,并且可以对网页内容做一个简单修改。比如这里我们调皮一下,把下面这个标签修改一下:
然后打开页面,就看到效果:
2、Console(控制台)面板
在控制台面板中,可以看到网页运行的一些诊断信息,或者可以使用它与页面上的javascript进行交互。
它可以理解为一个编辑器,我们经常用console输出变量的值,用console.log console.info console.error等不同形式打印信息,方便我们观察调试代码
console.count可以统计方法调用的次数
console.table可以以表格形式显示数据
我们在console面板中间的编辑器里先定义一个变量data,然后用console.table展示出来
console.copy方法可以复制变量的值
$_记录了最后一次在console中计算的表达式的值
$('.subject')可以找出所有类为subject的DOM
$x()可以结合xpath查看DOM内容
比如我们在网站上找到一个标签,在Element面板里找到这个标签,右键复制xpath地址
然后打开Console面板,在编辑器里输入如下代码
可以看到该标签内容被正确显示了出来。
3、Sources(源代码)面板
这是js逆向中使用最多的面板,因为网站的源代码都在这,我们就是要从中找到规律才能突破反爬获取数据。在这个面板中,我们可以通过设置断点来调整JavaScript的运行,或者使用我们的工作区域来连接本地文件,来使用开发者工具自带的实时编辑器来修改我们的源代码
可以看到sources面板分为三个部分:左边的是文件导航窗口,中间的是编辑器窗口,右边的是调试窗口。
3.1 调用本地文件
点击中间窗口的 select folder, 如果标题栏弹出要求获取权限的提示,点击允许
这时候就可以在local文件夹下看到我们准备好的本地文件
在这里可以对它进行打断点、调试等操作。
左边导航窗口的右箭头打开,选择overrides标签,可以进行本地代理操作
本地代理操作的意思是将远程的资源下载一份在本地,然后可以在开发者工具下进行编辑,开发者工具会更新展示我们编辑后的文件,即可以直接将一些请求代理到本地的文件当中,以更好地观察请求的运行情况。
点击 Select folder for overrides,跟上面一样添加一个本地文件夹local,也要允许权限,然后还要勾选 Enable Local Overrides。这时候我们就可以进行本地代理操作了。
打开Network,选择一个请求右键弹出菜单,选择override content
界面回到overrides,在中间编辑窗口就可以对文件进行修改,保存之后就可以在页面上看到效果
3.2 Snippets面板:
是一个代码片段工具,可以在该部分预先编辑好一些功能代码,在需要的时候方便运行。比如我们放一个常见的All Colors 脚本,用来输出RGB的颜色
// allcolors.js
// https://github.com/bgrins/devtools-snippets
// Print out CSS colors used in elements on the page.
(function () {
// Should include colors from elements that have a border color but have a zero width?
var includeBorderColorsWithZeroWidth = false;
var allColors = {};
var props = ["background-color", "color", "border-top-color", "border-right-color", "border-bottom-color", "border-left-color"];
var skipColors = {
"rgb(0, 0, 0)": 1,
"rgba(0, 0, 0, 0)": 1,
"rgb(255, 255, 255)": 1
};
[].forEach.call(document.querySelectorAll("*"), function (node) {
var nodeColors = {};
props.forEach(function (prop) {
var color = window.getComputedStyle(node, null).getPropertyValue(prop),
thisIsABorderProperty = (prop.indexOf("border") != -1),
notBorderZero = thisIsABorderProperty ? window.getComputedStyle(node, null).getPropertyValue(prop.replace("color", "width")) !== "0px" : true,
colorConditionsMet;
if (includeBorderColorsWithZeroWidth) {
colorConditionsMet = color && !skipColors[color];
} else {
colorConditionsMet = color && !skipColors[color] && notBorderZero;
}
if (colorConditionsMet) {
if (!allColors[color]) {
allColors[color] = {
count: 0,
nodes: []
};
}
if (!nodeColors[color]) {
allColors[color].count++;
allColors[color].nodes.push(node);
}
nodeColors[color] = true;
}
});
});
function rgbTextToRgbArray(rgbText) {
return rgbText.replace(/\s/g, "").match(/\d+,\d+,\d+/)[0].split(",").map(function(num) {
return parseInt(num, 10);
});
}
function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function rgbToHex(rgbArray) {
var r = rgbArray[0],
g = rgbArray[1],
b = rgbArray[2];
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
var allColorsSorted = [];
for (var i in allColors) {
var rgbArray = rgbTextToRgbArray(i);
var hexValue = rgbToHex(rgbArray);
allColorsSorted.push({
key: i,
value: allColors[i],
hexValue: hexValue
});
}
allColorsSorted = allColorsSorted.sort(function (a, b) {
return b.value.count - a.value.count;
});
var nameStyle = "font-weight:normal;";
var countStyle = "font-weight:bold;";
function colorStyle(color) {
return "background:" + color + ";color:" + color + ";border:1px solid #333;";
};
console.group("Total colors used in elements on the page: " + window.location.href + " are " + allColorsSorted.length);
allColorsSorted.forEach(function (c) {
console.groupCollapsed("%c %c " + c.key + " " + c.hexValue + " %c(" + c.value.count + " times)",
colorStyle(c.key), nameStyle, countStyle);
c.value.nodes.forEach(function (node) {
console.log(node);
});
console.groupEnd();
});
console.groupEnd("All colors used in elements on the page");
})();
运行后效果:
3.3 常用断点
在Sources(源代码)面板中我们经常会进行一些断点调试,这里总结一下常用的几种断点:
条件断点:
我们先准备一段测试代码放到Snippets
console.log("断点测试");
let i = 0;
while (i<10) {
console.log("本轮测试开始");
console.log("现在i的值为:"+ i);
// debugger;
console.log("本轮测试结束");
i++;
}
console.log("断点测试完成");
然后在代码行号点右键,弹出菜单里面选择 Add conditional breakpoint
在弹出的菜单里填写条件i=4,并在右边的watch里添加一个监控的变量 i
再次运行代码片段,发现运行到 i 的值为4时,程序就停住了
XHR断点:
我们先打开Network面板,勾选 XHR/fetch,然后刷新一下百度网站,看看有没有xhr请求
发现了一个,先不用管这请求是干嘛用的,我们截取前面一段字符串 sugrec ,然后点开Sources面板,在右边的XHR/fetch Breakpoints 标签右边点击 + 号增加一个xhr断点,然后把刚刚的字符串填进去,这样当网页再次发起包含 “sugrec" 这个字符串的xhr请求时,就会断点停下
再次刷新网站,发现果然断点了
DOM 断点:
在元素列表,找到想要断点的元素,点击右键,在弹出菜单里选择Break on => subtree modifications
然后在Sources面板里就可以看到该断点
当该元素发生改变的时候,就会断点停到这里
事件断点:
我们打开一个网站的登录界面,选择登录按钮,看到按钮的type是一个 submit,意味着这里调用了一个submit事件,我们打开Sources面板,选择Event Listenner Breakpoints => Control => submit
这样每当这个事件调用的时候,这里就会断点停到这里
3.4 工具栏介绍
最后再来说下右边的调试窗口最上方的这一排小图标
第1个 是暂停按钮,当运行到断点时会变成蓝色箭头,点击恢复执行直到下一个断点
第2个 是直接执行下一行然后直接就跳转到下一行
第3个 是如果下一行包含一个函数调用的话,就会进入到函数内部,并且在这个函数的第一行断上
就是经常会说的 追进去
第4个 是跳出当前函数的调用
第5个 是单步按钮,表示执行下一步
第6个 是暂时禁用所有的断点,用于恢复正常的执行
4、Network(网络)面板
这也是JS逆向中经常使用到的面板,在这个面板中可以用来抓包、查看每个请求的请求头、响应、以及它所耗费的时间等信息。
它包括控制器、过滤器、概览和请求
4.1 控制器
控制器可以用来控制我们网络面板的一个外观还有功能
第1个红色按钮控制是否抓包。
第2个是清除现有列表中的所有请求。
第3个是过滤器网格的开关。
第4个是一个搜索开关,打开可以出现一个搜索界面。
第5个是控制是否进行跨页面加载保存请求。不勾选的话,跨页面请求的时候之前的请求就会被清除。
第6个是控制是否禁用浏览器缓存。如果不勾选的话我们每一个请求都会去请求新的浏览器资源。
第7个是慢速网络模拟。可以使用slow 3G 或者离线状态来看一下浏览器在不同网络环境下请求是什么样子的。
4.2 过滤器
过滤器可以用来控制请求列表,显示哪些资源,比如说通过点选 Fetch/XHR,可以只显示异步请求(XHR),点选img标签,可以只显示图片资源。也可以通过Ctrl来多选。最左边的选择框可以进行关键字筛选,比如我们可以 输入 www.baidu.com 直接筛选出来自 www.baidu.com网站的请求。
4.3 概览
这里显示的是每个请求的时间线。
4.4 请求
这部分是重点。网页访问过程中的每一个请求都会被记录在这里。请求列表默认是以请求的时间顺序排列。这里可以看到请求的一些信息:Name(请求的名称) Status(状态码) Type(请求类型)Intiator(请求来源) Size(请求大小) Time(请求时间) 等等,这里最重要的是请求来源,可以看到请求的发起方,这很重要,很多时候我们可以通过它是从哪里发起的来判断它的JS大概是哪一个。
选中某个请求之后还可以看到该请求的详细情况:
Headers是请求头,包含了很多请求的信息。
Preview可以预览,比如图片啊之类的。
Response可以查看返回的数据。
Cookies 可以查看相关的cookies数据。
Timing 可以看到请求的耗时。
Tips小技巧1:用postman快速写一个爬虫:
随便找一个请求点击右键,选择 Copy as cURL(bash)注意:选别的格式postman不认。
然后在postman中打开import
在弹出的对话框中把刚刚复制的cURL地址粘贴进来,
然后界面跳转到如下,点击右边的这个</>符号
然后在右边会弹出相应的代码,如果显示的不是python代码,就点击这个下拉菜单,选择python-request,得到python爬虫代码
复制右边这些代码,到python程序中去执行,即可得到结果
tips小技巧2:查看依赖关系
选择一个请求,按住shift键,鼠标上下移动并悬停,可以看到下面显示红色的请求,都是依赖上面的请求而来
相反,我们按住shift键,选中某个请求,发现另一个请求是绿色的,则表示绿色的请求是该请求的发起者。
5、其他面板
其他面板jsweb逆向用到的不多,大致了解一下即可。
Performance(性能)面板:可以通过时间轴记录、查看网站生命周期内发生的各项事件来了解页面运行性能。
Memory(内存)面板:可以用来分析页面的执行时间以及内存的使用情况。
Security(安全)面板:可以用来调试混合内容问题、证书问题等等。
Application(应用)面板:可以记录网站加载的所有资源信息,比如cookie或者缓存数据、字体、图片、脚本、样式表等等。也可以清除网站数据。