7c77ed04f4
This is an initial implementation of the dart deobfuscator tool. Let me know your thoughts on the package name. I used to have this named as `package:deobfuscate`, but it feels like we will want to add more tools that are not about deobfuscation in the future, so I picked `package:dart2js_tools` instead. That also gives us the opportunity to move over the dart2js_info code here too. Change-Id: I2ff948982969c9c76bc84cdc78cbe237abc87378 Reviewed-on: https://dart-review.googlesource.com/69243 Reviewed-by: Stephen Adams <sra@google.com> Commit-Queue: Sigmund Cherem <sigmund@google.com>
90 lines
2.8 KiB
Dart
90 lines
2.8 KiB
Dart
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:dart2js_tools/src/util.dart';
|
|
|
|
/// Script to show a text representation of the inlining data attached to
|
|
/// source-map files.
|
|
///
|
|
/// This expands the push/pop operations and checks simple invariants (e.g. that
|
|
/// the stack is always empty at the beginning of a function).
|
|
main(List<String> args) {
|
|
if (args.length != 1) {
|
|
print('usage: show_inline_data.dart <js-file>');
|
|
exit(1);
|
|
}
|
|
var uri = Uri.base.resolve(args[0]);
|
|
var provider = new CachingFileProvider();
|
|
|
|
var mapping = provider.mappingFor(uri);
|
|
var starts = functionStarts(provider.sourcesFor(uri));
|
|
var file = provider.fileFor(uri);
|
|
var frames = mapping.frames;
|
|
var offsets = frames.keys.toList()..sort();
|
|
var sb = new StringBuffer();
|
|
int depth = 0;
|
|
int lastFunctionStart = null;
|
|
for (var offset in offsets) {
|
|
int functionStart = nextFunctionStart(starts, offset, lastFunctionStart);
|
|
if (lastFunctionStart == null || functionStart > lastFunctionStart) {
|
|
sb.write('\n${location(starts[functionStart], file)}: function start\n');
|
|
|
|
if (depth != 0) {
|
|
sb.write(
|
|
"[31m[invalid] function start with non-zero depth: $depth[0m\n");
|
|
}
|
|
lastFunctionStart = functionStart;
|
|
}
|
|
|
|
var offsetPrefix = '${location(offset, file)}:';
|
|
var pad = ' ' * offsetPrefix.length;
|
|
sb.write(offsetPrefix);
|
|
bool first = true;
|
|
for (var frame in frames[offset]) {
|
|
if (!first) sb.write('$pad');
|
|
sb.write(' $frame\n');
|
|
first = false;
|
|
if (frame.isPush) depth++;
|
|
if (frame.isPop) depth--;
|
|
if (frame.isEmpty && depth != 0) {
|
|
sb.write("[31m[invalid] pop-empty with non-zero depth: $depth[0m\n");
|
|
}
|
|
if (!frame.isEmpty && depth == 0) {
|
|
sb.write("[31m[invalid] non-empty pop with zero depth: $depth[0m\n");
|
|
}
|
|
if (depth < 0) {
|
|
sb.write("[31m[invalid] negative depth: $depth[0m\n");
|
|
}
|
|
}
|
|
}
|
|
print('$sb');
|
|
}
|
|
|
|
var _functionDeclarationRegExp = new RegExp(r':( )?function\(');
|
|
|
|
List<int> functionStarts(String sources) {
|
|
List<int> result = [];
|
|
int index = sources.indexOf(_functionDeclarationRegExp);
|
|
while (index != -1) {
|
|
result.add(index + 2);
|
|
index = sources.indexOf(_functionDeclarationRegExp, index + 1);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int nextFunctionStart(List<int> starts, int offset, int last) {
|
|
int j = last ?? 0;
|
|
for (; j < starts.length && starts[j] <= offset; j++);
|
|
return j - 1;
|
|
}
|
|
|
|
String location(int offset, file) {
|
|
var line = file.getLine(offset) + 1;
|
|
var column = file.getColumn(offset) + 1;
|
|
var location = '$offset ($line:$column)';
|
|
return location + (' ' * (16 - location.length));
|
|
}
|