想要找到Js加密参数的生成过程,就必须要找到参数的位置,然后通过debug来进行观察调试。下面总结了目前通用的调试方式。每种方法都有其独特的运用之道,大家只有灵活运用这些参数定位方法,才能更好地提高逆向效率。
搜索操作比较简单,打开控制台,通过快捷键Ctrl + F打开搜索框。在Network中的不同位置使用Ctrl + F会打开不同的搜索区域,有全局搜索、页面搜索。
另外关于搜索也有一定的技巧,如果加密参数的关键词是signature,可以直接全局搜索signature,搜索不到可以尝试搜索sign或者搜索接口名。如果还没有找到位置,则可以使用下面几种方法。
2 、堆栈调试
控制台的 Initiator 堆栈调试是我们比较喜欢的调试方式之一,不过新版本的谷歌浏览器才有,如果没有 Initiator 需要更新Chrome版本。Initiator主要是为了监听请求是怎样发起的,通过它可以快速定位到调用栈中。
具体使用方法是先确定请求的接口,然后进入Initiator,单击第一个Request call stack参数,进入Js文件后,在跳转行上打上断点,然后刷新页面等待调试。
3、 控制台调试
控制台的Console中可以由console.log()方法来执行某些函数,该方法对于开发调试很有帮助,有时通过输出会比找起来更便捷。在断点到某一处时,可以通过console.log()输出此时的参数来查看状态和属性,console.log()方法在后面的参数还原中也很重要。
4 、监听XHR
XHR是XMLHttpRequest的简称,通过监听XHR的断点,可以匹配URl中params参数的触发点和调用堆栈,另外post请求中From Data的参数也可以用XHR来拦截。
使用方法:打开控制台,单击Sources,右侧有一个XHR/fetch Breakpoints,单击+号即可添加监听事件。像一些URL中的_signature参数就很适合使用XHR断点。
这里其实和监听XHR有些相似,为了方便记忆,我们将其单独放在一个小节中。
有的时候找不到参数位置,但是知道它的触发条件,此时可以使用事件监听器进行断点,在Sources中有DOM Breakpoints、Global Listeners、Event Listener Breakpoints都可以进行DOM事件监听。
比如需要对Canvas进行断点,就在Event Listener Breakpoints中选择Canvas,勾选Create canvas context时就是对创建canvas时的事件进行了断点。
在控制台中添加代码片来完成Js代码注入,也是一种不错的方式。
使用方法:打开控制台,单击Sources,然后单击左侧的snippets,新建一个Script Snippet,就可以在空白区域编辑Js代码了。
7、Hook
在Js中也需要用到Hook技术,例如当想分析某个cookie是如何生成时,如果想通过直接从代码里搜索该cookie的名称来找到生成逻辑,可能会需要审核非常多的代码。这个时候,如果能够用hook document.cookie的set方法,那么就可以通过打印当时的调用方法堆栈或者直接下断点来定位到该cookie的生成代码位置。
什么是hook?
在 JS 逆向中,我们通常把替换原函数的过程都称为 Hook。一般使用 Object.defineProperty() 来进行hook。
以下先用一段简单的代码理解Hook的过程:
function a() {
console.log("I'm a.");
}
a = function b() {
console.log("I'm b.");
};
a() // I'm b.
直接覆盖原函数是以最简单的做法,以上代码将a函数进行了重写,再次调用a函数将会输出I'm b.
如果还想执行原来a函数的内容,可以使用中间变量进行存储:
function a() {
console.log("I'm a.");
}
var c = a;
a = function b() {
console.log("I'm b.");
};
a() // I'm b.
c() // I'm a.
此时,调用 a 函数会输出 I’m b.,调用 c 函数会输出 I’m a.
这种原函数直接覆盖的方法通常只用来进行临时调试,实用性不大,但是它能够帮助我们理解 Hook 的过程,在实际 JS 逆向过程中,我们会用到更加高级一点的方法,比如 Object.defineProperty()。Object.defineProperty()
Object.defineProperty(obj, prop, descriptor)
obj:需要定义属性的当前对象;
prop:当前需要定义的属性名;
descriptor:属性描述符,可以取以下值;
属性描述符的取值通常为以下:
属性名默认值含义
getundefined存取描述符,目标属性获取值的方法
setundefined存取描述符,目标属性设置值的方法
valueundefined数据描述符,设置属性的值
writablefalse数据描述符,目标属性的值是否可以被重写
enumerablefalse目标属性是否可以被枚举
configurablefalse目标属性是否可以被删除或是否可以再次修改特性
通常情况下,对象的定义与赋值是这样的:
我们一般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);
通过这样的方法,我们就可以在设置某个值的时候,添加一些代码,比如 debugger;让其断下,然后利用调用栈进行调试,找到参数加密、或者参数生成的地方,需要注意的是,网站加载时首先要运行我们的Hook代码,再运行网站自己的代码,才能够成功断下,这个过程我们可以称之为Hook代码的注入。
TamperMonkey 注入
TamperMonkey 俗称油猴插件,是一款免费的浏览器扩展和最为流行的用户脚本管理器,支持很多主流的浏览器, 包括 Chrome、Microsoft Edge、Safari、Opera、Firefox、UC 浏览器、360 浏览器、QQ 浏览器等等,基本上实现了脚本的一次编写,所有平台都能运行,可以说是基于浏览器的应用算是真正的跨平台了。用户可以在 GreasyFork、OpenUserJS 等平台直接获取别人发布的脚本,功能众多且强大,比如视频解析、去广告等。
非原创,摘自于网络文章。
领取专属 10元无门槛券
私享最新 技术干货