百度对instrumentation的解释是:
个人感觉,这个翻译总差点什么,于是就保留原文了,不翻译了。
关于Frida中Instrumentation主要包含以下内容:
本问主要讲解前面没有提到过Stalker、WeakRef和ObjC。
Stalker
Introduction
Stalker is Frida’s code tracing engine. It allows threads to be followed, capturing every function, every block, even every instruction which is executed.
具体内容,后续在讲解Frida工作原理的时候会详细讲解。由于Stalker功能过于强大,在高级篇部分会重点讲解。高级篇内容均是付费内容,大家有兴趣欢迎订阅支持。
API
- Stalker.exclude(range): marks the specified memory range as excluded, which is an object with base and size properties – like the properties in an object returned by e.g. Process.getModuleByName(). Useful to improve performance and reduce noise.
- Stalker.follow([threadId, options]): start stalking threadId (or the current thread if omitted), optionally with options for enabling events.
- Stalker.flush(): flush out any buffered events. Useful when you don’t want to wait until the next Stalker.queueDrainInterval tick.
- Stalker.garbageCollect(): free accumulated memory at a safe point after Stalker#unfollow. This is needed to avoid race-conditions where the thread just unfollowed is executing its last instructions.
- Stalker.addCallProbe(address, callback[, data]): call callback (see Interceptor#attach#onEnter for signature) synchronously when a call is made to address. Returns an id that can be passed to Stalker#removeCallProbe later.
It is also possible to implement callback in C using CModule. - Stalker.removeCallProbe: remove a call probe added by Stalker#addCallProbe.
- Stalker.trustThreshold: an integer specifying how many times a piece of code needs to be executed before it is assumed it can be trusted to not mutate. Specify -1 for no trust (slow), 0 to trust code from the get-go, and N to trust code after it has been executed N times. Defaults to 1.
- Stalker.queueCapacity: an integer specifying the capacity of the event queue in number of events. Defaults to 16384 events.
- Stalker.queueDrainInterval: an integer specifying the time in milliseconds between each time the event queue is drained. Defaults to 250 ms, which means that the event queue is drained four times per second. You may also set this property to zero to disable periodic draining, and instead call Stalker.flush() when you would like the queue to be drained.
实施跟踪cpu指令
这里是实时跟踪cpu指令,关于如何修改cpu指令流程会在高级篇介绍。
"use strict"
console.log("Hello world");
const mainThread = Process.enumerateThreads()[0];
Stalker.follow(mainThread.id, {
events: {
call: true, // CALL instructions: yes please
// Other events:
ret: false, // RET instructions
exec: false, // all instructions: not recommended as it's
// a lot of data
block: false, // block executed: coarse execution trace
compile: false // block compiled: useful for coverage
},
onReceive: function (events) {
var parsedEvent = Stalker.parse(events);
//console.log("buring"+parsedEvent);
},
transform: function (iterator) {
let instruction = iterator.next();
do {
console.log("instruction:"+instruction);
iterator.keep();
} while ((instruction = iterator.next()) !== null);
}
})
运行上面的程序(在Win10系统下),使用脚本frida -l hello.js Calculator.exe
运行, 结果如下,每一步运行过程中都有相应的指令输出。这个需要对汇编有一定了解。
WeakRef
WeakRef.bind(value, fn): monitor value and call the fn callback as soon as value has been garbage-collected, or the script is about to get unloaded. Returns an id that you can pass to WeakRef.unbind() for explicit cleanup.
This API is useful if you’re building a language-binding, where you need to free native resources when a JS value is no longer needed.
WeakRef.unbind(id): stop monitoring the value passed to WeakRef.bind(value, fn), and call the fn callback immediately.
关于引用
强引用和弱引用
- JS的垃圾回收机制,如果我们持有对一个对象的引用,那么这个对象就不会被垃圾回收。这里的引用,指的是强引用。
- 一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。
JavaScript的WeakMap是弱引用使用的典型。
WeakMap是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。WeakMap是对对象的弱引用。
监测引用
本例使用的是WeakMap,成功监视到引用对象的变化。即使是强引用,也会被监测到。
"use strict"
Java.perform(function(){
const wm = new WeakMap();
let obj = { b: 2 };
wm.set(obj, '2');
obj = null;
gc();
var id = WeakRef.bind(wm, function(){
console.log("finish gc");
WeakRef.unbind(id);
}
)
})
运行脚本,结果如下:
ObjC
主要用在 苹果电脑和苹果手机,这里不做过多说明,直接看几个重要的API。
ObjC.available: a boolean specifying whether the current process has an Objective-C runtime loaded. Do not invoke any other ObjC properties or methods unless this is the case.
ObjC.api: an object mapping function names to NativeFunction instances for direct access to a big portion of the Objective-C runtime API.
ObjC.classes: an object mapping class names to ObjC.Object JavaScript bindings for each of the currently registered classes. You can interact with objects by using dot notation and replacing colons with underscores, i.e.: [NSString stringWithString:@“Hello World”] becomes const { NSString } = ObjC.classes; NSString.stringWithString_(“Hello World”);. Note the underscore after the method name. Refer to iOS Examples section for more details.
在Android手机上面运行ObjC.available返回false,显然Android是没有Object-C运行时的。
写在最后
Frida API进阶到这里基本结束了。接下来会写Frida的一些高级用法,更多内容,欢迎关注我的微信公众号:无情剑客。