Improve tracer error-handling and port embedded JS to ES6

This commit is contained in:
Ole André Vadla Ravnås
2015-07-17 01:16:22 +02:00
parent 65eff30f73
commit 93a6dbbe7e
3 changed files with 89 additions and 61 deletions
+14 -14
View File
@@ -34,32 +34,32 @@ class Discoverer(object):
})
def _create_discover_script(self):
return """\
return """"use strict";\
function Sampler() {
var threadIds = [];
var result = {};
let threadIds = [];
let result = {};
function onStanza(stanza) {
if (stanza.to === "/sampler") {
if (stanza.name === '+stop') {
if (stanza.name === '+stop')
stop();
}
}
recv(onStanza);
}
this.start = function () {
this.start = () => {
threadIds = [];
Process.enumerateThreads({
onMatch: function (thread) {
onMatch(thread) {
threadIds.push(thread.id);
},
onComplete: function () {
threadIds.forEach(function (threadId) {
onComplete() {
threadIds.forEach(threadId => {
Stalker.follow(threadId, {
events: { call: true },
onCallSummary: function (summary) {
onCallSummary(summary) {
for (var address in summary) {
if (summary.hasOwnProperty(address)) {
var count = result[address] || 0;
@@ -79,10 +79,10 @@ function Sampler() {
});
}
});
}
};
function stop() {
threadIds.forEach(function (threadId) {
threadIds.forEach(threadId => {
Stalker.unfollow(threadId);
});
threadIds = [];
@@ -100,8 +100,8 @@ function Sampler() {
recv(onStanza);
};
sampler = new Sampler();
setTimeout(function () { sampler.start(); }, 0);
const sampler = new Sampler();
setTimeout(() => { sampler.start(); }, 0);
"""
def _process_message(self, message, data, session, ui):
+7 -7
View File
@@ -265,10 +265,10 @@ def main():
self._reload()
elif command == 'time':
self._eval_and_print('''
(function() {{
var _startTime = Date.now();
var _result = eval({expression});
var _endTime = Date.now();
(() => {{
const _startTime = Date.now();
const _result = eval({expression});
const _endTime = Date.now();
console.log('Time: ' + (_endTime - _startTime).toLocaleString() + ' ms.');
return _result;
}})();'''.format(expression=json.dumps(' '.join(args))))
@@ -346,7 +346,7 @@ def main():
return user_script + """\
(function () {
(() => {
"use strict";
function onEvaluate(expression) {
@@ -386,7 +386,7 @@ def main():
return false;
if (v instanceof Array) // Object returned by Memory.readByteArray() isn't an Array
return false;
for (var i = 0; i !== v.length; i++) {
for (let i = 0; i !== v.length; i++) {
if (typeof v[i] !== 'number')
return false;
}
@@ -453,7 +453,7 @@ def main():
try:
if encountered_dot:
for key in self._get_keys("""(function(o) {
for key in self._get_keys("""(o => {
"use strict";
let k = [];
try {
+68 -40
View File
@@ -112,7 +112,7 @@ class TracerProfile(object):
def _create_resolver_script(self):
return r""""use strict";
recv(function (spec) {
recv(spec => {
try {
send({
name: '+result',
@@ -127,7 +127,7 @@ recv(function (spec) {
});
function resolve(spec) {
const workingSet = spec.reduce(function (workingSet, item) {
const workingSet = spec.reduce((workingSet, item) => {
const operation = item[0];
const scope = item[1];
const param = item[2];
@@ -322,7 +322,7 @@ function getObjCState() {
method_getImplementation: 1,
sel_getName: 1
};
Object.keys(apiSpec).forEach(function (name) {
Object.keys(apiSpec).forEach(name => {
const funPtr = Module.findExportByName("libobjc.A.dylib", name);
const argCount = apiSpec[name];
const argTypes = [];
@@ -395,7 +395,7 @@ function allFunctionExports(module) {
const moduleId = allModules().indexOf(module);
module._cachedFunctionExports = Module.enumerateExportsSync(module.path)
.filter(isFunctionExport)
.map(function (e) {
.map(e => {
e.module = moduleId;
return e;
});
@@ -443,7 +443,7 @@ const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?';
const reSpecials = charSet('().*{}+?[]^$\\!');
function charSet(s) {
return s.split("").reduce(function (set, c) {
return s.split("").reduce((set, c) => {
set[c] = true;
return set;
}, {});
@@ -455,10 +455,10 @@ function ext(a, b) {
a = a || {};
b = b || {};
const t = {};
Object.keys(b).forEach(function (k) {
Object.keys(b).forEach(k => {
t[k] = b[k];
});
Object.keys(a).forEach(function (k) {
Object.keys(a).forEach(k => {
t[k] = a[k];
});
return t;
@@ -480,7 +480,7 @@ function Minimatch(pattern, options) {
this.make();
}
Minimatch.prototype.make = function () {
Minimatch.prototype.make = () => {
if (this._made)
return;
@@ -500,22 +500,22 @@ Minimatch.prototype.make = function () {
let set = this.globSet = [this.pattern];
set = this.globParts = set.map(function (s) {
set = this.globParts = set.map(s => {
return s.split(slashSplit);
});
set = set.map(function (s, si, set) {
set = set.map((s, si, set) => {
return s.map(this.parse, this);
}, this);
set = set.filter(function (s) {
set = set.filter(s => {
return s.indexOf(false) === -1;
});
this.set = set;
};
Minimatch.prototype.parseNegate = function () {
Minimatch.prototype.parseNegate = () => {
const pattern = this.pattern;
let negate = false;
const options = this.options;
@@ -535,7 +535,7 @@ Minimatch.prototype.parseNegate = function () {
};
const SUBPARSE = {};
Minimatch.prototype.parse = function (pattern, isSub) {
Minimatch.prototype.parse = (pattern, isSub) => {
const options = this.options;
if (!options.noglobstar && pattern === '**')
@@ -726,7 +726,7 @@ Minimatch.prototype.parse = function (pattern, isSub) {
for (let pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
let tail = re.slice(pl.reStart + 3);
tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) {
tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, (_, $1, $2) => {
if (!$2)
$2 = '\\';
@@ -771,7 +771,7 @@ Minimatch.prototype.parse = function (pattern, isSub) {
return regExp;
};
Minimatch.prototype.makeRe = function () {
Minimatch.prototype.makeRe = () => {
if (this.regexp || this.regexp === false)
return this.regexp;
@@ -786,8 +786,8 @@ Minimatch.prototype.makeRe = function () {
const twoStar = options.noglobstar ? star : options.dot ? twoStarDot : twoStarNoDot;
const flags = options.nocase ? 'i' : '';
let re = set.map(function (pattern) {
return pattern.map(function (p) {
let re = set.map(pattern => {
return pattern.map(p => {
return (p === GLOBSTAR) ? twoStar : (typeof p === 'string') ? regExpEscape(p) : p._src;
}).join('\\\/');
}).join('|');
@@ -805,7 +805,7 @@ Minimatch.prototype.makeRe = function () {
return this.regexp;
};
Minimatch.prototype.match = function (f, partial) {
Minimatch.prototype.match = (f, partial) => {
if (this.comment)
return false;
if (this.empty)
@@ -844,7 +844,7 @@ Minimatch.prototype.match = function (f, partial) {
return this.negate;
};
Minimatch.prototype.matchOne = function (file, pattern, partial) {
Minimatch.prototype.matchOne = (file, pattern, partial) => {
const options = this.options;
let fi, pi, fl, pl;
@@ -943,6 +943,7 @@ class Tracer(object):
'name': '+update',
'payload': {
'items': [{
'name': function.name,
'absolute_address': hex(function.absolute_address),
'handler': handler
}]
@@ -961,6 +962,7 @@ class Tracer(object):
self._script.load()
for chunk in [working_set[i:i+1000] for i in range(0, len(working_set), 1000)]:
targets = [{
'name': function.name,
'absolute_address': hex(function.absolute_address),
'handler': self._repository.ensure_handler(function)
} for function in chunk]
@@ -989,12 +991,13 @@ class Tracer(object):
self._script = None
def _create_trace_script(self):
return """\
var started = new Date();
var pending = [];
var timer = null;
var handlers = {};
var state = {};
return """"use strict";
const started = Date.now();
const pending = [];
let timer = null;
const handlers = {};
const state = {};
function onStanza(stanza) {
if (stanza.to === "/targets") {
if (stanza.name === '+add') {
@@ -1009,29 +1012,31 @@ function onStanza(stanza) {
recv(onStanza);
}
function add(targets) {
targets.forEach(function (target) {
var targetAddress = target.absolute_address;
eval("var handler = " + target.handler);
targets.forEach(target => {
const handler = parseHandler(target);
if (handler === null)
return;
const targetAddress = target.absolute_address;
target = null;
var h = [handler];
const h = [handler];
handlers[targetAddress] = h;
function log(message) {
send({
from: "/events",
name: '+add',
payload: {
items: [[new Date().getTime() - started.getTime(), targetAddress, message]]
items: [[Date.now() - started, targetAddress, message]]
}
});
}
pending.push(function attachToTarget() {
pending.push(() => {
Interceptor.attach(ptr(targetAddress), {
onEnter: function onEnter(args) {
onEnter(args) {
h[0].onEnter.call(this, log, args, state);
},
onLeave: function onLeave(retval) {
onLeave(retval) {
h[0].onLeave.call(this, log, retval, state);
}
});
@@ -1041,13 +1046,26 @@ function add(targets) {
scheduleNext();
}
function update(targets) {
targets.forEach(function (target) {
eval("var handler = " + target.handler);
handlers[target.absolute_address][0] = handler;
targets.forEach(target => {
handlers[target.absolute_address][0] = parseHandler(target);
});
}
function parseHandler(target) {
try {
return (1, eval)("(" + target.handler + ")");
} catch (e) {
send({
from: "/targets",
name: '+error',
payload: {
message: "Invalid handler for '" + target.name + "': " + e.message
}
});
return null;
}
}
function start() {
pending.push(function acknowledgeStart() {
pending.push(() => {
send({
from: "/targets",
name: '+started',
@@ -1065,7 +1083,7 @@ function processNext() {
timer = null;
if (pending.length > 0) {
var work = pending.shift();
const work = pending.shift();
work();
scheduleNext();
}
@@ -1090,6 +1108,9 @@ recv(onStanza);
elif stanza['from'] == "/targets" and stanza['name'] == '+started':
ui.on_trace_progress('ready')
handled = True
elif stanza['from'] == "/targets" and stanza['name'] == '+error':
ui.on_trace_error(stanza['payload'])
handled = True
if not handled:
print(message)
@@ -1192,7 +1213,7 @@ class Repository(object):
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter: function onEnter(log, args, state) {
onEnter(log, args, state) {
log(%(log_str)s);
},
@@ -1206,7 +1227,7 @@ class Repository(object):
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave: function onLeave(log, retval, state) {
onLeave(log, retval, state) {
}
}
""" % {"display_name": display_name, "log_str": log_str}
@@ -1297,6 +1318,9 @@ class UI(object):
def on_trace_progress(self, operation):
pass
def on_trace_error(self, error):
pass
def on_trace_events(self, events):
pass
@@ -1308,6 +1332,7 @@ class UI(object):
def main():
from colorama import Fore, Style
from frida.application import ConsoleApplication, input_with_timeout
class TracerApplication(ConsoleApplication, UI):
@@ -1372,6 +1397,9 @@ def main():
self._update_status("Started tracing %d function%s. Press Ctrl+C to stop." % (len(self._targets), plural))
self._resume()
def on_trace_error(self, error):
print(Fore.RED + Style.BRIGHT + "Error" + Style.RESET_ALL + ": " + error['message'])
def on_trace_events(self, events):
self._status_updated = False
for timestamp, target_address, message in events: