// shell utilities on top of r2pipe import { R2Papi } from "./r2papi.js"; /** * Interface to hold the name and description for every filesystem type parser implementation. * * @typedef FileSystemType */ export interface FileSystemType { /** * name of the filesystem format, to be used when mounting it. * * @type {string} */ name: string; /** * short string that describes the plugin * * @type {string} */ description: string; } /** * Global static class providing information about the actual radare2 in use. * This class mimics the `Frida` global object in frida, which can be useful to * determine the executing environment of the script * * @typedef Radare2 */ export interface Radare2 { /** * string representing the radare2 version (3 numbers separated by dots) * * @type {string} */ version: string; } /** * Class that interacts with the `r2ai` plugin (requires `rlang-python` and `r2i` r2pm packages to be installed). * Provides a way to script the interactions with different language models using javascript from inside radare2. * * @typedef R2Shell */ export class R2Shell { /** * Keep a reference to the associated r2papi instance * * @type {R2Papi} */ public rp: R2Papi; /** * Create a new instance of the R2Shell * * @param {R2Papi} take the R2Papi intance to used as backend to run the commands * @returns {R2Shell} instance of the shell api */ constructor(papi: R2Papi) { this.rp = papi; } /** * Create a new directory in the host system, if the opational recursive argument is set to * true it will create all the necessary subdirectories instead of just the specified one. * * @param {string} text path to the new directory to be created * @param {boolean?} disabled by default, but if it's true, it will create subdirectories recursively if necessary * @returns {boolean} true if successful */ mkdir(file: string, recursive?: boolean): boolean { if (recursive === true) { this.rp.call(`mkdir -p ${file}`); } else { this.rp.call(`mkdir ${file}`); } return true; } /** * Deletes a file * * @param {string} path to the file to remove * @returns {boolean} true if successful */ unlink(file: string): boolean { this.rp.call(`rm ${file}`); return true; } /** * Change current directory * * @param {string} path to the directory * @returns {boolean} true if successful */ chdir(path: string): boolean { this.rp.call(`cd ${path}`); return true; } /** * List files in the current directory * * @returns {string[]} array of file names */ ls(): string[] { const files = this.rp.call(`ls -q`); return files.trim().split("\n"); } /** * TODO: Checks if a file exists (not implemented) * * @returns {boolean} true if the file exists, false if it does not */ fileExists(path: string): boolean { // TODO return false; } /** * Opens an URL or application * Execute `xdg-open` on linux, `start` on windows, `open` on Mac * * @param {string} URI or file to open by the system */ open(arg: string): void { this.rp.call(`open ${arg}`); } /** * Run a system command and get the return code * * @param {string} system command to be executed * @returns {number} return code (0 is success) */ system(cmd: string): number { this.rp.call(`!${cmd}`); return 0; } /** * Mount the given offset on the specified path using the filesytem. * This is not a system-level mountpoint, it's using the internal filesystem abstraction of radare2. * * @param {string} filesystem type name (see . * @param {string} system command to be executed * @param {string|number} * @returns {number} return code (0 is success) */ mount(fstype: string, path: string, offset: string | number): boolean { if (!offset) { offset = 0; } this.rp.call(`m ${fstype} ${path} ${offset}`); return true; } /** * Unmount the mountpoint associated with the given path. * * @param {string} path to the mounted filesystem * @returns {void} TODO: should return boolean */ umount(path: string): void { this.rp.call(`m-${path}`); } /** * Change current directory on the internal radare2 filesystem * * @param {string} path name to change to * @returns {void} TODO: should return boolean */ chdir2(path: string): void { this.rp.call(`mdq ${path}`); } /** * List the files contained in the given path within the virtual radare2 filesystem. * * @param {string} path name to change to * @returns {void} TODO: should return boolean */ ls2(path: string): string[] { const files = this.rp.call(`mdq ${path}`); return files.trim().split("\n"); } /** * Enumerate all the mountpoints set in the internal virtual filesystem of radare2 * @returns {any[]} array of mount */ enumerateFilesystemTypes(): any[] { return this.rp.cmdj("mLj"); } /** * Enumerate all the mountpoints set in the internal virtual filesystem of radare2 * @returns {any[]} array of mount */ enumerateMountpoints(): any[] { const output = this.rp.cmdj("mj"); return output["mountpoints"]; } /** * TODO: not implemented */ isSymlink(file: string): boolean { return false; } /** * TODO: not implemented */ isDirectory(file: string): boolean { return false; } }