├── .eslintignore
├── www
├── m
│ ├── .bowerrc
│ ├── css
│ │ ├── networkerr.css
│ │ ├── tables.css
│ │ ├── flexcontainer.css
│ │ ├── overview.css
│ │ ├── material-design-icons.css
│ │ ├── terminal.css
│ │ ├── autocomplete.css
│ │ ├── console.css
│ │ ├── widget.css
│ │ ├── contextmenu.css
│ │ ├── disasm.css
│ │ └── hexdump.css
│ ├── fonts.list
│ ├── .vscode
│ │ ├── settings.json
│ │ └── tasks.json
│ ├── images
│ │ ├── icon.png
│ │ ├── user.jpg
│ │ ├── rlogo256.png
│ │ └── touch
│ │ │ └── chrome-touch-icon-192x192.png
│ ├── js
│ │ ├── core
│ │ │ ├── ChunkStatus.js
│ │ │ ├── NavigatorDirection.js
│ │ │ └── SettingsManager.js
│ │ ├── layout
│ │ │ ├── Layouts.js
│ │ │ ├── Ruler.js
│ │ │ ├── RadareInfiniteBlock.js
│ │ │ └── FlexContainer.js
│ │ ├── modules
│ │ │ ├── hexdump
│ │ │ │ ├── WordSizes.js
│ │ │ │ └── tools.legacy.js
│ │ │ └── overview
│ │ │ │ ├── FortunesCard.js
│ │ │ │ ├── Overview.js
│ │ │ │ ├── EntropyCard.js
│ │ │ │ ├── GraphCard.js
│ │ │ │ └── AnalysisCard.js
│ │ ├── helpers
│ │ │ ├── project_management.legacy.js
│ │ │ ├── UpdateManager.js
│ │ │ ├── Speak.js
│ │ │ ├── tools.legacy.js
│ │ │ ├── prompts.legacy.js
│ │ │ ├── Format.js
│ │ │ ├── uiTables.legacy.js
│ │ │ ├── InfiniteScrolling.js
│ │ │ ├── Inputs.js
│ │ │ ├── statusbar
│ │ │ │ └── console.legacy.js
│ │ │ └── Table.js
│ │ ├── widgets
│ │ │ ├── DisassemblyBlocksWidget.js
│ │ │ ├── DisassemblyDecompileWidget.js
│ │ │ ├── DisassemblyFunctionsFullWidget.js
│ │ │ ├── DisassemblyInfosWidget.js
│ │ │ ├── Widgets.js
│ │ │ ├── DisassemblyFunctionsWidget.js
│ │ │ ├── OverviewWidget.js
│ │ │ ├── DisassemblyWidget.js
│ │ │ ├── HexdumpWidget.js
│ │ │ ├── NotesWidget.js
│ │ │ ├── DisassemblyGraphWidget.js
│ │ │ ├── FlagsWidget.js
│ │ │ ├── BasePreWidget.js
│ │ │ ├── ClassesWidget.js
│ │ │ ├── CommentsWidget.js
│ │ │ ├── BaseWidget.js
│ │ │ ├── ScriptWidget.js
│ │ │ ├── DebuggerWidget.js
│ │ │ ├── FunctionsWidget.js
│ │ │ ├── SearchWidget.js
│ │ │ ├── WidgetFactory.js
│ │ │ └── FlagsSpacesWidget.js
│ │ └── dialogs
│ │ │ └── dialog_networkerr.legacy.js
│ ├── .babelrc
│ ├── test
│ │ ├── specs
│ │ │ └── helpers
│ │ │ │ └── chai.js
│ │ ├── test.test.js
│ │ └── index.html
│ ├── manifest.webapp
│ ├── .eslintrc.json
│ ├── Makefile
│ ├── workers
│ │ ├── disasmNavProvider.js
│ │ ├── hexchunkProvider.js
│ │ └── disasmProvider.js
│ ├── webpack.config.js
│ ├── CONTRIBUTING.md
│ └── package.json
├── p
│ ├── .bowerrc
│ ├── rlogo-inv.png
│ ├── Makefile
│ ├── lib
│ │ ├── js
│ │ │ ├── panels
│ │ │ │ ├── settings_panel.js
│ │ │ │ ├── projects_panel.js
│ │ │ │ ├── entropy_panel.js
│ │ │ │ ├── logs_panel.js
│ │ │ │ └── types_panel.js
│ │ │ └── dependencies
│ │ │ │ └── jquery.donetyping.js
│ │ └── css
│ │ │ ├── jquery-ui.css
│ │ │ └── tree.jquery.css
│ ├── bower.json
│ ├── package.json
│ └── gulpfile.js
├── .bowerrc
├── enyo
│ ├── .bowerrc
│ ├── icon.png
│ ├── favicon.ico
│ ├── rlogo-tr.png
│ ├── css
│ │ ├── lib
│ │ │ └── onyx
│ │ │ │ └── images
│ │ │ │ ├── gradient.png
│ │ │ │ └── gradient-invert.png
│ │ ├── index.css
│ │ └── enyo
│ │ │ └── enyo.css
│ ├── README.md
│ ├── js
│ │ ├── search.js
│ │ ├── debugger.js
│ │ ├── config.js
│ │ ├── graph.js
│ │ ├── about.js
│ │ ├── console.js
│ │ ├── logs.js
│ │ ├── script.js
│ │ ├── main.js
│ │ ├── assembler.js
│ │ └── leftpanel.js
│ ├── Makefile
│ ├── DEPENDENCIES
│ ├── bower.json
│ ├── package.json
│ ├── index.html
│ └── gulpfile.js
├── rlogo.png
├── favicon.ico
├── t
│ ├── rlogo.png
│ ├── README.md
│ ├── gulpfile.js
│ ├── Makefile
│ ├── package.json
│ ├── index.html
│ └── css
│ │ └── style.css
├── old
│ ├── rlogo2.png
│ └── script.js
├── graph
│ ├── img
│ │ ├── arrow.gif
│ │ ├── arrow_d.gif
│ │ ├── arrow_l.gif
│ │ ├── arrow_r.gif
│ │ └── arrow_u.gif
│ ├── make.sh
│ ├── js-graph-it.css
│ ├── index.html
│ ├── index.js
│ └── sf-homepage.css
├── bolt
│ ├── Makefile
│ ├── r2bolt.sh
│ └── index.html
├── Makefile
├── upload.html
├── w
│ ├── Makefile
│ ├── index.js
│ └── index.html
├── gulpfile.js
├── log.html
├── package.json
├── r2.svg
└── lib
│ └── disasm.css
├── .gitmodules
├── .csslintrc
├── .gitignore
├── .codeclimate.yml
├── cherrypull.sh
├── Makefile
├── CONTRIBUTING.md
├── README.md
├── .github
└── workflows
│ ├── ci.yml
│ └── codeql-analysis.yml
└── LICENSES.md
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*{.,-}min.js
2 |
--------------------------------------------------------------------------------
/www/m/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "./vendors/"
3 | }
4 |
--------------------------------------------------------------------------------
/www/p/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "./vendors/"
3 | }
4 |
--------------------------------------------------------------------------------
/www/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "../dist/vendors/"
3 | }
4 |
--------------------------------------------------------------------------------
/www/enyo/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "./vendors/"
3 | }
4 |
--------------------------------------------------------------------------------
/www/m/css/networkerr.css:
--------------------------------------------------------------------------------
1 | .next-attempt {
2 | display: none;
3 | }
--------------------------------------------------------------------------------
/www/m/css/tables.css:
--------------------------------------------------------------------------------
1 | tr.active {
2 | background-color: #EEEEEE;
3 | }
--------------------------------------------------------------------------------
/www/m/fonts.list:
--------------------------------------------------------------------------------
1 | Roboto:400,100,300,500,700,900,400italic,700italic
2 |
--------------------------------------------------------------------------------
/www/m/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "vsicons.presets.angular": false
3 | }
--------------------------------------------------------------------------------
/www/rlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/rlogo.png
--------------------------------------------------------------------------------
/www/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/favicon.ico
--------------------------------------------------------------------------------
/www/t/rlogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/t/rlogo.png
--------------------------------------------------------------------------------
/www/enyo/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/enyo/icon.png
--------------------------------------------------------------------------------
/www/old/rlogo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/old/rlogo2.png
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "rarop"]
2 | path = rarop
3 | url = https://github.com/jpenalbae/rarop.git
4 |
--------------------------------------------------------------------------------
/www/enyo/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/enyo/favicon.ico
--------------------------------------------------------------------------------
/www/enyo/rlogo-tr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/enyo/rlogo-tr.png
--------------------------------------------------------------------------------
/www/m/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/m/images/icon.png
--------------------------------------------------------------------------------
/www/m/images/user.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/m/images/user.jpg
--------------------------------------------------------------------------------
/www/p/rlogo-inv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/p/rlogo-inv.png
--------------------------------------------------------------------------------
/www/graph/img/arrow.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/graph/img/arrow.gif
--------------------------------------------------------------------------------
/www/m/js/core/ChunkStatus.js:
--------------------------------------------------------------------------------
1 | export const ChunkStatus = {
2 | LAUNCHED: 0,
3 | COMPLETED: 1
4 | };
5 |
--------------------------------------------------------------------------------
/www/bolt/Makefile:
--------------------------------------------------------------------------------
1 | PWD=$(shell pwd)
2 | all:
3 | r2 -qcq -e http.sandbox=false -e http.root=${PWD} -c=H -
4 |
--------------------------------------------------------------------------------
/www/graph/img/arrow_d.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/graph/img/arrow_d.gif
--------------------------------------------------------------------------------
/www/graph/img/arrow_l.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/graph/img/arrow_l.gif
--------------------------------------------------------------------------------
/www/graph/img/arrow_r.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/graph/img/arrow_r.gif
--------------------------------------------------------------------------------
/www/graph/img/arrow_u.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/graph/img/arrow_u.gif
--------------------------------------------------------------------------------
/www/m/images/rlogo256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/m/images/rlogo256.png
--------------------------------------------------------------------------------
/.csslintrc:
--------------------------------------------------------------------------------
1 | --exclude-exts=.min.css
2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
3 |
--------------------------------------------------------------------------------
/www/m/js/core/NavigatorDirection.js:
--------------------------------------------------------------------------------
1 | export const NavigatorDirection = {
2 | BEFORE: -1,
3 | CURRENT: 0,
4 | AFTER: 1
5 | };
6 |
--------------------------------------------------------------------------------
/www/m/js/layout/Layouts.js:
--------------------------------------------------------------------------------
1 | export const Layouts = {
2 | FULL: 'full',
3 | HORIZONTAL: 'horizontal',
4 | VERTICAL: 'vertical'
5 | };
6 |
--------------------------------------------------------------------------------
/www/enyo/css/lib/onyx/images/gradient.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/enyo/css/lib/onyx/images/gradient.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | vendors/
3 | www/m/vendors
4 | dev/
5 | dist/
6 | .config
7 | *.log
8 | npm-debug.log*
9 | *~
10 | dist.tar.gz
11 |
--------------------------------------------------------------------------------
/www/enyo/css/lib/onyx/images/gradient-invert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/enyo/css/lib/onyx/images/gradient-invert.png
--------------------------------------------------------------------------------
/www/m/images/touch/chrome-touch-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radareorg/radare2-webui/master/www/m/images/touch/chrome-touch-icon-192x192.png
--------------------------------------------------------------------------------
/www/Makefile:
--------------------------------------------------------------------------------
1 | build:
2 | npm install
3 | $(shell npm bin)/gulp
4 |
5 | dist release:
6 | $(shell npm bin)/gulp
7 | $(MAKE) -C p release
8 | $(MAKE) -C m release
9 |
--------------------------------------------------------------------------------
/www/graph/make.sh:
--------------------------------------------------------------------------------
1 | cd img
2 | for FILE in *.gif ; do
3 | printf ''
6 | done
7 |
--------------------------------------------------------------------------------
/www/m/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "transform-class-properties",
4 | "@babel/plugin-proposal-object-rest-spread"
5 | ],
6 | "presets": ["@babel/preset-env"]
7 | }
8 |
--------------------------------------------------------------------------------
/www/m/js/modules/hexdump/WordSizes.js:
--------------------------------------------------------------------------------
1 | /** Size in number of bytes to make a word */
2 | export const WordSizes = {
3 | PAIRS: -1,
4 | HALF: 2, // 16 bits
5 | WORD: 4, // 32 bits
6 | QUADWORD: 8 // 64 bits
7 | };
8 |
--------------------------------------------------------------------------------
/www/upload.html:
--------------------------------------------------------------------------------
1 |
2 |
| 23 | 24 | | 25 ||
| 28 | | 34 |35 | |
| ' + col + ' | '; 24 | } 25 | out += '
|---|
| ' + col + ' | '; 43 | } 44 | return out + '
| ' + idx + ' | ' + value + ' |
' + table + ''); 21 | $('#entropy_chart').horizontalTableGraph(); 22 | }; 23 | 24 | jQuery.fn.horizontalTableGraph = function() { 25 | $(this).find('thead').remove(); 26 | var maxvalue = 0; 27 | $(this).find('tr').each(function() { 28 | $(this).removeClass(); 29 | $(this).find('td').eq(0).animate({width: '50px'}, 1000); 30 | $(this).find('td').eq(1).animate({width: '500px'}, 1000).css('text-align', 'left'); 31 | $(this).find('td').eq(1).css('width', '500px'); 32 | var getvalue = $(this).find('td').eq(1).html(); 33 | maxvalue = Math.max(maxvalue, getvalue); 34 | }); 35 | $(this).find('tr').each(function() { 36 | var thevalue = $(this).find('td').eq(1).html(); 37 | var newBar = $('').html(thevalue); 38 | newBar.css({ 39 | 'display': 'block', 40 | 'width': '0px', 41 | 'backgroundColor': '#600', 42 | 'marginBottom': '0px', 43 | 'padding': '0px', 44 | 'color': '#FFF' 45 | }); 46 | $(this).find('td').eq(1).html(newBar); 47 | newBar.animate({'width': (100 * thevalue / maxvalue) + '%'}, 'slow'); 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /www/enyo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
8 | */
9 | export class BasePreWidget extends BaseWidget {
10 |
11 | /**
12 | * Creates an instance of BasePreWidget.
13 | * @param {any} name Name of the widget, displayed on the top bar
14 | * @param {any} formatFunc Function used to format the r2cmd output (used as innerHTML)
15 | * @param {any} r2cmd Command executed to obtain the output
16 | * @param {any} [backButton=null] Optional button to be inserted into the widget
17 | */
18 | constructor(name, formatFunc, r2cmd, backButton = null) {
19 | super(name, 'dark');
20 | this.formatFunc = formatFunc;
21 | this.r2cmd = r2cmd;
22 | if (backButton !== null)
23 | this.backButton = backButton;
24 | }
25 |
26 | /** @override */
27 | init() {
28 | if (typeof this.backButton === 'undefined') {
29 | return;
30 | }
31 | this.backButton.style.position = 'absolute';
32 | this.backButton.style.top = '1em';
33 | this.backButton.style.left = '1em';
34 |
35 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
36 | if (this.displayed) {
37 | this.draw();
38 | }
39 | });
40 | }
41 |
42 | /** @override */
43 | draw() {
44 | if (typeof this.backButton !== 'undefined') {
45 | this.node.appendChild(this.backButton);
46 | }
47 | this.node.appendChild(this.getPre());
48 | }
49 |
50 | /** Format text from registered r2cmd and provides a element */
51 | getPre() {
52 | const pre = document.createElement('pre');
53 | r2.cmd(this.r2cmd, output => {
54 | pre.appendChild(this.formatFunc(output));
55 | });
56 | return pre;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/www/m/js/widgets/ClassesWidget.js:
--------------------------------------------------------------------------------
1 | import {BaseWidget} from './BaseWidget';
2 | import {Inputs} from '../helpers/Inputs';
3 | import {Table} from '../helpers/Table';
4 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper';
5 | import {Widgets} from '../widgets/Widgets';
6 |
7 | export class ClassesWidget extends BaseWidget {
8 | constructor() {
9 | super('Classes');
10 | }
11 |
12 | init() {
13 | this.inColor = true; // TODO
14 |
15 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
16 | if (!this.displayed) {
17 | return;
18 | }
19 | this.draw();
20 | });
21 | }
22 |
23 | draw() {
24 | this.node.innerHTML = '';
25 | this.node.scrollTop = 0;
26 | this.node.appendChild(this.getPanel());
27 | }
28 |
29 | getPanel() {
30 | var c = document.createElement('div');
31 |
32 | var header = document.createElement('div');
33 | header.style.position = 'fixed';
34 | header.style.margin = '0.5em';
35 | c.appendChild(header);
36 |
37 | header.appendChild(Inputs.button('Refresh', () => {
38 | statusMessage('Analyzing symbols...');
39 | r2.cmd('aa', () => {
40 | statusMessage('done');
41 | this.draw();
42 | });
43 | }));
44 |
45 | var content = document.createElement('div');
46 | content.style.paddingTop = '70px';
47 | c.appendChild(content);
48 |
49 | r2.cmd('ic', function(d) {
50 | var table = new Table(
51 | ['+Address', 'Type', 'Name'],
52 | [false, true, false],
53 | 'classesTable',
54 | null,
55 | Widgets.CLASSES);
56 |
57 | var lines = d.split(/\n/); //clickable offsets (d).split (/\n/);
58 | for (var i in lines) {
59 | var items = lines[i].match(/^(0x[0-9a-f]+)\s+([0-9]+)\s+([0-9]+(\s+\->\s+[0-9]+)?)\s+(.+)$/);
60 | if (items !== null) {
61 | table.addRow([items[1], items[5], items[2]]);
62 | }
63 | }
64 | table.insertInto(content);
65 | });
66 |
67 | return c;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/www/m/js/widgets/CommentsWidget.js:
--------------------------------------------------------------------------------
1 | import {BaseWidget} from './BaseWidget';
2 |
3 | import {uiContext} from '../core/UIContext';
4 | import {Widgets} from './Widgets';
5 | import {Inputs} from '../helpers/Inputs';
6 | import {Table} from '../helpers/Table';
7 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper';
8 |
9 | export class CommentsWidget extends BaseWidget {
10 | constructor() {
11 | super('Comments');
12 | }
13 |
14 | init() {
15 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
16 | if (this.displayed) {
17 | this.draw();
18 | }
19 | });
20 | }
21 |
22 | draw() {
23 | this.node.innerHTML = '';
24 | this.node.appendChild(this.getPanel());
25 | }
26 |
27 | getPanel() {
28 | var c = document.createElement('div');
29 |
30 | var header = document.createElement('div');
31 | header.style.position = 'fixed';
32 | header.style.margin = '0.5em';
33 | c.appendChild(header);
34 |
35 | header.appendChild(Inputs.button('Notes', () => uiContext.navigateTo(Widgets.NOTES)));
36 |
37 | var content = document.createElement('div');
38 | content.style.paddingTop = '70px';
39 | c.appendChild(content);
40 |
41 | r2.cmd('CC', (d) => {
42 | var table = new Table(
43 | ['+Offset', '~Comment'],
44 | [true, false],
45 | 'commentsTable',
46 | (row, newVal) => {
47 | var offset = row[0];
48 |
49 | // remove
50 | r2.cmd('CC- @ ' + offset);
51 |
52 | // add new
53 | r2.cmd('CCu base64:' + window.btoa(newVal) + ' @ ' + offset);
54 |
55 | this.draw();
56 | },
57 | Widgets.HEXDUMP);
58 |
59 | var lines = d.split(/\n/); //clickable offsets (d).split (/\n/);
60 | for (var i in lines) {
61 | var line = lines[i].split(/ (.+)?/);
62 | if (line.length >= 2) {
63 | table.addRow([line[0], line[1]]);
64 | }
65 | }
66 | table.insertInto(content);
67 | });
68 |
69 | return c;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/www/graph/index.js:
--------------------------------------------------------------------------------
1 |
2 | window.onresize = function () {
3 | resizeCanvas ();
4 | }
5 |
6 | function resizeBlocks() {
7 | }
8 |
9 | function Ajax (method, uri, body, fn) {
10 | var x = new XMLHttpRequest ();
11 | x.open (method, uri, false);
12 | x.onreadystatechange = function (y) {
13 | if (x.status == 200) {
14 | if (fn) fn (x.responseText);
15 | }
16 | }
17 | x.send (body);
18 | }
19 |
20 | function get_graph() {
21 | Ajax ('GET', "/cmd/ag $$", '', function (x) {
22 | document.getElementById ('mainCanvas').innerHTML = x.replace (/\\l/g,"\n");
23 | setMenu ();
24 | resizeCanvas ();
25 | initPageObjects ();
26 | });
27 | }
28 |
29 | function onLoad() {
30 | get_graph ();
31 | }
32 |
33 | /**
34 | * Resizes the main canvas to the maximum visible height.
35 | */
36 | function resizeCanvas() {
37 | var divElement = document.getElementById("mainCanvas");
38 | var screenHeight = window.innerHeight || document.body.offsetHeight;
39 | divElement.style.height = (screenHeight - 16) + "px";
40 | }
41 |
42 | /**
43 | * sets the active menu scanning for a menu item which url is a prefix
44 | * of the one of the current page ignoring file extension.
45 | * Nice trick!
46 | */
47 | function setMenu() {
48 | var url = document.location.href;
49 | // strip extension
50 | url = stripExtension(url);
51 |
52 | var ulElement = document.getElementById("menu");
53 | var links = ulElement.getElementsByTagName("A");
54 | var i;
55 | for(i = 0; i < links.length; i++) {
56 | if(url.indexOf(stripExtension(links[i].href)) == 0) {
57 | links[i].className = "active_menu";
58 | return;
59 | }
60 | }
61 | }
62 |
63 | /**
64 | * Strips the file extension and everything after from a url
65 | */
66 | function stripExtension(url) {
67 | var lastDotPos = url.lastIndexOf('.');
68 | return (lastDotPos <= 0)? url:
69 | url.substring (0, lastDotPos - 1);
70 | }
71 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | VERSION=1.2.0
2 |
3 | all: build
4 | $(MAKE) run
5 |
6 | # Default UI is Material
7 | run: runm
8 |
9 | ###############
10 | # Building UI #
11 | ###############
12 |
13 | build: root enyo material tiles panel
14 |
15 | root:
16 | $(MAKE) -C www build
17 |
18 | enyo:
19 | $(MAKE) -C www/enyo build
20 |
21 | material:
22 | $(MAKE) -C www/m build
23 |
24 | tiles:
25 | $(MAKE) -C www/t build
26 |
27 | panel:
28 | $(MAKE) -C www/p build
29 |
30 | ###############################
31 | # Running R2 with specitic UI #
32 | ###############################
33 |
34 | runenyo:
35 | r2 -q -e http.sandbox=0 -e http.homeroot=dist -e http.ui=enyo -c=H /bin/ls
36 |
37 | runm:
38 | r2 -q -e http.sandbox=false -e http.homeroot=dist -e http.ui=m -c=H /bin/ls
39 |
40 | runt:
41 | r2 -q -e http.homeroot=dist -e http.ui=t -c=H /bin/ls
42 |
43 | runp:
44 | r2 -q -e http.homeroot=dev -e http.ui=p -c=H /bin/ls
45 |
46 | #####################
47 | # Building releases #
48 | #####################
49 |
50 | release-root: root
51 |
52 | release-enyo: enyo
53 |
54 | release-material: material
55 | $(MAKE) -C www/m release
56 |
57 | release-tiles: tiles
58 |
59 | release-panel: panel
60 | $(MAKE) -C www/p release
61 |
62 | release: release-root release-enyo release-material release-tiles release-panel
63 |
64 | ################################
65 | # Making archives for releases #
66 | ################################
67 |
68 | dist: release
69 | tar cJvf radare2-webui-$(VERSION).tar.xz dist
70 |
71 | indivualdist:
72 | cd dist
73 | tar zcvf ../r2-webui-enyo.tar.gz enyo
74 | tar zcvf ../r2-webui-m.tar.gz m
75 | tar zcvf ../r2-webui-t.tar.gz t
76 | tar zcvf ../r2-webui-p.tar.gz p
77 |
78 | ##################
79 | # Cleaning files #
80 | ##################
81 |
82 | clean:
83 | $(MAKE) -C www/enyo clean
84 | rm -rf dist
85 | rm -rf dev
86 |
87 | mrproper:
88 | git clean -xdf
89 |
90 | .PHONY: enyo all
91 | .ONESHELL: indivualdist
92 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | CONTRIBUTING
2 | ============
3 |
4 | We will explain how to set up your environment to start working with the UI.
5 |
6 | This will require: `radare2`, `node` and `npm`.
7 |
8 | Fork
9 | ----
10 |
11 | Fork the [official repository](https://github.com/radare/radare2-webui) and clone it on your computer:
12 |
13 | $ git clone https://github.com//radare2-webui.git
14 |
15 | Build
16 | -----
17 |
18 | UI can be built in *development* mode or to be released (minified output). This part explain the development building process.
19 |
20 | You can build all UI all at once:
21 |
22 | $ make build
23 |
24 | It will retrieve all the required dependencies using `npm`, `gulp` and `bower` and placing the right files into the `dev` directory (UI other than `m` will directly use the `dist` folder since they doesn't use a separated dev process at this time) that will be used when we will *run* them.
25 |
26 | You can also build them separatly:
27 |
28 | $ make enyo
29 | $ make material
30 | $ make panel
31 | $ make tiles
32 |
33 | If you encounter some problem with a *call method 'join' of undefined* building the material UI, try to [update](https://davidwalsh.name/upgrade-nodejs) `node`:
34 |
35 | sudo npm cache clean -f
36 | sudo npm install -g n
37 | sudo n stable
38 |
39 | Run
40 | ---
41 |
42 | Once built, you can see them working through this commands.
43 |
44 | $ make runenyo # enyo (mobile)
45 | $ make runm # material (responsive)
46 | $ make runp # panels (desktop)
47 | $ make runt # tiles (legacy)
48 |
49 | Work
50 | ----
51 |
52 | You are ready to make your modifications inside the `www` directory. You will find more instructions on the dedicated CONTRIBUTING file for each UI:
53 |
54 | * [material](https://github.com/radareorg/radare2-webui/blob/master/www/m/CONTRIBUTING.md)
55 |
56 | Contribute
57 | ----------
58 |
59 | Commit your changes and send a pull request!
60 |
--------------------------------------------------------------------------------
/www/m/js/modules/overview/Overview.js:
--------------------------------------------------------------------------------
1 | import {AnalysisCard} from './AnalysisCard';
2 | import {EntropyCard} from './EntropyCard';
3 | import {FortunesCard} from './FortunesCard';
4 | import {GraphCard} from './GraphCard';
5 | import {InfoCard} from './InfoCard';
6 |
7 | export class Overview {
8 |
9 | get DOM() { return this.dom; }
10 |
11 | constructor() {
12 | this.analysisCard = new AnalysisCard();
13 | this.entropyCard = new EntropyCard(600, 120);
14 | this.fortuneCard = new FortunesCard();
15 | this.graphCard = new GraphCard();
16 | this.infoCard = new InfoCard();
17 |
18 | this.build();
19 |
20 | this.analysisCard.onAnalysis = () => {
21 | this.entropyCard.refresh();
22 | this.graphCard.refresh();
23 | this.infoCard.refresh();
24 | };
25 | }
26 |
27 | build() {
28 | this.dom = document.createElement('div');
29 | this.dom.className = 'mdl-grid demo-content';
30 |
31 | const rightPanelsContainer = document.createElement('div');
32 | rightPanelsContainer.className = 'demo-cards mdl-cell mdl-cell--4-col mdl-cell--8-col-tablet mdl-grid mdl-grid--no-spacing';
33 |
34 | const separator = document.createElement('div');
35 | separator.className = 'demo-separator mdl-cell--1-col';
36 |
37 | rightPanelsContainer.appendChild(this.fortuneCard.DOM);
38 | rightPanelsContainer.appendChild(separator);
39 | rightPanelsContainer.appendChild(this.analysisCard.DOM);
40 |
41 | this.dom.appendChild(this.infoCard.DOM);
42 | this.dom.appendChild(rightPanelsContainer);
43 | this.dom.appendChild(this.entropyCard.DOM);
44 | this.dom.appendChild(this.graphCard.DOM);
45 | }
46 |
47 | refresh() {
48 | this.analysisCard.refresh();
49 | this.entropyCard.refresh();
50 | this.fortuneCard.refresh();
51 | this.graphCard.refresh();
52 | this.infoCard.refresh();
53 | }
54 |
55 | adjustLayout() {
56 | window.addEventListener('resize', () => this.infoCard.fixHeight(300), true);
57 | this.infoCard.fixHeight(300);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/www/m/js/layout/Ruler.js:
--------------------------------------------------------------------------------
1 | /** Ruler component for splitted layout */
2 | export class Ruler {
3 |
4 | get position() { return this._position; }
5 | set position(value) {
6 | this._position = value;
7 | this.triggerListeners();
8 | }
9 |
10 | constructor(containerNode, rulerNode) {
11 | this.containerNode = containerNode;
12 | this.rulerNode = rulerNode;
13 |
14 | this.listeners = [];
15 | this.moving = false;
16 | this.position = 0.5;
17 |
18 | this.init();
19 | this.reset();
20 |
21 | this.addListeners((position) => this.move(position));
22 | }
23 |
24 | /** Add events listeners on the node */
25 | init() {
26 | const doDrag = (e) => {
27 | e.preventDefault();
28 | const containerBoundingBox = this.containerNode.getBoundingClientRect();
29 | this.position = (e.clientX - containerBoundingBox.left) / containerBoundingBox.width;
30 | };
31 |
32 | const stopDrag = () => {
33 | document.documentElement.removeEventListener('mousemove', doDrag, false);
34 | document.documentElement.removeEventListener('mouseup', stopDrag, false);
35 | };
36 |
37 | this.rulerNode.addEventListener('mousedown', (e) => {
38 | document.documentElement.addEventListener('mousemove', doDrag, false);
39 | document.documentElement.addEventListener('mouseup', stopDrag, false);
40 | });
41 | }
42 |
43 | /** Invoke listener with new position */
44 | triggerListeners() {
45 | this.listeners.forEach(l => l(this.position));
46 | }
47 |
48 | addListeners(fn) {
49 | this.listeners.push(fn);
50 | }
51 |
52 | /** Move the ruler between [0;1] */
53 | move(position) {
54 | this.rulerNode.style.marginLeft = (position) * 100 + '%';
55 | }
56 |
57 | /** Place the ruler in the middle (doesn't change display mode) */
58 | reset() {
59 | this.position = 0.5;
60 | this.move(0.5);
61 | }
62 |
63 | show() {
64 | this.rulerNode.style.display = 'block';
65 | }
66 |
67 | hide() {
68 | this.rulerNode.style.display = 'none';
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/www/m/js/layout/RadareInfiniteBlock.js:
--------------------------------------------------------------------------------
1 | import {NavigatorDirection} from '../core/NavigatorDirection';
2 | import {InfiniteScrolling} from '../helpers/InfiniteScrolling';
3 |
4 | /** How many screen we want to retrieve in one round-trip with r2 */
5 | export const defaultHeightProvisioning = 3;
6 |
7 | export class RadareInfiniteBlock {
8 |
9 | constructor(heightProvisioning = defaultHeightProvisioning) {
10 | this.heightProvisioning = heightProvisioning
11 | }
12 |
13 | /**
14 | * Helper to delay drawing
15 | */
16 | getCurChunk() {
17 | return this.curChunk;
18 | }
19 |
20 | /**
21 | * Helper for dynamic callback at first drawing
22 | * Allows to place the scroll on current chunk.
23 | */
24 | getFirstElement() {
25 | return this.firstElement;
26 | }
27 |
28 | /**
29 | * Load the *new* initial offset from the "s" value
30 | */
31 | refreshInitialOffset() {
32 | r2.cmd('s', (offset) => {
33 | this.initialOffset = parseInt(offset, 16);
34 | });
35 | }
36 |
37 | /**
38 | * Gather data and set event to configure infinite scrolling
39 | */
40 | defineInfiniteParams(trigger) {
41 | var height = (this.container.getBody().offsetHeight === 0) ? 800 : this.container.getBody().offsetHeight;
42 | this.howManyLines = Math.floor(height / this.lineHeight * this.heightProvisioning);
43 |
44 | var infiniteScrolling = new InfiniteScrolling(
45 | this.container.getBody(),
46 | 3, /* before, current, after */
47 | (typeof trigger !== 'undefined') ? trigger : 0.20 /* when there less than 1/5 visible */
48 | );
49 |
50 | infiniteScrolling.setTopEvent((pos, endCallback) => {
51 | this.nav.go(NavigatorDirection.BEFORE);
52 | this.infiniteDrawingContent(NavigatorDirection.BEFORE, pos, endCallback);
53 | });
54 |
55 | infiniteScrolling.setBottomEvent((pos, endCallback) => {
56 | this.nav.go(NavigatorDirection.AFTER);
57 | this.infiniteDrawingContent(NavigatorDirection.AFTER, pos, endCallback);
58 | });
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/www/m/js/widgets/BaseWidget.js:
--------------------------------------------------------------------------------
1 | /**
2 | * BaseWidget is an abstract class which wrap a Widget
3 | * This abstraction ensure two concerns:
4 | * - A Widget can be instanciated several times if we want
5 | * - A Widget shouldn't be bothered by dimension change (TODO)
6 | */
7 | export class BaseWidget {
8 |
9 | /** Node provided by UIContext to draw content */
10 | get rootNode() { return this._rootNode; }
11 |
12 | /** Node provided by the Widget to draw content */
13 | get node() { return this._node; }
14 |
15 | /** Pass the widgetContainer instance with name of the widget */
16 | constructor(name, ...classNames) {
17 | this.name = name;
18 | this.classNames = classNames;
19 | this.classNames.push('rwidget');
20 | this.init();
21 |
22 | this.focused = false;
23 | this.displayed = false;
24 | }
25 |
26 | /** Init the module used inside component, called once */
27 | init() { }
28 |
29 | /** Define what should be done to render the Widget */
30 | drawWidget(destinationNode, ...args) {
31 | this._node = destinationNode;
32 | this._rootNode = destinationNode;
33 | this._rootNode.focus();
34 |
35 | // Set state
36 | this.displayed = true;
37 | this.focused = true;
38 |
39 | // Clear previous content
40 | this._node.innerHTML = '';
41 | this._node.className = '';
42 |
43 | // Apply CSS classes
44 | this.classNames.forEach(className => this._rootNode.classList.add(className));
45 |
46 | // Insert content
47 | this.draw(...args);
48 | }
49 |
50 | /** Method to insert content to Widget.node */
51 | draw(...args) { }
52 |
53 | /** When focus is gained */
54 | gotFocus() {
55 | this.gotDisplay();
56 | this.focused = true;
57 | }
58 |
59 | /** When focus is lost */
60 | lostFocus() {
61 | this.focused = false;
62 | }
63 |
64 | /** When widget is displayed */
65 | gotDisplay() {
66 | this.displayed = true;
67 | }
68 |
69 | /** When widget is replaced */
70 | lostDisplay() {
71 | this.lostFocus();
72 | this.displayed = false;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/www/m/css/hexdump.css:
--------------------------------------------------------------------------------
1 | .hexdump {
2 | background-color: rgb(16, 16, 16);
3 | color: white;
4 | overflow: hidden !important;
5 | }
6 |
7 | .hex.flex-controls {
8 | border-bottom:1px dotted white;
9 | background:white;
10 | color:black;
11 | }
12 |
13 | .hex.flex-controls ul.controlList {
14 | margin:0;
15 | padding:0;
16 | list-style-type: none;
17 | }
18 |
19 | .hex.flex-controls ul.controlList li {
20 | padding:0;
21 | display:inline-block;
22 | width:16%;
23 | height:40px;
24 | padding-top:10px;
25 | margin-left:3%;
26 | }
27 |
28 | .hex.flex-body {
29 | font-family: "Roboto Mono", "DejaVu Sans Mono", Console, Courier New, monospace;
30 | font-weight: bold;
31 | }
32 |
33 | ul.listContent li {
34 | line-height: 1em;
35 | height: 1.2em;
36 | white-space: nowrap;
37 | }
38 |
39 | ul.offset, ul.hexpairs, ul.ascii {
40 | margin:0;
41 | padding:0;
42 | display: inline-block;
43 | list-style-type: none;
44 | }
45 |
46 | ul.offset {
47 | width:120px;
48 | text-align:right;
49 | margin-right:20px;
50 | }
51 |
52 | ul.hexpairs {
53 | text-align:center;
54 | user-select: none;
55 | }
56 |
57 | ul.ascii {
58 | margin:0 20px 0 20px;
59 | }
60 |
61 | ul.hexpairs li input, ul.ascii li input {
62 | border:1px dashed white;
63 | background:rgba(255,255,255,0.33) !important;
64 | color:white !important;
65 | font-size:inherit;
66 | font-family: "Roboto Mono", "Console";
67 | font-weight: bold;
68 | width:18px;
69 | text-align:center;
70 | }
71 |
72 | ul.offset li, ul.hexpairs li, ul.ascii li {
73 | display:inline;
74 | line-height: 1em;
75 | border:1px solid transparent;
76 | }
77 |
78 | ul.hexpairs li.modified, ul.ascii li.modified {
79 | background-color: rgba(255,255,255,0.4);
80 | }
81 |
82 | ul.hexpairs li.selected {
83 | border-bottom:0px solid rgba(255,255,255,0.8);
84 | }
85 |
86 | ul.hexpairs li.active, ul.ascii li.active {
87 | border:1px dotted white;
88 | }
89 |
90 | ul.hexpairs.pairs > li:nth-child(2n), ul.hexpairs.words > li:nth-child(n) {
91 | margin-right:0.8em;
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/www/m/workers/hexchunkProvider.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const m_root = self.location.pathname.split('/').slice(0, -1).join('/');
4 | importScripts(m_root + '/r2.js');
5 |
6 | var howManyBytes;
7 | var nbCols;
8 | var configurationDone = false;
9 |
10 | function hexPairToASCII(pair) {
11 | var chr = parseInt(pair, 16);
12 | if (chr >= 33 && chr <= 126) {
13 | return String.fromCharCode(chr);
14 | }
15 |
16 | return '.';
17 | };
18 |
19 | function getChunk(howManyBytes, addr, nbCols) {
20 | if (addr < 0) {
21 | return {
22 | offset: 0,
23 | hex: [],
24 | ascii: [],
25 | flags: [],
26 | modified: []
27 | };
28 | }
29 |
30 | var raw;
31 |
32 | // BUG? callback called more than once
33 | r2.cmd('p8 ' + howManyBytes + ' @' + addr, function(d) {
34 | raw = {
35 | offset: addr,
36 | hex: [],
37 | ascii: [],
38 | flags: [],
39 | modified: []
40 | };
41 |
42 | var hex = [];
43 | var ascii = '';
44 | for (var myIt = 0 ; myIt < howManyBytes ; myIt++) {
45 | var pair = d[myIt * 2] + d[(myIt * 2) + 1];
46 | hex.push(pair);
47 | ascii += hexPairToASCII(pair);
48 | if (myIt % nbCols === nbCols-1) {
49 | raw.hex.push(hex);
50 | raw.ascii.push(ascii);
51 |
52 | hex = [];
53 | ascii = '';
54 | }
55 | }
56 | });
57 |
58 | r2.cmdj('fij ' + addr + ' ' + (addr + howManyBytes), function(d) {
59 | raw.flags = d;
60 | for (var i in raw.flags) {
61 | raw.flags[i].size = parseInt(raw.flags[i].size);
62 | }
63 | });
64 |
65 | return raw;
66 | }
67 |
68 | self.onmessage = function(e) {
69 | if (!configurationDone || e.data.reset) {
70 | // Providing block size (how many byte retrieved)
71 | howManyBytes = e.data.howManyBytes;
72 | nbCols = e.data.nbCols;
73 | configurationDone = true;
74 | } else {
75 | // Sending the data from r2 (arg is start offset)
76 | // TODO: handle "substract" if partial required (first)
77 | var chunk = getChunk(howManyBytes, e.data.offset, nbCols);
78 | chunk.dir = e.data.dir;
79 |
80 | self.postMessage(chunk);
81 | }
82 | };
83 |
--------------------------------------------------------------------------------
/www/p/lib/js/panels/logs_panel.js:
--------------------------------------------------------------------------------
1 | // SETTINGS PANEL
2 | var output = [];
3 | var logger = null;
4 |
5 | var LogsPanel = function() {
6 | // TODO: move here
7 | //this.logger = null;
8 | //this.output = [];
9 | };
10 |
11 | LogsPanel.prototype.render = function() {
12 | function encode(r) {
13 | return r.replace(/[\x26\x0A\<>'"]/g, function(r) {return '' + r.charCodeAt(0) + ';';});
14 | }
15 | var self = this;
16 | $('#logs_tab').html(
17 | '' +
18 | '' +
19 | ' ' +
20 | ' ' +
21 | ' ' +
22 | '
' +
23 | ' ');
24 | r2ui.selected_panel = 'Logs';
25 | function loginit() {
26 | console.log('loginit', logger);
27 | var out = document.getElementById('logs_out');
28 | if (logger === null) {
29 | logger = r2.getTextLogger();
30 | }
31 | logger.render = function() {
32 | out.innerHTML = output.join('
');
33 | };
34 | logger.on('message', function(msg) {
35 | output.push(encode(msg.text));
36 | logger.render();
37 | });
38 | logger.render();
39 | logger.autorefresh(3);
40 | }
41 | function sendmsg() {
42 | var nick = document.getElementById('logs_nick').value.trim();
43 | var msg = document.getElementById('logs_input').value.trim();
44 | //if (!logger) {
45 | loginit();
46 | //}
47 | if (msg && logger) {
48 | if (nick) {
49 | msg = '<' + nick + '> ' + msg;
50 | }
51 | logger.send(msg);
52 | }
53 | document.getElementById('logs_input').value = '';
54 | }
55 | // loginit();
56 | $(document).ready(loginit);
57 | $('#logs_input').keypress(function(e) {
58 | if (e.which == 13) {
59 | sendmsg();
60 | }
61 | });
62 | $('#logs_button').click(sendmsg);
63 | // $('#logs_tab').css('color', "rgb(127,127,127);");
64 | };
65 |
--------------------------------------------------------------------------------
/www/m/js/helpers/Inputs.js:
--------------------------------------------------------------------------------
1 | // TODO, progressive rewriting from ui.legacy.js
2 |
3 | const MARGIN = '3px';
4 |
5 | function pictogramInputButton(iconName, name, onclick = null) {
6 | const button = document.createElement('a');
7 | button.className = 'mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect';
8 | button.style.margin = MARGIN;
9 | const icon = document.createElement('i')
10 | icon.className = 'material-icons';
11 | icon.innerHTML = iconName;
12 | button.appendChild(icon);
13 | button.appendChild(document.createTextNode(name));
14 | if (onclick !== null) button.addEventListener('click', onclick);
15 | return button;
16 | }
17 |
18 | function inputButton(name, onclick = null) {
19 | const button = document.createElement('a');
20 | button.className = 'mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect';
21 | button.style.margin = MARGIN;
22 | button.textContent = name;
23 | if (onclick !== null) button.addEventListener('click', onclick);
24 | return button;
25 | }
26 |
27 | function imgButton(iconName, title, onclick = null) {
28 | const button = document.createElement('button');
29 | button.className = 'mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect';
30 | button.style.margin = MARGIN;
31 | button.title = title;
32 | const icon = document.createElement('i')
33 | icon.className = 'material-icons';
34 | icon.textContent = iconName;
35 | button.appendChild(icon);
36 | if (onclick !== null) button.addEventListener('click', onclick);
37 | return button;
38 | }
39 |
40 | function iconButton(iconName, title, onclick = null) {
41 | const button = document.createElement('button');
42 | button.className = 'mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect';
43 | button.style.margin = MARGIN;
44 | button.title = title;
45 | const icon = document.createElement('i')
46 | icon.className = 'material-icons md-dark';
47 | icon.innerHTML = iconName;
48 | button.appendChild(icon);
49 | if (onclick !== null) button.addEventListener('click', onclick);
50 | return button;
51 | }
52 |
53 | export const Inputs = {
54 | button: inputButton,
55 | imgButton: imgButton,
56 | iconButton: iconButton,
57 | pictogramInputButton: pictogramInputButton
58 | };
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | radare2-webui
2 | =============
3 |
4 | 
5 | 
6 | [](https://codeclimate.com/github/radare/radare2-webui)
7 |
8 | This repository contains the different WebUIs for radare2:
9 | * `enyo` enyo (mobile)
10 | * `m` material (responsive)
11 | * `p` panels (desktop)
12 | * `t` tiles (legacy)
13 |
14 | # Install
15 |
16 | First, you should install [radare2](https://github.com/radare/radare2), then `r2pm` will handle this for you:
17 |
18 | ```console
19 | $ r2pm -i www-enyo
20 | $ r2pm -i www-m
21 | $ r2pm -i www-p
22 | $ r2pm -i www-t
23 | ```
24 |
25 | This process will install the proper UI by downloading the latest version available.
26 |
27 | ## Troubleshooting
28 |
29 | The Web UIs (/m specifically) are using some tools that require an updated version of `node`, so if you encounter the following error, you should consider an update.
30 |
31 | ```console
32 | ~/radare2-webui/www/m/node_modules/gulp-google-webfonts/index.js:209
33 | request.name = path.posix.join(options.fontsDir, request.name);
34 | TypeError: Cannot call method 'join' of undefined
35 | ```
36 |
37 | Updating node is easy, I recommand you to follow this [article](https://davidwalsh.name/upgrade-nodejs):
38 |
39 | ```shell
40 | sudo npm cache clean -f
41 | sudo npm install -g n
42 | sudo n stable
43 | ```
44 |
45 | # Use it
46 |
47 | You can run one of the UI by typing the following command with: `enyo`, `m`, `p` and `t`.
48 |
49 | ```shell
50 | $ r2 -q -e http.ui= -c=H /bin/ls
51 | ```
52 |
53 | # Uninstall
54 |
55 | To uninstall an UI, you can use this command.
56 |
57 | ```shell
58 | $ r2pm -u
59 | ```
60 |
61 | # Soon...
62 |
63 | You will soon be able to chose between a global installation or an installation from your home directory with `-g` option.
64 |
65 | Also, we will propose you to install the last released version from a tarball with a specific option.
66 |
67 | # Contribute
68 |
69 | If you want to contribute, you should [read this](https://github.com/radare/radare2-webui/blob/master/CONTRIBUTING.md) to know how to set your environment.
70 |
--------------------------------------------------------------------------------
/www/w/index.js:
--------------------------------------------------------------------------------
1 |
2 | document.addEventListener('DOMContentLoaded', function () {
3 | dragElement(document.getElementById('alert-window-'));
4 | dragElement(document.getElementById('options'));
5 | })
6 |
7 | var newTop = 1000;
8 |
9 | function dragElement(elmnt) {
10 | var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
11 | if (document.getElementById(elmnt.id + "header")) {
12 | // if present, the header is where you move the DIV from:
13 | document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
14 | } else {
15 | // otherwise, move the DIV from anywhere inside the DIV:
16 | elmnt.onmousedown = dragMouseDown;
17 | }
18 |
19 | function dragMouseDown(e) {
20 | e = e || window.event;
21 | e.preventDefault();
22 | elmnt.style.zIndex = newTop;
23 | newTop++;
24 | document.getElementById(elmnt.id + "header").classList.toggle('active')
25 | // get the mouse cursor position at startup:
26 | pos3 = e.clientX;
27 | pos4 = e.clientY;
28 | document.onmouseup = closeDragElement;
29 | // call a function whenever the cursor moves:
30 | document.onmousemove = elementDrag;
31 | }
32 |
33 | function elementDrag(e) {
34 | e = e || window.event;
35 | e.preventDefault();
36 | // calculate the new cursor position:
37 | pos1 = pos3 - e.clientX;
38 | pos2 = pos4 - e.clientY;
39 | pos3 = e.clientX;
40 | pos4 = e.clientY;
41 | // set the element's new position:
42 | var y = (elmnt.offsetTop - pos2);
43 | var x = (elmnt.offsetLeft - pos1);
44 | if (x < 0) { x = 0; }
45 | if (y < 29) { y = 29; }
46 | elmnt.style.top = y + "px";
47 | elmnt.style.left = x + "px";
48 | //elmnt.style.top = (elmnt.style.top +2) + "px";
49 | //elmnt.style.left = (elmnt.style.left +2) + "px";
50 | }
51 |
52 | function closeDragElement() {
53 | // stop moving when mouse button is released:
54 | document.onmouseup = null;
55 | document.onmousemove = null;
56 | }
57 | }
58 |
59 | function ok() {
60 | var w = document.getElementById('alert-window-');
61 | w.style.visibility = 'hidden';
62 | }
63 |
64 | function as() {
65 | var inp = document.getElementById('assembler-input');
66 | r2.cmd("pad " + inp.value, function(res) {
67 | var out = document.getElementById('assembler-output');
68 | out.innerHTML = res;
69 | });
70 | }
71 |
--------------------------------------------------------------------------------
/www/enyo/js/main.js:
--------------------------------------------------------------------------------
1 | enyo.kind({
2 | name: 'RadareApp',
3 | kind: 'Panels',
4 | classes: 'panels enyo-unselectable',
5 | realtimeFit: true,
6 | fit: true,
7 | arrangerKind: 'CollapsingArranger',
8 | components: [
9 | { name: 'lp', kind: 'LeftPanel' },
10 | { name: 'mp', kind: 'MainPanel' },
11 | { name: 'rp', kind: 'RightPanel' },
12 | { kind: enyo.Signals, onkeypress: 'handleKeyPress' }
13 | ],
14 | handlers: {
15 | onTransitionFinish: 'handleTransitionFinish'
16 | },
17 | handleTransitionFinish: function() {
18 | if (r2ui._dis.display == 'graph' && r2ui._dis.minimap) update_minimap();
19 | },
20 | setPanel0: function() {
21 | this.$.RadareApp.setIndex(1);
22 | },
23 | create: function() {
24 | r2.load_settings();
25 | this.inherited(arguments);
26 | var data = [
27 | { name: 'Disassembler', active: true },
28 | { name: 'Assembler' },
29 | { name: 'Hexdump' },
30 | { name: 'Graph' },
31 | { name: 'Search' },
32 | { name: 'Console' },
33 | { name: 'Debugger' },
34 | { name: 'Script' },
35 | { name: 'Settings', separator: true },
36 | { name: 'Logs' },
37 | { name: 'About' }
38 | ];
39 | this.$.lp.data = data;
40 | this.$.mp.data = data;
41 | r2ui.ra =
42 | this.$.mp.ra =
43 | this.$.lp.ra =
44 | this.$.rp.ra = this;
45 | var mp = this.$.mp;
46 | r2ui.mp = mp;
47 | this.$.lp.openCallback = function(idx) {
48 | mp.openPage(idx);
49 | };
50 | this.$.lp.refresh();
51 | },
52 | handleKeyPress: function(inSender, inEvent) {
53 | for (var key in Config.keys) {
54 | if (key.substring(0, 2) == 'C-') {
55 | if (inEvent.ctrlKey) {
56 | var k = key.substring(2).charCodeAt(0);
57 | if (inEvent.charCode == k) {
58 | var cmd = Config.keys[key];
59 | eval(cmd + ';');
60 | }
61 | }
62 | } else {
63 | var k = key.charCodeAt(0);
64 | if (inEvent.charCode == k) {
65 | var cmd = Config.keys[key];
66 | eval(cmd + ';');
67 | }
68 | }
69 | }
70 | //dump (inEvent);
71 | //alert (inEvent.ctrlKey);
72 | // Use inEvent.charCode to detect spacebar
73 | /*
74 | if (inEvent.charCode === 32) {
75 | this.$.myContent.setContent("I thought");
76 | } else {
77 | var key = String.fromCharCode(inEvent.charCode).toUpperCase();
78 | this.$.myContent.setContent("Last key pressed: " + key);
79 | }
80 | */
81 | }
82 | });
83 |
84 | window.onload = function() {
85 | var obj = new RadareApp().renderInto(document.body);
86 | };
87 |
--------------------------------------------------------------------------------
/www/graph/sf-homepage.css:
--------------------------------------------------------------------------------
1 | .draggable {
2 | position: absolute;
3 | }
4 |
5 | div.block, h1.block, h2.block, p.block {
6 | border: 1px solid #9DA3B3;
7 | /*background-color: #E0E8FF; */
8 | background-color: #404040;
9 | color: white;
10 | padding: 5px;
11 | }
12 |
13 | div.canvas {
14 | border: 0px solid #262A37;
15 | background-color: black;
16 | /*
17 | background-image: url('gradient.jpg');
18 | background-repeat: no-repeat;
19 | background-position: top right;
20 | */
21 | padding: 0px;
22 | }
23 |
24 | .highlighter {
25 | border: 1px solid #CFDF62 !important;
26 | background-color: #F1FF90 !important;
27 | margin-bottom: 2px !important;
28 | padding: 0px !important;
29 | z-index: 3;
30 | }
31 |
32 | .highlighter .highlighter {
33 | border: 1px solid #7DAB76 !important;
34 | background-color: #BAFFB0 !important;
35 | margin-left: 2px !important;
36 | margin-right: 2px !important;
37 | }
38 |
39 | html {
40 | padding: 0px;
41 | margin: 0px;
42 | }
43 |
44 | body {
45 | font-family: verdana;
46 | font-size: 11px;
47 | color: #33333F;
48 | padding: 0px;
49 | margin: 0px;
50 | background-color: black;
51 | }
52 |
53 | h1 {
54 | color: #FF7521;
55 | margin: 0px;
56 | font-size: 20px;
57 | }
58 |
59 | h2 {
60 | font-size: 15px;
61 | margin: 0px;
62 | }
63 |
64 | p, div {
65 | font-size: 11px;
66 | margin: 0px;
67 | }
68 |
69 | a {
70 | text-decoration: none;
71 | color: #FF9900;
72 | }
73 |
74 | .middle-label, .source-label, .destination-label {
75 | font-size: 11px;
76 | font-weight: bold;
77 | padding: 5px;
78 | }
79 |
80 | div.connector {
81 | background-color: #ff9900;
82 | width: 5px;
83 | z-index: 1000;
84 | }
85 |
86 | table.main_table {
87 | width: 100%;
88 | border-collapse: separate;
89 | }
90 |
91 | td.menu {
92 | padding: 5px;
93 | }
94 |
95 | .menu ul {
96 | margin: 0px;
97 | padding: 0px;
98 | list-style-type: none;
99 | list-style-position: outside;
100 | }
101 |
102 | .menu li {
103 | border: none;
104 | padding: 0px;
105 | font-size: 12px;
106 | margin-bottom: 3px;
107 | }
108 |
109 | .block ol, .block ul {
110 | margin-top: 3px;
111 | margin-bottom: 3px;
112 | margin-left: 0px;
113 | padding-left: 25px;
114 | }
115 |
116 | .code {
117 | font-family: monospace;
118 | line-height: 1.5em !important;
119 | }
120 |
--------------------------------------------------------------------------------
/www/enyo/css/index.css:
--------------------------------------------------------------------------------
1 | a {
2 | color: #3030a0;
3 | }
4 | .sourcecode {
5 | width:280px;
6 | height:200px;
7 | margin-left:10px;
8 | font-size:12px;
9 | background-color:#e0e0e0;
10 | font-family: Consolas, monospace;
11 | }
12 |
13 | .sourcebutton {
14 | margin:4px;
15 | vertical-align:top;
16 | }
17 |
18 | h2 {
19 | padding-left:14px;
20 | }
21 |
22 | .app-panels > * {
23 | width: 320px;
24 | background-color: #eaeaea;
25 | box-shadow: -4px -4px 4px rgba(0,0,0,0.3);
26 | }
27 |
28 | .menu-button {
29 | clear:none;
30 | float:left;
31 | margin:10px !important;
32 | width:150px;
33 | }
34 |
35 | .rowline {
36 | width:200px;
37 | color:black;
38 | }
39 |
40 | @media all and (max-width: 600px) {
41 | .app-panels > * {
42 | min-width: 100%;
43 | max-width: 100%;
44 | }
45 | }
46 |
47 | .onyx-sample-tools {
48 | padding-bottom:10px;
49 | }
50 | .onyx-sample-tools > * {
51 | margin: 3px;
52 | }
53 |
54 | .r2ui-terminal {
55 | color: black;
56 | editable: false;
57 | }
58 |
59 | .r2ui-label {
60 | color:black;
61 | }
62 |
63 | .r2ui-input {
64 | color: black;
65 | margin-top:8px;
66 | background-color: #909090;
67 | width: 90%;
68 | display: inline-block;
69 | }
70 |
71 | /* TODO: :hover change mouse pointer */
72 | .moreless:hover {
73 | background-color:#d0d0d0;
74 | cursor:pointer;
75 | }
76 |
77 | .moreless {
78 | background-color:#a0a0a0;
79 | width:90%;
80 | height:24px;
81 | padding-left:10px;
82 | border:0px;
83 | }
84 |
85 | .r2panel {
86 | color: black !important;
87 | /*background-color:#b0b0b0;*/
88 | /* padding-left:8px; */
89 | }
90 |
91 | .colorbar {
92 | padding: 0px;
93 | border-spacing:0px;
94 | spacing: 0px;
95 | border: 0px;
96 | height: 16px;
97 | background-color: black;
98 | width: 380px;
99 | max-width:100%;
100 | margin:0px;
101 | }
102 |
103 | .colorbar_item {
104 | max-width:100%;
105 | width:100%;
106 | border:0px;
107 | spacing:0px;
108 | padding:0px;
109 | }
110 | .topbox {
111 | position:absolute;
112 | left: 70px;
113 | padding:0px;
114 | margin:0px;
115 | top:0px;
116 | display:inline;
117 | }
118 |
119 | .top {
120 | display:inline-block;
121 | position:relative;
122 | vertical-align:top;
123 | padding:10px;
124 | margin:1px;
125 | margin-top:0px;
126 | }
127 |
128 | pre {
129 | font-size:13px;
130 | }
131 |
132 | .addr {
133 | -moz-user-select: text;
134 | }
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow that is manually triggered
2 |
3 | name: ci
4 |
5 | on: push
6 |
7 | # Controls when the action will run. Workflow runs when manually triggered using the UI
8 | # or API.
9 | # on:
10 | # workflow_dispatch:
11 | # # Inputs the workflow accepts.
12 | # inputs:
13 | # name:
14 | # # Friendly description to be shown in the UI instead of 'name'
15 | # description: 'Build and test'
16 | # # Default value if no value is explicitly provided
17 | # default: 'ACR'
18 | # # Input has to be provided for the workflow to run
19 | # required: true
20 |
21 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
22 | jobs:
23 | build:
24 | name: Material
25 | runs-on: ubuntu-latest
26 | steps:
27 | - uses: actions/checkout@v2
28 | - name: MaterialUI
29 | run: cd www/m
30 | - name: Building & Zipping
31 | run: make -C www/m release
32 | - name: Pub
33 | uses: actions/upload-artifact@v2
34 | with:
35 | path: dist/*.zip
36 | tiled:
37 | name: Tiled
38 | runs-on: ubuntu-latest
39 | steps:
40 | - uses: actions/checkout@v2
41 | - name: TiledUI
42 | run: cd www/t
43 | - name: Installing dependencies
44 | run: cd www/t && npm i
45 | - name: Building
46 | run: make -C www/t build
47 | - name: Zipping
48 | run: make -C www/t dist
49 | - name: Pub
50 | uses: actions/upload-artifact@v2
51 | with:
52 | path: dist/*.zip
53 | panels:
54 | name: Panels
55 | runs-on: ubuntu-latest
56 | steps:
57 | - uses: actions/checkout@v2
58 | - name: Panels
59 | run: cd www/p
60 | - name: Installing dependencies
61 | run: cd www/p && npm i
62 | - name: Building
63 | run: make -C www/p
64 | - name: Install
65 | run: make -C www/p release
66 | - name: Pub
67 | uses: actions/upload-artifact@v2
68 | with:
69 | path: dist/*.zip
70 | enyo:
71 | name: Enyo
72 | runs-on: ubuntu-latest
73 | steps:
74 | - uses: actions/checkout@v2
75 | - name: EnyoJS
76 | run: cd www/enyo
77 | - name: Installing dependencies
78 | run: cd www/enyo && npm i
79 | - name: Building & Install
80 | run: make -C www/enyo build
81 | - name: Zipping
82 | run: make -C www/enyo dist
83 | - name: Pub
84 | uses: actions/upload-artifact@v2
85 | with:
86 | path: dist/*.zip
87 |
--------------------------------------------------------------------------------
/www/m/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": {
3 | "name": "pancake",
4 | "email": "pancake@nopcode.org"
5 | },
6 | "bugs": {
7 | "url": "https://github.com/radare/radare2-webui"
8 | },
9 | "description": "Material Lite interface for radare2",
10 | "homepage": "https://radare.org",
11 | "license": "LGPL-3.0",
12 | "maintainers": [
13 | {
14 | "name": "pancake",
15 | "email": "pancake@nopcode.org"
16 | }
17 | ],
18 | "name": "radare2-webui-material",
19 | "repository": {
20 | "type": "git",
21 | "url": "git://github.com/radare/radare2-webui.git"
22 | },
23 | "scripts": {
24 | "test": "mocha --require test/specs/helpers/chai.js",
25 | "postinstall": "node -e \"try { require('fs').symlinkSync(require('path').resolve('node_modules/@bower_components'), 'vendors', 'junction') } catch (e) { }\""
26 | },
27 | "version": "3.1.0",
28 | "devDependencies": {
29 | "acorn": "^8.0.4",
30 | "bower": "^1.8.13",
31 | "browserify": "^17.0.0",
32 | "chai": ">=4.0",
33 | "css-loader": "^5.0.0",
34 | "eslint": "^7.12.1",
35 | "extract-loader": "^5.1.0",
36 | "file-loader": "^6.2.0",
37 | "gulp": "4.0.2",
38 | "gulp-clean-css": "^4.3.0",
39 | "gulp-concat": "^2.6.1",
40 | "gulp-eslint": "^6.0.0",
41 | "gulp-google-webfonts": "^4.0.0",
42 | "gulp-htmlmin": "^5.0.1",
43 | "gulp-livereload": "^4.0.2",
44 | "gulp-replace": "^1.1.3",
45 | "gulp-sourcemaps": "^3.0.0",
46 | "gulp-uglify": "^3.0.2",
47 | "gulp-uglifycss": "*",
48 | "jsdom": "^19.0.0",
49 | "jsdom-global": ">=3.0.2",
50 | "merge-stream": "^2.0.0",
51 | "mocha": "^9.2.2",
52 | "npm": "^8.11.0",
53 | "sass": "^1.49.7",
54 | "semistandard": "^16.0.1",
55 | "sinon": "^9.2.1",
56 | "sinon-chai": "^3.7.0",
57 | "terser-webpack-plugin": "^5.3.1",
58 | "through2": "^4.0.2",
59 | "vinyl-source-stream": "2.0.0",
60 | "webpack": "^5.72.0",
61 | "webpack-cli": "^4.9.2"
62 | },
63 | "dependencies": {
64 | "datatables.net": "^1.12.1",
65 | "datatables.net-dt": "^1.12.1",
66 | "dialog-polyfill": "^0.5.6",
67 | "file-saver": "^2.0.5",
68 | "infinite-scroll": "^3.0.6",
69 | "jquery": "^3.6.1",
70 | "material-components-web": ">=14.0.0",
71 | "material-design-icons-iconfont": "^6.7.0",
72 | "material-design-lite": "^1.3.0",
73 | "mdl-selectfield": "^1.0.4",
74 | "postinstall": "^0.7.4"
75 | },
76 | "overrides": {
77 | "micromatch": "4.0.1",
78 | "core-js": "3.21.1",
79 | "chokidar": "3.5.3"
80 | },
81 | "engines": {
82 | "node": ">=0.10.0"
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [master]
9 | schedule:
10 | - cron: '0 6 * * 1'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | fail-fast: false
19 | matrix:
20 | # Override automatic language detection by changing the below list
21 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
22 | language: ['javascript']
23 | # Learn more...
24 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
25 |
26 | steps:
27 | - name: Checkout repository
28 | uses: actions/checkout@v2
29 | with:
30 | # We must fetch at least the immediate parents so that if this is
31 | # a pull request then we can checkout the head.
32 | fetch-depth: 2
33 |
34 | # If this run was triggered by a pull request event, then checkout
35 | # the head of the pull request instead of the merge commit.
36 | - run: git checkout HEAD^2
37 | if: ${{ github.event_name == 'pull_request' }}
38 |
39 | # Initializes the CodeQL tools for scanning.
40 | - name: Initialize CodeQL
41 | uses: github/codeql-action/init@v1
42 | with:
43 | languages: ${{ matrix.language }}
44 | # If you wish to specify custom queries, you can do so here or in a config file.
45 | # By default, queries listed here will override any specified in a config file.
46 | # Prefix the list here with "+" to use these queries and those in the config file.
47 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
48 |
49 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
50 | # If this step fails, then you should remove it and run the build manually (see below)
51 | - name: Autobuild
52 | uses: github/codeql-action/autobuild@v1
53 |
54 | # ℹ️ Command-line programs to run using the OS shell.
55 | # 📚 https://git.io/JvXDl
56 |
57 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
58 | # and modify them (or add more) to build your code if your project
59 | # uses a compiled language
60 |
61 | #- run: |
62 | # make bootstrap
63 | # make release
64 |
65 | - name: Perform CodeQL Analysis
66 | uses: github/codeql-action/analyze@v1
67 |
--------------------------------------------------------------------------------
/www/t/css/style.css:
--------------------------------------------------------------------------------
1 | img {
2 | border: 0px;
3 | }
4 |
5 | div {
6 | overflow:hidden;
7 | }
8 |
9 | p {
10 | margin:0px;
11 | border:0px;
12 | }
13 | textarea {
14 | background-color: #203040;
15 | color:white;
16 | border:0px;
17 | padding:5px;
18 | }
19 | a {
20 | color: #a06000;
21 | }
22 | a:hover {
23 | color: white;
24 | }
25 |
26 | .link {
27 | color:white;
28 | }
29 | html, body {
30 | overflow:hidden;
31 | background-color:black;
32 | }
33 | iframe {
34 | width:100%;
35 | border: 1px solid black;
36 | }
37 | @keyframes fadeInOpacity {
38 | 0% {
39 | opacity: 0;
40 | }
41 | 100% {
42 | opacity: 1;
43 | }
44 | }
45 | .modal {
46 | font-family: monospace;
47 | border: 3px solid black;
48 |
49 | left:10%;
50 | top:10%;
51 | right:10%;
52 | border-radius: 1em;
53 | padding-top:20px;
54 | bottom:10%;
55 | background-color: #202020;
56 | color: #e0e0e0;
57 | position:absolute;
58 | z-index: 10000 !important;
59 | }
60 | .modal_title {
61 | position:absolute;
62 | background-color:black;
63 | color:#e0e0e0;
64 | padding:0px;
65 | top:0px;
66 | height:20px;
67 | font-family: monospace;
68 | width:100%;
69 | z-index:10001;
70 | }
71 | .frame {
72 | font-family: monospace;
73 | border: 1px solid black;
74 | height:100%;
75 | background-color:#505050;
76 | color: #e0e0e0;
77 | }
78 | .frame_title {
79 | background-color:black;
80 | color:white;
81 | padding:0px;
82 | top:0px;
83 | height:20px;
84 | font-family: monospace;
85 | width:100%;
86 | }
87 | .frame_body {
88 | background-color:#303030;
89 | overflow:scroll;
90 | height:100%;
91 | }
92 | .canvas {
93 | padding-top:3px;
94 | width:100%;
95 | height:100%;
96 | background-color:black;
97 | border-top:5px;
98 | font-size:12px;
99 | font-family:monospace;
100 | }
101 | input {
102 | width: 98%;
103 | border: 1px solid black;
104 | text-align:left;
105 | margin:5px;
106 | background-color: rgba(0,0,0,0.3);
107 | overflow:hidden;
108 | color: white;
109 | font-family: monospace;
110 | }
111 | h2 {
112 | padding:0px;
113 | color:black;
114 | border:0px;
115 | margin:10px;
116 | }
117 | .minibut {
118 | text-decoration: none;
119 | font-weight: bold;
120 | font-family: monospace;
121 | color: #a0a0f0;
122 | }
123 |
124 | ::-webkit-scrollbar {
125 | width: 0.5em;
126 | }
127 | ::-webkit-scrollbar-track {
128 | -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
129 | box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
130 | }
131 | ::-webkit-scrollbar-thumb {
132 | background-color: darkgrey;
133 | outline: 1px solid slategrey;
134 | }
135 | ::-webkit-scrollbar:hover {
136 | width: 0.7em;
137 | }
138 |
--------------------------------------------------------------------------------
/www/m/js/widgets/ScriptWidget.js:
--------------------------------------------------------------------------------
1 | import {BaseWidget} from './BaseWidget';
2 |
3 | import {uiContext} from '../core/UIContext';
4 | import {Widgets} from './Widgets';
5 | import {Inputs} from '../helpers/Inputs';
6 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper';
7 |
8 | export class ScriptWidget extends BaseWidget {
9 | constructor() {
10 | super('Script');
11 | }
12 |
13 | init() {
14 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
15 | if (this.displayed) {
16 | this.draw();
17 | }
18 | });
19 | }
20 |
21 | draw() {
22 | this.toggleFoo = '';
23 | this.node.appendChild(this.getPanel());
24 | }
25 |
26 | getPanel() {
27 | var c = document.createElement('div');
28 |
29 | c.appendChild(Inputs.button('Run', () => this.runScript()));
30 | c.appendChild(Inputs.button('Indent', () => this.indentScript()));
31 | c.appendChild(Inputs.button('Output', () => this.toggleScriptOutput()));
32 | // c.appendChild(Inputs.button('Console', () => uiContext.navigateTo(Widgets.CONSOLE)));
33 |
34 | c.appendChild(document.createElement('br'));
35 |
36 | const textarea = document.createElement('textarea');
37 | textarea.id = 'script';
38 | textarea.rows = 20;
39 | textarea.className = 'pre';
40 | textarea.style.width = '100%';
41 | c.appendChild(textarea);
42 |
43 | c.appendChild(document.createElement('br'));
44 |
45 | const output = document.createElement('div');
46 | output.id = 'scriptOutput';
47 | output.className = 'output';
48 | c.appendChild(output);
49 |
50 | var localScript = localStorage.getItem('script');
51 | if (!localScript) {
52 | localScript = 'r2.cmd("?V", log);';
53 | }
54 | textarea.value = localScript;
55 |
56 | return c;
57 | }
58 |
59 | toggleScriptOutput() {
60 | var o = document.getElementById('scriptOutput');
61 | if (o) {
62 | if (this.toggleFoo === '') {
63 | this.toggleFoo = o.innerHTML;
64 | o.innerHTML = '';
65 | } else {
66 | o.innerHTML = this.toggleFoo;
67 | this.toggleFoo = '';
68 | }
69 | }
70 | }
71 |
72 | indentScript() {
73 | var str = document.getElementById('script').value;
74 | var indented = /* NOT DEFINED js_beautify*/ (str);
75 | document.getElementById('script').value = indented;
76 | localStorage.script = indented;
77 | }
78 |
79 | runScript() {
80 | var str = document.getElementById('script').value;
81 | localStorage.script = str;
82 | document.getElementById('scriptOutput').innerHTML = '';
83 | try {
84 | var msg = '"use strict";' +
85 | 'function log(x) { var a = ' +
86 | 'document.getElementById(\'scriptOutput\'); ' +
87 | 'if (a) a.innerHTML += x + \'\\n\'; }\n';
88 | // CSP violation here
89 | eval(msg + str);
90 | } catch (e) {
91 | alert(e);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/www/m/workers/disasmProvider.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const m_root = self.location.pathname.split('/').slice(0, -1).join('/');
4 |
5 | importScripts(m_root + '/r2.js');
6 |
7 | function extractOffset(str) {
8 | var res = str.match(/(0x[a-fA-F0-9]+)/);
9 | if (res === null) {
10 | return null;
11 | }
12 | return res[1];
13 | };
14 |
15 | function extractFct(str) {
16 | var withoutHTML = str.replace(/<[^>]*>/g, '');
17 | var res = withoutHTML.match(/\(fcn\) ([\S^]+)/);
18 | if (res === null) {
19 | return null;
20 | }
21 | return res[1];
22 | }
23 |
24 | function extractVar(str) {
25 | var withoutHTML = str.replace(/<[^>]*>/g, '');
26 | var res = withoutHTML.match(/; var ([a-zA-Z0-9]+) ([\S^]+)/);
27 | if (res === null) {
28 | return null;
29 | }
30 | return res[2];
31 | }
32 |
33 | // TODO dirty
34 | function prepareClickableOffsets(x) {
35 | x = x.replace(/0x([a-zA-Z0-9]*)/g,
36 | '0x$1');
37 | x = x.replace(/sym\.([\.a-zA-Z0-9_]*)/g,
38 | 'sym.$1');
39 | x = x.replace(/fcn\.([\.a-zA-Z0-9_]*)/g,
40 | 'fcn.$1');
41 | x = x.replace(/str\.([\.a-zA-Z0-9_]*)/g,
42 | 'str.$1');
43 | return x;
44 | }
45 |
46 | function getChunk(where, howManyLines) {
47 | var raw;
48 |
49 | let scrColor = 3;
50 | // TODO var a = r2Settings.getItem(r2Settings.keys.BYTES)
51 | // Line retrieved from the current offset
52 | r2.cmd('pD ' + howManyLines + '@e:scr.color='+ scrColor + '@' + where + '|H', function(d) {
53 | raw = d;
54 | });
55 |
56 | raw = prepareClickableOffsets(raw);
57 | var lines = raw.split('\n');
58 | for (var i = 0 ; i < lines.length ; i++) {
59 |
60 | var fct = extractFct(lines[i]);
61 | if (fct !== null) {
62 | lines[i] = '' + lines[i] + '';
63 | }
64 |
65 | var variable = extractVar(lines[i]);
66 | if (variable !== null) {
67 | lines[i] = '' + lines[i] + '';
68 | }
69 |
70 | var offset = extractOffset(lines[i]);
71 | if (offset !== null) {
72 | lines[i] = '' + lines[i] + '';
73 | }
74 | }
75 |
76 | var withContext = lines.join('\n');
77 |
78 | return '' + withContext + '
';
79 | }
80 |
81 | self.onmessage = function(e) {
82 | if (e.data.offset < 0) {
83 | self.postMessage({
84 | offset: 0,
85 | data: 'before 0x00'
86 | });
87 | } else {
88 | var chunk = {
89 | offset: e.data.offset,
90 | size: e.data.size,
91 | data: getChunk(e.data.offset, e.data.size)
92 | };
93 |
94 | // Sending the data from r2
95 | self.postMessage(chunk);
96 | }
97 | };
98 |
--------------------------------------------------------------------------------
/www/enyo/js/assembler.js:
--------------------------------------------------------------------------------
1 | enyo.kind({
2 | name: 'Assembler',
3 | kind: 'Scroller',
4 | classes: 'r2panel',
5 | style: 'background-color:#c0c0c0;',
6 | components: [
7 | {tag: 'form', style: 'margin-top:8px;margin-left:8px', attributes: {action: 'javascript:#'}, components: [
8 | {kind: 'FittableRows', fit: true, components: [
9 | {kind: 'onyx.InputDecorator', classes: 'r2ui-input', components: [
10 | {tag: 'font', content: 'opcode', classes: 'r2ui-input', style: 'width:64px;font-weight:bold'},
11 | {kind: 'Input', value: '', style: 'width:60%', onkeydown: 'assembleOpcode', attributes: {autocapitalize: 'off'}, name: 'opcode'}
12 | ]},
13 | {kind: 'onyx.InputDecorator', classes: 'r2ui-input', components: [
14 | {tag: 'font', content: 'bytes', classes: 'r2ui-input', style: 'width:64px;font-weight:bold'},
15 | {kind: 'Input', value: '', style: 'width:120px', onkeydown: 'assembleOpcode', attributes: {autocapitalize: 'off'}, name: 'bytes'}
16 | ]},
17 | {kind: 'onyx.InputDecorator', classes: 'r2ui-input', components: [
18 | {tag: 'font', content: 'offset', classes: 'r2ui-input', style: 'width:64px;font-weight:bold'},
19 | {kind: 'Input', value: 'entry0', style: 'width:120px', onkeydown: 'assembleOpcode', attributes: {autocapitalize: 'off'}, name: 'offset'}
20 | ]}
21 | ]}
22 | ]},
23 | {tag: 'form', style: 'margin-top:8px;margin-left:8px', attributes: {action: 'javascript:#'}, components: [
24 | {tag: 'h2', content: 'Calculator' },
25 | {kind: 'onyx.InputDecorator', classes: 'r2ui-input', components: [
26 | {tag: 'font', name: 'value', content: '0', classes: 'r2ui-input', style: 'width:200px;font-weight:bold'},
27 | {kind: 'Input', name: 'ivalue', value: '0', style: 'width:300',
28 | onkeydown: 'calculateValue', attributes: {autocapitalize: 'off'} }
29 | ]}
30 | ]}
31 | ],
32 | calculateValue: function(inSender, inEvent) {
33 | if (inEvent.keyCode === 13) {
34 | var v = this.$.value;
35 | var val = inSender.getValue();
36 | v.setContent('...');
37 | r2.cmd('?v ' + val, function(x) {
38 | v.setContent(x);
39 | });
40 | }
41 | },
42 | assembleOpcode: function(inSender, inEvent) {
43 | if (inEvent.keyCode === 13) {
44 | var arg = inSender.getValue();
45 | var off = this.$.offset.getValue();
46 | switch (inSender.name) {
47 | case 'opcode':
48 | var hex = this.$.bytes;
49 | r2.assemble(off, arg, function(bytes) {
50 | hex.setValue(bytes); // ? s/\n/;/g
51 | });
52 | break;
53 | case 'bytes':
54 | var op = this.$.opcode;
55 | //r2.cmd ("pi 1@b:"+arg, function (x) {
56 | r2.disassemble(off, arg, function(x) {
57 | op.setValue(x); // ? s/\n/;/g
58 | });
59 | break;
60 | case 'offset':
61 | break;
62 | }
63 | }
64 | }
65 | });
66 |
--------------------------------------------------------------------------------
/www/m/js/widgets/DebuggerWidget.js:
--------------------------------------------------------------------------------
1 | import {BaseWidget} from './BaseWidget';
2 | import {Inputs} from '../helpers/Inputs';
3 | import {formatOffsets} from '../helpers/Format';
4 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper';
5 |
6 | export class DebuggerWidget extends BaseWidget {
7 | constructor() {
8 | super('Debugger', 'dark');
9 | }
10 |
11 | init() {
12 | this.inColor = true; // TODO
13 | this.nativeDebugger = false;
14 | r2.cmd('e cfg.debug', (x) => {
15 | this.nativeDebugger = (x.trim() === 'true');
16 | });
17 |
18 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
19 | if (!this.displayed) {
20 | return;
21 | }
22 | this.draw();
23 | });
24 | }
25 |
26 | draw() {
27 | this.node.innerHTML = '';
28 | this.node.scrollTop = 0;
29 | this.node.appendChild(this.getPanel());
30 | }
31 |
32 | getPanel() {
33 | var c = document.createElement('div');
34 | if (this.inColor) {
35 | c.style.backgroundColor = '#202020';
36 | }
37 |
38 | var header = document.createElement('div');
39 | header.style.position = 'fixed';
40 | header.style.margin = '0.5em';
41 | c.appendChild(header);
42 |
43 | header.appendChild(Inputs.iconButton('keyboard_arrow_up', 'UP', () => r2.cmd('s--', () => this.draw())));
44 | header.appendChild(Inputs.iconButton('keyboard_arrow_down', 'DOWN', () => r2.cmd('s++', () => this.draw())));
45 |
46 | header.appendChild(Inputs.button('PC', () => r2.cmd('sr pc', () => this.draw())));
47 | header.appendChild(Inputs.button('Step', () => r2.cmd(this.nativeDebugger ? 'ds' : 'aes', () => this.draw())));
48 | header.appendChild(Inputs.button('Cont', () => r2.cmd(this.nativeDebugger ? 'dc' : 'aec', () => this.draw())));
49 | header.appendChild(Inputs.button('BP', () => r2.cmd('db $$', () => this.draw())));
50 | header.appendChild(Inputs.button('REG', () => {
51 | var expr = prompt('register=value');
52 | if (this.nativeDebugger) {
53 | r2.cmd('dr ' + expr + ';.dr*', () => this.draw());
54 | } else {
55 | r2.cmd('aer ' + expr + ';.ar*', () => this.draw());
56 | }
57 | }));
58 |
59 | var content = document.createElement('div');
60 | content.style.paddingTop = '50px';
61 | c.appendChild(content);
62 |
63 | // stack
64 | const rcmd = (this.nativeDebugger) ? 'dr' : 'ar';
65 | r2.cmd('f cur;.' + rcmd + '*;sr sp;px 64', function(d) {
66 | const pre = document.createElement('pre');
67 | pre.style.margin = '10px';
68 | pre.style.color = 'grey';
69 | pre.appendChild(formatOffsets(d));
70 | content.appendChild(pre);
71 | });
72 | r2.cmd(rcmd + '=;s cur;f-cur;pd 128' + (this.inColor ? '|H' : ''), function(d) {
73 | const pre = document.createElement('pre');
74 | pre.style.color = 'grey';
75 | pre.appendChild(formatOffsets(d));
76 | content.appendChild(pre);
77 | });
78 |
79 | return c;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/www/m/js/widgets/FunctionsWidget.js:
--------------------------------------------------------------------------------
1 | import {BaseWidget} from './BaseWidget';
2 | import {Inputs} from '../helpers/Inputs';
3 | import {Table} from '../helpers/Table';
4 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper';
5 | import {Widgets} from '../widgets/Widgets';
6 |
7 | export class FunctionsWidget extends BaseWidget {
8 | constructor() {
9 | super('Functions');
10 | }
11 |
12 | init() {
13 | this.inColor = true; // TODO
14 | // r2.cmd('e scr.utf8=false');
15 |
16 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
17 | if (!this.displayed) {
18 | return;
19 | }
20 | this.draw();
21 | });
22 | }
23 |
24 | draw() {
25 | this.node.innerHTML = '';
26 | this.node.scrollTop = 0;
27 | this.node.appendChild(this.getPanel());
28 | }
29 |
30 | getPanel() {
31 | var c = document.createElement('div');
32 |
33 | var header = document.createElement('div');
34 | header.style.position = 'fixed';
35 | header.style.margin = '0.5em';
36 | c.appendChild(header);
37 |
38 | header.appendChild(Inputs.button('Symbols', () => {
39 | statusMessage('Analyzing symbols...');
40 | r2.cmd('aa', () => {
41 | statusMessage('done');
42 | this.draw();
43 | });
44 | }));
45 |
46 | header.appendChild(Inputs.button('Calls', () => {
47 | statusMessage('Analyzing calls...');
48 | r2.cmd('aac', () => {
49 | statusMessage('done');
50 | this.draw();
51 | });
52 | }));
53 |
54 | header.appendChild(Inputs.button('Function', () => {
55 | statusMessage('Analyzing function...');
56 | r2.cmd('af', () => {
57 | statusMessage('done');
58 | this.draw();
59 | });
60 | }));
61 |
62 | header.appendChild(Inputs.button('Refs', () => {
63 | statusMessage('Analyzing references...');
64 | r2.cmd('aar', () => {
65 | statusMessage('done');
66 | this.draw();
67 | });
68 | }));
69 |
70 | header.appendChild(Inputs.button('AutoName', () => {
71 | statusMessage('Analyzing names...');
72 | r2.cmd('.afna @@ fcn.*', () => {
73 | statusMessage('done');
74 | this.draw();
75 | });
76 | }));
77 |
78 | var content = document.createElement('div');
79 | content.style.paddingTop = '70px';
80 | c.appendChild(content);
81 |
82 | r2.cmd('afl', function(d) {
83 | var table = new Table(
84 | ['+Address', 'Name', 'Size', 'CC'],
85 | [false, true, false, false],
86 | 'functionTable',
87 | null,
88 | Widgets.DISASSEMBLY);
89 |
90 | var lines = d.split(/\n/); //clickable offsets (d).split (/\n/);
91 | for (var i in lines) {
92 | var items = lines[i].match(/^(0x[0-9a-f]+)\s+([0-9]+)\s+([0-9]+(\s+\->\s+[0-9]+)?)\s+(.+)$/);
93 | if (items !== null) {
94 | table.addRow([items[1], items[5], items[2], items[3]]);
95 | }
96 | }
97 | table.insertInto(content);
98 | });
99 |
100 | return c;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/www/m/js/layout/FlexContainer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Define a container in absolute position
3 | * Create two area: control + body
4 | */
5 | export class FlexContainer {
6 |
7 | constructor(dom, classes) {
8 | this.classes = (typeof classes === 'undefined') ? '' : classes;
9 | this.init(dom);
10 | }
11 |
12 | init(dom) {
13 | this.container = dom;
14 | this.container.innerHTML = '';
15 |
16 | this.controls = document.createElement('div');
17 | this.body = document.createElement('div');
18 |
19 | this.controls.className = 'flex flex-controls ' + this.classes;
20 | this.body.className = 'flex flex-body ' + this.classes;
21 |
22 | this.container.appendChild(this.controls);
23 | this.container.appendChild(this.body);
24 | }
25 |
26 | replug(dom) {
27 | this.container = dom;
28 | this.container.innerHTML = '';
29 | this.container.appendChild(this.controls);
30 | this.container.appendChild(this.body);
31 | }
32 |
33 | reset() {
34 | this.init(this.container);
35 | }
36 |
37 | getControls() {
38 | return this.controls;
39 | }
40 |
41 | drawControls(callback) {
42 | this.controls.innerHTML = '';
43 | callback(this.controls);
44 | }
45 |
46 | getBody() {
47 | return this.body;
48 | }
49 |
50 | drawBody(callback) {
51 | this.body.innerHTML = '';
52 | callback(this.body);
53 | }
54 |
55 | pause(msg) {
56 | if (!this.dialogHasBeenDrawn) {
57 | this.drawEmptyDialog();
58 | }
59 |
60 | this.textDialog.innerHTML = msg;
61 | this.dialog.showModal();
62 | }
63 |
64 | drawEmptyDialog() {
65 | var _this = this;
66 | this.dialog = document.createElement('dialog');
67 | this.dialog.className = 'mdl-dialog';
68 |
69 | if (!this.dialog.showModal) {
70 | dialogPolyfill.registerDialog(this.dialog);
71 | }
72 |
73 | var content = document.createElement('div');
74 | content.className = 'mdl-dialog__content';
75 | this.dialog.appendChild(content);
76 |
77 | var icon = document.createElement('p');
78 | icon.className = 'mdl-typography--text-center';
79 | content.appendChild(icon);
80 |
81 | var iIcon = document.createElement('i');
82 | iIcon.className = 'material-icons';
83 | iIcon.style.fontSize = '54px';
84 | iIcon.innerHTML = 'error_outline';
85 | icon.appendChild(iIcon);
86 |
87 | this.textDialog = document.createElement('p');
88 | content.appendChild(this.textDialog);
89 |
90 | var actions = document.createElement('div');
91 | actions.className = 'mdl-dialog__actions';
92 | this.dialog.appendChild(actions);
93 |
94 | var saveButton = document.createElement('button');
95 | saveButton.className = 'mdl-button';
96 | saveButton.innerHTML = 'Cancel';
97 | saveButton.addEventListener('click', function() {
98 | _this.dialog.close();
99 | });
100 | actions.appendChild(saveButton);
101 |
102 | document.body.appendChild(this.dialog);
103 | componentHandler.upgradeDom();
104 | }
105 |
106 | resume() {
107 | this.dialog.close();
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/www/enyo/js/leftpanel.js:
--------------------------------------------------------------------------------
1 | enyo.kind({
2 | name: 'LeftPanel',
3 | classes: 'onyx-toolbar',
4 | kind: 'Scroller',
5 | /* touch:true, */
6 | style: 'width: 200px;height:100%;margin:0px;',
7 | accelerated: true,
8 | horizontal: 'hidden',
9 | //strategyKind: "TranslateScrollStrategy",
10 | create: function() {
11 | this.inherited(arguments);
12 | this.$.strategy.setTranslateOptimized = true;
13 | },
14 | components: [
15 | {tag: 'center', components: [
16 | {tag: 'img', ontap: 'openRoot',src: 'rlogo-tr.png', style: 'margin:0px;margin-bottom:20px;cursor:pointer' },
17 | {kind: 'Group', onActivate: 'buttonActivated', classes: 'enyo-border-box group', defaultKind: 'onyx.Button', highlander: true, components: [
18 | {content: 'Disassembler', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Disassembler', active: true},
19 | {content: 'Assembler', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Assembler' },
20 | {content: 'Hexdump', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Hexdump' },
21 | {content: 'Graph', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Graph' },
22 | {content: 'Search', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Search' },
23 | {content: 'Console', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Console' },
24 | {content: 'Debugger', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Debugger' },
25 | {content: 'Script', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Script' },
26 | {content: 'Settings', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Settings' },
27 | {content: 'Logs', classes: 'onyx-dark menu-button', ontap: 'openPanel', name: 'Logs' },
28 | {content: 'About', classes: 'onyx-dark menu-button' , ontap: 'openPanel', name: 'About'}
29 | ]}
30 | ]}
31 | ],
32 | openRoot: function() {
33 | window.location = '..';
34 | },
35 | openPanel2: function() {
36 | this.ra.setIndex(2);
37 | },
38 | openPanel: function(x) {
39 | if (enyo.Panels.isScreenNarrow())
40 | this.ra.setIndex(1);
41 | if (x.name == this.oname)
42 | this.ra.setIndex(1);
43 | this.oname = x.name;
44 | r2ui.selected_panel = this.oname;
45 | if (this.oname === 'Logs')
46 | r2ui._log.connect();
47 | if (this.openCallback)
48 | this.openCallback(x.name);
49 | },
50 | oname: null,
51 | ra: null,
52 | oldSender: null,
53 | rowTap: function(inSender, inIndex) {
54 | if (this.oldSender)
55 | this.oldSender.setStyle('width:100%'); // background of row
56 | // TODO. use applystall
57 | //this.$.list.render ();
58 | inSender.setStyle('background-color: #202020;width:100%'); // background of row
59 | this.oldSender = inSender;
60 | if (this.openCallback)
61 | this.openCallback(inIndex.index); //this.data[inIndex.index]);
62 | },
63 | openCallback: undefined,
64 | data: [],
65 | iter: 1,
66 | refresh: function() {
67 | this.iter++;
68 | /*
69 | this.$.list.setCount (this.data.length);
70 | this.$.list.refresh ();
71 | */
72 | }
73 | });
74 |
--------------------------------------------------------------------------------
/www/w/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 98.css example
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
25 |
26 | Can't find r2 executable in PATH!
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
39 |
40 |
41 |
42 |
43 |
51 |
52 |
53 | Select architecture:
59 | and offset
60 |
61 |
62 |
73 |
74 |
83 |
84 |
85 |
86 |
89 |
90 |
91 |
92 |
93 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/www/r2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/www/m/js/helpers/statusbar/console.legacy.js:
--------------------------------------------------------------------------------
1 | var lastConsoleOutput = '';
2 |
3 | function console_submit(cmd) {
4 | var term = document.getElementById('console_terminal');
5 | var output = document.getElementById('console_output');
6 | var input = document.getElementById('console_input');
7 |
8 | var widget = widgetContainer.getWidget('Console');
9 | var c = widgetContainer.getWidgetDOMWrapper(widget);
10 |
11 | if (cmd === 'clear') {
12 | output.innerHTML = '';
13 | input.value = '';
14 | return;
15 | }
16 | r2.cmd(cmd, function(res) {
17 | output.innerHTML += ' > ' + cmd + '\n' + res;
18 | input.value = '';
19 | setTimeout(function() {
20 | window.scrollTo('console_input');
21 | }, 1000);
22 | });
23 | }
24 |
25 | function console_ready() {
26 | var input = document.getElementById('console_input');
27 | if (input === null) {
28 | return;
29 | }
30 | // r2.cmd('e scr.color=3');
31 | input.focus();
32 | input.onkeypress = function(e){
33 | if (e.keyCode === 13) {
34 | console_submit(input.value);
35 | }
36 | }
37 | }
38 |
39 | function consoleKey(e) {
40 | var inp = document.getElementById('console_input');
41 | if (!e) {
42 | inp.onkeypress = consoleKey;
43 | } else {
44 | if (e.keyCode === 13) {
45 | runCommand(inp.value);
46 | inp.value = '';
47 | }
48 | }
49 | }
50 |
51 | function panelConsole() {
52 | var widget = widgetContainer.getWidget('Console');
53 | var c = widgetContainer.getWidgetDOMWrapper(widget);
54 |
55 | updates.registerMethod(widget.getOffset(), panelConsole);
56 |
57 | /*
58 | c.innerHTML = '
';
59 | var common = 'onkeypress=\'consoleKey()\' class=\'mdl-card--expand mdl-textfield__input\' id=\'console_input\'';
60 | if (inColor) {
61 | c.style.backgroundColor = '#202020';
62 | var styles = 'position:fixed;padding-left:10px;top:4em;height:1.8em;color:white';
63 | c.innerHTML += '';
64 | //c.innerHTML += uiButton('javascript:runCommand()', 'Run');
65 | c.innerHTML += '';
66 | } else {
67 | c.style.backgroundColor = '#f0f0f0';
68 | c.innerHTML += '';
69 | c.innerHTML += uiButton('javascript:runCommand()', 'Run');
70 | c.innerHTML += '';
71 | }
72 | */
73 | const html = '
'
74 | + ''
75 | + ''
76 | + ''
77 | + ' > '
78 | + ''
79 | + '
'
80 | c.innerHTML = html;
81 | c.style.backgroundColor = '#303030';
82 | c.style.height = '100%';
83 | document.getElementById('console_output').innerHTML = lastConsoleOutput;
84 | console_ready();
85 | }
86 |
87 | function runCommand(text) {
88 | if (!text) {
89 | text = document.getElementById('input').value;
90 | }
91 | r2.cmd(text, function(d) {
92 | lastConsoleOutput = '\n' + d;
93 | document.getElementById('output').innerHTML = lastConsoleOutput;
94 | });
95 | }
96 |
--------------------------------------------------------------------------------
/www/m/js/modules/overview/EntropyCard.js:
--------------------------------------------------------------------------------
1 | import {r2Wrapper} from '../../core/R2Wrapper';
2 | import {Widgets} from '../../widgets/Widgets';
3 |
4 | const xmlns = "http://www.w3.org/2000/svg";
5 |
6 | export class EntropyCard {
7 |
8 | get DOM() { return this.card; }
9 |
10 | constructor(width, height) {
11 | this.width = width;
12 | this.height = height;
13 | this.entropy = [];
14 | this.build();
15 | this.refreshEntropy();
16 | this.draw();
17 | }
18 |
19 | build() {
20 | this.card = document.createElement('div');
21 | this.card.className = 'demo-charts mdl-color--white mdl-shadow--2dp mdl-cell mdl-cell--12-col mdl-grid';
22 | this.card.style.textAlign = 'center';
23 |
24 | this.svg = document.createElementNS(xmlns, 'svg');
25 | this.card.appendChild(this.svg);
26 | this.svg.style.display = 'block';
27 | this.svg.style.margin = 'auto';
28 | this.svg.setAttribute('fill', 'currentColor');
29 | this.svg.setAttribute('viewBox', '0 0 ' + this.width + ' ' + this.height);
30 | this.svg.setAttribute('width', this.width + 'px');
31 | this.svg.setAttribute('height', this.height + 'px');
32 | this.svg.setAttribute('title', 'Entropy graph');
33 | }
34 |
35 | refreshEntropy() {
36 | r2.cmdj('p=ej 50 $s @ $M|', (d) => {
37 | if (d && d.entropy) {
38 | this.entropy = d.entropy;
39 | }
40 | });
41 | }
42 |
43 | draw() {
44 | const nbVals = this.entropy.length;
45 | if (nbVals < 1) {
46 | return;
47 | }
48 | const minVal = this.entropy.reduce((prev, curr) => (prev.value < curr.value) ? prev : curr).value;
49 | const maxVal = this.entropy.reduce((prev, curr) => (prev.value > curr.value) ? prev : curr).value;
50 | const width = this.width / nbVals;
51 | const height = this.height;
52 |
53 | this.svg.innerHTML = '';
54 | for (let i in this.entropy)
55 | {
56 | const cur = this.entropy[i];
57 | const opacity = 0.1 + (1 - 0.1) * ((cur.value - minVal) / (maxVal - minVal));
58 |
59 | const g = document.createElementNS(xmlns, 'g');
60 | g.addEventListener('click', () => { r2Wrapper.seek(cur.addr, Widgets.DISASSEMBLY); });
61 | this.svg.appendChild(g);
62 |
63 | const title = document.createElementNS(xmlns, 'title');
64 | title.textContent = '0x' + cur.addr.toString(16);
65 | g.appendChild(title);
66 |
67 | const rect = document.createElementNS(xmlns, 'rect');
68 | rect.setAttribute('x', width * i);
69 | rect.setAttribute('y', 0);
70 | rect.setAttribute('width', width);
71 | rect.setAttribute('height', height);
72 | rect.setAttribute('fill', '#000');
73 | rect.setAttribute('fill-opacity', opacity);
74 |
75 | const text = document.createElementNS(xmlns, 'text');
76 | const color = (opacity > 0.4) ? '#EEEEEE' : 'black';
77 | text.setAttribute('x', width * i + 2);
78 | text.setAttribute('y', height + 10);
79 | text.setAttribute('fill', color);
80 | text.setAttribute('font-family', 'Roboto');
81 | text.setAttribute('font-size', 12);
82 | text.setAttribute('transform', 'rotate(-90, ' + width * i + ', ' + height + ')');
83 | text.textContent = '0x' + cur.addr.toString(16);
84 |
85 | g.appendChild(rect);
86 | g.appendChild(text);
87 | }
88 | }
89 |
90 | refresh() {
91 | this.refreshEntropy();
92 | this.draw();
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/LICENSES.md:
--------------------------------------------------------------------------------
1 | LICENSES
2 | ========
3 |
4 | This project is under LGPL3.
5 |
6 | This file summarizes what licenses are used in radare2 web interfaces:
7 |
8 | Globally:
9 | * [Gulp](http://gulpjs.com/) (MIT)
10 | * [Bower](http://bower.io/) (Twitter)
11 | * [npm](https://www.npmjs.com/) (Artistic License 2.0)
12 | * [radare](http://radare.org/) (LGPL3)
13 |
14 | enyo (mobile) interface
15 | --------------
16 |
17 | * [gulp-bower](https://www.npmjs.com/package/gulp-bower) (MIT)
18 | * [gulp-clean-css](https://www.npmjs.com/package/gulp-clean-css) (MIT)
19 | * [gulp-contact](https://www.npmjs.com/package/gulp-concat) (MIT)
20 | * [gulp-uglify](https://www.npmjs.com/package/gulp-uglify) (MIT)
21 | * [enyo](http://enyojs.com/) (Apache 2.0)
22 | * [Backbone.js](http://backbonejs.org/) (MIT)
23 | * [JointJS](http://www.jointjs.com/) (MPL v2)
24 | * [jQuery](https://jquery.com/) (MIT)
25 | * [UI Layout](http://plugins.jquery.com/layout/) (MPI, GPL v3)
26 | * [jQuery UI](https://jqueryui.com/) (MIT)
27 | * [jQuery.scrollTo](https://github.com/flesler/jquery.scrollTo) (MIT)
28 |
29 | material (responsive) interface
30 | -----------
31 |
32 | * [gulp-bower](https://www.npmjs.com/package/gulp-bower) (MIT)
33 | * [gulp-clean-css](https://www.npmjs.com/package/gulp-clean-css) (MIT)
34 | * [gulp-contact](https://www.npmjs.com/package/gulp-concat) (MIT)
35 | * [gulp-uglify](https://www.npmjs.com/package/gulp-uglify) (MIT)
36 | * [gulp-watch](https://www.npmjs.com/package/gulp-watch) (MIT)
37 | * [gulp-google-webfonts](https://www.npmjs.com/package/gulp-google-webfonts) (GPL-3.0)
38 | * [gulp-jscs](https://www.npmjs.com/package/gulp-jscs) (MIT)
39 | * [gulp-livereload](https://www.npmjs.com/package/gulp-livereload) (MIT)
40 | * [gulp-replace](https://www.npmjs.com/package/gulp-replace) (MIT)
41 | * [material-design-lite](https://getmdl.io/) (Apache 2.0)
42 | * [material-design-icons-iconfont](https://github.com/jossef/material-design-icons-iconfont) (MIT)
43 | * [jQuery](https://jquery.com/) (MIT)
44 | * [dialog-polyfill](https://github.com/GoogleChrome/dialog-polyfill) (BSD)
45 | * [DataTables](https://datatables.net/) (MIT)
46 | * [FileSaver](https://github.com/eligrey/FileSaver.js) (MIT)
47 | * [mdl-selectfield](https://github.com/mebibou/mdl-selectfield) (MIT)
48 |
49 | panels (desktop) interface
50 | -----------
51 |
52 | * [gulp-bower](https://www.npmjs.com/package/gulp-bower) (MIT)
53 | * [gulp-clean-css](https://www.npmjs.com/package/gulp-clean-css) (MIT)
54 | * [gulp-contact](https://www.npmjs.com/package/gulp-concat) (MIT)
55 | * [gulp-uglify](https://www.npmjs.com/package/gulp-uglify) (MIT)
56 | * [Backbone.js](http://backbonejs.org/) (MIT)
57 | * [JointJS](http://www.jointjs.com/) (MPL v2)
58 | * [Spectrum](https://github.com/bgrins/spectrum/) (MIT)
59 | * [jQuery](https://jquery.com/) (MIT)
60 | * [UI Layout](http://plugins.jquery.com/layout/) (MPI, GPL v3)
61 | * [jQuery UI](https://jqueryui.com/) (MIT)
62 | * [jQuery.scrollTo](https://github.com/flesler/jquery.scrollTo) (MIT)
63 | * [jQuery.ui-contextmenu](https://github.com/mar10/jquery-ui-contextmenu) (MIT)
64 | * [jQuery On-Off](https://plugins.jquery.com/onoff/) (MIT)
65 |
66 | tiles (legacy) interface
67 | -----------
68 |
69 | * [gulp-bower](https://www.npmjs.com/package/gulp-bower) (MIT)
70 | * [jQuery](https://jquery.com/) (MIT)
71 |
--------------------------------------------------------------------------------
/www/m/js/widgets/SearchWidget.js:
--------------------------------------------------------------------------------
1 | import {BaseWidget} from './BaseWidget';
2 | import {Inputs} from '../helpers/Inputs';
3 | import {formatOffsets} from '../helpers/Format';
4 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper';
5 |
6 | function searchResults(d) {
7 | const node = document.getElementById('search_output');
8 | node.innerHTML = "";
9 | node.appendChild(formatOffsets(d));
10 | }
11 |
12 | export class SearchWidget extends BaseWidget {
13 | constructor() {
14 | super('Search');
15 | }
16 |
17 | init() {
18 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
19 | if (this.displayed) {
20 | this.draw();
21 | }
22 | });
23 | }
24 |
25 | draw() {
26 | this.node.appendChild(this.getPanel());
27 | }
28 |
29 | getPanel() {
30 | const c = document.createElement('div');
31 | var header = document.createElement('div');
32 | header.style.margin = '0.5em';
33 | c.appendChild(header);
34 |
35 | const form = document.createElement('input');
36 | form.id = 'search_input';
37 | form.className = 'mdl-card--expand mdl-textfield__input';
38 | form.style.backgroundColor = 'white';
39 | form.style.paddingLeft = '10px';
40 | form.style.top = '3.5em';
41 | form.style.height = '1.8em';
42 | form.addEventListener('keypress', (e) => this.searchKey(e.keyCode));
43 |
44 | header.appendChild(form);
45 | header.appendChild(document.createElement('br'));
46 |
47 | header.appendChild(Inputs.button('Hex', () => this.runSearch()));
48 | header.appendChild(Inputs.button('String', () => this.runSearchString()));
49 | header.appendChild(Inputs.button('Code', () => this.runSearchCode()));
50 | header.appendChild(Inputs.button('ROP', () => this.runSearchROP()));
51 | header.appendChild(Inputs.button('Magic', () => this.runSearchMagic()));
52 |
53 | const content = document.createElement('div');
54 | content.id = 'search_output';
55 | content.style.paddingTop = '50px';
56 | content.style.color = 'black';
57 | content.className = 'pre';
58 | c.appendChild(content);
59 |
60 | return c;
61 | }
62 |
63 | searchKey(keyCode) {
64 | var inp = document.getElementById('search_input');
65 | if (keyCode === 13) {
66 | this.runSearch(inp.value);
67 | inp.value = '';
68 | }
69 | }
70 |
71 | runSearchMagic() {
72 | r2.cmd('/m', searchResults);
73 | }
74 |
75 | runSearchCode(text) {
76 | if (!text) {
77 | text = document.getElementById('search_input').value;
78 | }
79 | r2.cmd('"/c ' + text + '"', searchResults);
80 | }
81 |
82 | runSearchString(text) {
83 | if (!text) {
84 | text = document.getElementById('search_input').value;
85 | }
86 | r2.cmd('/ ' + text, searchResults);
87 | }
88 |
89 | runSearchROP(text) {
90 | if (!text) {
91 | text = document.getElementById('search_input').value;
92 | }
93 | r2.cmd('"/R ' + text + '"', searchResults);
94 | }
95 |
96 | runSearch(text) {
97 | if (!text) {
98 | text = document.getElementById('search_input').value;
99 | }
100 | if (text.startsWith('"') && text.endsWith('"')) {
101 | const a = text.replace(/"/g, '');
102 | r2.cmd('/ ' + a, searchResults);
103 | } else {
104 | r2.cmd('"/x ' + text + '"', searchResults);
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/www/m/js/modules/overview/GraphCard.js:
--------------------------------------------------------------------------------
1 | import {uiContext} from '../../core/UIContext';
2 | import {r2Wrapper} from '../../core/R2Wrapper';
3 | import {Widgets} from '../../widgets/Widgets';
4 |
5 | export class GraphCard {
6 |
7 | get DOM() { return this.card; }
8 |
9 | constructor() {
10 | this.build();
11 | }
12 |
13 | build() {
14 | this.card = document.createElement('div');
15 | this.card.className = 'demo-charts mdl-color--white mdl-shadow--2dp mdl-cell mdl-cell--12-col mdl-grid';
16 |
17 | const codeChart = this.createChart('code', 'Go to assembly', undefined, 82, () => {
18 | r2Wrapper.seek('entry0', Widgets.DISASSEMBLY);
19 | });
20 | const dataChart = this.createChart('data', 'Go to hexdump', undefined, 22, () => {
21 | r2Wrapper.seek('0x00', Widgets.HEXDUMP);
22 | });
23 | const stringsChart = this.createChart('strings', 'Go to strings', undefined, 4, () => { uiContext.navigateTo(Widgets.STRINGS); });
24 | const functionsChart = this.createChart('functions', 'Go to functions', undefined, 82, () => { uiContext.navigateTo(Widgets.FUNCTIONS) });
25 |
26 | this.card.appendChild(codeChart);
27 | this.card.appendChild(dataChart);
28 | this.card.appendChild(stringsChart);
29 | this.card.appendChild(functionsChart);
30 | }
31 |
32 | createChart(name, title, color, value, onclick) {
33 | const xmlns = "http://www.w3.org/2000/svg";
34 | const svg = document.createElementNS(xmlns, 'svg');
35 | svg.setAttribute('class', 'demo-chart mdl-cell mdl-cell--4-col mdl-cell--3-col-desktop');
36 | svg.setAttribute('fill', 'currentColor');
37 | svg.setAttribute('viewBox', '0 0 1 1');
38 | svg.setAttribute('width', '200px');
39 | svg.setAttribute('height', '200px');
40 | svg.setAttribute('title', title);
41 |
42 | svg.addEventListener('click', onclick);
43 |
44 | const use = document.createElementNS(xmlns, 'use');
45 | use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#piechart');
46 | use.setAttribute('mask', 'url(#piemask)');
47 | svg.appendChild(use);
48 |
49 | const textLegend = document.createElementNS(xmlns, 'text');
50 | textLegend.setAttribute('x', '0.3');
51 | textLegend.setAttribute('y', '0.2');
52 | textLegend.setAttribute('font-family', 'Roboto');
53 | textLegend.setAttribute('font-size', '0.1');
54 | textLegend.setAttribute('fill', '#888');
55 | textLegend.setAttribute('text-anchor', 'top');
56 | textLegend.setAttribute('dy', '0.1');
57 | textLegend.textContent = name;
58 | svg.appendChild(textLegend);
59 |
60 | const textValue = document.createElementNS(xmlns, 'text');
61 | textValue.setAttribute('x', '0.5');
62 | textValue.setAttribute('y', '0.5');
63 | textValue.setAttribute('font-family', 'Roboto');
64 | textValue.setAttribute('font-size', '0.3');
65 | textValue.setAttribute('fill', '#888');
66 | textValue.setAttribute('text-anchor', 'middle');
67 | textValue.setAttribute('dy', '0.1');
68 | textValue.textContent = value;
69 | svg.appendChild(textValue);
70 |
71 | const textPercentage = document.createElementNS(xmlns, 'tspan');
72 | textPercentage.setAttribute('dy', '-0.07');
73 | textPercentage.setAttribute('font-size', '0.2');
74 | textPercentage.textContent = '%';
75 | textValue.appendChild(textPercentage);
76 |
77 | return svg;
78 | }
79 |
80 | refresh() {
81 | // Do nothing yet
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/www/enyo/gulpfile.js:
--------------------------------------------------------------------------------
1 | const { src, series, dest } = require('gulp');
2 |
3 | var uglify = require('gulp-uglify'),
4 | cleanCSS = require('gulp-clean-css'),
5 | replace = require('gulp-replace'),
6 | concat = require('gulp-concat'),
7 | bower = require('bower');
8 |
9 | var paths = {
10 | r2: '../lib/',
11 | dev: '../../dev/enyo/',
12 | dist: '../../dist/enyo/'
13 | };
14 |
15 |
16 |
17 | const _concatCommonJs = function() {
18 | return src(paths.r2 + '*.js')
19 | .pipe(uglify())
20 | .pipe(concat('r2core.js'))
21 | .pipe(dest(paths.dist));
22 | }
23 | const _concatCommonCss = function() {
24 | return src(paths.r2 + '*.css')
25 | .pipe(cleanCSS())
26 | .pipe(concat('r2core.css'))
27 | .pipe(dest(paths.dist));
28 | }
29 |
30 |
31 | const _concatR2appJs = function() {
32 | return src('js/*.js')
33 | .pipe(uglify())
34 | .pipe(concat('r2app.js'))
35 | .pipe(dest(paths.dist));
36 | }
37 | const _concatEnyoAppJs = function() {
38 | return src(['js/enyo/enyo.js', 'js/enyo/app.js'])
39 | .pipe(concat('enyo_app.js'))
40 | .pipe(dest(paths.dist));
41 | }
42 | const _concatMainJs = function() {
43 | return src('js/core/disassembler_old.js')
44 | .pipe(uglify())
45 | .pipe(concat('disassembler_old.js'))
46 | .pipe(dest(paths.dist));
47 | }
48 |
49 | const _common = series(
50 | _concatCommonJs,
51 | _concatCommonCss
52 | );
53 |
54 | const _js = series(
55 | _concatR2appJs,
56 | _concatEnyoAppJs,
57 | _concatMainJs
58 | );
59 |
60 |
61 | const _concatAllCss = function() {
62 | return src('css/*.css')
63 | .pipe(cleanCSS())
64 | .pipe(concat('stylesheet.css'))
65 | .pipe(dest(paths.dist));
66 | }
67 | const _concatEnyoCss = function() {
68 | return src('css/enyo/*.css')
69 | .pipe(replace(/\.\.\/lib\/onyx\/images\//g, ''))
70 | .pipe(cleanCSS())
71 | .pipe(concat('enyo.css'))
72 | .pipe(dest(paths.dist));
73 | }
74 | const _copyNestedPng = function() {
75 | return src('css/**/*.png')
76 | .pipe(dest(paths.dist+'enyo/'));
77 | }
78 | const _copyPng = function() {
79 | return src(['css/lib/onyx/images/*.png','*.png'])
80 | .pipe(dest(paths.dist))
81 | }
82 |
83 | const _css = series(
84 | _concatAllCss,
85 | _concatEnyoCss,
86 | _copyNestedPng,
87 | _copyPng
88 | );
89 |
90 | const _bowerInstall = function() {
91 | //return bower({ cmd: 'install'});
92 | return new Promise((resolve) => {
93 | bower.commands.install(undefined, undefined, {
94 | cwd: process.cwd()
95 | }).on('end', resolve);
96 | });
97 | };
98 |
99 | const _copyVendors = function() {
100 | // Moving neccesary vendors files from bower
101 | return src([
102 | 'vendors/jquery/dist/jquery.min.js',
103 | 'vendors/jquery.scrollTo/jquery.scrollTo.min.js',
104 | 'vendors/jquery-ui/jquery-ui.min.js',
105 | 'vendors/jquery.layout/dist/jquery.layout-latest.min.js',
106 | 'vendors/lodash/dist/lodash.min.js',
107 | 'vendors/backbone/backbone-min.js',
108 | 'vendors/jointjs/dist/joint.min.css',
109 | 'vendors/jointjs/dist/joint.min.js',
110 | 'vendors/jointjs/plugins/layout/DirectedGraph/joint.layout.DirectedGraph.js'
111 | ])
112 | .pipe(dest(paths.dist+'vendors/'));
113 | }
114 |
115 | const _default = () => {
116 | return src('index.html').pipe(dest(paths.dist))
117 | }
118 |
119 | exports.default = series( _bowerInstall, _copyVendors, _js, _css, _common, _default);
120 |
121 |
122 |
--------------------------------------------------------------------------------
/www/m/js/widgets/WidgetFactory.js:
--------------------------------------------------------------------------------
1 | import {Widgets} from './Widgets';
2 |
3 | import {OverviewWidget} from './OverviewWidget';
4 | import {HexdumpWidget} from './HexdumpWidget';
5 | import {DebuggerWidget} from './DebuggerWidget';
6 | import {FunctionsWidget} from './FunctionsWidget';
7 | import {FlagsWidget} from './FlagsWidget';
8 | import {FlagsSpacesWidget} from './FlagsSpacesWidget';
9 | import {SearchWidget} from './SearchWidget';
10 | import {ScriptWidget} from './ScriptWidget';
11 | import {CommentsWidget} from './CommentsWidget';
12 | import {NotesWidget} from './NotesWidget';
13 | import {SettingsWidget} from './SettingsWidget';
14 |
15 | import {DisassemblyWidget} from './DisassemblyWidget';
16 | import {DisassemblyGraphWidget} from './DisassemblyGraphWidget';
17 | import {DisassemblyInfosWidget} from './DisassemblyInfosWidget';
18 | import {DisassemblyFunctionsWidget} from './DisassemblyFunctionsWidget';
19 | import {DisassemblyFunctionsFullWidget} from './DisassemblyFunctionsFullWidget';
20 | import {DisassemblyBlocksWidget} from './DisassemblyBlocksWidget';
21 | import {DisassemblyDecompileWidget} from './DisassemblyDecompileWidget';
22 |
23 | export class WidgetFactory {
24 |
25 | constructor() {
26 | this.widgets = {};
27 | }
28 |
29 | get(widget) {
30 | if (!this.contains(widget)) {
31 | this.instanciate_(widget);
32 | }
33 |
34 | return this.widgets[widget];
35 | }
36 |
37 | contains(widget) {
38 | return typeof this.widgets[widget] !== 'undefined';
39 | }
40 |
41 | instanciate_(widget) {
42 | switch (widget) {
43 | case Widgets.OVERVIEW:
44 | this.widgets[widget] = new OverviewWidget();
45 | break;
46 | case Widgets.DISASSEMBLY:
47 | this.widgets[widget] = new DisassemblyWidget();
48 | break;
49 | case Widgets.DISASSEMBLY_GRAPH:
50 | this.widgets[widget] = new DisassemblyGraphWidget();
51 | break;
52 | case Widgets.DISASSEMBLY_INFOS:
53 | this.widgets[widget] = new DisassemblyInfosWidget();
54 | break;
55 | case Widgets.DISASSEMBLY_FUNCTIONS:
56 | this.widgets[widget] = new DisassemblyFunctionsWidget();
57 | break;
58 | case Widgets.DISASSEMBLY_FUNCTIONS_FULL:
59 | this.widgets[widget] = new DisassemblyFunctionsFullWidget();
60 | break;
61 | case Widgets.DISASSEMBLY_BLOCKS:
62 | this.widgets[widget] = new DisassemblyBlocksWidget();
63 | break;
64 | case Widgets.DISASSEMBLY_DECOMPILE:
65 | this.widgets[widget] = new DisassemblyDecompileWidget();
66 | break;
67 | case Widgets.HEXDUMP:
68 | this.widgets[widget] = new HexdumpWidget();
69 | break;
70 | case Widgets.DEBUGGER:
71 | this.widgets[widget] = new DebuggerWidget();
72 | break;
73 | case Widgets.FUNCTIONS:
74 | this.widgets[widget] = new FunctionsWidget();
75 | break;
76 | case Widgets.FLAGS:
77 | this.widgets[widget] = new FlagsWidget();
78 | break;
79 | case Widgets.FLAGS_SPACE:
80 | this.widgets[widget] = new FlagsSpacesWidget();
81 | break;
82 | case Widgets.SEARCH:
83 | this.widgets[widget] = new SearchWidget();
84 | break;
85 | case Widgets.SCRIPTS:
86 | this.widgets[widget] = new ScriptWidget();
87 | break;
88 | case Widgets.COMMENTS:
89 | this.widgets[widget] = new CommentsWidget();
90 | break;
91 | case Widgets.NOTES:
92 | this.widgets[widget] = new NotesWidget();
93 | break;
94 | case Widgets.SETTINGS:
95 | this.widgets[widget] = new SettingsWidget();
96 | break;
97 | default:
98 | console.error('Not instanciable widget: ' + widget);
99 | }
100 |
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/www/enyo/css/enyo/enyo.css:
--------------------------------------------------------------------------------
1 |
2 | /* ../source/dom/dom.css */
3 |
4 | /* things we always want */
5 | body {
6 | font-family: 'Helvetica Neue', 'Nimbus Sans L', Arial, sans-serif;
7 | }
8 |
9 | /* allow hw-accelerated scrolling on platforms that support it */
10 | body.webkitOverflowScrolling {
11 | -webkit-overflow-scrolling: touch;
12 | }
13 |
14 | /* for apps */
15 | .enyo-document-fit {
16 | margin: 0;
17 | height: 100%;
18 | /* note: giving html overflow: auto is odd and was only ever done to avoid duplication
19 | however, android 4.04 sometimes does not hide nodes when their display is set to none
20 | if document is overflow auto.
21 | */
22 | position: relative;
23 | }
24 |
25 | .enyo-body-fit {
26 | margin: 0;
27 | height: 100%;
28 | /* helps prevent ios page scroll */
29 | overflow: auto;
30 | position: relative;
31 | }
32 |
33 | .enyo-no-touch-action {
34 | -ms-touch-action: none;
35 | }
36 |
37 | /* reset */
38 |
39 | button {
40 | font-size: inherit;
41 | font-family: inherit;
42 | }
43 | button::-moz-focus-inner {
44 | border: 0;
45 | padding: 0;
46 | }
47 |
48 | /* user selection */
49 |
50 | .enyo-unselectable {
51 | cursor: default;
52 | -ms-user-select: none;
53 | -webkit-user-select: none;
54 | -moz-user-select: -moz-none;
55 | user-select: none;
56 | }
57 |
58 | .enyo-unselectable::selection, .enyo-unselectable ::selection {
59 | color: transparent;
60 | }
61 |
62 | .enyo-selectable {
63 | cursor: auto;
64 | -ms-user-select: element;
65 | -webkit-user-select: text;
66 | -moz-user-select: text;
67 | user-select: text;
68 | }
69 |
70 | .enyo-selectable::selection, .enyo-selectable ::selection {
71 | background: #3297FD;
72 | color: #FFF;
73 | }
74 |
75 | /* layout */
76 |
77 | body .enyo-fit {
78 | position: absolute;
79 | left: 0;
80 | top: 0;
81 | right: 0;
82 | bottom: 0;
83 | }
84 |
85 | .enyo-clip {
86 | overflow: hidden;
87 | }
88 |
89 | .enyo-border-box {
90 | -webkit-box-sizing: border-box;
91 | -moz-box-sizing: border-box;
92 | box-sizing: border-box;
93 | }
94 |
95 | /* compositing */
96 |
97 | .enyo-composite {
98 | -webkit-transform: translateZ(0);
99 | -moz-transform: translateZ(0);
100 | -ms-transform: translateZ(0);
101 | -o-transform: translateZ(0);
102 | transform: translateZ(0);
103 | }
104 |
105 |
106 | /* ../source/touch/Thumb.css */
107 |
108 | .enyo-thumb {
109 | position: absolute;
110 | -moz-box-sizing: border-box;
111 | box-sizing: border-box;
112 | border-radius: 4px;
113 | background: #333;
114 | border: 1px solid #666;
115 | opacity: 0.75;
116 | z-index: 1;
117 | }
118 |
119 | .enyo-vthumb {
120 | top: 0;
121 | right: 2px;
122 | width: 4px;
123 | }
124 |
125 | .enyo-hthumb {
126 | left: 0;
127 | bottom: 2px;
128 | height: 4px;
129 | }
130 |
131 |
132 | /* ../source/touch/Scroller.css */
133 |
134 | .enyo-scroller {
135 | position: relative;
136 | }
137 |
138 | .enyo-fit.enyo-scroller {
139 | position: absolute;
140 | }
141 |
142 | .enyo-touch-scroller {
143 | overflow: hidden;
144 | }
145 |
146 | .enyo-touch-strategy-container {
147 | overflow: hidden;
148 | }
149 |
150 | .enyo-scrollee-fit {
151 | height: 100%;
152 | }
153 |
154 | /* ../source/ui/ui.css */
155 |
156 | .enyo-inline, .enyo-tool-decorator {
157 | display: inline-block;
158 | }
159 |
160 | .enyo-children-inline > *, .enyo-tool-decorator > * {
161 | display: inline-block;
162 | }
163 |
164 | .enyo-children-middle > *, .enyo-tool-decorator > * {
165 | vertical-align: middle;
166 | }
167 |
168 | .enyo-positioned {
169 | position: relative;
170 | }
171 |
172 | .enyo-fill {
173 | position: relative;
174 | width: 100%;
175 | height: 100%;
176 | }
177 |
178 | .enyo-popup {
179 | position: absolute;
180 | z-index: 10;
181 | }
182 |
--------------------------------------------------------------------------------
/www/p/lib/css/tree.jquery.css:
--------------------------------------------------------------------------------
1 | ul.jqtree-tree {
2 | margin-left: 0;
3 | }
4 |
5 | ul.jqtree-tree,
6 | ul.jqtree-tree ul.jqtree_common {
7 | list-style: none outside;
8 | margin-bottom: 0;
9 | padding: 0;
10 | }
11 |
12 | ul.jqtree-tree ul.jqtree_common {
13 | display: block;
14 | margin-left: 12px;
15 | margin-right: 0;
16 | }
17 | ul.jqtree-tree li.jqtree-closed > ul.jqtree_common {
18 | display: none;
19 | }
20 |
21 | ul.jqtree-tree li.jqtree_common {
22 | clear: both;
23 | list-style-type: none;
24 | }
25 | ul.jqtree-tree .jqtree-toggler {
26 | border-bottom: none;
27 | /*color: #333;*/
28 | text-decoration: none;
29 | margin-right: 0.5em;
30 | }
31 |
32 | ul.jqtree-tree .jqtree-toggler:hover {
33 | /*color: #000;*/
34 | text-decoration: none;
35 | }
36 |
37 | ul.jqtree-tree .jqtree-element {
38 | cursor: auto;
39 | }
40 |
41 | .jqtree-tree .jqtree-title {
42 | color: #1C4257;
43 | vertical-align: middle;
44 | margin-left: 1.5em;
45 | }
46 |
47 | .jqtree-tree .jqtree-title.jqtree-title-folder {
48 | margin-left: 0;
49 | }
50 |
51 | span.addr:hover,
52 | div#strings .jqtree-title-folder:hover,
53 | div#types .jqtree-title-folder:hover {
54 | cursor: default;
55 | }
56 |
57 | ul.jqtree-tree li.jqtree-folder {
58 | margin-bottom: 4px;
59 | }
60 |
61 | ul.jqtree-tree li.jqtree-folder.jqtree-closed {
62 | margin-bottom: 1px;
63 | }
64 |
65 | ul.jqtree-tree .jqtree-toggler.jqtree-closed {
66 | background-position: 0 0;
67 | }
68 |
69 | span.jqtree-dragging {
70 | color: #fff;
71 | background: #000;
72 | opacity: 0.6;
73 | cursor: pointer;
74 | padding: 2px 8px;
75 | }
76 |
77 | ul.jqtree-tree li.jqtree-ghost {
78 | position: relative;
79 | z-index: 10;
80 | margin-right: 10px;
81 | }
82 |
83 | ul.jqtree-tree li.jqtree-ghost span {
84 | display: block;
85 | }
86 |
87 | ul.jqtree-tree li.jqtree-ghost span.jqtree-circle {
88 | border: solid 2px #0000ff;
89 | -webkit-border-radius: 100px;
90 | -moz-border-radius: 100px;
91 | border-radius: 100px;
92 | height: 8px;
93 | width: 8px;
94 | position: absolute;
95 | top: -4px;
96 | left: -6px;
97 | }
98 |
99 | /* IE 6, 7, 8 */
100 | @media \0screen\,screen\9 {
101 | ul.jqtree-tree li.jqtree-ghost span.jqtree-circle {
102 | background: url(jqtree-circle.png) no-repeat;
103 | border: 0 none;
104 | }
105 | }
106 |
107 | ul.jqtree-tree li.jqtree-ghost span.jqtree-line {
108 | background-color: #0000ff;
109 | height: 2px;
110 | padding: 0;
111 | position: absolute;
112 | top: -1px;
113 | left: 2px;
114 | width: 100%;
115 | }
116 |
117 | ul.jqtree-tree li.jqtree-ghost.jqtree-inside {
118 | margin-left: 48px;
119 | }
120 |
121 | ul.jqtree-tree span.jqtree-border {
122 | position: absolute;
123 | display: block;
124 | left: -2px;
125 | top: 0;
126 | border: solid 2px #0000ff;
127 | border-radius: 6px;
128 | margin: 0;
129 | box-sizing: content-box;
130 | }
131 |
132 | ul.jqtree-tree .jqtree-element {
133 | position: relative;
134 | }
135 |
136 | ul.jqtree-tree li.jqtree-selected > .jqtree-element,
137 | ul.jqtree-tree li.jqtree-selected > .jqtree-element:hover {
138 | background-color: #97BDD6;
139 | background: -webkit-gradient(linear, left top, left bottom, from(#BEE0F5), to(#89AFCA));
140 | background: -moz-linear-gradient(top, #BEE0F5, #89AFCA);
141 | background: -ms-linear-gradient(top, #BEE0F5, #89AFCA);
142 | background: -o-linear-gradient(top, #BEE0F5, #89AFCA);
143 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
144 | }
145 |
146 | ul.jqtree-tree .jqtree-moving > .jqtree-element .jqtree-title {
147 | outline: dashed 1px #0000ff;
148 | }
149 |
--------------------------------------------------------------------------------
/www/m/js/widgets/FlagsSpacesWidget.js:
--------------------------------------------------------------------------------
1 | import {BaseWidget} from './BaseWidget';
2 |
3 | import {uiContext} from '../core/UIContext';
4 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper';
5 | import {Widgets} from './Widgets';
6 | import {Table} from '../helpers/Table';
7 | import {Inputs} from '../helpers/Inputs';
8 |
9 | export class FlagsSpacesWidget extends BaseWidget {
10 | activeEls = [];
11 |
12 | constructor() {
13 | super('Flag Spaces');
14 | }
15 |
16 | init() {
17 | r2Wrapper.registerListener(R2Actions.SEEK, () => {
18 | if (!this.displayed) {
19 | return;
20 | }
21 | this.draw();
22 | });
23 | }
24 |
25 | draw() {
26 | this.node.innerHTML = '';
27 | this.node.scrollTop = 0;
28 | this.current = null;
29 | this.node.appendChild(this.getPanel());
30 | }
31 |
32 | getPanel() {
33 | var c = document.createElement('div');
34 | if (this.inColor) {
35 | c.style.backgroundColor = '#202020';
36 | }
37 |
38 | var header = document.createElement('div');
39 | header.style.position = 'fixed';
40 | header.style.margin = '0.5em';
41 | c.appendChild(header);
42 |
43 | header.appendChild(Inputs.iconButton('undo', 'Back to flags', () => uiContext.navigateTo(Widgets.FLAGS)));
44 | header.appendChild(Inputs.button('Deselect', () => { this.current = null; r2.cmd('fs *', () => this.draw()); } ));
45 | header.appendChild(Inputs.button('Add', () => this.setFlagspace()));
46 | header.appendChild(Inputs.button('Delete', () => this.delFlagspace()));
47 | header.appendChild(Inputs.button('Rename', () => this.renameFlagspace()));
48 |
49 | var content = document.createElement('div');
50 | content.appendChild(document.createTextNode('Click on a row to select it.'));
51 | content.style.paddingTop = '70px';
52 | c.appendChild(content);
53 |
54 | r2.cmd('fsj', (d) => {
55 | const data = JSON.parse(d);
56 | const table = new Table(
57 | ['+Flags', 'Flagspace'],
58 | [true, false],
59 | 'flagspaceTable');
60 |
61 | this.activeEls = this.activeEls.filter(e => {
62 | e.classList.remove(['active']);
63 | return false;
64 | });
65 |
66 | data.map( x => {
67 | const a = document.createElement('a');
68 | a.textContent = x.name;
69 | if (x.selected){
70 | a.classList.add(['active']);
71 | this.activeEls.push(a);
72 | }
73 |
74 | a.addEventListener('click', (e) => {
75 | console.log(x.name, e);
76 | r2.cmd('fs ' + x.name, (h)=>{
77 | this.activeEls = this.activeEls.filter(e => {
78 | e.classList.remove(['active']);
79 | return false;
80 | });
81 | a.classList.add(['active']);
82 | this.activeEls.push(a);
83 | });
84 | this.draw();
85 | });
86 |
87 | const row = table.addRow([x.count, a]);
88 | row.addEventListener('click', () => {
89 | table.getRows().forEach((curRow) => {
90 | curRow.classList.remove('active');
91 | });
92 | row.classList.add('active');
93 | this.current = x.name;
94 | });
95 | });
96 | table.insertInto(content);
97 | });
98 |
99 | return c;
100 | }
101 |
102 | setFlagspace() {
103 | let fs = this.current;
104 | if (!fs) {
105 | fs = prompt('name');
106 | }
107 | if (!fs) {
108 | return;
109 | }
110 | r2.cmd('fs ' + fs, () => {
111 | this.draw();
112 | });
113 | }
114 |
115 | renameFlagspace() {
116 | let fs = this.current;
117 | if (!fs) {
118 | fs = prompt('name');
119 | }
120 | if (!fs) {
121 | return;
122 | }
123 | r2.cmd('fsr ' + fs, () => {
124 | this.draw();
125 | });
126 | }
127 |
128 |
129 | delFlagspace() {
130 | let fs = this.current;
131 | if (!fs) {
132 | fs = '.';
133 | }
134 | if (!fs) {
135 | return;
136 | }
137 | r2.cmd('fs-' + fs, () => {
138 | this.draw();
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/www/m/js/helpers/Table.js:
--------------------------------------------------------------------------------
1 | import {applySeek} from '../helpers/Format';
2 |
3 | /**
4 | * Handling DataTables with jQuery plugin
5 | *
6 | * @param {Array} cols - List of columns, add "+" at beginning to specify a clickable field (seek method)
7 | * @param {Array} nonum - List of booleans, set true if non-numeric
8 | * @param {String} id - Id (DOM) of the current table, internal usage for DataTable plugin
9 | */
10 | export class Table {
11 | constructor(cols, nonum, id, onChange, seekNavigation = null) {
12 | this.cols = cols;
13 | this.nonum = nonum;
14 | this.clickableOffset = new Array(cols.length);
15 | this.clickableOffset.fill(false);
16 | this.contentEditable = new Array(cols.length);
17 | this.contentEditable.fill(false);
18 | this.onChange = onChange;
19 | this.seekNavigation = seekNavigation;
20 | this.id = id || false;
21 |
22 | this.init();
23 | }
24 |
25 | init() {
26 | this.root = document.createElement('table');
27 | this.root.className = 'mdl-data-table mdl-data-table--selectable mdl-shadow--2dp';
28 | if (this.root.id !== false) {
29 | this.root.id = this.id;
30 | }
31 |
32 | this.thead = document.createElement('thead');
33 | this.root.appendChild(this.thead);
34 | this.tbody = document.createElement('tbody');
35 | this.root.appendChild(this.tbody);
36 |
37 | var tr = document.createElement('tr');
38 | this.thead.appendChild(tr);
39 |
40 | for (var c in this.cols) {
41 | if (this.cols[c][0] == '+') {
42 | this.clickableOffset[c] = true;
43 | this.cols[c] = this.cols[c].substr(1);
44 | } else if (this.cols[c][0] == '~') {
45 | this.contentEditable[c] = true;
46 | }
47 |
48 | var th = document.createElement('th');
49 | th.appendChild(document.createTextNode(this.cols[c]));
50 | if (this.nonum[c]) {
51 | th.className = 'mdl-data-table__cell--non-numeric';
52 | }
53 | tr.appendChild(th);
54 | }
55 | }
56 |
57 | getRows() {
58 | return Array.prototype.slice.call(this.tbody.children);
59 | }
60 |
61 | addRow(cells) {
62 | var tr = document.createElement('tr');
63 | this.tbody.appendChild(tr);
64 |
65 | for (var i = 0; i < cells.length; i++) {
66 | var td = document.createElement('td');
67 | if (this.clickableOffset[i]) {
68 | const a = document.createElement('a');
69 | a.innerHTML = cells[i];
70 | td.appendChild(a);
71 | applySeek(a, cells[i], this.seekNavigation);
72 | } else if (typeof cells[i] === 'object') {
73 | td.appendChild(cells[i]);
74 | } else {
75 | td.innerHTML = cells[i];
76 | }
77 |
78 | if (this.contentEditable[i]) {
79 | var _this = this;
80 | td.initVal = td.innerHTML;
81 | td.contentEditable = true;
82 | td.busy = false;
83 |
84 | td.addEventListener('blur', function (evt) {
85 | if (evt.target.busy) {
86 | return;
87 | }
88 | if (evt.target.initVal === evt.target.innerHTML) {
89 | return;
90 | }
91 | evt.target.busy = true;
92 | _this.onChange(cells, evt.target.innerHTML);
93 | evt.target.initVal = evt.target.innerHTML;
94 | evt.target.busy = false;
95 | });
96 |
97 | td.addEventListener('keydown', function (evt) {
98 | if (evt.keyCode !== 13 || evt.target.busy) {
99 | return;
100 | }
101 | if (evt.target.initVal === evt.target.innerHTML) {
102 | return;
103 | }
104 | evt.preventDefault();
105 | evt.target.busy = true;
106 | _this.onChange(cells, evt.target.innerHTML);
107 | evt.target.initVal = evt.target.innerHTML;
108 | evt.target.busy = false;
109 | evt.target.blur();
110 | });
111 | }
112 |
113 | tr.appendChild(td);
114 | }
115 | return tr;
116 | }
117 |
118 | insertInto(node) {
119 | node.appendChild(this.root);
120 | if (this.id !== false) {
121 | $('#' + this.id).DataTable();
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/www/m/js/modules/overview/AnalysisCard.js:
--------------------------------------------------------------------------------
1 | export class AnalysisCard {
2 |
3 | get DOM() { return this.card; }
4 | set onAnalysis(value ) { this.analysisCallback = value; }
5 |
6 | constructor() {
7 | this.analysisMethods = [
8 | { id: 'symbols', name: 'Analyse symbols', cmd: 'aa' },
9 | { id: 'ref', name: 'Analyse References', cmd: 'aar' },
10 | { id: 'calls', name: 'Analyse calls', cmd: 'e anal.calls=true;aac', disabledCmd: 'e anal.calls=false' },
11 | { id: 'emu', name: 'Emulate code', cmd: 'e asm.emu=1;aae;e asm.emu=0', disabledCmd: 'e asm.emu=false' },
12 | { id: 'prelude', name: 'Find preludes', cmd: 'aap' },
13 | { id: 'autoname', name: 'Autoname fcns', cmd: 'aan' },
14 | ];
15 |
16 | this.build();
17 | }
18 |
19 | build() {
20 | this.card = document.createElement('div');
21 | this.card.className = 'demo-options mdl-card mdl-color--teal-300 mdl-shadow--2dp mdl-cell mdl-cell--4-col mdl-cell--3-col-tablet mdl-cell--12-col-desktop';
22 |
23 | const title = document.createElement('div');
24 | title.className = 'mdl-card__title mdl-card--expand mdl-color--teal-300';
25 | title.innerHTML = 'Analysis Options
';
26 | this.card.appendChild(title);
27 |
28 | const content = document.createElement('div');
29 | content.className = 'mdl-card__supporting-text mdl-color-grey-600';
30 | this.card.appendChild(content);
31 |
32 | const choiceList = document.createElement('ul');
33 | content.appendChild(choiceList);
34 |
35 | const action = document.createElement('div');
36 | action.className = 'mdl-card__actions mdl-card--border';
37 | this.card.appendChild(action);
38 |
39 | const analyseButton = document.createElement('a');
40 | analyseButton.className = 'mdl-button mdl-js-button mdl-js-ripple-effect mdl-color--blue-grey-50 mdl-color-text--blue-greu-50';
41 | analyseButton.textContent = 'Analyse',
42 | analyseButton.addEventListener('click', () => this.analyse());
43 | action.appendChild(analyseButton);
44 |
45 | const spacer = document.createElement('div');
46 | spacer.className = 'mdl-layout-spacer';
47 | action.appendChild(spacer);
48 |
49 | const icon = document.createElement('i');
50 | icon.className = 'material-icons';
51 | icon.textContent = 'room';
52 | action.appendChild(icon);
53 |
54 | this.addAnalysisOptions(choiceList);
55 | }
56 |
57 | addAnalysisOptions(dom) {
58 | for (let i in this.analysisMethods)
59 | {
60 | const method = this.analysisMethods[i];
61 | const methodId = 'anal_' + method.id;
62 | const li = document.createElement('li');
63 | dom.appendChild(li);
64 |
65 | const label = document.createElement('label');
66 | label.className = 'mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect';
67 | label.for = methodId;
68 | li.appendChild(label);
69 |
70 | const checkbox = document.createElement('input');
71 | checkbox.className = 'mdl-checkbox__input';
72 | checkbox.id = methodId;
73 | checkbox.type = 'checkbox';
74 | label.appendChild(checkbox);
75 |
76 | const text = document.createElement('span');
77 | text.className = 'mdl-checkbox__label';
78 | text.innerHTML = method.name;
79 | label.appendChild(text);
80 | }
81 | }
82 |
83 | refresh() {
84 | var collection = [].slice.call(this.card.getElementsByTagName('input'));
85 | collection.forEach((checkbox) => checkbox.checked = false);
86 | }
87 |
88 | analyse() {
89 | let atLeastOneChecked = false;
90 | for (let i in this.analysisMethods)
91 | {
92 | const method = this.analysisMethods[i];
93 | const methodId = 'anal_' + method.id;
94 | const element = document.getElementById(methodId);
95 |
96 | if (element.checked) {
97 | r2.cmd(method.cmd);
98 | atLeastOneChecked = true;
99 | } else if (typeof method.disabledCmd !== 'undefined') {
100 | r2.cmd(method.cmd);
101 | }
102 | }
103 |
104 | if (atLeastOneChecked && typeof this.analysisCallback !== 'undefined') {
105 | this.analysisCallback();
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/www/p/gulpfile.js:
--------------------------------------------------------------------------------
1 | import { src, series, dest } from 'gulp';
2 | import gulp from 'gulp';
3 | import uglify from 'gulp-uglify';
4 | import concat from 'gulp-concat';
5 | import cleanCSS from 'gulp-clean-css';
6 |
7 | import bower from 'bower';
8 |
9 | var paths = {
10 | r2: '../lib/',
11 | dev: '../../dev/p/',
12 | dist: '../../dist/p/'
13 | };
14 |
15 | const _concatCommonJs = function() {
16 | return src(paths.r2 + '*.js')
17 | .pipe(concat('r2core.js'))
18 | .pipe(dest(paths.dev));
19 | }
20 | const _concatCommonCss = function() {
21 | return src(paths.r2 + '*.css')
22 | .pipe(concat('r2core.css'))
23 | .pipe(dest(paths.dev));
24 | }
25 |
26 | const _concatPanelJs = function() {
27 | return src('./lib/js/panels/*.js')
28 | .pipe(concat('panels.js'))
29 | .pipe(dest(paths.dev));
30 | }
31 | const _concatDepsJs = function() {
32 | return src('./lib/js/dependencies/*.js')
33 | .pipe(concat('dependencies.js'))
34 | .pipe(dest(paths.dev));
35 | }
36 | const _concatMainJs = function() {
37 | return src('./lib/js/*.js')
38 | .pipe(concat('main.js'))
39 | .pipe(dest(paths.dev));
40 | }
41 |
42 | const _common = series(
43 | _concatCommonJs,
44 | _concatCommonCss
45 | );
46 |
47 | const _js = series(
48 | _concatPanelJs,
49 | _concatDepsJs,
50 | _concatMainJs
51 | );
52 |
53 |
54 | const _watch = function() {
55 | gulp.watch('./*.html', ['html']);
56 | gulp.watch(['./lib/js/*.js'], ['js:main']);
57 | gulp.watch(['./lib/js/**/*.js'], ['js:app']);
58 | gulp.watch(['./lib/css/**/*.css'], ['js:css']);
59 | done();
60 | };
61 |
62 | const _css = function() {
63 |
64 | return src(['./lib/css/jquery-ui.css', './lib/css/tree.jquery.css'])
65 | .pipe(concat('dependencies.css'))
66 | .pipe(dest(paths.dev));
67 | };
68 |
69 | const _bowerInstall = function() {
70 | //return bower({ cmd: 'install'});
71 | return new Promise((resolve) => {
72 | bower.commands.install(undefined, undefined, {
73 | cwd: process.cwd()
74 | }).on('end', resolve);
75 | });
76 | };
77 |
78 |
79 | const _copyVendors = function() {
80 | // Moving neccesary vendors files from bower
81 | return src([
82 | 'vendors/jquery.layout/dist/layout-default-latest.css',
83 | 'vendors/jointjs/dist/joint.min.css',
84 | 'vendors/onoff/dist/jquery.onoff.css',
85 | 'vendors/jquery/dist/jquery.min.js',
86 | 'vendors/jquery.scrollTo/jquery.scrollTo.min.js',
87 | 'vendors/jquery.layout/dist/jquery.layout-latest.min.js',
88 | 'vendors/jquery-ui/jquery-ui.min.js',
89 | 'vendors/jquery-ui-contextmenu/jquery.ui-contextmenu.min.js',
90 | 'vendors/onoff/dist/jquery.onoff.min.js',
91 | 'vendors/lodash/lodash.min.js',
92 | 'vendors/backbone/backbone-min.js',
93 | 'vendors/graphlib/dist/graphlib.core.js',
94 | 'vendors/dagre/dist/dagre.core.js',
95 | 'vendors/jointjs/dist/joint.min.js',
96 | 'vendors/jointjs/dist/joint.layout.DirectedGraph.min.js'
97 | ])
98 | .pipe(dest(paths.dev+'vendors/'));
99 | };
100 |
101 | const _default = function() {
102 | return src(['./index.html', '*.png'])
103 | .pipe(dest(paths.dev));
104 | };
105 |
106 | const _releaseHtml = function() {
107 | return src([paths.dev + 'index.html', paths.dev + '*.png'])
108 | .pipe(dest(paths.dist));
109 | }
110 | const _releaseCss = function() {
111 | return src([paths.dev + '*.css'])
112 | .pipe(cleanCSS())
113 | .pipe(dest(paths.dist));
114 | }
115 | const _releaseJs = function() {
116 | return src([paths.dev + '*.js'])
117 | .pipe(uglify())
118 | .pipe(dest(paths.dist));
119 | }
120 | const _releaseVendor = function() {
121 | return src([paths.dev + 'vendors/*.*'])
122 | .pipe(dest(paths.dist + 'vendors/'));
123 | }
124 |
125 | const _release = series(
126 | _releaseHtml,
127 | _releaseCss,
128 | _releaseJs,
129 | _releaseVendor
130 | );
131 |
132 | export const defaultTask = series(_bowerInstall, _copyVendors, _js, _css, _common, _default);
133 | export default defaultTask;
134 | export const release = series(defaultTask, _release);
135 | export const watch = series(defaultTask, _watch);
136 |
137 |
138 |
--------------------------------------------------------------------------------
/www/lib/disasm.css:
--------------------------------------------------------------------------------
1 | .bbcanvas { float: left; }
2 |
3 | .flatcanvas { float: left; }
4 |
5 | .insaddr {
6 | min-width: 7em;
7 | display: inline-block;
8 | }
9 |
10 | #outergbox {
11 | position: absolute;
12 | height: 100%;
13 | width: 100%;
14 | }
15 |
16 | .instruction {
17 | font-family: monospace;
18 | white-space: nowrap;
19 | }
20 |
21 | .instructiondesc {
22 | display: inline-block;
23 | }
24 |
25 | .data {
26 | text-align: right;
27 | min-width: 18px;
28 | padding-top: 0px;
29 | padding-bottom: 0px;
30 | }
31 |
32 | .instructionbox {
33 | position: absolute;
34 | }
35 |
36 | #gbox {
37 | position: relative;
38 | /*margin: 10px;*/
39 | }
40 |
41 | .bytes {
42 | display: inline-block;
43 | width: 170px;
44 | }
45 |
46 | input:focus {outline: none; }
47 |
48 | .ec_fline {color: rgb(0,127,127);}
49 | .ec_help {color: rgb(0,127,127);}
50 | .ec_args {color: rgb(0,127,127);}
51 | .ec_label {color: rgb(0,127,127);}
52 | .ec_flow {color: rgb(0,127,127);}
53 | .ec_prompt {color: rgb(0,127,127);}
54 | .ec_input {color: rgb(0,127,127);}
55 | .ec_btext {color: rgb(0,127,127);}
56 | .ec_swi {color: rgb(0,127,127);}
57 | .ec_comment {color: rgb(0,127,127);}
58 | .ec_fname {color: rgb(127,0,0);}
59 | .ec_flag {color: rgb(0,127,127);}
60 | .ec_offset {color: rgb(0,127,0);}
61 | .ec_other {color: rgb(127,127,127);} /* byte color bu default */
62 | .ec_b0x00 {color: rgb(0,127,0);}
63 | .ec_b0x7f {color: rgb(0,127,127);}
64 | .ec_b0xff {color: rgb(127,0,0);}
65 | .ec_math {color: rgb(127,127,0);}
66 | .ec_bin {color: rgb(127,127,0);}
67 | .ec_push {color: rgb(127,0,127);}
68 | .ec_pop {color: rgb(255,0,255);}
69 | .ec_jmp {color: rgb(0,127,0);}
70 | .ec_cjmp {color: rgb(0,127,0);}
71 | .ec_call {color: rgb(0,255,0);}
72 | .ec_nop {color: rgb(0,0,127);}
73 | .ec_ret {color: rgb(127,0,0);}
74 | .ec_trap {color: rgb(255,0,0);}
75 | .ec_invalid {color: rgb(255,0,0);}
76 | .ec_cmp {color: rgb(0,127,127);}
77 | .ec_reg {color: rgb(0,127,127);} /* (also applies to qword, brackets, etc) */
78 | .ec_creg {color: rgb(0,127,127);}
79 | .ec_mov {color: rgb(127,127,127);}
80 | .ec_num {color: rgb(127,127,0);}
81 |
82 | .ec_gui_cflow {color: rgb(255,255,0);}
83 | .ec_gui_dataoffset {color: rgb(127,127,0);}
84 | .ec_gui_background {background-color: rgb(20,20,20); }
85 | .ec_gui_alt_background {background-color: rgb(50,50,50); }
86 | .ec_gui_border {border-color: rgb(50,50,50); }
87 |
88 | .autohighlight { background-color: #8AFF77 !important; }
89 | .autohighlighti { background-color: #8AFF77; }
90 |
91 | .hidden {display:none;}
92 |
93 | .lines {margin-left: 100px;}
94 |
95 | .basicblock {
96 | border: 1px solid;
97 | padding: 5px;
98 | position: absolute;
99 | pointer-events: none;
100 | -webkit-user-select: none;
101 | box-sizing: border-box;
102 | z-index: 2;
103 | }
104 |
105 | .basicblock .instruction,
106 | .basicblock input {
107 | pointer-events: auto;
108 | }
109 |
110 | #canvas {
111 | position: relative;
112 | display: inline-block;
113 | background: transparent;
114 | width:100%;
115 | height:100%;
116 | margin:10px;
117 | }
118 |
119 | #canvas svg,
120 | #minimap svg {
121 | background: transparent;
122 | }
123 |
124 | #minimap svg .link,
125 | #canvas svg .link {
126 | pointer-events: none;
127 | }
128 |
129 | #minimap svg .connection {
130 | stroke-width: 5;
131 | }
132 |
133 | #minimap {
134 | /*border: 1px solid black;*/
135 | position:absolute;
136 | width:200px;
137 | height:200px;
138 | z-index: 1000;
139 | background: #999;
140 | /*opacity: 0.8;*/
141 | filter: alpha(opacity=80); [> For IE8 and earlier <]
142 | }
143 |
144 | #minimap .basicblock {
145 | display: none;
146 | }
147 |
148 | #canvas #minimap_area {
149 | display: none;
150 | z-index: 0;
151 | }
152 |
153 | #canvas #minimap_area svg {
154 | stroke: transparent;
155 | }
156 |
157 | #minimap_area {
158 | border: 1px solid black;
159 | position:absolute;
160 | background: black;
161 | opacity: 0.2;
162 | filter: alpha(opacity=20); /* For IE8 and earlier */
163 | }
164 |
165 | #radareApp_mp_panels_pageDisassembler {
166 | padding: 0px;
167 | }
168 |
169 | #main_panel {
170 | overflow: auto;
171 | }
172 |
173 | .right_label {
174 | float: right;
175 | }
176 |
177 |
--------------------------------------------------------------------------------
/www/p/lib/js/panels/types_panel.js:
--------------------------------------------------------------------------------
1 | var TypesPanel = function() {
2 | this.data = [];
3 | this.optionSpacer = 300; //space in px for option buttons
4 | };
5 |
6 | TypesPanel.prototype.insertData = function(k, v, array) {
7 | if (typeof array === 'undefined') { array = this.data; };
8 | var kt = k[0].trim();
9 |
10 | if (k.length == 1) {
11 | //base case
12 | array.push({
13 | label: kt,
14 | id: kt,
15 | value: v
16 | });
17 | return;
18 | } else if (array.length < 1) {
19 | //if current part of k's path doesn't exist, create it
20 | array.push({
21 | label: kt ,
22 | children: []
23 | });
24 | this.insertData(k.slice(1), v, array[0].children);
25 | return;
26 | }
27 |
28 | //traverse already populated array to find right spot for insertion
29 | for (var i in array) {
30 | if (array[i].hasOwnProperty('label') && array[i].label === kt) {
31 | if (array[i].hasOwnProperty('children')) {
32 | this.insertData(k.slice(1), v, array[i].children);
33 | return;
34 | } else if (k.length > 1) {
35 | array[i].children = [];
36 | this.insertData(k.slice(1), v, array[i].children);
37 | return;
38 | }
39 | }
40 | }
41 |
42 | //was not found in array, create + traverse
43 | array.push({
44 | label: kt
45 | });
46 | if (k.length > 1) {
47 | array[array.length - 1].children = [];
48 | this.insertData(k.slice(1), v, array[array.length - 1].children);
49 | }
50 | };
51 |
52 | TypesPanel.prototype.generateContent = function() {
53 | var ref = this;
54 | r2.cmd('tk', function(result) {
55 | var strings = result.split('\n');
56 | for (var i in strings) {
57 | var s = strings[i].split('=');
58 |
59 | if (s.length < 2)
60 | continue;
61 |
62 | var k = s[0].split('.');
63 | var v = s[1];
64 |
65 | if (k.length < 2) {
66 | continue;
67 | }
68 |
69 | ref.insertData(k, v);
70 | }
71 | });
72 | };
73 |
74 | TypesPanel.prototype.createBarButtons = function() {
75 | var $bar = $('#typesButtonBar');
76 | var $addButton = $('');
77 | //Can only do files once we can resolve the non-sandboxed path
78 | //var $addFileButton = $('');
79 |
80 | $addButton.click(function() {
81 | var str = prompt('Enter C string:');
82 | r2.cmd('"td ' + str + '"', function() { r2ui._typ.render(); });
83 | });
84 |
85 | // $addFileButton.change(function() {
86 | // var val = $("#addFileButton").val();
87 | // r2.cmd('to ' + val, function() { r2ui._typ.render(); });
88 | // });
89 |
90 | $bar.append($addButton);
91 | // $bar.append($addFileButton);
92 |
93 | };
94 |
95 | TypesPanel.prototype.createTree = function() {
96 | var $tree = $('#types');
97 | $tree.tree({
98 | data: this.data,
99 | slide: false,
100 | autoOpen: 0,
101 | useContextMenu: false, //TODO custom context menu for add/remove/edit?
102 | selectable: false,
103 | onCreateLi: function(node, $li) {
104 | var app = '';
105 | if (typeof node.value !== 'undefined') {
106 | app += ' (' + node.value + ')';
107 | }
108 | if (node.getLevel() == 2) {
109 | //depth level 2 means we're dealing with an actual type
110 | var w = r2ui._typ.optionSpacer;
111 | if (node.children && node.children.length != 0) {
112 | w -= 5; //sub 5px to compensate for fold icon
113 | }
114 |
115 | var style = 'font-size: 80%; font-style: normal; font-family: monospace;' +
116 | ' cursor: pointer; position: absolute; left:' + w + 'px';
117 | app += '[-]';
119 | }
120 | $li.find('.jqtree-element').append(app);
121 | }
122 | });
123 |
124 | $tree.on('click', '.remove',
125 | function(e) {
126 | var label = $(e.target).data('node-name');
127 | r2.cmd('t- ' + label, function() { r2ui._typ.render(); });
128 | });
129 | };
130 |
131 | TypesPanel.prototype.render = function() {
132 | $('#types_tab').html(
133 | '' +
134 | '');
135 |
136 | this.createBarButtons();
137 |
138 | this.data = [];
139 | this.maxstr = 0;
140 | this.generateContent();
141 | this.createTree();
142 |
143 | };
144 |
--------------------------------------------------------------------------------