├── .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 ''$FILE'' 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 | 3 |
4 | 5 | 6 |
7 | 8 | 9 | -------------------------------------------------------------------------------- /www/enyo/README.md: -------------------------------------------------------------------------------- 1 | Enyo Radare2 WebUI 2 | ================== 3 | 4 | js/ 5 | Contains all webui specific javascript files 6 | css/ 7 | CSS files 8 | lib/ 9 | javascript libraries (jquery, enyo, ...) 10 | img/ 11 | images for this webui 12 | -------------------------------------------------------------------------------- /www/m/css/flexcontainer.css: -------------------------------------------------------------------------------- 1 | .flex-controls { 2 | height:50px; 3 | width:100%; 4 | overflow:auto; 5 | } 6 | 7 | .flex-body { 8 | position:absolute; 9 | bottom:0; 10 | top:50px; 11 | width:100%; 12 | overflow:auto; 13 | background:inherit; 14 | } -------------------------------------------------------------------------------- /www/enyo/js/search.js: -------------------------------------------------------------------------------- 1 | enyo.kind({ 2 | name: 'Search', 3 | kind: 'Scroller', 4 | style: 'background-color:#303030', 5 | components: [ 6 | {tag: 'center', components: [ 7 | {tag: 'h1', style: 'color:#f0f0f0', content: 'TODO: Search'} 8 | ]} 9 | ] 10 | }); 11 | -------------------------------------------------------------------------------- /www/enyo/js/debugger.js: -------------------------------------------------------------------------------- 1 | enyo.kind({ 2 | name: 'Debugger', 3 | kind: 'Scroller', 4 | style: 'background-color:#303030', 5 | components: [ 6 | {tag: 'center', components: [ 7 | {tag: 'h1', style: 'color:#f0f0f0', content: 'TODO: Debugger'} 8 | ]} 9 | ] 10 | }); 11 | -------------------------------------------------------------------------------- /www/w/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | r2 -q -e http.sandbox=false -e http.root=$$PWD/.. -e http.ui=w -c=H /bin/ls 3 | 4 | update: 5 | git clone https://github.com/jdan/98.css git-98-css 6 | mkdir -p git-98-css/node_modules 7 | cd git-98-css && npm i && npm run build 8 | cp git-98-css/dist/98.css 98.css 9 | -------------------------------------------------------------------------------- /www/m/js/helpers/project_management.legacy.js: -------------------------------------------------------------------------------- 1 | function saveProject() { 2 | r2.cmd('Ps', function() { 3 | alert('Project saved'); 4 | }); 5 | } 6 | function deleteProject() { 7 | alert('Project deleted'); 8 | location.href = 'open.html'; 9 | } 10 | function closeProject() { 11 | alert('Project closed'); 12 | location.href = 'open.html'; 13 | } 14 | -------------------------------------------------------------------------------- /www/m/test/specs/helpers/chai.js: -------------------------------------------------------------------------------- 1 | var chai = require('chai'); 2 | var sinonChai = require('sinon-chai'); 3 | 4 | global.sinon = require('sinon'); 5 | global.expect = chai.expect; 6 | global.Assert = chai.assert; 7 | global.sAssert = sinon.assert; 8 | 9 | chai.use(sinonChai); 10 | 11 | require('jsdom-global')(); 12 | 13 | require('../../../../../dev/m/app.js'); 14 | -------------------------------------------------------------------------------- /www/gulpfile.js: -------------------------------------------------------------------------------- 1 | // builds r2core.js from lib/*.js 2 | 3 | var gulp = require('gulp'), 4 | bower = require('gulp-bower'); 5 | 6 | var R2 = 'lib/'; 7 | var DEST = '../dist/' 8 | 9 | gulp.task('default', function() { 10 | gulp.src(['./*.html', '*.png', '*.svg', 'favicon.ico', R2+'*.js']) 11 | .pipe(gulp.dest(DEST)); 12 | 13 | return bower({ cmd: 'install'}); 14 | }); 15 | -------------------------------------------------------------------------------- /www/m/test/test.test.js: -------------------------------------------------------------------------------- 1 | describe('Module', function () { 2 | describe('Method', function () { 3 | 4 | it('Should...', function () { 5 | // Arrange 6 | var op = () => 1 + 2; 7 | var infScrolling = new InfiniteScrolling(document.body, 3, 0.2); 8 | 9 | // Act 10 | var result = op(); 11 | 12 | // Assert 13 | Assert.equal(result, 3); 14 | }); 15 | }); 16 | }); -------------------------------------------------------------------------------- /www/enyo/Makefile: -------------------------------------------------------------------------------- 1 | VERSION=0.1.2 2 | DISTZIP=radare2-webui-enyo-$(VERSION).zip 3 | 4 | 5 | build: 6 | npm install 7 | npx gulp 8 | 9 | run: build 10 | r2 -q -e http.ui=enyo -e http.sandbox=0 -e http.root=$(PWD)/../../dist -c=H /bin/ls 11 | 12 | watch: 13 | npx gulp watch 14 | 15 | dist: 16 | rm -f $(DISTZIP) 17 | cd ../../dist && zip -r $(DISTZIP) enyo 18 | 19 | clean: 20 | rm -rf node_modules 21 | rm -rf vendors 22 | -------------------------------------------------------------------------------- /www/graph/js-graph-it.css: -------------------------------------------------------------------------------- 1 | .draggable { 2 | position: absolute; 3 | cursor: move; 4 | z-index: 1; 5 | } 6 | 7 | .connector { 8 | background-color: red; 9 | } 10 | 11 | .dock_point { 12 | height: 1px; 13 | width: 1px; 14 | overflow: hidden; 15 | padding: 0px !important; 16 | border: none !important; 17 | margin: 0px !important; 18 | position: absolute; 19 | font-size: 1px; 20 | visibility: hidden; 21 | } 22 | -------------------------------------------------------------------------------- /www/old/script.js: -------------------------------------------------------------------------------- 1 | function Ajax (method, uri, body, fn) { 2 | var x = new XMLHttpRequest (); 3 | x.open (method, uri, false); 4 | x.onreadystatechange = function (y) { 5 | if (fn) fn (x.responseText); 6 | } 7 | x.send (body); 8 | } 9 | 10 | function r_core_cmd_str (x, cb) { 11 | Ajax ("POST", "?setComment="+hwid, cmt, function (x) { 12 | alert (x); 13 | /* force refresh */ 14 | location.reload (true); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | --- 2 | engines: 3 | csslint: 4 | enabled: true 5 | duplication: 6 | enabled: true 7 | config: 8 | languages: 9 | - javascript 10 | eslint: 11 | enabled: true 12 | fixme: 13 | enabled: true 14 | ratings: 15 | paths: 16 | - "**.css" 17 | - "**.js" 18 | exclude_paths: 19 | - "www/enyo/css/enyo/enyo.css" 20 | - "www/enyo/js/enyo/enyo.js" 21 | - "www/enyo/js/enyo/app.js" 22 | - "www/graph/js-graph-it.js" 23 | - "**/gulpfile.js" 24 | -------------------------------------------------------------------------------- /www/m/js/helpers/UpdateManager.js: -------------------------------------------------------------------------------- 1 | export class UpdateManager { 2 | 3 | constructor() { 4 | this.updateMethods = [{}, {}]; 5 | this.currentFocus; 6 | } 7 | 8 | registerMethod(offset, method) { 9 | this.updateMethods[offset] = method; 10 | } 11 | 12 | focusHasChanged(offset) { 13 | this.currentFocus = offset; 14 | } 15 | 16 | apply() { 17 | if (typeof this.currentFocus === 'undefined') { 18 | return; 19 | } 20 | this.updateMethods[this.currentFocus](); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /www/m/css/overview.css: -------------------------------------------------------------------------------- 1 | @media (max-width: 1024px) { 2 | div.overview-tabs > a { 3 | padding:0 1vw; 4 | } 5 | } 6 | 7 | dl.infocard { 8 | -webkit-column-count: 2; 9 | -moz-column-count: 2; 10 | column-count: 2; 11 | } 12 | 13 | dl.infocard dt { 14 | float: left; 15 | font-weight: bold; 16 | text-align: right; 17 | margin-right: 10px; 18 | padding: 3px; 19 | width: 100px; 20 | } 21 | 22 | dl.infocard dd { 23 | margin: 2px 0; 24 | padding: 3px 0; 25 | } -------------------------------------------------------------------------------- /www/p/Makefile: -------------------------------------------------------------------------------- 1 | VERSION=0.1.1 2 | DISTZIP=radare2-webui-p-$(VERSION).zip 3 | 4 | build: node_modules 5 | npx gulp 6 | 7 | node_modules: 8 | npm install 9 | 10 | dist release: 11 | npm install 12 | npx gulp release 13 | rm -f $(DISTZIP) 14 | cd ../../dist && zip -r $(DISTZIP) p 15 | 16 | all: build 17 | 18 | run: 19 | r2 -q -e scr.html=0 -e http.sandbox=false -e http.ui=p -e http.root=$(PWD)/../../dev -c=H /bin/ls 20 | 21 | watch: 22 | npx gulp watch 23 | 24 | indent: 25 | # TODO: use semistandard 26 | jsfmt -w lib/js/*.js 27 | -------------------------------------------------------------------------------- /www/m/manifest.webapp: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "radare2", 3 | "description": "Material Remote Web UI for radare2", 4 | "version" : "0.2", 5 | "default_locale" : "en", 6 | "type" : "privileged", 7 | "developer" : { 8 | "name" : "pancake", 9 | "url" : "http://github.com/radare/radare2/" 10 | }, 11 | "permissions" : { 12 | "systemXHR": { 13 | "description": "communicate with remote r2 servers" 14 | } 15 | }, 16 | "launch_path" : "/index.html", 17 | "icons" : { 18 | "256" : "/images/rlogo256.png" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /www/m/js/helpers/Speak.js: -------------------------------------------------------------------------------- 1 | import {r2Settings} from '../core/R2Wrapper'; 2 | 3 | export function speak(text, callback) { 4 | if (!r2Settings.getItem(r2Settings.keys.USE_TTS)) { 5 | return; 6 | } 7 | 8 | if (typeof SpeechSynthesisUtterance === 'undefined') { 9 | return; 10 | } 11 | 12 | var u = new SpeechSynthesisUtterance(); 13 | u.text = text; 14 | u.lang = 'en-US'; 15 | 16 | u.onend = function() { 17 | if (callback) { 18 | callback(); 19 | } 20 | }; 21 | 22 | u.onerror = function(e) { 23 | if (callback) { 24 | callback(e); 25 | } 26 | }; 27 | 28 | speechSynthesis.speak(u); 29 | } 30 | -------------------------------------------------------------------------------- /www/m/js/widgets/DisassemblyBlocksWidget.js: -------------------------------------------------------------------------------- 1 | import {BasePreWidget} from './BasePreWidget'; 2 | import {Inputs} from '../helpers/Inputs'; 3 | 4 | import {uiContext} from '../core/UIContext'; 5 | import {Widgets} from './Widgets'; 6 | import {formatOffsets} from '../helpers/Format'; 7 | 8 | const inColor = true; // TODO inColor 9 | 10 | export class DisassemblyBlocksWidget extends BasePreWidget { 11 | constructor() { 12 | super( 13 | 'Blocks', 14 | x => formatOffsets(x), 15 | 'pdr|H', 16 | Inputs.iconButton('undo', 'Back to Disassembly', () => uiContext.navigateTo(Widgets.DISASSEMBLY))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/enyo/js/config.js: -------------------------------------------------------------------------------- 1 | var Config = { 2 | 'keys': { 3 | '1': 'this.setIndex(0)', 4 | '2': 'this.setIndex(1)', 5 | '3': 'this.setIndex(2)' 6 | // Most of this keya are used in disassembly so it makes no sense leaving the rest. maybe moving around with numbers 7 | //"d": "r2ui.openpage(0)", 8 | // "a": "r2ui.openpage(1)", 9 | //"h": "r2ui.openpage(2)", 10 | //"g": "r2ui.openpage(3)", 11 | //"c": "r2ui.openpage(5)", 12 | // "s": "r2ui.openpage(8)", 13 | // Moved to disassembled panel 14 | //";": "r2.cmd('CC '+prompt('comment'));r2ui.seek('$$',false);", 15 | //"C-3": "this.setIndex(2)", 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /www/m/js/widgets/DisassemblyDecompileWidget.js: -------------------------------------------------------------------------------- 1 | import {BasePreWidget} from './BasePreWidget'; 2 | import {Inputs} from '../helpers/Inputs'; 3 | 4 | import {uiContext} from '../core/UIContext'; 5 | import {Widgets} from './Widgets'; 6 | import {formatOffsets} from '../helpers/Format'; 7 | 8 | const inColor = true; // TODO inColor 9 | 10 | export class DisassemblyDecompileWidget extends BasePreWidget { 11 | constructor() { 12 | super( 13 | 'Decompile', 14 | x => formatOffsets(x), 15 | 'pdc|H', 16 | Inputs.iconButton('undo', 'Back to Disassembly', () => uiContext.navigateTo(Widgets.DISASSEMBLY))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/bolt/r2bolt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # arg1 = compiler+flags 3 | # arg2 = base64(source) 4 | 5 | if [ -z "$1" ]; then 6 | CC="gcc -S" 7 | else 8 | CC="`rax2 -D $1`" 9 | fi 10 | if [ -z "$2" ]; then 11 | CS="main() {}" 12 | else 13 | CS="`rax2 -D $2`" 14 | fi 15 | 16 | USE_R2=1 17 | if [ "$USE_R2" = 1 ]; then 18 | echo "$CS" > .a.c 19 | gcc -o a.out .a.c 20 | # r2 -qcq -e scr.color=0 -e asm.lines=0 -e asm.bytes=0 -c'pD $SS@$S;aa;agf' a.out 21 | r2 -qcq -e scr.color=0 -e asm.lines=0 -e asm.bytes=0 -c'af;agf' a.out 22 | rm -f .a.c a.out 23 | else 24 | echo "$CS" > .a.c 25 | $CC .a.c 26 | cat .a.s 27 | rm -f .a.s .a.c 28 | fi 29 | -------------------------------------------------------------------------------- /www/t/README.md: -------------------------------------------------------------------------------- 1 | Tiled r2 webui 2 | ============== 3 | 4 | widgets required 5 | ---------------- 6 | 7 | notes: notepad with textarea to put your notes there 8 | disasm: proper disasm widget 9 | hexdump: proper hexdump widget 10 | assemble: assemble instructions 11 | console: 12 | scrips: 13 | floating/modal frame. invalidating the rest. 14 | 15 | features 16 | -------- 17 | follow in -> 18 | 19 | Frames must have the following properties: 20 | - update() -> refresh the contents (run r2 command again, generate html, etc.) 21 | - seek(off) -> used by follow in... 22 | - selected 23 | - name -> we need a method to rename frames 24 | -------------------------------------------------------------------------------- /www/enyo/js/graph.js: -------------------------------------------------------------------------------- 1 | enyo.kind({ 2 | name: 'Graph', 3 | kind: 'Scroller', 4 | style: 'background-color:#c0c0c0', 5 | components: [ 6 | {tag: 'h2', content: 'Open graph', style: 'margin-left:10px;'}, 7 | {kind: 'Group', classes: 'enyo-border-box group', defaultKind: 'onyx.Button', components: [ 8 | {content: 'Basic blocks', classes: 'onyx-dark menu-button', ontap: 'openGraphBB' }, 9 | {content: 'Callgraph', classes: 'onyx-dark menu-button', ontap: 'openGraphCG' } 10 | ]} 11 | ], 12 | openGraphBB: function() { 13 | window.open('/graph/', '_self'); 14 | }, 15 | openGraphCG: function() { 16 | window.open('/d3/', '_self'); 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /www/m/css/material-design-icons.css: -------------------------------------------------------------------------------- 1 | /* Rules for sizing the icon. */ 2 | .material-icons.md-18 { font-size: 18px; } 3 | .material-icons.md-24 { font-size: 24px; } 4 | .material-icons.md-36 { font-size: 36px; } 5 | .material-icons.md-48 { font-size: 48px; } 6 | 7 | /* Rules for using icons as black on a light background. */ 8 | .material-icons.md-dark { color: rgba(0, 0, 0, 0.54); } 9 | .material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); } 10 | 11 | /* Rules for using icons as white on a dark background. */ 12 | .material-icons.md-light { color: rgba(255, 255, 255, 0.6); } 13 | .material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); } -------------------------------------------------------------------------------- /www/m/js/widgets/DisassemblyFunctionsFullWidget.js: -------------------------------------------------------------------------------- 1 | import {BasePreWidget} from './BasePreWidget'; 2 | import {Inputs} from '../helpers/Inputs'; 3 | 4 | import {uiContext} from '../core/UIContext'; 5 | import {Widgets} from './Widgets'; 6 | import {formatOffsets} from '../helpers/Format'; 7 | 8 | const inColor = true; // TODO inColor 9 | 10 | export class DisassemblyFunctionsFullWidget extends BasePreWidget { 11 | constructor() { 12 | super( 13 | 'Functions (full)', 14 | x => formatOffsets(x), 15 | 'pD $SS@$S@e:scr.color=2', 16 | Inputs.iconButton('undo', 'Back to Disassembly', () => uiContext.navigateTo(Widgets.DISASSEMBLY))); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /www/m/js/widgets/DisassemblyInfosWidget.js: -------------------------------------------------------------------------------- 1 | import {BasePreWidget} from './BasePreWidget'; 2 | import {Inputs} from '../helpers/Inputs'; 3 | 4 | import {uiContext} from '../core/UIContext'; 5 | import {Widgets} from './Widgets'; 6 | 7 | const inColor = true; // TODO inColor 8 | 9 | export class DisassemblyInfosWidget extends BasePreWidget { 10 | constructor() { 11 | super( 12 | 'Infos', 13 | x => { 14 | const container = document.createElement('span'); 15 | container.innerHTML = x; 16 | return container; 17 | }, 'afi', 18 | Inputs.iconButton('undo', 'Back to Disassembly', () => uiContext.navigateTo(Widgets.DISASSEMBLY))); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /www/m/js/widgets/Widgets.js: -------------------------------------------------------------------------------- 1 | export const Widgets = { 2 | OVERVIEW: 'overview', 3 | DISASSEMBLY: 'disassembly', 4 | DISASSEMBLY_GRAPH: 'disasm_graph', 5 | DISASSEMBLY_INFOS: 'disasm_infos', 6 | DISASSEMBLY_INFOS_FULL: 'disasm_infos_full', 7 | DISASSEMBLY_FUNCTIONS: 'disasm_functions', 8 | DISASSEMBLY_BLOCKS: 'disasm_blocks', 9 | DISASSEMBLY_DECOMPILE: 'disasm_decompile', 10 | HEXDUMP: 'hexdump', 11 | DEBUGGER: 'debugger', 12 | FUNCTIONS: 'functions', 13 | CLASSES: 'classes', 14 | FLAGS: 'flags', 15 | FLAGS_SPACE: 'flags_space', 16 | SEARCH: 'search', 17 | SCRIPTS: 'scripts', 18 | COMMENTS: 'comments', 19 | NOTES: 'notes', 20 | SETTINGS: 'settings' 21 | } 22 | -------------------------------------------------------------------------------- /www/enyo/DEPENDENCIES: -------------------------------------------------------------------------------- 1 | Dependencies are handled by both bower and gulp. Gulp has the responsability to run bower. 2 | 3 | Makefile is still available (runs gulp). 4 | 5 | 6 | Special case for enyo! Dependencies were broken, I've copied the version from radare2 repository. I've made some researches about the official enyo repository but the four files (enyo.js/css and app.js/css) were extracted from an example and not from the official repository. There is some incompatibilities when an other version of enyo is downloaded (I've checked several versions around the date of the radare2 last commit about those files). So, for now, I've inserted them in the repository waiting for a better solution. 7 | -------------------------------------------------------------------------------- /www/m/js/widgets/DisassemblyFunctionsWidget.js: -------------------------------------------------------------------------------- 1 | import {BasePreWidget} from './BasePreWidget'; 2 | import {Inputs} from '../helpers/Inputs'; 3 | 4 | import {uiContext} from '../core/UIContext'; 5 | import {Widgets} from './Widgets'; 6 | 7 | const inColor = true; // TODO inColor 8 | 9 | export class DisassemblyFunctionsWidget extends BasePreWidget { 10 | constructor() { 11 | super( 12 | 'Functions', 13 | x => { 14 | const container = document.createElement('span'); 15 | container.innerHTML = x; 16 | return container; 17 | }, 18 | 'pdf @e:asm.lines.width=0|H', 19 | Inputs.iconButton('undo', 'Back to Disassembly', () => uiContext.navigateTo(Widgets.DISASSEMBLY))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /www/p/lib/js/panels/settings_panel.js: -------------------------------------------------------------------------------- 1 | // SETTINGS PANEL 2 | var SettingsPanel = function() { 3 | }; 4 | 5 | SettingsPanel.prototype.render = function() { 6 | var colors = '

Colors:



'; 7 | var settings = '

Settings:


'; 8 | settings += '
Test:
'; 9 | settings += '

'; 10 | settings += '
'; 11 | var html = settings + colors; 12 | $('#settings_tab').html(html); 13 | $('#settings_tab').css('color', 'rgb(127,127,127);'); 14 | $('input[type=checkbox]').onoff(); 15 | }; 16 | -------------------------------------------------------------------------------- /www/m/js/modules/hexdump/tools.legacy.js: -------------------------------------------------------------------------------- 1 | function hexPairToASCII(pair) { 2 | var chr = parseInt(pair, 16); 3 | if (chr >= 33 && chr <= 126) { 4 | return String.fromCharCode(chr); 5 | } 6 | 7 | return '.'; 8 | }; 9 | 10 | function ASCIIToHexpair(ascii) { 11 | var hex = ascii.charCodeAt(0).toString(16); 12 | if (hex.length < 2) { 13 | hex = '0' + hex; 14 | } 15 | 16 | return hex; 17 | }; 18 | 19 | function isAsciiVisible(offset) { 20 | return (offset >= 33 && offset <= 126); 21 | } 22 | 23 | function basename(path) { 24 | return path.split(/[\\/]/).pop(); 25 | } 26 | 27 | function int2fixedHex(nb, length) { 28 | var hex = nb.toString(16); 29 | while (hex.length < length) { 30 | hex = '0' + hex; 31 | } 32 | return '0x' + hex; 33 | } 34 | -------------------------------------------------------------------------------- /www/enyo/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enyo", 3 | "main": "main.js", 4 | "homepage": "https://github.com/radare/radare2", 5 | "authors": [ 6 | "pancake " 7 | ], 8 | "description": "enyo ui for radare2", 9 | "moduleType": [], 10 | "license": "MIT", 11 | "ignore": [ 12 | "**/.*", 13 | "node_modules", 14 | "bower_components", 15 | "test", 16 | "tests" 17 | ], 18 | "dependencies": { 19 | "enyo": "git://github.com/enyojs/enyo#86fb4f6ec0d52a05cf5324cbc630c2fce4880e67", 20 | "jquery": "^2.2.1", 21 | "jquery.scrollTo": "^2.1.2", 22 | "backbone": "^1.3.3", 23 | "jointjs": "joint#^0.9.7", 24 | "jquery.layout": "*", 25 | "jquery-ui": "^1.11.4", 26 | "lodash": "^4.17.21" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /www/log.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | r2 log chat 4 | 5 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /www/m/js/helpers/tools.legacy.js: -------------------------------------------------------------------------------- 1 | function E(x) { 2 | return document.getElementById(x); 3 | } 4 | 5 | function encode(r) { 6 | return r.replace(/[\x26\x0A\<>'"]/g, function(r) { return '&#' + r.charCodeAt(0) + ';';}); 7 | } 8 | 9 | function clickableOffsets(x) { 10 | console.error('Using clickableOffsets(str) no longer work'); 11 | console.trace(); 12 | x = x.replace(/0x([a-zA-Z0-9]*)/g, 13 | '0x$1'); 14 | x = x.replace(/sym\.([\.a-zA-Z0-9_]*)/g, 15 | 'sym.$1'); 16 | x = x.replace(/fcn\.([\.a-zA-Z0-9_]*)/g, 17 | 'fcn.$1'); 18 | x = x.replace(/str\.([\.a-zA-Z0-9_]*)/g, 19 | 'str.$1'); 20 | return x; 21 | } 22 | -------------------------------------------------------------------------------- /cherrypull.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ "$1" = git ] && shift 4 | [ "$1" = pull ] && shift 5 | 6 | RR=$1 7 | RB=$2 8 | N=$3 9 | 10 | if ! git diff --exit-code >/dev/null 2>&1; then 11 | echo "ERROR: There are local changes that must be commited or reseted" 12 | echo "ERROR: Cherrypulling process stopped to avoid data loss." 13 | exit 1 14 | fi 15 | 16 | if test -z "$N"; then 17 | echo "Usage: sys/cherrypull.sh [url] [branch] [ncommits]" 18 | exit 1 19 | fi 20 | 21 | git branch -D branch 22 | git checkout -b branch 23 | git reset --hard @~10 24 | git pull $RR $RB 25 | C=`git log | grep ^commit | head -n $N | cut -d ' ' -f2` 26 | RC="" 27 | git checkout master 28 | for a in $C ; do 29 | RC="$a $RC" 30 | done 31 | for a in $RC ; do 32 | git cherry-pick $a 33 | done 34 | git branch -D branch 35 | -------------------------------------------------------------------------------- /www/t/gulpfile.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import tar from 'gulp-tar'; 3 | import uglify from 'gulp-uglify'; 4 | import cleanCSS from 'gulp-clean-css'; 5 | import concat from 'gulp-concat'; 6 | import gulpUtil from 'gulp-util'; 7 | 8 | const R2 = '../lib/'; 9 | const DEST = '../../dist/t/' 10 | 11 | gulp.task('default', async function() { 12 | await gulp.src(['js/tiled.js', 'js/modals.js', R2 + 'r2.js', 'js/main.js']) 13 | // .pipe(uglify()) 14 | .pipe(uglify().on('error', gulpUtil.log)) 15 | .pipe(concat('app.js')) 16 | .pipe(gulp.dest(DEST)); 17 | 18 | await gulp.src(['css/*.css']) 19 | .pipe(cleanCSS()) 20 | .pipe(concat('stylesheet.css')) 21 | .pipe(gulp.dest(DEST)); 22 | 23 | return gulp.src(['./index.html', './rlogo.png']) 24 | .pipe(gulp.dest(DEST)); 25 | }); 26 | -------------------------------------------------------------------------------- /www/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 | "dependencies": {}, 10 | "description": "Collection of radare2 web user interfaces", 11 | "homepage": "https://radare.org", 12 | "license": "MIT", 13 | "maintainers": [ 14 | { 15 | "name": "pancake", 16 | "email": "pancake@nopcode.org" 17 | } 18 | ], 19 | "name": "radare2-webui-enyo", 20 | "repository": { 21 | "type": "git", 22 | "url": "git://github.com/radare/radare2-webui.git" 23 | }, 24 | "scripts": {}, 25 | "version": "0.10.2", 26 | "devDependencies": { 27 | "bower": "*", 28 | "gulp": "^3.9.1", 29 | "gulp-bower": "0.0.13" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /www/m/css/terminal.css: -------------------------------------------------------------------------------- 1 | .terminal { 2 | left: 5; 3 | right: 5; 4 | width: 100%; 5 | border-radius: 10px; 6 | background-color: black; 7 | font-family: "Roboto Mono", monospace; 8 | color: white; 9 | } 10 | 11 | .terminal_output { 12 | border-radius: 10px; 13 | overflow:scroll; 14 | width: 100%; 15 | font-family: "Roboto Mono", monospace; 16 | color: white; 17 | white-space: pre-wrap; 18 | padding-bottom: 2em; 19 | } 20 | 21 | .terminal_prompt { 22 | overflow: hidden; 23 | background-color: red; 24 | } 25 | 26 | .terminal_input { 27 | border: 2px solid #238082; 28 | position: fixed; 29 | bottom: 0em; 30 | height: 2em; 31 | color: white; 32 | background-color: black; 33 | font-size: 1.2em; 34 | width: 100%; 35 | overflow: hidden; 36 | font-family: "Roboto Mono", monospace; 37 | } 38 | -------------------------------------------------------------------------------- /www/m/css/autocomplete.css: -------------------------------------------------------------------------------- 1 | div.mydropdown > div > .ddcontent { 2 | display: none; 3 | position: absolute; 4 | right:0; 5 | background-color: #f9f9f9; 6 | box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); 7 | width: 400px; 8 | margin:0; 9 | padding:0; 10 | } 11 | 12 | div.mydropdown, div.mydropdown div { 13 | margin: 0; 14 | min-width: 0; 15 | } 16 | 17 | div.mydropdown.is-focused > div { 18 | padding:0; 19 | margin-left:12px; 20 | } 21 | 22 | ul.ddcontent li { 23 | display:block; 24 | padding:5px 10px; 25 | margin:0; 26 | border-bottom: 1px solid silver; 27 | overflow: hidden; 28 | font-family: "DejaVu Sans Mono"; 29 | font-size:11px; 30 | } 31 | 32 | ul.ddcontent li.active { 33 | background-color: #eeeeee; 34 | } 35 | 36 | ul.ddcontent li:last-child { 37 | border:none; 38 | } 39 | -------------------------------------------------------------------------------- /www/m/js/widgets/OverviewWidget.js: -------------------------------------------------------------------------------- 1 | import { BaseWidget } from './BaseWidget'; 2 | import { Overview } from '../modules/overview/Overview' 3 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper'; 4 | 5 | /** 6 | * @class OverviewWidget 7 | * @extends {BaseWidget} 8 | */ 9 | export class OverviewWidget extends BaseWidget { 10 | 11 | /** Creates an instance of OverviewWidget */ 12 | constructor() { 13 | super('Overview'); 14 | } 15 | 16 | /** @override*/ 17 | init() { 18 | this.overview = new Overview(); 19 | r2Wrapper.registerListener(R2Actions.SEEK, () => { 20 | if (this.displayed) { 21 | this.draw(); 22 | } 23 | }); 24 | } 25 | 26 | /** @override*/ 27 | draw(...args) { 28 | this.node.appendChild(this.overview.DOM); 29 | this.overview.adjustLayout(); 30 | componentHandler.upgradeDom(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /www/m/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es6": true 6 | }, 7 | "globals": { 8 | "r2": true, 9 | "componentHandler": true 10 | }, 11 | "rules": { 12 | "indent": ["error", "tab"], 13 | "eol-last": ["error", "always"], 14 | "no-undefined": 2, 15 | "no-undef": 2, 16 | "eqeqeq": ["error", "always", {"null": "ignore"}], 17 | "quotes": ["warn", "single"], 18 | "require-jsdoc": ["warn", { 19 | "require": { 20 | "FunctionDeclaration": true, 21 | "MethodDefinition": true, 22 | "ClassDeclaration": true 23 | } 24 | }] 25 | }, 26 | "parserOptions": { 27 | "ecmaVersion": 6, 28 | "sourceType": "module" 29 | }, 30 | "parser": "babel-eslint", 31 | "parserOptions": { 32 | "sourceType": "module", 33 | "allowImportExportEverywhere": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /www/m/css/console.css: -------------------------------------------------------------------------------- 1 | .console_terminal { 2 | left: auto; 3 | margin: auto; 4 | border-left: 5px; 5 | border-right: 5px; 6 | border-radius: 10px; 7 | background-color:black; 8 | font-family: monospace; 9 | color:white; 10 | } 11 | .console_output { 12 | background-color: black; 13 | border-radius: 10px; 14 | font-family: monospace; 15 | color: white; 16 | white-space: pre-wrap; 17 | } 18 | .console_input { 19 | color: white !important; 20 | border: none; 21 | position:absolute; 22 | background: transparent !important; 23 | padding-left:20px; 24 | width:100%; 25 | margin-left:-20px; 26 | overflow:hidden; 27 | font-family: monospace; 28 | height:1.5em; 29 | } 30 | .console_prompt { 31 | overflow:hidden; 32 | } 33 | -------------------------------------------------------------------------------- /www/graph/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | r2 code graph 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 |
23 |

back

24 | 25 | 26 | -------------------------------------------------------------------------------- /www/m/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mocha Tests 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /www/p/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "panel", 3 | "main": "main.js", 4 | "homepage": "https://github.com/radare/radare2", 5 | "authors": [ 6 | "pwntester " 7 | ], 8 | "description": "Panel ui for radare2", 9 | "moduleType": [], 10 | "license": "MIT", 11 | "ignore": [ 12 | "**/.*", 13 | "node_modules", 14 | "bower_components", 15 | "test", 16 | "tests" 17 | ], 18 | "dependencies": { 19 | "jquery": "3.6.1", 20 | "jquery-ui": "1.12.1", 21 | "jquery.scrollTo": "2.1.3", 22 | "jquery.layout": "*", 23 | "backbone": "1.4.1", 24 | "jointjs": "joint#1.0.3", 25 | "graphlib": "^1.0.5", 26 | "dagre": "0.7.4", 27 | "onoff": "jquery.onoff#0.3.6", 28 | "jquery-ui-contextmenu": "mar10/jquery-ui-contextmenu#6a185167e1c7b5de6e8b85eebca12465f1265ca4" 29 | }, 30 | "resolutions": { 31 | "jquery": "2.2.4" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /www/m/js/widgets/DisassemblyWidget.js: -------------------------------------------------------------------------------- 1 | import {BaseWidget} from './BaseWidget'; 2 | import {Disassembly} from '../modules/disasm/Disassembly'; 3 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper'; 4 | 5 | export class DisassemblyWidget extends BaseWidget { 6 | 7 | constructor() { 8 | super('Disassembly', 'disasmPanel', 'dark'); 9 | } 10 | 11 | init() { 12 | this.firstTime = true; 13 | } 14 | 15 | draw() { 16 | if (this.firstTime) { 17 | this.disasm = new Disassembly(this.node, 24); 18 | r2Wrapper.registerListener(R2Actions.SEEK, () => { 19 | if (!this.displayed) return; 20 | this.disasm.refreshInitialOffset(); 21 | this.disasm.resetContainer(this.node); 22 | this.disasm.draw(); 23 | this.disasm.onSeek(); 24 | }); 25 | this.firstTime = false; 26 | } else { 27 | this.disasm.resetContainer(this.node); 28 | } 29 | 30 | this.disasm.draw(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /www/enyo/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": "Collection of radare2 web user interfaces", 10 | "homepage": "https://radare.org", 11 | "license": "MIT", 12 | "maintainers": [ 13 | { 14 | "name": "pancake", 15 | "email": "pancake@nopcode.org" 16 | } 17 | ], 18 | "name": "radare2-webui-enyo", 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/radare/radare2-webui.git" 22 | }, 23 | "scripts": {}, 24 | "version": "0.10.2", 25 | "devDependencies": { 26 | "bower": "^1.8.0", 27 | "gulp": "^4.0.2", 28 | "gulp-bower": "0.0.13", 29 | "gulp-clean-css": "^3.9.0", 30 | "gulp-concat": "^2.6.1", 31 | "gulp-replace": "^0.6.1", 32 | "gulp-uglify": "^3.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /www/p/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "pwntester", 4 | "email": "alvaro@pwntester" 5 | }, 6 | "bugs": { 7 | "url": "https://github.com/radare/radare2-webui" 8 | }, 9 | "description": "Panel UI for radare2", 10 | "homepage": "https://radare.org", 11 | "type": "module", 12 | "license": "MIT", 13 | "maintainers": [ 14 | { 15 | "name": "pancake", 16 | "email": "pancake@nopcode.org" 17 | } 18 | ], 19 | "name": "radare2-webui-enyo", 20 | "repository": { 21 | "type": "git", 22 | "url": "git://github.com/radare/radare2-webui.git" 23 | }, 24 | "scripts": {}, 25 | "version": "0.10.2", 26 | "devDependencies": { 27 | "bower": "^1.8.0", 28 | "gulp": "^5.0.0", 29 | "gulp-clean-css": "^4.3.0", 30 | "gulp-concat": "^2.6.1", 31 | "gulp-uglify": "^3.0.0" 32 | }, 33 | "dependencies": { 34 | "jquery-ui": "^1.14.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /www/t/Makefile: -------------------------------------------------------------------------------- 1 | VERSION=0.1.1 2 | NPMBIN=node_modules/.bin 3 | 4 | GLOBALS= 5 | GLOBALS+=--global _ 6 | GLOBALS+=--global r2 7 | GLOBALS+=--global alert 8 | GLOBALS+=--global prompt 9 | GLOBALS+=--global Tiled 10 | GLOBALS+=--global html 11 | 12 | DISTZIP=radare2-webui-t-$(VERSION).zip 13 | 14 | all: build 15 | $(MAKE) dist 16 | 17 | node_modules: 18 | npm install 19 | 20 | build: node_modules 21 | mkdir -p dist/t 22 | rm -rf dist 23 | $(NPMBIN)/gulp 24 | 25 | dist: 26 | rm -f $(DISTZIP) 27 | cd ../../dist && zip -r $(DISTZIP) t 28 | 29 | run: dist 30 | # r2 -e http.ui=dist -e http.root=$$PWD -qc=H /bin/ls 31 | (sleep 1 && open http://localhost:9090/t) & 32 | r2 -qcq -e http.verbose=true -e http.root=$$PWD/../../dist -e http.ui=t -e http.sandbox=0 -c=H /bin/ls 33 | 34 | watch: 35 | #$(shell npm bin)/gulp watch 36 | $(NPMBIN)/gulp watch 37 | 38 | mrproper: clean 39 | rm -rf node_modules 40 | 41 | 42 | indent: 43 | $(NPMBIN)/semistandard $(GLOBALS) --fix js/*.js 44 | -------------------------------------------------------------------------------- /www/bolt/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 34 | 35 | 36 |
23 | 24 |
28 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /www/enyo/js/about.js: -------------------------------------------------------------------------------- 1 | enyo.kind({ 2 | name: 'About', 3 | kind: 'Scroller', 4 | style: 'background-color:#303030', 5 | components: [ 6 | {tag: 'center', components: [ 7 | {tag: 'h1', style: 'color:#f0f0f0', content: 'r2wui'}, 8 | {kind: 'Image', src: 'icon.png'}, 9 | {tag: 'h3', style: 'color:#707070;margin-bottom:50px', 10 | content: 'the web frontend for radare2'}, 11 | {tag: 'h2', style: 'color:#a0a0a0', content: 'author: pancake 2013-2024'}, 12 | {tag: 'h2', style: 'color:#a0a0a0', content: 'version: ???', name: 'vertext'}, 13 | {tag: 'h2', style: 'color:#a0a0a0', content: 'revision: ???', name: 'revtext'} 14 | ]} 15 | ], 16 | create: function() { 17 | this.inherited(arguments); 18 | (function(me) { 19 | setTimeout(function() { 20 | r2.cmd('?V', function(v) { 21 | var version = v.split(' ')[0]; 22 | var revision = v.split(' ')[2]; 23 | me.$.vertext.setContent('version: ' + version); 24 | me.$.revtext.setContent('revision: ' + revision); 25 | }); 26 | }, 1000); 27 | })(this); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /www/m/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "command": "gulp", 6 | "isShellCommand": true, 7 | "args": [], 8 | "tasks": [ 9 | { 10 | "taskName": "build", 11 | "args": [], 12 | "isBuildCommand": true, 13 | "isBackground": false, 14 | "problemMatcher": [ 15 | "$lessCompile", 16 | "$tsc", 17 | "$jshint" 18 | ] 19 | }, 20 | { 21 | "taskName": "watch", 22 | "args": [], 23 | "isBuildCommand": true, 24 | "isBackground": true, 25 | "problemMatcher": [ 26 | "$lessCompile", 27 | "$tsc", 28 | "$jshint" 29 | ] 30 | }, 31 | { 32 | "taskName": "test", 33 | "args": [], 34 | "isTestCommand": true 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /www/t/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 | "dependencies": { 10 | "gulp-util": "^3.0.8", 11 | "source-map": "*" 12 | }, 13 | "description": "Tiles UI for radare2", 14 | "homepage": "https://radare.org", 15 | "license": "MIT", 16 | "maintainers": [ 17 | { 18 | "name": "pancake", 19 | "email": "pancake@nopcode.org" 20 | } 21 | ], 22 | "name": "radare2-webui-enyo", 23 | "repository": { 24 | "type": "git", 25 | "url": "git://github.com/radare/radare2-webui.git" 26 | }, 27 | "type": "module", 28 | "scripts": {}, 29 | "version": "0.10.2", 30 | "devDependencies": { 31 | "gulp": "^5.0.0", 32 | "gulp-clean-css": "^4.3.0", 33 | "gulp-concat": "^2.6.1", 34 | "gulp-gzip": "^1.4.0", 35 | "gulp-util": "*", 36 | "gulp-replace": "^1.0.0", 37 | "gulp-tar": "^4.0.0", 38 | "gulp-uglify": "^3.0.2", 39 | "semistandard": "*" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /www/enyo/js/console.js: -------------------------------------------------------------------------------- 1 | enyo.kind({ 2 | name: 'Console', 3 | kind: 'Scroller', 4 | classes: 'r2panel', 5 | style: 'background-color:#c0c0c0;padding-left:7px', 6 | components: [ 7 | {tag: 'form', attributes: {action: 'javascript:#'}, components: [ 8 | {kind: 'FittableRows', fit: true, classes: 'fittable-sample-shadow', components: [ 9 | {kind: 'onyx.InputDecorator', style: 'margin-top:8px;background-color:#404040;width: 90%;display:inline-block', components: [ 10 | {kind: 'Input', style: 'width:100%;color:white', value: '', onkeydown: 'runCommand', attributes: {autocapitalize: 'off'}, name: 'input'} 11 | ]}, 12 | {tag: 'pre', classes: 'r2ui-terminal', style: 'width:90%;', fit: true, allowHtml: true, name: 'output'} 13 | ]} 14 | ]} 15 | ], 16 | runCommand: function(inSender, inEvent) { 17 | if (inEvent.keyCode === 13) { 18 | var cmd = this.$.input.getValue(); 19 | this.$.input.setValue(''); 20 | (function(out) { 21 | r2.cmd(cmd, function(x) { 22 | out.setContent(x); 23 | }); 24 | })(this.$.output); 25 | } 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /www/m/js/widgets/HexdumpWidget.js: -------------------------------------------------------------------------------- 1 | import {BaseWidget} from './BaseWidget'; 2 | import {Hexdump} from '../modules/hexdump/Hexdump'; 3 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper'; 4 | 5 | export class HexdumpWidget extends BaseWidget { 6 | constructor() { 7 | super('Hexdump', 'dark'); 8 | } 9 | 10 | init() { 11 | r2.cmd('e cfg.bigendian', b => { this.isBigEndian = (b === 'true'); }); 12 | this.firstTime = true; 13 | } 14 | 15 | draw() { 16 | if (this.firstTime) { 17 | this.firstTime = false; 18 | this.hexdump = new Hexdump(this.node, 16, this.isBigEndian); 19 | this.hexdump.setOnChangeCallback(function (offset, before, after) { 20 | console.log('changed'); 21 | }); 22 | r2Wrapper.registerListener(R2Actions.SEEK, () => { 23 | if (!this.displayed) { 24 | return; 25 | } 26 | this.hexdump.refreshInitialOffset(); 27 | this.hexdump.resetContainer(this.node); 28 | this.hexdump.draw(); 29 | }); 30 | } else { 31 | this.hexdump.resetContainer(this.node); 32 | } 33 | 34 | this.hexdump.draw(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /www/m/css/widget.css: -------------------------------------------------------------------------------- 1 | #container { 2 | clear:both; 3 | position:relative; 4 | height:100%; 5 | } 6 | 7 | .rwidget { 8 | height:100%; 9 | overflow:auto; 10 | box-sizing: border-box; 11 | } 12 | 13 | .rwidget.dark { 14 | background-color: #202020; 15 | color: white; 16 | } 17 | 18 | .rwidget.full { 19 | } 20 | 21 | .rwidget.focus { 22 | } 23 | 24 | .rwidget:nth-child(2) { 25 | display: none; 26 | } 27 | 28 | /** 29 | * Horizontal widgets 30 | */ 31 | 32 | .rwidget.horizontal { 33 | height:50%; 34 | } 35 | 36 | .rwidget.horizontal:first-child { 37 | 38 | } 39 | 40 | .rwidget.horizontal:last-child { 41 | 42 | } 43 | 44 | /** 45 | * Vertical widgets 46 | */ 47 | 48 | .rwidget.vertical { 49 | width:49.5%; 50 | position:absolute; 51 | } 52 | 53 | .rwidget.vertical:first-child { 54 | left:0; 55 | } 56 | 57 | .rwidget.vertical:nth-child(2) { 58 | right:0; 59 | display: block; 60 | } 61 | 62 | /** 63 | * Ruler to set space 64 | */ 65 | 66 | #ruler { 67 | position:absolute; 68 | margin-left:50%; 69 | height:100%; 70 | border-right:4px solid #5C5C5C; 71 | z-index:1000; 72 | cursor: col-resize; 73 | 74 | display:none; 75 | } -------------------------------------------------------------------------------- /www/m/Makefile: -------------------------------------------------------------------------------- 1 | VERSION=$(shell jq .version package.json) 2 | DISTZIP=radare2-webui-m-$(VERSION).zip 3 | 4 | PM=npm 5 | PWD=$(shell pwd) 6 | 7 | all: build 8 | $(MAKE) dist 9 | 10 | build: node_modules 11 | 12 | dist release: node_modules 13 | mkdir -p ../../dist/m 14 | cp -f index.html ../../dist/m/index.html 15 | cp -rf css ../../dist/m 16 | npx webpack-cli -o $$PWD/www/ $$PWD/js/app.js 17 | npx gulp release 18 | cp $$PWD/www/* ../../dist/m/. 19 | rm -f $(DISTZIP) 20 | cd ../../dist && ls -la && zip -r $(DISTZIP) m 21 | @echo zip -r ../../dist/$(DISTZIP) m 22 | 23 | 24 | node_modules: 25 | mkdir -p node_modules 26 | $(PM) install 27 | 28 | watch: 29 | $(PM) run watch 30 | 31 | tests: 32 | $(PM) run test 33 | 34 | r: 35 | r2 -qe http.root=$$PWD/../../dist -e http.ui=m -c=H /bin/ls 36 | 37 | run: 38 | r2 -q -e scr.html=0 -e http.sandbox=0 -e http.ui=m -e http.root=$(PWD)/../../dist -c=H /bin/ls 39 | 40 | FILES=$(shell git ls-files .) 41 | 42 | zip: clean 43 | zip -r radare2.zip $(FILES) 44 | 45 | clean_nodes: 46 | rm -rf ./node_modules/ 47 | rm package-lock.json 48 | 49 | clean: 50 | rm -f *.gz *.zip 51 | 52 | .PHONY: zip sync up update all clean dist release 53 | -------------------------------------------------------------------------------- /www/m/js/helpers/prompts.legacy.js: -------------------------------------------------------------------------------- 1 | function write() { 2 | var str = prompt('hexpairs, quoted string or :assembly'); 3 | if (str != '') { 4 | switch (str[0]) { 5 | case ':': 6 | str = str.substring(1); 7 | r2.cmd('"wa ' + str + '"', update); 8 | break; 9 | case '"': 10 | str = str.replace(/"/g, ''); 11 | r2.cmd('w ' + str, update); 12 | break; 13 | default: 14 | r2.cmd('wx ' + str, update); 15 | break; 16 | } 17 | } 18 | } 19 | 20 | function comment() { 21 | var addr = prompt('comment'); 22 | if (addr) { 23 | if (addr === '-') { 24 | r2.cmd('CC-'); 25 | } else { 26 | r2.cmd('"CC ' + addr + '"'); 27 | } 28 | update(); 29 | } 30 | } 31 | 32 | function flag() { 33 | var addr = prompt('flag'); 34 | if (addr) { 35 | if (addr === '-') { 36 | r2.cmd('f' + addr); 37 | } else { 38 | r2.cmd('f ' + addr); 39 | } 40 | update(); 41 | } 42 | } 43 | 44 | function block() { 45 | var size = prompt('block'); 46 | if (size && size.trim()) { 47 | r2.cmd('b ' + size); 48 | update(); 49 | } 50 | } 51 | 52 | function flagsize() { 53 | var size = prompt('size'); 54 | if (size && size.trim()) { 55 | r2.cmd('fl $$ ' + size); 56 | update(); 57 | } 58 | } -------------------------------------------------------------------------------- /www/m/workers/disasmNavProvider.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 LINES = 80; 7 | var MAXLINES = Math.round(LINES * 1.20); // +20% 8 | var TOOLONG = (LINES * 2) * 3; 9 | 10 | function appendTo(list, elems) { 11 | if (elems === null) { 12 | return; 13 | } 14 | for (var i = 0 ; i < elems.length ; i++) { 15 | var offset = parseInt(elems[i].offset); 16 | 17 | // If the "flag" is empty, we don't care 18 | if (elems[i].size == '0' || elems[i].size >= TOOLONG) { 19 | continue; 20 | } 21 | 22 | // If there is already a shortest element, don't care 23 | if (typeof list[offset] !== 'undefined' && elems[i].size <= list[offset]) { 24 | continue; 25 | } 26 | 27 | list[offset] = parseInt(elems[i].size); 28 | } 29 | } 30 | 31 | self.onmessage = function() { 32 | var data = {}; 33 | 34 | var allFlags; 35 | r2.cmdj('fj ', function(flags) { 36 | allFlags = flags; 37 | }); 38 | 39 | var allFcts; 40 | r2.cmdj('aflj', function(fcts) { 41 | allFcts = fcts; 42 | }); 43 | 44 | appendTo(data, allFlags); 45 | appendTo(data, allFcts); 46 | 47 | self.postMessage(data); 48 | }; 49 | -------------------------------------------------------------------------------- /www/m/js/widgets/NotesWidget.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 NotesWidget extends BaseWidget { 9 | constructor() { 10 | super('Notes'); 11 | } 12 | 13 | init() { 14 | r2Wrapper.registerListener(R2Actions.SEEK, () => { 15 | if (this.displayed) { 16 | this.draw(); 17 | } 18 | }); 19 | } 20 | 21 | draw() { 22 | this.node.appendChild(this.getPanel()); 23 | } 24 | 25 | getPanel() { 26 | var c = document.createElement('div'); 27 | 28 | var header = document.createElement('div'); 29 | header.style.position = 'fixed'; 30 | header.style.margin = '0.5em'; 31 | c.appendChild(header); 32 | 33 | header.appendChild(Inputs.iconButton('undo', 'Back to Comments', () => uiContext.navigateTo(Widgets.COMMENTS))); 34 | 35 | var content = document.createElement('div'); 36 | content.style.paddingTop = '70px'; 37 | content.innerHTML = ''; 38 | c.appendChild(content); 39 | 40 | return c; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /www/enyo/js/logs.js: -------------------------------------------------------------------------------- 1 | enyo.kind({ 2 | name: 'Logs', 3 | kind: 'Scroller', 4 | style: 'background-color:#c0c0c0;padding-left:8px', 5 | components: [ 6 | {tag: 'form', attributes: {action: 'javascript:#'}, components: [ 7 | {kind: 'FittableRows', fit: true, classes: 'fittable-sample-shadow', components: [ 8 | {kind: 'onyx.InputDecorator', style: 'margin-top:8px;background-color:#404040;width: 90%;display:inline-block', components: [ 9 | {kind: 'Input', style: 'width:100%;color:white', value: '', onkeydown: 'sendMessage', attributes: {autocapitalize: 'off'}, name: 'input'} 10 | ]}, 11 | {tag: 'pre', classes: 'r2ui-terminal', style: 'width:90%;', fit: true, allowHtml: true, name: 'output'} 12 | ]} 13 | ]} 14 | ], 15 | logger: null, 16 | create: function() { 17 | this.inherited(arguments); 18 | r2ui._log = this; 19 | }, 20 | connect: function() { 21 | var out = this.$.output; 22 | this.logger = r2.getTextLogger().on('message', function(msg) { 23 | out.setContent(out.getContent() + msg.text + '\n'); 24 | }); 25 | this.logger.autorefresh(3); 26 | }, 27 | sendMessage: function(inSender, inEvent) { 28 | if (inEvent.keyCode === 13) { 29 | var msg = this.$.input.getValue(); 30 | this.$.input.setValue(''); 31 | this.logger.send(msg); 32 | } 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /www/m/js/helpers/Format.js: -------------------------------------------------------------------------------- 1 | import {r2Wrapper} from '../core/R2Wrapper'; 2 | 3 | const offsetRegex = new RegExp(/(0x[a-zA-Z0-9]+|(?:sym|fcn|str)\.[\.a-zA-Z0-9_]+)/, "g"); 4 | 5 | /** Takes a block and makes all offsets clickables */ 6 | export function formatOffsets(str, navigateTo = null) { 7 | const chunks = str.split(offsetRegex); 8 | const node = document.createElement('span'); 9 | 10 | for (const chunk of chunks) { 11 | node.appendChild(formatOffset(chunk, navigateTo)); 12 | } 13 | 14 | return node; 15 | } 16 | 17 | /** Read the value and format if it's exactly an offset */ 18 | export function formatOffset(str, navigateTo = null) { 19 | let chunkNode; 20 | if (offsetRegex.test(str)) { 21 | chunkNode = document.createElement('a'); 22 | chunkNode.innerHTML = str; 23 | applySeek(chunkNode, str, navigateTo); 24 | } else { 25 | chunkNode = document.createElement('span'); 26 | chunkNode.innerHTML = str; 27 | } 28 | 29 | return chunkNode; 30 | } 31 | 32 | /** Consider node's content as seekable, apply events to trigger seek event */ 33 | export function applySeek(node, dest = null, navigateTo = null) { 34 | dest = dest || node.textContent; 35 | node.addEventListener('click', () => r2Wrapper.seek(dest, navigateTo)); 36 | node.title = 'Seek ' + dest; 37 | node.href = '#' + dest; 38 | } 39 | -------------------------------------------------------------------------------- /www/p/lib/js/panels/projects_panel.js: -------------------------------------------------------------------------------- 1 | // PROJECTS PANEL 2 | var ProjectsPanel = function() { 3 | 4 | }; 5 | 6 | ProjectsPanel.prototype.render = function() { 7 | $('#projects_tab').html('
Open Project:

'); 8 | r2.cmdj('Plj', function(projects) { 9 | var data = []; 10 | for (var i in projects) { 11 | var p = projects[i]; 12 | var fd = { 13 | label: p 14 | }; 15 | data[data.length] = fd; 16 | } 17 | $('#projects').tree({data: [],selectable: false,slide: false,useContextMenu: false}); 18 | $('#projects').tree('loadData', data); 19 | $('#submit').on('click', function() { 20 | var project_name = prompt('Project Name:', r2.project_name); 21 | if (project_name !== '') { 22 | r2.cmd(':Ps ' + project_name, function() {}); 23 | } else { 24 | alert('Enter a valid name'); 25 | } 26 | r2.project_name = project_name; 27 | }); 28 | $('.jqtree-element').on('click', function() { 29 | var project_name = $(this)[0].firstChild.innerText; 30 | r2.cmd('Po ' + project_name, function() {}); 31 | r2.project_name = project_name; 32 | window.location.assign('./p'); 33 | }); 34 | }); 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /www/p/lib/css/jquery-ui.css: -------------------------------------------------------------------------------- 1 | 2 | .ui-menu { 3 | list-style: none; 4 | padding: 0; 5 | /*margin: 50px 50px;*/ 6 | display: block; 7 | outline: none; 8 | background: #c0c0c0; 9 | width: 200px; 10 | border: 1px solid #AAA; 11 | color: #222; 12 | z-index: 100; 13 | } 14 | 15 | 16 | .ui-menu .ui-menu { 17 | position: absolute; 18 | 19 | } 20 | .ui-menu .ui-menu-item { 21 | font-family: monospace; 22 | position: relative; 23 | margin: 0; 24 | padding: 3px 1em 3px .4em; 25 | cursor: pointer; 26 | min-height: 0; /* support: IE7 */ 27 | } 28 | .ui-menu .ui-menu-item:hover { 29 | font-family: monospace; 30 | position: relative; 31 | margin: 0; 32 | background: yellow; 33 | padding: 3px 1em 3px .4em; 34 | cursor: pointer; 35 | min-height: 0; /* support: IE7 */ 36 | } 37 | 38 | .ui-menu .ui-menu-item a { 39 | color: #555555; 40 | text-decoration: none; 41 | outline: none; 42 | } 43 | 44 | .ui-menu .ui-menu-item a:visited { 45 | color: #555555; 46 | text-decoration: none; 47 | outline: none; 48 | } 49 | 50 | .ui-menu .ui-menu-divider { 51 | margin: 5px 0; 52 | height: 0; 53 | font-size: 0; 54 | line-height: 0; 55 | border-width: 1px 0 0 0; 56 | } 57 | .ui-menu .ui-state-focus, 58 | .ui-menu .ui-state-active { 59 | margin: -1px; 60 | } 61 | 62 | .ui-menu kbd { 63 | padding-left: 1em; 64 | float: right; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /www/m/css/contextmenu.css: -------------------------------------------------------------------------------- 1 | nav.context-menu { 2 | display: none; 3 | position: absolute; 4 | z-index: 10; 5 | background: rgb(255,255,255); 6 | margin: 0; 7 | padding: 0; 8 | border: none; 9 | border-radius: 2px; 10 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); 11 | } 12 | 13 | nav.context-menu.active { 14 | display: block; 15 | } 16 | 17 | nav.context-menu ul { 18 | margin: 0; 19 | padding: 0; 20 | list-style-type: none; 21 | } 22 | 23 | nav.context-menu ul li { 24 | display:block; 25 | line-height:22px; 26 | padding:5px 20px; 27 | border-bottom:1px solid #E0E0E0; 28 | } 29 | 30 | nav.context-menu ul li.disabled { 31 | color: #A0A0A0; 32 | } 33 | 34 | nav.context-menu ul > li > ul { 35 | display: none; 36 | z-index: 10; 37 | position: absolute; 38 | background:white; 39 | border-radius: 2px; 40 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); 41 | } 42 | 43 | nav.context-menu ul > li > ul > li { 44 | line-height:18px; 45 | font-size:85%; 46 | padding:2px 10px; 47 | } 48 | 49 | nav.context-menu ul > li.subactive > ul { 50 | display: block; 51 | width:180px; 52 | } 53 | 54 | nav.context-menu ul li:hover, nav.context-menu ul > li.subactive > ul > li:hover { 55 | background-color:#CCCCCC; 56 | cursor:pointer; 57 | } 58 | -------------------------------------------------------------------------------- /www/m/js/helpers/uiTables.legacy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Legacy methods, extracted from main JS 3 | */ 4 | function uiTableBegin(cols, domId) { 5 | console.warn('Usage is deprecated: migrate to Table'); 6 | var out = ''; 7 | var id = domId || ''; 8 | var classes = 'mdl-data-table mdl-js-data-table mdl-data-table--selectable mdl-shadow--2dp'; 9 | out += ''; 10 | //out += '
'; 11 | 12 | out += ' '; 13 | 14 | var type; 15 | for (var i in cols) { 16 | var col = cols[i]; 17 | if (col[0] === '+') { 18 | col = col.substring(1); 19 | type = ''; 20 | } else { 21 | type = ' class="mdl-data-table__cell--non-numeric"'; 22 | } 23 | out += '' + col + ''; 24 | } 25 | out += ''; 26 | return out; 27 | } 28 | 29 | function uiTableRow(cols) { 30 | var type = ''; 31 | var out = ''; 32 | for (var i in cols) { 33 | var col = cols[i]; 34 | if (!col) { 35 | continue; 36 | } 37 | if (col[0] === '+') { 38 | col = clickableOffsets(col.substring(1)); 39 | } else { 40 | type = ' class="mdl-data-table__cell--non-numeric"'; 41 | } 42 | out += '' + col + ''; 43 | } 44 | return out + ''; 45 | } 46 | 47 | function uiTableEnd() { 48 | return '
'; 49 | } 50 | -------------------------------------------------------------------------------- /www/m/webpack.config.js: -------------------------------------------------------------------------------- 1 | const TerserPlugin = require("terser-webpack-plugin"); 2 | const _path_ = require('path'); 3 | const PROD_MODE = 'production'; 4 | const DEV_MODE = 'development'; 5 | 6 | const MODE = DEV_MODE; 7 | 8 | const EXT_LIBS = './node_modules' ; // ./vendors 9 | 10 | module.exports = [{ 11 | entry: { 12 | main: './js/app.js' 13 | }, 14 | mode: MODE, 15 | output: { 16 | path: _path_.resolve(__dirname, 'dist'), 17 | filename: 'main.min.js', 18 | }, 19 | optimization: { 20 | minimize: true, 21 | minimizer: [new TerserPlugin()], 22 | }, 23 | module: { 24 | rules: [ 25 | { 26 | test: /\.js$/, 27 | use: [] 28 | }/*, 29 | { 30 | test: /\.scss$/, 31 | use: [ 32 | { loader: 'file-loader', options: { name: 'bundle.css' } }, 33 | { loader: 'extract-loader' }, 34 | { loader: 'css-loader' }, 35 | { loader: 'sass-loader', 36 | options: { 37 | // Prefer Dart Sass 38 | implementation: require('sass'), 39 | 40 | // See https://github.com/webpack-contrib/sass-loader/issues/804 41 | webpackImporter: false, 42 | }, 43 | } 44 | ] 45 | }, 46 | { 47 | test: /\.(woff|woff2|eot|ttf|otf)$/i, 48 | type: 'asset/resource', 49 | use: [] 50 | },*/ 51 | ] 52 | }, 53 | }]; 54 | -------------------------------------------------------------------------------- /www/m/js/dialogs/dialog_networkerr.legacy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function() { 4 | var networkerrDialog = document.getElementById('networkerr'); 5 | var isOpen = false; 6 | var attemps = 0; 7 | 8 | if (!networkerrDialog.showModal) { 9 | dialogPolyfill.registerDialog(networkerrDialog); 10 | } 11 | 12 | function retry() { 13 | attemps++; 14 | r2.cmdj('?V', function(j) { 15 | if (typeof j !== 'undefined') { 16 | attemps = 0; 17 | } 18 | }); 19 | } 20 | 21 | networkerrDialog.querySelector('.retry').addEventListener('click', function() { 22 | networkerrDialog.close(); 23 | retry(); 24 | isOpen = false; 25 | }); 26 | 27 | networkerrDialog.querySelector('.close').addEventListener('click', function() { 28 | networkerrDialog.close(); 29 | isOpen = false; 30 | }); 31 | 32 | networkerrDialog.querySelector('.ok').addEventListener('click', function() { 33 | networkerrDialog.close(); 34 | isOpen = false; 35 | }); 36 | 37 | function refresh() { 38 | if (attemps > 0) { 39 | var firstAttempt = document.getElementsByClassName('first-attempt'); 40 | for (var i = 0 ; i < firstAttempt.length; i++) { 41 | firstAttempt[i].style.display = 'none'; 42 | } 43 | 44 | var nextAttempts = document.getElementsByClassName('next-attempt'); 45 | for (var i = 0 ; i < nextAttempts.length; i++) { 46 | nextAttempts[i].style.display = 'block'; 47 | } 48 | } 49 | } 50 | 51 | r2.err = function() { 52 | if (!isOpen) { 53 | refresh(); 54 | networkerrDialog.showModal(); 55 | } 56 | }; 57 | })(); 58 | -------------------------------------------------------------------------------- /www/m/js/core/SettingsManager.js: -------------------------------------------------------------------------------- 1 | export class SettingsManager { 2 | 3 | get keys() { return this.itemKeys }; 4 | 5 | constructor(keys, baseConf) { 6 | this.itemKeys = keys; 7 | this.conf = baseConf; 8 | } 9 | 10 | loadAll(force = false) { 11 | for (let key in this.conf) { 12 | const curValue = this.getItem(key); 13 | const defaultValue = this.getItemDefaultValue(key); 14 | if ((!force && curValue !== defaultValue) || force) { 15 | this.conf[key].apply(curValue); 16 | } 17 | } 18 | } 19 | 20 | resetAll() { 21 | for (let key in this.conf) 22 | localStorage.removeItem(key); 23 | this.loadAll(true); 24 | } 25 | 26 | getItem(key) { 27 | if (!this.keyExists(key)) throw new Error(`ConfKey ${key} doesn't exist!`); 28 | 29 | var local = localStorage.getItem(key); 30 | if (local !== null) { 31 | if (local === 'false') { 32 | local = false; 33 | } else if (local === 'true') { 34 | local = true; 35 | } 36 | return local; 37 | } else { 38 | return this.getItemDefaultValue(key); 39 | } 40 | } 41 | 42 | setItem(key, value) { 43 | if (!this.keyExists(key)) throw new Error(`ConfKey ${key} doesn't exist!`); 44 | 45 | localStorage.setItem(key, value); 46 | this.conf[key].apply(value); 47 | } 48 | 49 | getItemDefaultValue(key) { 50 | if (!this.keyExists(key)) throw new Error(`ConfKey ${key} doesn't exist!`); 51 | 52 | return this.conf[key].defVal; 53 | } 54 | 55 | /** Tell if the key is defined in the declared item keys */ 56 | keyExists(key) { 57 | return (typeof this.conf[key]) !== 'undefined'; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /www/m/js/widgets/DisassemblyGraphWidget.js: -------------------------------------------------------------------------------- 1 | import {BaseWidget} from './BaseWidget'; 2 | import {Inputs} from '../helpers/Inputs'; 3 | 4 | import {uiContext} from '../core/UIContext'; 5 | import {Widgets} from './Widgets'; 6 | import {formatOffsets} from '../helpers/Format'; 7 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper'; 8 | 9 | const inColor = true; // TODO inColor 10 | 11 | export class DisassemblyGraphWidget extends BaseWidget { 12 | constructor() { 13 | super('Graph', 'dark'); 14 | } 15 | 16 | init() { 17 | this.backButton = Inputs.iconButton('undo', 'Back to Disassembly', () => uiContext.navigateTo(Widgets.DISASSEMBLY)); 18 | this.backButton.style.position = 'absolute'; 19 | this.backButton.style.top = '1em'; 20 | this.backButton.style.left = '1em'; 21 | 22 | r2Wrapper.registerListener(R2Actions.SEEK, () => { 23 | if (this.displayed) { 24 | this.draw(); 25 | } 26 | }); 27 | } 28 | 29 | draw() { 30 | this.node.appendChild(this.backButton); 31 | this.node.appendChild(this.getGraph()); 32 | } 33 | 34 | getGraph() { 35 | const graph = document.createElement('div'); 36 | graph.style.overflow = 'auto'; 37 | graph.setAttribute( 38 | 'content', 39 | 'user-scalable=yes, width=device-width, minimum-scale=1, maximum-scale=1' 40 | ); 41 | 42 | var tail = inColor ? '|H': ''; 43 | r2.cmd('agf' + tail, (d) => { 44 | const pre = document.createElement('pre'); 45 | pre.style.color = inColor ? 'white' : 'black'; 46 | pre.appendChild(formatOffsets(d)) 47 | graph.appendChild(pre); 48 | }); 49 | 50 | return graph; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /www/m/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | CONTRIBUTING 2 | ============ 3 | 4 | How to contribute on the *material* UI? 5 | 6 | This UI use extensively `gulp` to be built. In an abstraction concern for the main build system, we have abstracted the whole process inside npm scripts. 7 | 8 | Run UI from dev 9 | --------------- 10 | 11 | The webserver is handled by `radare2`. From the root folder, you would run: 12 | 13 | ```sh 14 | make run 15 | ``` 16 | 17 | This command will open your browser at http://localhost:9090/m pointing to `dev/m/` folder. 18 | 19 | Development 20 | ----------- 21 | 22 | You would develop modifying files inside this folder and having your updated inside your browser. The build process is fairly simple: 23 | 24 | ```sh 25 | npm run build 26 | ``` 27 | 28 | You can make the choice to run the `watcher` instead to have the file processed at the same time you save them: 29 | 30 | ```sh 31 | npm run watch # gulp watch 32 | ``` 33 | 34 | Tests 35 | ----- 36 | 37 | Tests run against the `dev` version. 38 | 39 | You can run the tests both ways, inside your commandline: 40 | 41 | ```sh 42 | npm run test # calling mocha 43 | ``` 44 | 45 | Or into your browser if you need to debug: 46 | 47 | ```sh 48 | npm run testbrowser # gulp test 49 | ``` 50 | 51 | As a part of the test, you can also run ESLint: 52 | 53 | ```sh 54 | npm run checkstyle # gulp checkstyle 55 | ``` 56 | 57 | Release 58 | ------- 59 | 60 | The release process stricly use the development but compress the output by minifying HTML, CSS and JS. 61 | 62 | ```sh 63 | make dist 64 | ``` 65 | 66 | or 67 | 68 | ```sh 69 | npm run release 70 | ``` 71 | -------------------------------------------------------------------------------- /www/m/js/helpers/InfiniteScrolling.js: -------------------------------------------------------------------------------- 1 | /** 2 | * domTarget must have a "measurable" height 3 | * limit, when there is less than {limit}% available to scroll 4 | * we call the associated event 5 | */ 6 | export class InfiniteScrolling { 7 | 8 | constructor(domTarget, howManyScreens, limit) { 9 | this.domTarget = domTarget; 10 | this.limit = limit; 11 | this.howManyScreens = howManyScreens; 12 | this.screenProportion = 1.0 / this.howManyScreens; 13 | this.pauseScrollEvent = false; 14 | this.prevScroll = 0.; 15 | 16 | var _this = this; 17 | this.domTarget.addEventListener('scroll', function(e) { 18 | _this.scrollEvent_(e); 19 | }); 20 | } 21 | 22 | setTopEvent(fct) { 23 | this.ontop = fct; 24 | } 25 | 26 | setBottomEvent(fct) { 27 | this.onbottom = fct; 28 | } 29 | 30 | scrollEvent_(e) { 31 | var _this = this; 32 | if (this.pauseScrollEvent) { 33 | return; 34 | } 35 | 36 | var height = e.target.scrollHeight - e.target.offsetHeight; 37 | var p = e.target.scrollTop / height; 38 | 39 | if (!this.isTopMax && p < this.limit && this.prevScroll > p) { 40 | this.pauseScrollEvent = true; 41 | var pos = Math.floor(((this.limit + (p - this.limit)) + this.screenProportion) * height); 42 | this.ontop(pos, function(isTopMax) { 43 | _this.pauseScrollEvent = false; 44 | }); 45 | } 46 | 47 | if (p > (1 - this.limit) && this.prevScroll < p) { 48 | this.pauseScrollEvent = true; 49 | var pos = Math.floor((((1 - this.limit) + (p - (1 - this.limit))) - this.screenProportion) * height); 50 | this.onbottom(pos, function(isTopMax) { 51 | _this.pauseScrollEvent = false; 52 | }); 53 | } 54 | 55 | this.prevScroll = p; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /www/t/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /www/enyo/js/script.js: -------------------------------------------------------------------------------- 1 | enyo.kind({ 2 | name: 'Script', 3 | kind: 'Scroller', 4 | style: 'background-color:#c0c0c0', 5 | clear: function() { 6 | const field = this.$.input; 7 | field.setContent(value = ''); 8 | field.render(); 9 | }, 10 | demo: function() { 11 | const field = this.$.input; 12 | field.setContent(value = [ 13 | 'r2.disassemble (0, "9090", function(text) {', 14 | ' show (text)', 15 | ' show ()', 16 | ' r2.assemble (0, "mov eax, 33", function (text) {', 17 | ' show (text);', 18 | ' });', 19 | ' show (r2)', 20 | '});'].join('\n')); 21 | field.render(); 22 | }, 23 | run: function() { 24 | var code = this.$.input.value; 25 | var out = ''; 26 | /* helper functions */ 27 | function show(x) { 28 | if (!x) out += '\n'; else 29 | if (typeof x == 'object') { 30 | out += '{'; 31 | for (var y in x) { 32 | var v = x[y]; //(typeof x[y] == 'function')? 'function': x[y]; 33 | out += y + ': ' + v + '\n , '; 34 | } 35 | out += '}'; 36 | } else { 37 | out += x + '\n'; 38 | } 39 | } 40 | try { 41 | eval(code); 42 | this.$.output.setContent(out); 43 | } catch (e) { 44 | alert(e); 45 | } 46 | }, 47 | components: [ 48 | {tag: 'p', style: 'margin-left:10px', components: [ 49 | {kind: 'onyx.Button', content: 'Run', classes: 'sourcebutton', ontap: 'run' }, 50 | {kind: 'onyx.Button', content: 'Clear', classes: 'sourcebutton', ontap: 'clear' }, 51 | {kind: 'onyx.Button', content: 'Demo', classes: 'sourcebutton', ontap: 'demo' } 52 | ]}, 53 | {kind: 'onyx.TextArea', name: 'input', classes: 'sourcecode' }, 54 | {tag: 'pre', name: 'output', style: 'margin-left:12px' } 55 | ] 56 | }); 57 | -------------------------------------------------------------------------------- /www/p/lib/js/panels/entropy_panel.js: -------------------------------------------------------------------------------- 1 | // ENTROPY PANEL 2 | var EntropyPanel = function() { 3 | 4 | }; 5 | 6 | EntropyPanel.prototype.render = function() { 7 | var table = ''; 8 | r2.cmd('p=', function(x) { 9 | var blocks = x.split('\n'); 10 | for (var i in blocks) { 11 | var block = blocks[i]; 12 | var idx = block.split(' ')[0]; 13 | var value = parseInt(block.split(' ')[1], 16); 14 | if (value > 0) { 15 | table += ''; 16 | } 17 | } 18 | }); 19 | table += '
' + idx + '' + value + '
'; 20 | $('#entropy_tab').html('
' + 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 | onyx r2ui 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /www/m/js/modules/overview/FortunesCard.js: -------------------------------------------------------------------------------- 1 | import {speak} from '../../helpers/Speak.js'; 2 | 3 | export class FortunesCard { 4 | 5 | get DOM() { return this.card; } 6 | 7 | constructor() { 8 | this.currentFortune = this.getNewFortune(); 9 | speak(this.currentFortune); 10 | 11 | this.build(); 12 | } 13 | 14 | build() { 15 | this.card = document.createElement('div'); 16 | this.card.className = 'demo-updates mdl-card mdl-shadow--2dp mdl-cell mdl-cell--4-col mdl-cell--4-col-tablet mdl-cell--12-col-desktop'; 17 | 18 | const title = document.createElement('div'); 19 | title.className = 'mdl-card__title mdl-card--expand mdl-color--teal-300'; 20 | title.innerHTML = '

Fortunes

'; 21 | 22 | this.fortuneBlock = document.createElement('div'); 23 | this.fortuneBlock.className = 'mdl-card__supporting-text mdl-color-text--grey-600'; 24 | this.fortuneBlock.innerHTML = this.currentFortune; 25 | 26 | const action = document.createElement('div'); 27 | action.className = 'mdl-card__actions mdl-card--border'; 28 | 29 | const refreshButton = document.createElement('a'); 30 | refreshButton.className = 'mdl-button mdl-js-button mdl-js-ripple-effect'; 31 | refreshButton.innerHTML = 'Next'; 32 | refreshButton.addEventListener('click', () => this.refresh()); 33 | 34 | action.appendChild(refreshButton); 35 | 36 | this.card.appendChild(title); 37 | this.card.appendChild(this.fortuneBlock); 38 | this.card.appendChild(action); 39 | } 40 | 41 | refresh() { 42 | this.currentFortune = this.getNewFortune(); 43 | this.fortuneBlock.innerHTML = this.currentFortune; 44 | speak(this.currentFortune); 45 | } 46 | 47 | getNewFortune() { 48 | let fortune; 49 | r2.cmd('fo', function(d) { 50 | fortune = d; 51 | }); 52 | return fortune; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /www/p/lib/js/dependencies/jquery.donetyping.js: -------------------------------------------------------------------------------- 1 | ;(function($){ 2 | $.fn.extend({ 3 | donetyping: function(callback,timeout){ 4 | timeout = timeout || 1e3; // 1 second default timeout 5 | var timeoutReference, 6 | doneTyping = function(el){ 7 | if (!timeoutReference) return; 8 | timeoutReference = null; 9 | callback.call(el); 10 | }; 11 | return this.each(function(i,el){ 12 | var $el = $(el); 13 | // Chrome Fix (Use keyup over keypress to detect backspace) 14 | // thank you @palerdot 15 | $el.is(':input') && $el.on('keyup keypress',function(e){ 16 | // This catches the backspace button in chrome, but also prevents 17 | // the event from triggering too premptively. Without this line, 18 | // using tab/shift+tab will make the focused element fire the callback. 19 | if (e.type=='keyup' && e.keyCode!=8) return; 20 | 21 | // Check if timeout has been set. If it has, "reset" the clock and 22 | // start over again. 23 | if (timeoutReference) clearTimeout(timeoutReference); 24 | timeoutReference = setTimeout(function(){ 25 | // if we made it here, our timeout has elapsed. Fire the 26 | // callback 27 | doneTyping(el); 28 | }, timeout); 29 | }).on('blur',function(){ 30 | // If we can, fire the event since we're leaving the field 31 | doneTyping(el); 32 | }); 33 | }); 34 | } 35 | }); 36 | })(jQuery); -------------------------------------------------------------------------------- /www/m/js/widgets/FlagsWidget.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 FlagsWidget extends BaseWidget { 10 | constructor() { 11 | super('Flags'); 12 | } 13 | 14 | init() { 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 | if (this.inColor) { 32 | c.style.backgroundColor = '#202020'; 33 | } 34 | 35 | var header = document.createElement('div'); 36 | header.style.position = 'fixed'; 37 | header.style.margin = '0.5em'; 38 | c.appendChild(header); 39 | 40 | 41 | header.appendChild(Inputs.button('Spaces', () => uiContext.navigateTo(Widgets.FLAGS_SPACE))); 42 | header.appendChild(Inputs.button('Delete All', () => r2.cmd('f-*', () => this.draw()))); 43 | 44 | var content = document.createElement('div'); 45 | content.style.paddingTop = '50px'; 46 | c.appendChild(content); 47 | 48 | r2.cmd('fj', function(d) { 49 | let data = JSON.parse(d); 50 | var table = new Table( 51 | ['+Offset', 'Size', 'Name'], 52 | [true, true, false], 53 | 'flagsTable', 54 | null, 55 | Widgets.HEXDUMP); 56 | 57 | data.map(x => { 58 | table.addRow(['0x'+x.offset.toString(16), x.size, x.name]) 59 | //table.addRow(Object.values(x)) 60 | }); 61 | table.insertInto(content); 62 | }); 63 | 64 | return c; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /www/m/css/disasm.css: -------------------------------------------------------------------------------- 1 | .disasmPanel { 2 | background-color: rgb(16, 16, 16); 3 | color: white; 4 | overflow: hidden !important; 5 | } 6 | 7 | .disasm.flex-controls { 8 | border-bottom:1px dotted white; 9 | background:white; 10 | color:black; 11 | height:80px; 12 | } 13 | 14 | .disasm.flex-controls .button-controls-disasm { 15 | padding:16px; 16 | display: inline-block; 17 | } 18 | 19 | .disasm.flex-body { 20 | top:80px; 21 | line-height: 1em; 22 | } 23 | 24 | .disasm.flex-body { 25 | font-family: "Roboto Mono", "DejaVu Sans Mono", Console, Courier New, monospace; 26 | font-weight:bold; 27 | } 28 | 29 | div.disasm span.offset, div.disasm span.fcn { 30 | display: inline-block; 31 | width: 100%; 32 | } 33 | 34 | /* 35 | div.disasm span:hover.offset, div.disasm span:hover.fcn { 36 | background-color: rgb(16, 16, 16); 37 | } 38 | */ 39 | 40 | .currentOffset { 41 | background-color: rgb(64, 64, 64); 42 | } 43 | 44 | ul#disasm-history { 45 | display: inline-block; 46 | } 47 | 48 | ul#disasm-history li { 49 | display: inline-block; 50 | line-height: 1em; 51 | font-size:85%; 52 | padding: 0 4px; 53 | margin: 0 3px; 54 | 55 | background:white; 56 | border-radius: 2px; 57 | box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12); 58 | } 59 | 60 | ul#disasm-history li.active { 61 | background-color: #E0E0E0; 62 | } 63 | 64 | ul#disasm-history li:hover { 65 | background-color: #CCCCCC; 66 | cursor: pointer; 67 | } 68 | 69 | table.disasm-table-dialog { 70 | border-collapse: collapse; 71 | } 72 | 73 | table.disasm-table-dialog, table.disasm-table-dialog th, table.disasm-table-dialog td { 74 | border: 1px solid #A0A0A0; 75 | } 76 | 77 | table.disasm-table-dialog td { 78 | font-family: "Roboto Mono", "DejaVu Sans Mono", Console, Courier New, monospace; 79 | text-align: center; 80 | } 81 | -------------------------------------------------------------------------------- /www/m/js/widgets/BasePreWidget.js: -------------------------------------------------------------------------------- 1 | import {BaseWidget} from './BaseWidget'; 2 | import {Inputs} from '../helpers/Inputs'; 3 | import {r2Wrapper, R2Actions} from '../core/R2Wrapper'; 4 | 5 | /** 6 | * Very simple Widget designed to handle RAW content from R2 7 | * Would be eventually formatted then encapsulated with
 
 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 | ![ci](https://github.com/radareorg/radare2-webui/workflows/ci/badge.svg) 5 | ![CodeQL](https://github.com/radareorg/radare2-webui/workflows/CodeQL/badge.svg) 6 | [![Code Climate](https://codeclimate.com/github/radare/radare2-webui/badges/gpa.svg)](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 |
18 |
19 | radare2 20 |
21 |
22 |
24 |
25 |
26 |

Can't find r2 executable in PATH!

27 |

28 | 29 | 30 |

31 |
32 |
33 | 36 | 39 |
40 |
41 | 42 |
43 |
44 |
45 | Assembler options 46 |
47 |
48 |
50 |
51 |
52 |

53 | Select architecture: 59 | and offset 60 | 61 |

62 |
63 | Input bytes:
64 | 65 |

66 | Disassembly
67 | 72 |

73 |

74 | 83 | 84 | 85 |
86 | 89 |
90 |
91 | 92 | 93 |
94 |
95 | 98 |
99 |
100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /www/r2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------