习惯了用javascript写frida脚本,为什么要用typescript?

学完javascript之后再看ts,应该就会觉得ts是一个大号的js——ts之于js就像c++之于c,前者是后者的超集,相当于js的一个大型dlc,这个dlc完全和本体兼容(ts脚本可以直接编译成js脚本),而且添加了很多特性的语言拓展:由弱类型语言变为强类型,静态类型检查在编译阶段就可以发现变量类型不匹配的错误;支持接口,方便开发与拓展;与node.js协作,有丰富的开源模块与工具,把你的脚本像项目一样管理(js其实就可以……
哇,好处一大堆。
那就让我们开始吧
环境配置
直接看网上的教程可能有点迷糊:我就写个hook脚本而已,要配这么多东西吗???
网上的教程(包括frida-agent-example)都是将ts项目构建在node.js项目之上,这一点跟着做可能会不明所以,其实是方便使用node.js的各种模块和功能(包括frida),同时又能利用ts的类型检查和其他特性。
确保你有node.js和npm环境
新建一个项目,或者文件夹
1
mkdir frida-agent-test
建立一个node.js项目
1
npm init
终端上会让你设置一些其他的,包括程序入口,作者之类的,随你便。之后目录下会出现一个package.json,这个文件会记录一些项目的基本信息,包括你刚才的那些设置、自定义脚本命令、项目依赖之类的。
安装项目依赖——typescript
1
npm install typescript --save-dev
为了保证项目的独立性,每次新建一个node.js项目时都要单独安装typescript
某个项目可能需要使用 TypeScript 的最新特性,因此依赖较新的版本,而另一个项目可能因为兼容性问题需要使用旧版本
–save-dev选项会将包安装到项目的node_modules目录下,同时作为开发依赖项记录到package.json中

创建ts配置文件tsconfig.json
1
tsc --init
tsconfig.json可以对ts项目中ts编译器的行为进行控制,比如指定js版本,严格类型检查之类的

这个配置文件的内容多的要死,一条一条看吧
安装依赖
1
npm install @types/node @types/frida-gum frida-compile@10.2.1 --save-dev
@types/node@types是一个用于存放 TypeScript 类型定义文件的命名空间。在 TypeScript 项目中,很多 JavaScript 库本身并没有附带类型定义,这会导致 TypeScript 编译器无法理解这些库的类型信息,使用时会缺少类型检查和智能提示。而@types社区为众多流行的 JavaScript 库提供了类型定义文件。@types/node就是为 Node.js 标准库提供的类型定义包。当你使用 TypeScript 开发 Node.js 项目时,安装它可以让 TypeScript 编译器理解 Node.js 相关的 API 和模块的类型信息,提高开发效率和代码的可靠性。
frida-compile- Frida 是一款强大的动态代码插桩工具,可用于在运行时修改应用程序的行为。
frida-compile是 Frida 的一个编译工具,它可以帮助开发者将 Frida 脚本进行编译和打包,以便在不同的环境中使用。例如,你可以使用它来编写脚本,在运行时注入到目标应用程序中,实现调试、监控等功能。
- Frida 是一款强大的动态代码插桩工具,可用于在运行时修改应用程序的行为。
@types/frida-gum- 同样属于
@types命名空间,frida-gum是 Frida 框架的一部分,它提供了一些用于动态代码插桩的基础功能和 API。@types/frida-gum为frida-gum提供了 TypeScript 类型定义,这样在 TypeScript 项目中使用frida-gum时,就可以获得类型检查和智能提示等功能。像之前的Java、Interceptor、Module之类的api就由frida-gum提供

如果在这一步之前你直接在项目下写ts脚本,可能编辑器会对Java、Module之类的api调用标错,但是安装了frida的依赖之后就ok了
- 同样属于
编写脚本
首先,将package.json中main入口修改为index.js
然后编写一个简单的脚本:
1
2const test_str: string = 'hello world'
console.log('I want to say ${test_str} to you')仿照frida-agent-example将自定义构建脚本写入package.json

frida-compile中参数-c是采用压缩方式编译(什么意思,我试了就是普通的编译成js呀),-w就是–watch,实时监测脚本改动并重新编译,执行编译指令后你在ts脚本上的改动会直接影响frida注入。
通过npm run就能执行自定义脚本的指令

尝试编译

据说这个报错是因为调用了废弃的api,我尝试将node版本降级后仍然会报错

但是他仍然会正常编译出一个_agent.js,之后frida怎么用怎么来。我秉持着能用就行的准则,有时间再查解决方案。
ts和js有哪些不同?
难说。因为之前做的大部分hook练习都是用js写的,估计要自己摸索才能体会到ts的好。
那就把一些比较有意思的ts脚本练习记录弃置于此吧
frida入门小练习-第一题

onClick通过VVVVV的VVVV方法检测flag是否正确,看看:

输入的字符串通过一大坨加密再与预设字符串6f452303f18605510aac694b0f5736beebf110bf比对,只不过看到输入长度固定在5个字符以内且必须为数字就不用分析加密了,完全可以爆破eeee方法,分析返回的字符串是否与”6f452303f18605510aac694b0f5736beebf110bf”相同就能得出flag数字。
这几个加密方法都是静态方法,更加方便我们进行hook,可以直接指定类进行调用。你肯定有疑问:为什么不调用VVVV,就可以直接通过返回值判断字符串是否正确?VVVV需要调用一个OnClickListener的对象作为参数,这样的参数我们当然不好找。
这是我的第一版脚本:
1 | Java.perform((): void => { |
由于我使用的是模拟器,爆破过多会导致脚本中断退出,但是没有关系,记住这次爆破大概中断在哪个数上,下次改改脚本接着爆就行了
但是这个脚本是爆不出来的。比对了其他writeup和我的脚本区别之后我发现了问题所在:
vvvvv.eeeee(flag)实际上返回的只是字符串吗?
是的,但是是java的字符串对象。java的字符串对象能直接和js的字符串对象比对吗?问题就在于此——hook java层的返回值可以打印出来,看起来别无二致,但是还是有区别!这样子一万年比不出来
1 | Java.perform((): void => { |
通过 Java.use("java.lang.String").$new() 转换为 Java 字符串对象,再使用 toString() 方法将其转换为 JavaScript 字符串,最后使用 === 进行严格比较,这样就能得出最终的flag为66888.
##reference
https://github.com/oleavr/frida-agent-example
https://blog.csdn.net/kinghzking/article/details/136772475
https://www.52pojie.cn/thread-1363328-1-1.html