├── .codeclimate.yml ├── .csslintrc ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ ├── ci.yml │ └── codeql-analysis.yml ├── .gitignore ├── .gitmodules ├── CONTRIBUTING.md ├── LICENSES.md ├── Makefile ├── README.md ├── cherrypull.sh └── www ├── .bowerrc ├── Makefile ├── bolt ├── Makefile ├── index.html ├── r2.js └── r2bolt.sh ├── enyo ├── .bowerrc ├── DEPENDENCIES ├── Makefile ├── README.md ├── bower.json ├── css │ ├── enyo │ │ ├── app.css │ │ └── enyo.css │ ├── index.css │ └── lib │ │ └── onyx │ │ └── images │ │ ├── gradient-invert.png │ │ └── gradient.png ├── favicon.ico ├── gulpfile.js ├── icon.png ├── index.html ├── js │ ├── about.js │ ├── assembler.js │ ├── config.js │ ├── console.js │ ├── core │ │ └── disassembler_old.js │ ├── debugger.js │ ├── disassembler.js │ ├── enyo │ │ ├── app.js │ │ └── enyo.js │ ├── graph.js │ ├── hexdump.js │ ├── leftpanel.js │ ├── logs.js │ ├── main.js │ ├── mainpanel.js │ ├── rightpanel.js │ ├── script.js │ ├── search.js │ └── settings.js ├── package-lock.json ├── package.json └── rlogo-tr.png ├── favicon.ico ├── graph ├── img │ ├── arrow.gif │ ├── arrow_d.gif │ ├── arrow_l.gif │ ├── arrow_r.gif │ └── arrow_u.gif ├── index.html ├── index.js ├── js-graph-it.css ├── js-graph-it.js ├── make.sh └── sf-homepage.css ├── gulpfile.js ├── index.html ├── lib ├── disasm.css ├── disasm.js ├── main.css ├── r2.js └── r2ui.js ├── log.html ├── m ├── .babelrc ├── .bowerrc ├── .eslintrc.json ├── .vscode │ ├── settings.json │ └── tasks.json ├── CONTRIBUTING.md ├── Makefile ├── css │ ├── autocomplete.css │ ├── console.css │ ├── contextmenu.css │ ├── disasm.css │ ├── flexcontainer.css │ ├── hexdump.css │ ├── material-design-icons.css │ ├── networkerr.css │ ├── overview.css │ ├── styles.css │ ├── tables.css │ ├── terminal.css │ └── widget.css ├── fonts.list ├── gulpfile.js ├── images │ ├── icon.png │ ├── rlogo256.png │ ├── touch │ │ └── chrome-touch-icon-192x192.png │ └── user.jpg ├── index.html ├── js │ ├── app.js │ ├── core │ │ ├── BlockNavigator.js │ │ ├── ChunkStatus.js │ │ ├── NavigatorDirection.js │ │ ├── R2Wrapper.js │ │ ├── SettingsManager.js │ │ └── UIContext.js │ ├── dialogs │ │ └── dialog_networkerr.legacy.js │ ├── helpers │ │ ├── Autocompletion.js │ │ ├── Format.js │ │ ├── InfiniteScrolling.js │ │ ├── Inputs.js │ │ ├── Speak.js │ │ ├── Table.js │ │ ├── UpdateManager.js │ │ ├── project_management.legacy.js │ │ ├── prompts.legacy.js │ │ ├── statusbar │ │ │ ├── console.legacy.js │ │ │ └── statusbar.legacy.js │ │ ├── tools.legacy.js │ │ ├── ui.legacy.js │ │ └── uiTables.legacy.js │ ├── layout │ │ ├── ContainerZone.js │ │ ├── FlexContainer.js │ │ ├── Layouts.js │ │ ├── RadareInfiniteBlock.js │ │ └── Ruler.js │ ├── modules │ │ ├── disasm │ │ │ ├── Disassembly.js │ │ │ └── DisassemblyNavigator.js │ │ ├── hexdump │ │ │ ├── HexPairNavigator.js │ │ │ ├── Hexdump.js │ │ │ ├── WordSizes.js │ │ │ └── tools.legacy.js │ │ └── overview │ │ │ ├── AnalysisCard.js │ │ │ ├── EntropyCard.js │ │ │ ├── FortunesCard.js │ │ │ ├── GraphCard.js │ │ │ ├── InfoCard.js │ │ │ └── Overview.js │ └── widgets │ │ ├── BasePreWidget.js │ │ ├── BaseWidget.js │ │ ├── ClassesWidget.js │ │ ├── CommentsWidget.js │ │ ├── DebuggerWidget.js │ │ ├── DisassemblyBlocksWidget.js │ │ ├── DisassemblyDecompileWidget.js │ │ ├── DisassemblyFunctionsFullWidget.js │ │ ├── DisassemblyFunctionsWidget.js │ │ ├── DisassemblyGraphWidget.js │ │ ├── DisassemblyInfosWidget.js │ │ ├── DisassemblyWidget.js │ │ ├── FlagsSpacesWidget.js │ │ ├── FlagsWidget.js │ │ ├── FunctionsWidget.js │ │ ├── HexdumpWidget.js │ │ ├── NotesWidget.js │ │ ├── OverviewWidget.js │ │ ├── ScriptWidget.js │ │ ├── SearchWidget.js │ │ ├── SettingsWidget.js │ │ ├── WidgetFactory.js │ │ └── Widgets.js ├── manifest.webapp ├── package-lock.json ├── package.json ├── test │ ├── index.html │ ├── specs │ │ └── helpers │ │ │ └── chai.js │ └── test.test.js ├── webpack.config.js └── workers │ ├── disasmNavProvider.js │ ├── disasmProvider.js │ └── hexchunkProvider.js ├── old ├── index.html ├── rlogo2.png ├── script.js └── style.css ├── p ├── .bowerrc ├── Makefile ├── bower.json ├── colors.html ├── gulpfile.js ├── index.html ├── lib │ ├── css │ │ ├── jquery-ui.css │ │ └── tree.jquery.css │ └── js │ │ ├── dependencies │ │ ├── jquery.donetyping.js │ │ ├── taphold.js │ │ └── tree.jquery.js │ │ ├── main.js │ │ └── panels │ │ ├── disasm_panel.js │ │ ├── entropy_panel.js │ │ ├── hex_panel.js │ │ ├── logs_panel.js │ │ ├── projects_panel.js │ │ ├── settings_panel.js │ │ ├── strings_panel.js │ │ └── types_panel.js ├── package-lock.json ├── package.json └── rlogo-inv.png ├── package.json ├── r2.svg ├── rlogo.png ├── t ├── Makefile ├── README.md ├── css │ └── style.css ├── gulpfile.js ├── index.html ├── js │ ├── main.js │ ├── modals.js │ └── tiled.js ├── package-lock.json ├── package.json └── rlogo.png ├── upload.html └── w ├── 98.css ├── Makefile ├── custom.html ├── index.html └── index.js /.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 | -------------------------------------------------------------------------------- /.csslintrc: -------------------------------------------------------------------------------- 1 | --exclude-exts=.min.css 2 | --ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/*{.,-}min.js 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "rarop"] 2 | path = rarop 3 | url = https://github.com/jpenalbae/rarop.git 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "../dist/vendors/" 3 | } 4 | -------------------------------------------------------------------------------- /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/bolt/Makefile: -------------------------------------------------------------------------------- 1 | PWD=$(shell pwd) 2 | all: 3 | r2 -qcq -e http.sandbox=false -e http.root=${PWD} -c=H - 4 | -------------------------------------------------------------------------------- /www/bolt/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 34 | 35 | 36 |
23 | 24 |
28 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /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/enyo/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "./vendors/" 3 | } 4 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | } -------------------------------------------------------------------------------- /www/enyo/css/lib/onyx/images/gradient-invert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/enyo/css/lib/onyx/images/gradient-invert.png -------------------------------------------------------------------------------- /www/enyo/css/lib/onyx/images/gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/enyo/css/lib/onyx/images/gradient.png -------------------------------------------------------------------------------- /www/enyo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/enyo/favicon.ico -------------------------------------------------------------------------------- /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/enyo/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/enyo/icon.png -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/enyo/rlogo-tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/enyo/rlogo-tr.png -------------------------------------------------------------------------------- /www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/favicon.ico -------------------------------------------------------------------------------- /www/graph/img/arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/graph/img/arrow.gif -------------------------------------------------------------------------------- /www/graph/img/arrow_d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/graph/img/arrow_d.gif -------------------------------------------------------------------------------- /www/graph/img/arrow_l.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/graph/img/arrow_l.gif -------------------------------------------------------------------------------- /www/graph/img/arrow_r.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/graph/img/arrow_r.gif -------------------------------------------------------------------------------- /www/graph/img/arrow_u.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/graph/img/arrow_u.gif -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/graph/make.sh: -------------------------------------------------------------------------------- 1 | cd img 2 | for FILE in *.gif ; do 3 | printf ''$FILE'' 6 | done 7 | -------------------------------------------------------------------------------- /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/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/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/log.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | r2 log chat 4 | 5 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /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/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "./vendors/" 3 | } 4 | -------------------------------------------------------------------------------- /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/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "vsicons.presets.angular": false 3 | } -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/css/networkerr.css: -------------------------------------------------------------------------------- 1 | .next-attempt { 2 | display: none; 3 | } -------------------------------------------------------------------------------- /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/m/css/tables.css: -------------------------------------------------------------------------------- 1 | tr.active { 2 | background-color: #EEEEEE; 3 | } -------------------------------------------------------------------------------- /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/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/fonts.list: -------------------------------------------------------------------------------- 1 | Roboto:400,100,300,500,700,900,400italic,700italic 2 | -------------------------------------------------------------------------------- /www/m/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/m/images/icon.png -------------------------------------------------------------------------------- /www/m/images/rlogo256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/m/images/rlogo256.png -------------------------------------------------------------------------------- /www/m/images/touch/chrome-touch-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/m/images/touch/chrome-touch-icon-192x192.png -------------------------------------------------------------------------------- /www/m/images/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/m/images/user.jpg -------------------------------------------------------------------------------- /www/m/js/core/ChunkStatus.js: -------------------------------------------------------------------------------- 1 | export const ChunkStatus = { 2 | LAUNCHED: 0, 3 | COMPLETED: 1 4 | }; 5 | -------------------------------------------------------------------------------- /www/m/js/core/NavigatorDirection.js: -------------------------------------------------------------------------------- 1 | export const NavigatorDirection = { 2 | BEFORE: -1, 3 | CURRENT: 0, 4 | AFTER: 1 5 | }; 6 | -------------------------------------------------------------------------------- /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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/m/js/layout/Layouts.js: -------------------------------------------------------------------------------- 1 | export const Layouts = { 2 | FULL: 'full', 3 | HORIZONTAL: 'horizontal', 4 | VERTICAL: 'vertical' 5 | }; 6 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | 


--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/old/rlogo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/old/rlogo2.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /www/p/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "./vendors/" 3 | } 4 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/p/rlogo-inv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/p/rlogo-inv.png -------------------------------------------------------------------------------- /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/r2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /www/rlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/rlogo.png -------------------------------------------------------------------------------- /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/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/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/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/t/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /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/t/rlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/radare2-webui/071494a0da517b113fb06239b0bf30f1de9a3c28/www/t/rlogo.png -------------------------------------------------------------------------------- /www/upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 | -------------------------------------------------------------------------------- /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/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/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 | --------------------------------------------------------------------------------