diff --git a/shlr/qjs/Makefile b/shlr/qjs/Makefile index e01bceb37d41c..96447fafbccc0 100644 --- a/shlr/qjs/Makefile +++ b/shlr/qjs/Makefile @@ -64,7 +64,12 @@ R2PAPI_FILES+=shell.js R2PAPI_FILES+=esil.js R2PAPI_FILES_JS=$(addprefix $(NM)/r2papi/,$(R2PAPI_FILES)) +USE_CUSTOM_R2PAPI=1 + js_r2papi.c: node_modules +ifeq ($(USE_CUSTOM_R2PAPI),1) + cp /tmp/r2papi.r2.js js_r2papi.qjs +else # npm i js_r2papi printf "Using r2papi version: " -jq .version node_modules/r2papi/package.json @@ -80,6 +85,7 @@ js_r2papi.c: node_modules | grep -v 'r2pipe\.js' \ >> js_r2papi.qjs echo 'const r2pipe_js_1 = G;' >> js_r2papi.qjs +endif ifeq ($(USE_MINIFY),1) npx minify --help > /dev/null npm i minify npx minify --js < js_r2papi.qjs > js_r2papi.mini.qjs diff --git a/shlr/qjs/js_r2papi.c b/shlr/qjs/js_r2papi.c index 81bec90a5332e..9be7d72002e89 100644 --- a/shlr/qjs/js_r2papi.c +++ b/shlr/qjs/js_r2papi.c @@ -1,341 +1,362 @@ static const char *const js_r2papi_qjs = "" \ - "Object.defineProperty(G,\"__esModule\",{value:!0}),G.NativePoin"\ - "ter=G.NativeCallback=G.NativeFunction=G.R2Papi=G.Assembler=G."\ - "ProcessClass=G.ModuleClass=G.ThreadClass=void 0;const shell_j"\ - "s_1=G;class ThreadClass{constructor(t){this.api=null,this.api"\ - "=t}backtrace(){return r2pipe_js_1.r2.call(\"dbtj\")}sleep(t){re"\ - "turn r2pipe_js_1.r2.call(\"sleep \"+t)}}G.ThreadClass=ThreadCla"\ - "ss;class ModuleClass{constructor(t){this.api=null,this.api=t}"\ - "fileName(){return this.api.call(\"dpe\").trim()}name(){return\"M"\ - "odule\"}findBaseAddress(){return\"TODO\"}findExportByName(t){ret"\ - "urn\"TODO\"}getBaseAddress(t){return\"TODO\"}getExportByName(t){r"\ - "eturn r2pipe_js_1.r2.call(\"iE,name/eq/\"+t+\",vaddr/cols,:quiet"\ - "\")}enumerateExports(){return r2pipe_js_1.r2.callj(\"iEj\")}enum"\ - "erateImports(){return r2pipe_js_1.r2.callj(\"iij\")}enumerateRa"\ - "nges(){return r2pipe_js_1.r2.callj(\"isj\")}enumerateSymbols(){"\ - "return r2pipe_js_1.r2.callj(\"isj\")}}G.ModuleClass=ModuleClass"\ - ";class ProcessClass{constructor(t){this.r2=null,this.r2=t}enu"\ - "merateMallocRanges(){}enumerateSystemRanges(){}enumerateRange"\ - "s(){}enumerateThreads(){return r2pipe_js_1.r2.call(\"dptj\")}en"\ - "umerateModules(){if(r2pipe_js_1.r2.call(\"cfg.json.num=string\""\ - "),r2pipe_js_1.r2.callj(\"e cfg.debug\")){const t=r2pipe_js_1.r2"\ - ".callj(\"dmmj\"),e=[];for(const r of t){const t={base:new Nativ"\ - "ePointer(r.addr),size:new NativePointer(r.addr_end).sub(r.add"\ - "r),path:r.file,name:r.name};e.push(t)}return e}{const t=t=>{c"\ - "onst e=t.split(\"/\");return e[e.length-1]},e=r2pipe_js_1.r2.ca"\ - "llj(\"obj\"),r=[];for(const s of e){const e={base:new NativePoi"\ - "nter(s.addr),size:s.size,path:s.file,name:t(s.file)};r.push(e"\ - ")}const s=r2pipe_js_1.r2.callj(\"ilj\");for(const e of s){const"\ - " s={base:0,size:0,path:e,name:t(e)};r.push(s)}return r}}getMo"\ - "duleByAddress(t){}getModuleByName(t){}codeSigningPolicy(){ret"\ - "urn\"optional\"}getTmpDir(){return this.r2.call(\"e dir.tmp\").tr"\ - "im()}getHomeDir(){return this.r2.call(\"e dir.home\").trim()}pl"\ - "atform(){return this.r2.call(\"e asm.os\").trim()}getCurrentDir"\ - "(){return this.r2.call(\"pwd\").trim()}getCurrentThreadId(){ret"\ - "urn+this.r2.call(\"dpq\")}pageSize(){return 64===this.r2.callj("\ - "\"e asm.bits\")&&this.r2.call(\"e asm.arch\").startsWith(\"arm\")?1"\ - "6384:4096}isDebuggerAttached(){return this.r2.callj(\"e cfg.de"\ - "bug\")}setExceptionHandler(){}id(){return this.r2.callj(\"dpq\")"\ - "}pointerSize(){return r2pipe_js_1.r2.callj(\"e asm.bits\")/8}}G"\ - ".ProcessClass=ProcessClass;class Assembler{constructor(t){thi"\ - "s.program=\"\",this.labels={},this.endian=!1,this.pc=0,this.r2="\ - "null,this.r2=void 0===t?r2pipe_js_1.r2:t,this.program=\"\",this"\ - ".labels={}}setProgramCounter(t){this.pc=t}setEndian(t){this.e"\ - "ndian=t}toString(){return this.program}append(t){this.pc+=t.l"\ - "ength/2,this.program+=t}label(t){const e=this.pc;return this."\ - "labels[t]=this.pc,e}asm(t){let e=this.r2.cmd('\"\"pa '+t).trim("\ - ");e.length<16||(e=\"____\"),this.append(e)}}G.Assembler=Assembl"\ - "er;class R2Papi{constructor(t){this.r2=t}toString(){return\"[o"\ - "bject R2Papi]\"}toJSON(){return this.toString()}getBaseAddress"\ - "(){return new NativePointer(this.cmd(\"e bin.baddr\"))}jsonToTy"\ - "pescript(t,e){let r=`interface ${t} {\\n`;e.length&&e.length>0"\ - "&&(e=e[0]);for(let t of Object.keys(e)){r+=` ${t}: ${typeo"\ - "f e[t]};\\n`}return`${r}}\\n`}getBits(){return this.cmd(\"-b\")}g"\ - "etArch(){return this.cmd(\"-a\")}getCpu(){return this.cmd(\"-e a"\ - "sm.cpu\")}setArch(t,e){this.cmd(\"-a \"+t),void 0!==e&&this.cmd("\ - "\"-b \"+e)}setFlagSpace(t){this.cmd(\"fs \"+t)}setLogLevel(t){ret"\ - "urn this.cmd(\"e log.level=\"+t),this}newMap(t,e,r,s,i,n=\"\"){th"\ - "is.cmd(`om ${t} ${e} ${r} ${s} ${i} ${n}`)}at(t){return new N"\ - "ativePointer(t)}getShell(){return new shell_js_1.R2PapiShell("\ - "this)}version(){return this.r2.cmd(\"?Vq\").trim()}platform(){r"\ - "eturn this.r2.cmd(\"uname\").trim()}arch(){return this.r2.cmd(\""\ - "uname -a\").trim()}bits(){return this.r2.cmd(\"uname -b\").trim("\ - ")}id(){return+this.r2.cmd(\"?vi:$p\")}printAt(t,e,r){}clearScre"\ - "en(){return this.r2.cmd(\"!clear\"),this}getConfig(t){if(\"\"===t"\ - ")return new Error(\"Empty key\");return\"\"===this.r2.cmd(`e~^${t"\ - "} =`).trim()?new Error(\"Config key does not exist\"):this.r2.c"\ - "all(\"e \"+t).trim()}setConfig(t,e){return this.r2.call(\"e \"+t+"\ - "\"=\"+e),this}getRegisterStateForEsil(){return this.cmdj(\"dre\")"\ - ".trim()}getRegisters(){return this.cmdj(\"drj\")}resizeFile(t){"\ - "return this.cmd(`r ${t}`),this}insertNullBytes(t,e){return vo"\ - "id 0===e&&(e=\"$$\"),this.cmd(`r+${t}@${e}`),this}removeBytes(t"\ - ",e){return void 0===e&&(e=\"$$\"),this.cmd(`r-${t}@${e}`),this}"\ - "seek(t){return this.cmd(`s ${t}`),this}currentSeek(){return n"\ - "ew NativePointer(\"$$\")}seekToRelativeOpcode(t){return this.cm"\ - "d(`so ${t}`),this.currentSeek()}getBlockSize(){return+this.cm"\ - "d(\"b\")}setBlockSize(t){return this.cmd(`b ${t}`),this}countFl"\ - "ags(){return Number(this.cmd(\"f~?\"))}countFunctions(){return "\ - "Number(this.cmd(\"aflc\"))}analyzeFunctionsWithEsil(t){this.cmd"\ - "(\"aaef\")}analyzeProgramWithEsil(t){this.cmd(\"aae\")}analyzePro"\ - "gram(t){switch(void 0===t&&(t=0),t){case 0:this.cmd(\"aa\");bre"\ - "ak;case 1:this.cmd(\"aaa\");break;case 2:this.cmd(\"aaaa\");break"\ - ";case 3:this.cmd(\"aaaaa\")}return this}enumerateThreads(){retu"\ - "rn[{context:this.cmdj(\"drj\"),id:0,state:\"waiting\",selected:!0"\ - "}]}currentThreadId(){return+this.cmd(\"e cfg.debug\")?+this.cmd"\ - "(\"dpt.\"):this.id()}setRegisters(t){for(let e of Object.keys(t"\ - ")){const r=t[e];this.r2.cmd(\"dr \"+e+\"=\"+r)}}hex(t){return thi"\ - "s.r2.cmd(\"?v \"+t).trim()}step(){return this.r2.cmd(\"ds\"),this"\ - "}stepOver(){return this.r2.cmd(\"dso\"),this}math(t){return+thi"\ - "s.r2.cmd(\"?v \"+t)}stepUntil(t){this.cmd(`dsu ${t}`)}enumerate"\ - "XrefsTo(t){return this.call(\"axtq \"+t).trim().split(/\\n/)}fin"\ - "dXrefsTo(t,e){e?this.call(\"/r \"+t):this.call(\"/re \"+t)}analyz"\ - "eFunctionsFromCalls(){return this.call(\"aac\"),this}analyzeFun"\ - "ctionsWithPreludes(){return this.call(\"aap\"),this}analyzeObjC"\ - "References(){return this.cmd(\"aao\"),this}analyzeImports(){ret"\ - "urn this.cmd(\"af @ sym.imp.*\"),this}searchDisasm(t){return th"\ - "is.callj(\"/ad \"+t)}searchString(t){return this.cmdj(\"/j \"+t)}"\ - "searchBytes(t){const e=t.map((function(t){return(255&t).toStr"\ - "ing(16)})).join(\"\");return this.cmdj(\"/xj \"+e)}binInfo(){try{"\ - "return this.cmdj(\"ij~{bin}\")}catch(t){return{}}}selectBinary("\ - "t){this.call(`ob ${t}`)}openFile(t){const e=this.call(\"oqq\")."\ - "trim();this.call(`o ${t}`);const r=this.call(\"oqq\").trim();re"\ - "turn e===r?new Error(\"Cannot open file\"):parseInt(r)}openFile"\ - "Nomap(t){const e=this.call(\"oqq\").trim();this.call(`of ${t}`)"\ - ";const r=this.call(\"oqq\").trim();return e===r?new Error(\"Cann"\ - "ot open file\"):parseInt(r)}currentFile(t){return this.call(\"o"\ - ".\").trim()}enumeratePlugins(t){switch(t){case\"bin\":return thi"\ - "s.callj(\"Lij\");case\"io\":return this.callj(\"Loj\");case\"core\":r"\ - "eturn this.callj(\"Lcj\");case\"arch\":return this.callj(\"LAj\");c"\ - "ase\"anal\":return this.callj(\"Laj\");case\"lang\":return this.cal"\ - "lj(\"Llj\")}return[]}enumerateModules(){return this.callj(\"dmmj"\ - "\")}enumerateFiles(){return this.callj(\"oj\")}enumerateBinaries"\ - "(){return this.callj(\"obj\")}enumerateMaps(){return this.callj"\ - "(\"omj\")}enumerateClasses(){return this.callj(\"icj\")}enumerate"\ - "Symbols(){return this.callj(\"isj\")}enumerateExports(){return "\ - "this.callj(\"iEj\")}enumerateImports(){return this.callj(\"iij\")"\ - "}enumerateLibraries(){return this.callj(\"ilj\")}enumerateSecti"\ - "ons(){return this.callj(\"iSj\")}enumerateSegments(){return thi"\ - "s.callj(\"iSSj\")}enumerateEntrypoints(){return this.callj(\"iej"\ - "\")}enumerateRelocations(){return this.callj(\"irj\")}enumerateF"\ - "unctions(){return this.cmdj(\"aflj\")}enumerateFlags(){return t"\ - "his.cmdj(\"fj\")}skip(){this.r2.cmd(\"dss\")}ptr(t){return new Na"\ - "tivePointer(t,this)}call(t){return this.r2.call(t)}callj(t){r"\ - "eturn JSON.parse(this.call(t))}cmd(t){return this.r2.cmd(t)}c"\ - "mdj(t){return JSON.parse(this.cmd(t))}log(t){return this.r2.l"\ - "og(t)}clippy(t){this.r2.log(this.r2.cmd(\"?E \"+t))}ascii(t){th"\ - "is.r2.log(this.r2.cmd(\"?ea \"+t))}}G.R2Papi=R2Papi;class Nativ"\ - "eFunction{constructor(){}}G.NativeFunction=NativeFunction;cla"\ - "ss NativeCallback{constructor(){}}G.NativeCallback=NativeCall"\ - "back;class NativePointer{constructor(t,e){this.api=void 0===e"\ - "?G.R:e,this.addr=(\"\"+t).trim()}setFlag(t){this.api.call(`f ${"\ - "t}=${this.addr}`)}unsetFlag(){this.api.call(`f-${this.addr}`)"\ - "}hexdump(t){let e=void 0===t?\"\":\"\"+t;return this.api.cmd(`x${"\ - "e}@${this.addr}`)}functionGraph(t){return\"dot\"===t?this.api.c"\ - "md(`agfd@ ${this.addr}`):\"json\"===t?this.api.cmd(`agfj@${this"\ - ".addr}`):\"mermaid\"===t?this.api.cmd(`agfm@${this.addr}`):this"\ - ".api.cmd(`agf@${this.addr}`)}readByteArray(t){return JSON.par"\ - "se(this.api.cmd(`p8j ${t}@${this.addr}`))}readHexString(t){re"\ - "turn this.api.cmd(`p8 ${t}@${this.addr}`).trim()}and(t){const"\ - " e=this.api.call(`?v ${this.addr} & ${t}`).trim();return new "\ - "NativePointer(e)}or(t){const e=this.api.call(`?v ${this.addr}"\ - " | ${t}`).trim();return new NativePointer(e)}add(t){const e=t"\ - "his.api.call(`?v ${this.addr}+${t}`).trim();return new Native"\ - "Pointer(e)}sub(t){const e=this.api.call(`?v ${this.addr}-${t}"\ - "`).trim();return new NativePointer(e)}writeByteArray(t){retur"\ - "n this.api.cmd(\"wx \"+t.join(\"\")),this}writeAssembly(t){return"\ - " this.api.cmd(`wa ${t} @ ${this.addr}`),this}writeCString(t){"\ - "return this.api.call(\"w \"+t),this}writeWideString(t){return t"\ - "his.api.call(\"ww \"+t),this}isNull(){return 0==this.toNumber()"\ - "}compare(t){return\"string\"!=typeof t&&\"number\"!=typeof t||(t="\ - "new NativePointer(t)),t.addr===this.addr||new NativePointer(t"\ - ".addr).toNumber()===this.toNumber()}pointsToNull(){return thi"\ - "s.readPointer().compare(0)}toJSON(){return this.api.cmd(\"?vi "\ - "\"+this.addr.trim()).trim()}toString(){return this.api.cmd(\"?v"\ - " \"+this.addr.trim()).trim()}toNumber(){return parseInt(this.t"\ - "oString())}writePointer(t){this.api.cmd(`wvp ${t}@${this}`)}r"\ - "eadRelativePointer(){return this.add(this.readS32())}readPoin"\ - "ter(){return new NativePointer(this.api.call(\"pvp@\"+this.addr"\ - "))}readS8(){return parseInt(this.api.cmd(`pv1d@${this.addr}`)"\ - ")}readU8(){return parseInt(this.api.cmd(`pv1u@${this.addr}`))"\ - "}readU16(){return parseInt(this.api.cmd(`pv2d@${this.addr}`))"\ - "}readU16le(){return parseInt(this.api.cmd(`pv2d@${this.addr}@"\ - "e:cfg.bigendian=false`))}readU16be(){return parseInt(this.api"\ - ".cmd(`pv2d@${this.addr}@e:cfg.bigendian=true`))}readS16(){ret"\ - "urn parseInt(this.api.cmd(`pv2d@${this.addr}`))}readS16le(){r"\ - "eturn parseInt(this.api.cmd(`pv2d@${this.addr}@e:cfg.bigendia"\ - "n=false`))}readS16be(){return parseInt(this.api.cmd(`pv2d@${t"\ - "his.addr}@e:cfg.bigendian=true`))}readS32(){return parseInt(t"\ - "his.api.cmd(`pv4d@${this.addr}`))}readU32(){return parseInt(t"\ - "his.api.cmd(`pv4u@${this.addr}`))}readU32le(){return parseInt"\ - "(this.api.cmd(`pv4u@${this.addr}@e:cfg.bigendian=false`))}rea"\ - "dU32be(){return parseInt(this.api.cmd(`pv4u@${this.addr}@e:cf"\ - "g.bigendian=true`))}readU64(){return parseInt(this.api.cmd(`p"\ - "v8u@${this.addr}`))}readU64le(){return parseInt(this.api.cmd("\ - "`pv8u@${this.addr}@e:cfg.bigendian=false`))}readU64be(){retur"\ - "n parseInt(this.api.cmd(`pv8u@${this.addr}@e:cfg.bigendian=tr"\ - "ue`))}writeInt(t){return this.writeU32(t)}writeU8(t){return t"\ - "his.api.cmd(`wv1 ${t}@${this.addr}`),!0}writeU16(t){return th"\ - "is.api.cmd(`wv2 ${t}@${this.addr}`),!0}writeU16be(t){return t"\ - "his.api.cmd(`wv2 ${t}@${this.addr}@e:cfg.bigendian=true`),!0}"\ - "writeU16le(t){return this.api.cmd(`wv2 ${t}@${this.addr}@e:cf"\ - "g.bigendian=false`),!0}writeU32(t){return this.api.cmd(`wv4 $"\ - "{t}@${this.addr}`),!0}writeU32be(t){return this.api.cmd(`wv4 "\ - "${t}@${this.addr}@e:cfg.bigendian=true`),!0}writeU32le(t){ret"\ - "urn this.api.cmd(`wv4 ${t}@${this.addr}@e:cfg.bigendian=false"\ - "`),!0}writeU64(t){return this.api.cmd(`wv8 ${t}@${this.addr}`"\ - "),!0}writeU64be(t){return this.api.cmd(`wv8 ${t}@${this.addr}"\ - "@e:cfg.bigendian=true`),!0}writeU64le(t){return this.api.cmd("\ - "`wv8 ${t}@${this.addr}@e:cfg.bigendian=false`),!0}readInt32()"\ - "{return this.readU32()}readCString(){return JSON.parse(this.a"\ - "pi.cmd(`pszj@${this.addr}`)).string}readWideString(){return J"\ - "SON.parse(this.api.cmd(`pswj@${this.addr}`)).string}readPasca"\ - "lString(){return JSON.parse(this.api.cmd(`pspj@${this.addr}`)"\ - ").string}instruction(){return this.api.cmdj(`aoj@${this.addr}"\ - "`)[0]}disassemble(t){let e=void 0===t?\"\":\"\"+t;return this.api"\ - ".cmd(`pd ${e}@${this.addr}`)}analyzeFunction(){return this.ap"\ - "i.cmd(\"af@\"+this.addr),this}analyzeFunctionRecursively(){retu"\ - "rn this.api.cmd(\"afr@\"+this.addr),this}name(){return this.api"\ - ".cmd(\"fd \"+this.addr).trim()}methodName(){return this.api.cmd"\ - "(\"ic.@\"+this.addr).trim()}symbolName(){return this.api.cmd(\"i"\ - "sj.@\"+this.addr).trim()}getFunction(){return this.api.cmdj(\"a"\ - "fij@\"+this.addr)}basicBlock(){return this.api.cmdj(\"abj@\"+thi"\ - "s.addr)}functionBasicBlocks(){return this.api.cmdj(\"afbj@\"+th"\ - "is.addr)}xrefs(){return this.api.cmdj(\"axtj@\"+this.addr)}}G.N"\ - "ativePointer=NativePointer,Object.defineProperty(G,\"__esModul"\ - "e\",{value:!0}),Object.defineProperty(G,\"__esModule\",{value:!0"\ - "}),G.Base64=void 0;class Base64{static encode(t){return(0,G.b"\ - "64)(t)}static decode(t){return(0,G.b64)(t,!0)}}G.Base64=Base6"\ - "4,Object.defineProperty(G,\"__esModule\",{value:!0}),G.R2AI=voi"\ - "d 0;class R2AI{constructor(t,e){if(this.available=!1,this.mod"\ - "el=\"\",this.available=\"\"!==r2pipe_js_1.r2.cmd(\"r2ai -h\").trim("\ - "),!this.available)throw new Error(\"ERROR: r2ai is not install"\ - "ed\");t&&r2pipe_js_1.r2.call(`r2ai -n ${t}`),e&&(this.model=e)"\ - "}reset(){this.available&&r2pipe_js_1.r2.call(\"r2ai -R\")}setRo"\ - "le(t){this.available&&r2pipe_js_1.r2.call(`r2ai -r ${t}`)}set"\ - "Model(t){this.available&&r2pipe_js_1.r2.call(`r2ai -m ${this."\ - "model}`)}getModel(){return this.available?r2pipe_js_1.r2.call"\ - "(\"r2ai -m\"):this.model}listModels(){return this.available?r2p"\ - "ipe_js_1.r2.call(\"r2ai -M\").trim().split(/\\n/g):[]}query(t){i"\ - "f(!this.available||\"\"==t)return\"\";const e=t.trim().replace(/\\"\ - "n/g,\".\");return r2pipe_js_1.r2.call(`r2ai ${e}`)}}G.R2AI=R2AI"\ - ",Object.defineProperty(G,\"__esModule\",{value:!0}),G.R2PapiShe"\ - "ll=void 0;class R2PapiShell{constructor(t){this.rp=t}mkdir(t,"\ - "e){return!0===e?this.rp.call(`mkdir -p ${t}`):this.rp.call(`m"\ - "kdir ${t}`),!0}unlink(t){return this.rp.call(`rm ${t}`),!0}ch"\ - "dir(t){return this.rp.call(`cd ${t}`),!0}ls(){return this.rp."\ - "call(\"ls -q\").trim().split(\"\\n\")}fileExists(t){return!1}open("\ - "t){this.rp.call(`open ${t}`)}system(t){return this.rp.call(`!"\ - "${t}`),0}run(t){return this.rp.call(`rm ${t}`),0}mount(t,e){r"\ - "eturn this.rp.call(`m ${t} ${e}`),!0}umount(t){this.rp.call(`"\ - "m-${t}`)}chdir2(t){return void 0===t&&(t=\"/\"),this.rp.call(`m"\ - "dq ${t}`),!0}ls2(t){return void 0===t&&(t=\"/\"),this.rp.call(`"\ - "mdq ${t}`).trim().split(\"\\n\")}enumerateMountpoints(){return t"\ - "his.rp.cmdj(\"mlj\")}isSymlink(t){return!1}isDirectory(t){retur"\ - "n!1}}G.R2PapiShell=R2PapiShell,Object.defineProperty(G,\"__esM"\ - "odule\",{value:!0}),G.EsilParser=G.EsilNode=G.EsilToken=void 0"\ - ";class EsilToken{constructor(t=\"\",e=0){this.label=\"\",this.com"\ - "ment=\"\",this.text=\"\",this.addr=\"0\",this.position=0,this.text="\ - "t,this.position=e}toString(){return this.text}}G.EsilToken=Es"\ - "ilToken;class EsilNode{constructor(t=new EsilToken,e=\"none\"){"\ - "this.type=\"none\",this.token=t,this.children=[]}setSides(t,e){"\ - "this.lhs=t,this.rhs=e}addChildren(t,e){void 0!==t&&this.child"\ - "ren.push(t),void 0!==e&&this.children.push(e)}toEsil(){if(voi"\ - "d 0!==this.lhs&&void 0!==this.rhs){let t=this.lhs.toEsil();re"\ - "turn\"\"!==t&&(t+=\",\"),`${this.rhs.toEsil()},${t}${this.token}`"\ - "}return\"\"}toString(){let t=\"\";if(\"\"!==this.token.label&&(t+=t"\ - "his.token.label+\":\\n\"),this.token.addr,\"\"!==this.token.commen"\ - "t&&(t+=\"/*\"+this.token.comment+\"*/\\n\"),\"GOTO\"===this.token.to"\ - "String())if(this.children.length>0){t+=\"goto label_\"+this.chi"\ - "ldren[0].token.position+\";\\n\"}else{t+=`goto label_${0};\\n`}if"\ - "(this.children.length>0){t+=` (if (${this.rhs})\\n`;for(let e"\ - " of this.children)if(null!==e){const r=e.toString();\"\"!=r&&(t"\ - "+=` ${r}\\n`)}t+=\" )\\n\"}return void 0!==this.lhs&&void 0!==t"\ - "his.rhs?t+` ( ${this.lhs} ${this.token} ${this.rhs} )`:t+t"\ - "his.token.toString()}}G.EsilNode=EsilNode;class EsilParser{co"\ - "nstructor(t){this.cur=0,this.r2=t,this.cur=0,this.stack=[],th"\ - "is.nodes=[],this.tokens=[],this.root=new EsilNode(new EsilTok"\ - "en(\"function\",0),\"block\")}toJSON(){if(this.stack.length>0)thr"\ - "ow new Error(\"The ESIL stack is not empty\");return JSON.strin"\ - "gify(this.root,null,2)}toEsil(){return this.nodes.map((t=>t.t"\ - "oEsil())).join(\",\")}optimizeFlags(t){void 0!==t.rhs&&this.opt"\ - "imizeFlags(t.rhs),void 0!==t.lhs&&this.optimizeFlags(t.lhs);f"\ - "or(let e=0;e4096){const r=r2.cmd(`fd.@"\ - " ${e}`).trim().split(\"\\n\")[0].trim();\"\"!=r&&-1===r.indexOf(\"+"\ - "\")&&(t.token.text=r)}}optimize(t){-1!=t.indexOf(\"flag\")&&this"\ - ".optimizeFlags(this.root)}toString(){return this.root.childre"\ - "n.map((t=>t.toString())).join(\";\\n\")}reset(){this.nodes=[],th"\ - "is.stack=[],this.tokens=[],this.cur=0,this.root=new EsilNode("\ - "new EsilToken(\"function\",0),\"block\")}parseRange(t,e){let r=t;"\ - "for(;r1&&(r2.cmd(`s ${r[0]}`),e.parse(r[1],r[0]),e.optimize(\"f"\ - "lags,labels\"))}}const s=r2.cmd(\"?v $$\").trim();void 0===t&&(t"\ - "=s);const i=r2.cmdj(`afbj@${t}`);for(let t of i)r2.cmd(`s ${t"\ - ".addr}`),r(t.ninstr);r2.cmd(`s ${s}`)}parse(t,e){const r=t.tr"\ - "im().split(\",\").map((t=>t.trim())),s=this.tokens.length;for(l"\ - "et t of r){const r=new EsilToken(t,this.tokens.length);void 0"\ - "!==e&&(r.addr=e),this.tokens.push(r)}const i=this.tokens.leng"\ - "th;this.parseRange(s,i)}peek(t){return this.tokens[t]}pushTok"\ - "en(t){if(this.isNumber(t)){const e=new EsilNode(t,\"number\");t"\ - "his.stack.push(e),this.nodes.push(e)}else if(this.isInternal("\ - "t)){const e=new EsilNode(t,\"flag\");this.stack.push(e),this.no"\ - "des.push(e)}else if(this.isOperation(t));else{const e=new Esi"\ - "lNode(t,\"register\");this.stack.push(e),this.nodes.push(e)}}is"\ - "Number(t){return!!t.toString().startsWith(\"0\")||+t>0}isIntern"\ - "al(t){const e=t.toString();return e.startsWith(\"$\")&&e.length"\ - ">1}parseUntil(t){const e=t+1;let r=e;const s=[],i=this.nodes."\ - "length;for(this.stack.forEach((t=>s.push(t)));r=1))throw new Error(\"Stack needs"\ - " more items\");{const t=this.stack.pop();new EsilNode(t.token,"\ - "\"operation\");this.stack.push(t)}return!0;case\"!\":if(!(this.st"\ - "ack.length>=1))throw new Error(\"Stack needs more items\");{con"\ - "st e=new EsilNode(new EsilToken(\"\",t.position),\"none\"),r=this"\ - ".stack.pop(),s=new EsilNode(t,\"operation\");s.setSides(e,r),th"\ - "is.stack.push(s)}return!0;case\"\":case\"}\":case\"}{\":return!0;ca"\ - "se\"DUP\":{if(this.stack.length<1)throw new Error(\"goto cant po"\ - "p\");const t=this.stack.pop();this.stack.push(t),this.stack.pu"\ - "sh(t)}return!0;case\"GOTO\":if(null!==this.peek(t.position-1)){"\ - "if(this.stack.length<1)throw new Error(\"goto cant pop\");const"\ - " e=this.stack.pop();if(null!==e){const r=0|+e.toString();if(r"\ - ">0){const e=this.peek(r);if(void 0!==e){e.label=\"label_\"+r,e."\ - "comment=\"hehe\";const s=new EsilNode(t,\"goto\"),i=this.getNodeF"\ - "or(e.position);null!=i&&s.children.push(i),this.root.children"\ - ".push(s)}else console.error(\"Cannot find goto node\")}else con"\ - "sole.error(\"Cannot find dest node for goto\")}}return!0;case\"?"\ - "{\":if(!(this.stack.length>=1))throw new Error(\"Stack needs mo"\ - "re items\");{const e=new EsilNode(new EsilToken(\"if\",t.positio"\ - "n),\"none\"),r=this.stack.pop(),s=new EsilNode(t,\"operation\");s"\ - ".setSides(e,r);let i=this.parseUntil(t.position),n=null;null!"\ - "==i&&(s.children.push(i),this.nodes.push(i),n=this.parseUntil"\ - "(i.token.position+1),null!==n&&(s.children.push(n),this.nodes"\ - ".push(n))),this.nodes.push(s),this.root.children.push(s),null"\ - "!==n&&(this.cur=n.token.position)}return!0;case\"-\":if(!(this."\ - "stack.length>=2))throw new Error(\"Stack needs more items\");{c"\ - "onst e=this.stack.pop(),r=this.stack.pop(),s=new EsilNode(t,\""\ - "operation\");s.setSides(e,r),this.stack.length,this.stack.push"\ - "(s),this.nodes.push(s)}return!0;case\"<\":case\">\":case\"^\":case\""\ - "&\":case\"|\":case\"+\":case\"*\":case\"/\":case\">>=\":case\"<<=\":case\">"\ - ">>=\":case\"<<<=\":case\">>>>=\":case\"<<<<=\":if(!(this.stack.lengt"\ - "h>=2))throw new Error(\"Stack needs more items\");{const e=this"\ - ".stack.pop(),r=this.stack.pop(),s=new EsilNode(t,\"operation\")"\ - ";s.setSides(e,r),this.stack.length,this.stack.push(s),this.no"\ - "des.push(s)}return!0;case\"=\":case\":=\":case\"-=\":case\"+=\":case\""\ - "==\":case\"=[1]\":case\"=[2]\":case\"=[4]\":case\"=[8]\":if(!(this.sta"\ - "ck.length>=2))throw new Error(\"Stack needs more items\");{cons"\ - "t e=this.stack.pop(),r=this.stack.pop(),s=new EsilNode(t,\"ope"\ - "ration\");s.setSides(e,r),0===this.stack.length&&this.root.chi"\ - "ldren.push(s),this.nodes.push(s)}return!0}return!1}}G.EsilPar"\ - "ser=EsilParser;const r2pipe_js_1=G;\n"; + "\"use strict\";var A=a=>typeof a==='number';var b=a=>typeof a=="\ + "='string';const{keys:c}=Object;const{defineProperty:d}=Object"\ + ";d(exports,'__esModule',{value:!0});exports.R2Shell=void 0;cl"\ + "ass R2Shell{constructor(B){this.rp=B}mkdir(C,_b){_b===!0?this"\ + ".rp.call(`mkdir -p ${C}`):this.rp.call(`mkdir ${C}`);return!0"\ + "}unlink(_a){this.rp.call(`rm ${_a}`);return!0}chdir(D){this.r"\ + "p.call(`cd ${D}`);return!0}ls(){var _A=this.rp.call(`ls -q`);"\ + "return _A.trim().split('\\n')}fileExists(e){return!1}open(E){t"\ + "his.rp.call(`open ${E}`)}system(aA){this.rp.call(`!${aA}`);re"\ + "turn 0}mount(aB,_B,_c){!_c&&(_c=0);this.rp.call(`m ${aB} ${_B"\ + "} ${_c}`);return!0}umount(aC){this.rp.call(`m-${aC}`)}chdir2("\ + "aD){this.rp.call(`mdq ${aD}`)}ls2(aE){var aF=this.rp.call(`md"\ + "q ${aE}`);return aF.trim().split('\\n')}enumerateFilesystemTyp"\ + "es(){return this.rp.cmdj('mLj')}enumerateMountpoints(){var aG"\ + "=this.rp.cmdj('mj');return aG['mountpoints']}isSymlink(aH){re"\ + "turn!1}isDirectory(aI){return!1}}exports.R2Shell=R2Shell;d(ex"\ + "ports,'__esModule',{value:!0});exports.EsilParser=exports.Esi"\ + "lNode=exports.EsilToken=void 0;class EsilToken{constructor(aJ"\ + "='',aK=0){this.label=this.comment=this.text='';this.addr='0';"\ + "this.position=0;this.text=aJ;this.position=aK}toString(){retu"\ + "rn this.text}}exports.EsilToken=EsilToken;class EsilNode{cons"\ + "tructor(aL=new EsilToken(),aM='none'){this.type='none';this.t"\ + "oken=aL;this.children=[]}setSides(aN,aO){this.lhs=aN;this.rhs"\ + "=aO}addChildren(aP,aQ){aP!==void 0&&this.children.push(aP);aQ"\ + "!==void 0&&this.children.push(aQ)}toEsil(){if(this.lhs!==void"\ + " 0&&this.rhs!==void 0){let aS=this.lhs.toEsil();aS!==''&&(aS+"\ + "=',');var aR=this.rhs.toEsil();return`${aR},${aS}${this.token"\ + "}`}return''}toString(){let aT='';this.token.label!==''&&(aT+="\ + "this.token.label+':\\n');this.token.addr!=='0';this.token.comm"\ + "ent!==''&&(aT+='/*'+this.token.comment+'*/\\n');if(`${this.tok"\ + "en}`==='GOTO')if(this.children.length>0){var aU=this.children"\ + "[0];aT+='goto label_'+aU.token.position+';\\n'}else{var _C=0;a"\ + "T+=`goto label_${_C};\\n`}if(this.children.length>0){aT+=` (i"\ + "f (${this.rhs})\\n`;for(const aV of this.children)if(aV!==null"\ + "){var x=`${aV}`;x!=''&&(aT+=` ${x}\\n`)}aT+=' )\\n'}if(this.l"\ + "hs!==void 0&&this.rhs!==void 0)return aT+` ( ${this.lhs} $"\ + "{this.token} ${this.rhs} )`;return aT+`${this.token}`}}export"\ + "s.EsilNode=EsilNode;class EsilParser{constructor(aW){this.cur"\ + "=0;this.r2=aW;this.cur=0;this.stack=this.nodes=this.tokens=[]"\ + ";this.root=new EsilNode(new EsilToken('function', 0), 'block'"\ + ")}toJSON(){if(this.stack.length>0)throw Error('The ESIL stack"\ + " is not empty');return JSON.stringify(this.root,null,2)}toEsi"\ + "l(){return this.nodes.map(x=>x.toEsil()).join(',')}optimizeFl"\ + "ags(aX){aX.rhs!==void 0&&this.optimizeFlags(aX.rhs);aX.lhs!=="\ + "void 0&&this.optimizeFlags(aX.lhs);for(let i=0;i4096){var aZ=r2.cmd(`fd.@ ${aY}`),_d=aZ.trim().split('"\ + "\\n')[0].trim();(_d!=''&&_d.indexOf('+')===-1)&&(aX.token.text"\ + "=_d)}}optimize(bA){bA.indexOf('flag')!=-1&&this.optimizeFlags"\ + "(this.root)}toString(){return this.root.children.map(x=>`${x}"\ + "`).join(';\\n')}reset(){this.nodes=this.stack=this.tokens=[];t"\ + "his.cur=0;this.root=new EsilNode(new EsilToken('function', 0)"\ + ", 'block')}parseRange(bB,bC){let bD=bB;while (bD1&&(r2.cmd(`s ${bK[0]}`),bF.pars"\ + "e(bK[1],bK[0]),bF.optimize('flags,labels'))}}var bH=r2.cmd('?"\ + "v $$').trim();bE===void 0&&(bE=bH);for(const bb of _e){r2.cmd"\ + "(`s ${bb.addr}`);bG(bb.ninstr)}r2.cmd(`s ${bH}`)}parse(bM,bN)"\ + "{var bO=bM.trim().split(',').map(x=>x.trim());for(const bQ of"\ + " bO){var bP=new EsilToken(bQ, this.tokens.length);bN!==void 0"\ + "&&(bP.addr=bN);this.tokens.push(bP)}this.parseRange(this.toke"\ + "ns.length,this.tokens.length)}peek(a){return this.tokens[a]}p"\ + "ushToken(bR){if(this.isNumber(bR)){var bS=new EsilNode(bR, 'n"\ + "umber');this.stack.push(bS);this.nodes.push(bS)}else if(this."\ + "isInternal(bR)){const bT=new EsilNode(bR, 'flag');this.stack."\ + "push(bT);this.nodes.push(bT)}else if(this.isOperation(bR)){}e"\ + "lse{const bU=new EsilNode(bR, 'register');this.stack.push(bU)"\ + ";this.nodes.push(bU)}}isNumber(bV){if(`${bV}`.startsWith('0')"\ + ")return!0;return +bV>0}isInternal(bW){var bX=`${bW}`;return b"\ + "X.startsWith('$')&&bX.length>1}parseUntil(bY){var bZ=bY+1,cB="\ + "[],_E=this.nodes.length;let cA=bZ;for(const x of this.stack)c"\ + "B.push(x);while (cA=1){var cI=this.stack.pop();var c"\ + "J=new EsilNode(cI.token, 'operation');this.stack.push(cI)}els"\ + "e throw Error('Stack needs more items');return!0;case '!':if("\ + "this.stack.length>=1){var cK=new EsilNode(new EsilToken('', c"\ + "H.position), 'none');var cL=new EsilNode(cH, 'operation');cL."\ + "setSides(cK,this.stack.pop());this.stack.push(cL)}else throw "\ + "Error('Stack needs more items');return!0;case '':case '}':cas"\ + "e '}{':return!0;case 'DUP':if(this.stack.length<1)throw Error"\ + "('goto cant pop');else{var F=this.stack.pop();this.stack.push"\ + "(F);this.stack.push(F)}return!0;case 'GOTO':{var G=this.peek("\ + "cH.position-1);if(G!==null){if(this.stack.length<1)throw Erro"\ + "r('goto cant pop');const cM=this.stack.pop();if(cM!==null){va"\ + "r h=0| +`${cM}`;if(h>0){var I=this.peek(h);if(I!==void 0){I.l"\ + "abel=`label_${h}`;I.comment='hehe';const cN=new EsilNode(cH, "\ + "'goto');var j=this.getNodeFor(I.position);j!=null&&cN.childre"\ + "n.push(j);this.root.children.push(cN)}else console.error('Can"\ + "not find goto node')}else console.error('Cannot find dest nod"\ + "e for goto')}}}return!0;case '?{':if(this.stack.length>=1){co"\ + "nst cO=new EsilNode(cH, 'operation');cO.setSides(new EsilNode"\ + "(new EsilToken('if', cH.position), 'none'),this.stack.pop());"\ + "var K=this.parseUntil(cH.position);let cP=null;if(K!==null){c"\ + "O.children.push(K);this.nodes.push(K);cP=this.parseUntil(K.to"\ + "ken.position+1);cP!==null&&(cO.children.push(cP),this.nodes.p"\ + "ush(cP))}this.nodes.push(cO);this.root.children.push(cO);cP!="\ + "=null&&(this.cur=cP.token.position)}else throw Error('Stack n"\ + "eeds more items');return!0;case '-':if(this.stack.length>=2){"\ + "const cQ=new EsilNode(cH, 'operation');cQ.setSides(this.stack"\ + ".pop(),this.stack.pop());this.stack.length===0;this.stack.pus"\ + "h(cQ);this.nodes.push(cQ)}else throw Error('Stack needs more "\ + "items');return!0;case '<':case '>':case '^':case '&':case '|'"\ + ":case '+':case '*':case '/':case '>>=':case '<<=':case '>>>='"\ + ":case '<<<=':case '>>>>=':case '<<<<=':if(this.stack.length>="\ + "2){const cR=new EsilNode(cH, 'operation');cR.setSides(this.st"\ + "ack.pop(),this.stack.pop());this.stack.length===0;this.stack."\ + "push(cR);this.nodes.push(cR)}else throw Error('Stack needs mo"\ + "re items');return!0;case '=':case ':=':case '-=':case '+=':ca"\ + "se '==':case '=[1]':case '=[2]':case '=[4]':case '=[8]':if(th"\ + "is.stack.length>=2){const cS=new EsilNode(cH, 'operation');cS"\ + ".setSides(this.stack.pop(),this.stack.pop());this.stack.lengt"\ + "h===0&&this.root.children.push(cS);this.nodes.push(cS)}else t"\ + "hrow Error('Stack needs more items');return!0}return!1}}expor"\ + "ts.EsilParser=EsilParser;d(exports,'__esModule',{value:!0});e"\ + "xports.Base64=void 0;class Base64{static encode(cT){return 0,"\ + "exports.b64(cT)}static decode(cU){return 0,exports.b64(cU,!0)"\ + "}}exports.Base64=Base64;d(exports,'__esModule',{value:!0});ex"\ + "ports.newAsyncR2PipeFromSync=exports.R2PipeSyncFromSync=void "\ + "0;class R2PipeSyncFromSync{constructor(cV){this.r2p=cV}cmd(cW"\ + "){return this.r2p.cmd(cW)}cmdAt(cX,cY){return this.r2p.cmdAt("\ + "cX,cY)}cmdj(cZ){return this.r2p.cmdj(cZ)}call(dA){return this"\ + ".r2p.call(dA)}callj(dB){return this.r2p.cmdj(dB)}callAt(dC,dD"\ + "){return this.r2p.cmdAt(dC,dD)}log(dE){return this.r2p.log(dE"\ + ")}plugin(dF,dG){return this.r2p.plugin(dF,dG)}unload(dH,dI){r"\ + "eturn this.r2p.unload(dH,dI)}}exports.R2PipeSyncFromSync=R2Pi"\ + "peSyncFromSync;function _(dJ){return new R2PipeSyncFromSync(d"\ + "J)}exports.newAsyncR2PipeFromSync=_;d(exports,'__esModule',{v"\ + "alue:!0});exports.R2AI=void 0;class R2AI{constructor(dK,dL,dM"\ + "){this.available=!1;this.model='';this.r2=dK;this.available=!"\ + "1}checkAvailability(){if(this.available)return!0;this.availab"\ + "le=r2pipe_js_1.r2.cmd('r2ai -h').trim()!=='';return this.avai"\ + "lable}reset(){this.checkAvailability();this.available&&r2pipe"\ + "_js_1.r2.call('r2ai -R')}setRole(dN){if(this.available){r2pip"\ + "e_js_1.r2.call(`r2ai -r ${dN}`);return!0}return!1}setModel(dO"\ + "){if(this.available){r2pipe_js_1.r2.call(`r2ai -m ${this.mode"\ + "l}`);return!0}return!1}getModel(){this.available&&(this.model"\ + "=r2pipe_js_1.r2.call('r2ai -m').trim());return this.model}lis"\ + "tModels(){if(this.available){var models=r2pipe_js_1.r2.call('"\ + "r2ai -M');return models.replace('-m ','').trim().split(/\\n/g)"\ + ".filter(x=>x.indexOf(':')!==-1)}return[]}query(dP){if(!this.a"\ + "vailable||dP=='')return'';var dQ=dP.trim().replace(/\\n/g,'.')"\ + ",dR=r2pipe_js_1.r2.call(`r2ai ${dQ}`);return dR.trim()}}expor"\ + "ts.R2AI=R2AI;d(exports,'__esModule',{value:!0});exports.Nativ"\ + "ePointer=exports.NativeCallback=exports.NativeFunction=export"\ + "s.R2PapiSync=exports.Assembler=exports.ProcessClass=exports.M"\ + "oduleClass=exports.ThreadClass=void 0;class ThreadClass{const"\ + "ructor(r2){this.api=null;this.api=r2}backtrace(){return r2pip"\ + "e_js_1.r2.call('dbtj')}sleep(dS){return r2pipe_js_1.r2.call(`"\ + "sleep ${dS}`)}}exports.ThreadClass=ThreadClass;class ModuleCl"\ + "ass{constructor(r2){this.api=null;this.api=r2}fileName(){retu"\ + "rn this.api.call('dpe').trim()}name(){return'Module'}findBase"\ + "Address(){return'TODO'}getBaseAddress(dT){return'TODO'}getExp"\ + "ortByName(dU){return ptr(r2pipe_js_1.r2.call(`iE,name/eq/${dU"\ + "},vaddr/cols,:quiet`))}findExportByName(dV){return this.getEx"\ + "portByName(dV)}enumerateExports(){return r2pipe_js_1.r2.callj"\ + "('iEj')}enumerateImports(){return r2pipe_js_1.r2.callj('iij')"\ + "}enumerateSymbols(){return r2pipe_js_1.r2.callj('isj')}enumer"\ + "ateEntrypoints(){return r2pipe_js_1.r2.callj('iej')}enumerate"\ + "Ranges(){return r2pipe_js_1.r2.callj('omj')}}exports.ModuleCl"\ + "ass=ModuleClass;class ProcessClass{constructor(r2){this.r2=nu"\ + "ll;this.r2=r2}enumerateMallocRanges(){}enumerateSystemRanges("\ + "){}enumerateRanges(){}enumerateThreads(){return r2pipe_js_1.r"\ + "2.callj('dptj')}enumerateModules(){r2pipe_js_1.r2.call('cfg.j"\ + "son.num=string');if(r2pipe_js_1.r2.callj('e cfg.debug')){var "\ + "dW=r2pipe_js_1.r2.callj('dmmj'),dX=[];for(const eB of dW){var"\ + " _f={base:new NativePointer(eB.addr),size:new NativePointer(e"\ + "B.addr_end).sub(eB.addr),path:eB.file,name:eB.name};dX.push(_"\ + "f)}return dX}{var dY=x=>{const y=x.split('/');return y[y.leng"\ + "th-1]},dZ=r2pipe_js_1.r2.callj('obj'),eC=[];for(const eD of d"\ + "Z){eC.push({base:new NativePointer(eD.addr),size:eD.size,path"\ + ":eD.file,name:dY(eD.file)})}var eA=r2pipe_js_1.r2.callj('ilj'"\ + ");for(const lib of eA){eC.push({base:0,size:0,path:lib,name:d"\ + "Y(lib)})}return eC}}getModuleByAddress(eE){}getModuleByName(e"\ + "F){}codeSigningPolicy(){return'optional'}getTmpDir(){return t"\ + "his.r2.call('e dir.tmp').trim()}getHomeDir(){return this.r2.c"\ + "all('e dir.home').trim()}platform(){return this.r2.call('e as"\ + "m.os').trim()}getCurrentDir(){return this.r2.call('pwd').trim"\ + "()}getCurrentThreadId(){return +this.r2.call('dpq')}pageSize("\ + "){if(this.r2.callj('e asm.bits')===64&&this.r2.call('e asm.ar"\ + "ch').startsWith('arm'))return 16384;return 4096}isDebuggerAtt"\ + "ached(){return this.r2.callj('e cfg.debug')}setExceptionHandl"\ + "er(){}id(){return this.r2.callj('dpq').trim()}pointerSize(){r"\ + "eturn r2pipe_js_1.r2.callj('e asm.bits')/8}}exports.ProcessCl"\ + "ass=ProcessClass;class Assembler{constructor(eG){this.program"\ + "='';this.labels={};this.endian=!1;this.pc=ptr(0);eG===void 0?"\ + "this.r2=0,r2pipe_js_1.newAsyncR2PipeFromSync(r2pipe_js_1.r2):"\ + "this.r2=eG;this.program='';this.labels={}}setProgramCounter(p"\ + "c){this.pc=pc}setEndian(eH){this.endian=eH}toString(){return "\ + "this.program}append(x){this.pc=this.pc.add(x.length/2);this.p"\ + "rogram+=x}label(s){var eI=this.pc;this.labels[s]=this.pc;retu"\ + "rn eI}encode(s){var eJ=this.r2.call(`pa ${s}`);return eJ.trim"\ + "()}decode(s){var eK=this.r2.call(`pad ${s}`);return eK.trim()"\ + "}}exports.Assembler=Assembler;class R2PapiSync{constructor(r2"\ + "){this.r2=r2}toString(){return'[object R2Papi]'}toJSON(){retu"\ + "rn`${this}`}getBaseAddress(){return new NativePointer(this.cm"\ + "d('e bin.baddr'))}jsonToTypescript(eL,a){let eM=`interface ${"\ + "eL} {\\n`;(a.length&&a.length>0)&&(a=a[0]);for(const k of c(a)"\ + "){var eN=typeof a[k],eO=k;eM+=` ${eO}: ${eN};\\n`}return`${"\ + "eM}}\\n`}getBits(){return +this.cmd('-b')}getArch(){return thi"\ + "s.cmdTrim('-a')}callTrim(x){var eP=this.call(x);return eP.tri"\ + "m()}cmdTrim(x){var eQ=this.cmd(x);return eQ.trim()}getCpu(){r"\ + "eturn this.cmdTrim('-e asm.cpu')}setArch(eR,eS){this.cmd(`-a "\ + "${eR}`);eS!==void 0&&this.cmd(`-b ${eS}`)}setFlagSpace(eT){th"\ + "is.cmd(`fs ${eT}`)}demangleSymbol(eU,eV){return this.cmdTrim("\ + "'iD '+eU+' '+eV)}setLogLevel(eW){this.cmd(`e log.level=${eW}`"\ + ")}newMap(eX,eY,eZ,fA,fB,_F=''){this.cmd(`om ${eX} ${eY} ${eZ}"\ + " ${fA} ${fB} ${_F}`)}at(a){return new NativePointer(a)}getShe"\ + "ll(){return new shell_js_1.R2Shell(this)}version(){var v=this"\ + ".r2.cmd('?Vq');return v.trim()}platform(){var fC=this.r2.cmd("\ + "'uname');return fC.trim()}arch(){var fD=this.r2.cmd('uname -a"\ + "');return fD.trim()}bits(){var fE=this.r2.cmd('uname -b');ret"\ + "urn fE.trim()}id(){return +this.r2.cmd('?vi:$p')}printAt(fF,x"\ + ",y){}clearScreen(){this.r2.cmd('!clear');return this}getConfi"\ + "g(fG){if(fG==='')return Error('Empty key');var fH=this.r2.cmd"\ + "(`e~^${fG} =`);if(fH.trim()==='')return Error('Config key doe"\ + "s not exist');var fI=this.r2.call(`e ${fG}`);return fI.trim()"\ + "}setConfig(fJ,fK){this.r2.call('e '+fJ+'='+fK);return this}ge"\ + "tRegisterStateForEsil(){var fL=this.cmdj('dre');return this.c"\ + "mdj('dre')}getRegisters(){return this.cmdj('drj')}resizeFile("\ + "fM){this.cmd(`r ${fM}`);return this}insertNullBytes(fN,fO){fO"\ + "===void 0&&(fO='$$');this.cmd(`r+${fN}@${fO}`);return this}re"\ + "moveBytes(fP,fQ){fQ===void 0&&(fQ='$$');this.cmd(`r-${fP}@${f"\ + "Q}`);return this}seek(fR){this.cmd(`s ${fR}`);return this}cur"\ + "rentSeek(){return new NativePointer('$$')}seekToRelativeOpcod"\ + "e(fS){this.cmd(`so ${fS}`);return this.currentSeek()}getBlock"\ + "Size(){return +this.cmd('b')}setBlockSize(a){this.cmd(`b ${a}"\ + "`);return this}countFlags(){return +this.cmd('f~?')}countFunc"\ + "tions(){return +this.cmd('aflc')}analyzeFunctionsWithEsil(fT)"\ + "{this.cmd('aaef')}analyzeProgramWithEsil(fU){this.cmd('aae')}"\ + "analyzeProgram(fV){fV===void 0&&(fV=0);switch(fV) {case 0:thi"\ + "s.cmd('aa');break;case 1:this.cmd('aaa');break;case 2:this.cm"\ + "d('aaaa');break;case 3:this.cmd('aaaaa');break}return this}en"\ + "umerateThreads(){var fW=this.cmdj('drj'),fX={context:fW,id:0,"\ + "state:'waiting',selected:!0};return[fX]}currentThreadId(){if("\ + "+this.cmd('e cfg.debug'))return +this.cmd('dpt.');return this"\ + ".id()}setRegisters(fY){for(const r of c(fY)){var v=fY[r];this"\ + ".r2.cmd('dr '+r+'='+v)}}hex(s){var fZ=this.r2.cmd(`?v ${s}`);"\ + "return fZ.trim()}step(){this.r2.cmd('ds');return this}stepOve"\ + "r(){this.r2.cmd('dso');return this}math(gA){return +this.r2.c"\ + "md(`?v ${gA}`)}stepUntil(gB){this.cmd(`dsu ${gB}`)}enumerateX"\ + "refsTo(s){var gC=this.call(`axtq ${s}`);return gC.trim().spli"\ + "t(/\\n/)}findXrefsTo(s,gD){gD?this.call(`/r ${s}`):this.call(`"\ + "/re ${s}`)}analyzeFunctionsFromCalls(){this.call('aac');retur"\ + "n this}autonameAllFunctions(){this.call('aan');return this}an"\ + "alyzeFunctionsWithPreludes(){this.call('aap');return this}ana"\ + "lyzeObjCReferences(){this.cmd('aao');return this}analyzeImpor"\ + "ts(){this.cmd('af @ sym.imp.*');return this}searchDisasm(s){r"\ + "eturn this.callj(`/ad ${s}`)}searchString(s){return this.cmdj"\ + "(`/j ${s}`)}searchBytes(gE){function gF(gG){return (gG&0xff)."\ + "toString(16)}var s=gE.map(gF).join('');return this.cmdj(`/xj "\ + "${s}`)}binInfo(){try{return this.cmdj('ij~{bin}')}catch(e){re"\ + "turn{}}}selectBinary(id){this.call(`ob ${id}`)}openFile(gH){v"\ + "ar gI=this.call('oqq');this.call(`o ${gH}`);var gJ=this.call("\ + "'oqq');if(gI.trim()===gJ.trim())return Error('Cannot open fil"\ + "e');return parseInt(gJ)}openFileNomap(gK){var gL=this.call('o"\ + "qq');this.call(`of ${gK}`);var gM=this.call('oqq');if(gL.trim"\ + "()===gM.trim())return Error('Cannot open file');return parseI"\ + "nt(gM)}currentFile(gN){return this.call('o.').trim()}enumerat"\ + "ePlugins(gO){switch(gO) {case 'bin':return this.callj('Lij');"\ + "case 'io':return this.callj('Loj');case 'core':return this.ca"\ + "llj('Lcj');case 'arch':return this.callj('LAj');case 'anal':r"\ + "eturn this.callj('Laj');case 'lang':return this.callj('Llj')}"\ + "return[]}enumerateModules(){return this.callj('dmmj')}enumera"\ + "teFiles(){return this.callj('oj')}enumerateBinaries(){return "\ + "this.callj('obj')}enumerateMaps(){return this.callj('omj')}en"\ + "umerateClasses(){return this.callj('icj')}enumerateSymbols(){"\ + "return this.callj('isj')}enumerateExports(){return this.callj"\ + "('iEj')}enumerateImports(){return this.callj('iij')}enumerate"\ + "Libraries(){return this.callj('ilj')}enumerateSections(){retu"\ + "rn this.callj('iSj')}enumerateSegments(){return this.callj('i"\ + "SSj')}enumerateEntrypoints(){return this.callj('iej')}enumera"\ + "teRelocations(){return this.callj('irj')}enumerateFunctions()"\ + "{return this.cmdj('aflj')}enumerateFlags(){return this.cmdj('"\ + "fj')}skip(){this.r2.cmd('dss')}ptr(s){return new NativePointe"\ + "r(s, this)}call(s){return this.r2.call(s)}callj(s){return JSO"\ + "N.parse(this.call(s))}cmd(s){return this.r2.cmd(s)}cmdj(s){re"\ + "turn JSON.parse(this.cmd(s))}log(s){return this.r2.log(s)}cli"\ + "ppy(gP){this.r2.log(this.r2.cmd(`?E ${gP}`))}ascii(gQ){this.r"\ + "2.log(this.r2.cmd(`?ea ${gQ}`))}}exports.R2PapiSync=R2PapiSyn"\ + "c;class NativeFunction{constructor(){}}exports.NativeFunction"\ + "=NativeFunction;class NativeCallback{constructor(){}}exports."\ + "NativeCallback=NativeCallback;class NativePointer{constructor"\ + "(s,gR){this.api=gR??exports.R;this.addr=`${s}`.trim()}filterF"\ + "lag(gS){return this.api.call(`fD ${gS}`)}setFlag(gT){this.api"\ + ".call(`f ${gT}=${this.addr}`)}unsetFlag(){this.api.call(`f-${"\ + "this.addr}`)}hexdump(gU){var gV=gU===void 0?'':`${gU}`;return"\ + " this.api.cmd(`x${gV}@${this.addr}`)}functionGraph(gW){if(gW="\ + "=='dot')return this.api.cmd(`agfd@ ${this.addr}`);if(gW==='js"\ + "on')return this.api.cmd(`agfj@${this.addr}`);if(gW==='mermaid"\ + "')return this.api.cmd(`agfm@${this.addr}`);return this.api.cm"\ + "d(`agf@${this.addr}`)}readByteArray(gX){return JSON.parse(thi"\ + "s.api.cmd(`p8j ${gX}@${this.addr}`))}readHexString(gY){return"\ + " this.api.cmd(`p8 ${gY}@${this.addr}`).trim()}and(a){var gZ=t"\ + "his.api.call(`?v ${this.addr} & ${a}`);return new NativePoint"\ + "er(gZ.trim())}or(a){var hA=this.api.call(`?v ${this.addr} | $"\ + "{a}`);return new NativePointer(hA.trim())}add(a){var hB=this."\ + "api.call(`?v ${this.addr}+${a}`);return new NativePointer(hB)"\ + "}sub(a){var hC=this.api.call(`?v ${this.addr}-${a}`);return n"\ + "ew NativePointer(hC)}writeByteArray(hD){this.api.cmd('wx '+hD"\ + ".join(''));return this}writeAssembly(hE){this.api.cmd(`wa ${h"\ + "E} @ ${this.addr}`);return this}writeCString(s){this.api.call"\ + "(`w ${s}`);return this}writeWideString(s){this.api.call(`ww $"\ + "{s}`);return this}isNull(){return this.toNumber()==0}compare("\ + "a){var hF=b(a)||A(a)?new NativePointer(a):a,hG=r2pipe_js_1.r2"\ + ".call(`?vi ${this.addr} - ${hF.addr}`);if(hG[0]==='-')return "\ + "-1;if(hG[0]==='0')return 0;return 1}pointsToNull(){var hH=thi"\ + "s.readPointer();return hH.compare(0)==0}toJSON(){var hI=this."\ + "api.cmd('?vi '+this.addr.trim());return hI.trim()}toString(){"\ + "return this.api.cmd('?v '+this.addr.trim()).trim()}toNumber()"\ + "{return parseInt(`${this}`)}writePointer(p){}readRelativePoin"\ + "ter(){return this.add(this.readS32())}readPointer(){var hJ=th"\ + "is.api.call('pvp@'+this.addr);return new NativePointer(hJ)}re"\ + "adS8(){return parseInt(this.api.cmd(`pv1d@${this.addr}`))}rea"\ + "dU8(){return parseInt(this.api.cmd(`pv1u@${this.addr}`))}read"\ + "U16(){return parseInt(this.api.cmd(`pv2d@${this.addr}`))}read"\ + "U16le(){}readU16be(){}readS16(){}readS16le(){}readS16be(){}re"\ + "adS32(){}readU32(){}readU32le(){}readU32be(){}readU64(){retur"\ + "n parseInt(this.api.cmd(`pv8u@${this.addr}`))}readU64le(){}re"\ + "adU64be(){}writeInt(n){return this.writeU32(n)}writeU8(n){thi"\ + "s.api.cmd(`wv1 ${n}@${this.addr}`);return!0}writeU16(n){this."\ + "api.cmd(`wv2 ${n}@${this.addr}`);return!0}writeU16be(n){this."\ + "api.cmd(`wv2 ${n}@${this.addr}@e:cfg.bigendian=true`);return!"\ + "0}writeU16le(n){this.api.cmd(`wv2 ${n}@${this.addr}@e:cfg.big"\ + "endian=false`);return!0}writeU32(n){this.api.cmd(`wv4 ${n}@${"\ + "this.addr}`);return!0}writeU32be(n){this.api.cmd(`wv4 ${n}@${"\ + "this.addr}@e:cfg.bigendian=true`);return!0}writeU32le(n){this"\ + ".api.cmd(`wv4 ${n}@${this.addr}@e:cfg.bigendian=false`);retur"\ + "n!0}writeU64(n){this.api.cmd(`wv8 ${n}@${this.addr}`);return!"\ + "0}writeU64be(n){this.api.cmd(`wv8 ${n}@${this.addr}@e:cfg.big"\ + "endian=true`);return!0}writeU64le(n){this.api.cmd(`wv8 ${n}@$"\ + "{this.addr}@e:cfg.bigendian=false`);return!0}readInt32(){retu"\ + "rn this.readU32()}readCString(){return JSON.parse(this.api.cm"\ + "d(`pszj@${this.addr}`)).string}readWideString(){return JSON.p"\ + "arse(this.api.cmd(`pswj@${this.addr}`)).string}readPascalStri"\ + "ng(){return JSON.parse(this.api.cmd(`pspj@${this.addr}`)).str"\ + "ing}instruction(){var hK=this.api.cmdj(`aoj@${this.addr}`);re"\ + "turn hK[0]}disassemble(hL){var hM=hL===void 0?'':`${hL}`;retu"\ + "rn this.api.cmd(`pd ${hM}@${this.addr}`)}analyzeFunction(){th"\ + "is.api.cmd('af@'+this.addr);return this}analyzeFunctionRecurs"\ + "ively(){this.api.cmd('afr@'+this.addr);return this}name(){ret"\ + "urn this.api.cmd('fd '+this.addr).trim()}methodName(){return "\ + "this.api.cmd('ic.@'+this.addr).trim()}symbolName(){var hN=thi"\ + "s.api.cmd('isj.@'+this.addr);return hN.trim()}getFunction(){r"\ + "eturn this.api.cmdj('afij@'+this.addr)}basicBlock(){return th"\ + "is.api.cmdj('abj@'+this.addr)}functionBasicBlocks(){return th"\ + "is.api.cmdj('afbj@'+this.addr)}xrefs(){return this.api.cmdj('"\ + "axtj@'+this.addr)}}exports.NativePointer=NativePointer;var u="\ + "R2PapiSync;\n"; diff --git a/shlr/qjs/js_r2papi.qjs b/shlr/qjs/js_r2papi.qjs index aef8aa82c91c1..f136fd58fe1b4 100644 --- a/shlr/qjs/js_r2papi.qjs +++ b/shlr/qjs/js_r2papi.qjs @@ -1,1510 +1,1838 @@ -// r2papi main file -Object.defineProperty(G, "__esModule", { value: true }); -G.NativePointer = G.NativeCallback = G.NativeFunction = G.R2Papi = G.Assembler = G.ProcessClass = G.ModuleClass = G.ThreadClass = void 0; -// import { R, Module, Process, Thread } from "./global.js" -const shell_js_1 = G;//"./shell.js"); -; -; -; -; -; -; -; -; -class ThreadClass { - constructor(r2) { - this.api = null; - this.api = r2; +"use strict"; +// shell utilities on top of r2pipe +Object.defineProperty(exports, "__esModule", { value: true }); +exports.R2Shell = void 0; +/** + * Provides a way to script the interactions with different language models using javascript from inside radare2. + * + * @typedef R2Shell + */ +class R2Shell { + /** + * 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) { + this.rp = papi; } - backtrace() { - return r2pipe_js_1.r2.call("dbtj"); + /** + * 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, recursive) { + if (recursive === true) { + this.rp.call(`mkdir -p ${file}`); + } + else { + this.rp.call(`mkdir ${file}`); + } + return true; } - sleep(seconds) { - return r2pipe_js_1.r2.call("sleep " + seconds); + /** + * Deletes a file + * + * @param {string} path to the file to remove + * @returns {boolean} true if successful + */ + unlink(file) { + this.rp.call(`rm ${file}`); + return true; } -} -G.ThreadClass = ThreadClass; -class ModuleClass { - constructor(r2) { - this.api = null; - this.api = r2; + /** + * Change current directory + * + * @param {string} path to the directory + * @returns {boolean} true if successful + */ + chdir(path) { + this.rp.call(`cd ${path}`); + return true; } - fileName() { - return this.api.call("dpe").trim(); + /** + * List files in the current directory + * + * @returns {string[]} array of file names + */ + ls() { + const files = this.rp.call(`ls -q`); + return files.trim().split("\n"); } - name() { - return "Module"; + /** + * TODO: Checks if a file exists (not implemented) + * + * @returns {boolean} true if the file exists, false if it does not + */ + fileExists(path) { + // TODO + return false; } - findBaseAddress() { - return "TODO"; + /** + * 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) { + this.rp.call(`open ${arg}`); } - findExportByName(name) { - // TODO - return "TODO"; + /** + * 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) { + this.rp.call(`!${cmd}`); + return 0; } - getBaseAddress(name) { - return "TODO"; + /** + * 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, path, offset) { + if (!offset) { + offset = 0; + } + this.rp.call(`m ${fstype} ${path} ${offset}`); + return true; } - getExportByName(name) { - return r2pipe_js_1.r2.call("iE,name/eq/" + name + ",vaddr/cols,:quiet"); + /** + * Unmount the mountpoint associated with the given path. + * + * @param {string} path to the mounted filesystem + * @returns {void} TODO: should return boolean + */ + umount(path) { + this.rp.call(`m-${path}`); } - enumerateExports() { - // TODO: use frida json - return r2pipe_js_1.r2.callj("iEj"); + /** + * Change current directory on the internal radare2 filesystem + * + * @param {string} path name to change to + * @returns {void} TODO: should return boolean + */ + chdir2(path) { + this.rp.call(`mdq ${path}`); } - enumerateImports() { - // TODO: use frida json - return r2pipe_js_1.r2.callj("iij"); + /** + * 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) { + const files = this.rp.call(`mdq ${path}`); + return files.trim().split("\n"); } - enumerateRanges() { - // TODO: use frida json - return r2pipe_js_1.r2.callj("isj"); + /** + * Enumerate all the mountpoints set in the internal virtual filesystem of radare2 + * @returns {any[]} array of mount + */ + enumerateFilesystemTypes() { + return this.rp.cmdj("mLj"); } - enumerateSymbols() { - // TODO: use frida json - return r2pipe_js_1.r2.callj("isj"); + /** + * Enumerate all the mountpoints set in the internal virtual filesystem of radare2 + * @returns {any[]} array of mount + */ + enumerateMountpoints() { + const output = this.rp.cmdj("mj"); + return output["mountpoints"]; + } + /** + * TODO: not implemented + */ + isSymlink(file) { + return false; + } + /** + * TODO: not implemented + */ + isDirectory(file) { + return false; } } -G.ModuleClass = ModuleClass; -class ProcessClass { - constructor(r2) { - this.r2 = null; - this.r2 = r2; +exports.R2Shell = R2Shell; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.EsilParser = exports.EsilNode = exports.EsilToken = void 0; +// ("this is just a comment"), -- comments are also part of the runtime +/* +=("//", { + =(obj, {}()) + =([obj, comment], 32) + if(eq([obj,comment], 32), + ret() + ) + ret(obj) +}) +*/ +class EsilToken { + constructor(text = "", position = 0) { + this.label = ""; + this.comment = ""; + this.text = ""; + this.addr = "0"; // for ut64 we use strings for numbers :< + this.position = 0; + this.text = text; + this.position = position; } - enumerateMallocRanges() { + toString() { + return this.text; } - enumerateSystemRanges() { +} +exports.EsilToken = EsilToken; +class EsilNode { + constructor(token = new EsilToken(), type = "none") { + this.type = "none"; + this.token = token; + this.children = []; } - enumerateRanges() { + setSides(lhs, rhs) { + this.lhs = lhs; + this.rhs = rhs; } - enumerateThreads() { - return r2pipe_js_1.r2.call("dptj"); + addChildren(ths, fhs) { + if (ths !== undefined) { + this.children.push(ths); + } + if (fhs !== undefined) { + this.children.push(fhs); + } } - enumerateModules() { - r2pipe_js_1.r2.call("cfg.json.num=string"); // to handle 64bit values properly - if (r2pipe_js_1.r2.callj("e cfg.debug")) { - const modules = r2pipe_js_1.r2.callj("dmmj"); - const res = []; - for (const mod of modules) { - const entry = { - base: new NativePointer(mod.addr), - size: new NativePointer(mod.addr_end).sub(mod.addr), - path: mod.file, - name: mod.name, - }; - res.push(entry); + toEsil() { + if (this.lhs !== undefined && this.rhs !== undefined) { + // XXX handle ?{ }{ } + let left = this.lhs.toEsil(); + if (left !== "") { + left += ","; } - return res; + const right = this.rhs.toEsil(); + return `${right},${left}${this.token}`; } - else { - const fname = (x) => { - const y = x.split("/"); - return y[y.length - 1]; - }; - const bobjs = r2pipe_js_1.r2.callj("obj"); - const res = []; - for (const obj of bobjs) { - const entry = { - base: new NativePointer(obj.addr), - size: obj.size, - path: obj.file, - name: fname(obj.file) - }; - res.push(entry); + return ""; // this.token.text; + } + toString() { + let str = ""; + if (this.token.label !== "") { + str += this.token.label + ":\n"; + } + if (this.token.addr !== "0") { + // str += "// @ " + this.token.addr + "\n"; + } + if (this.token.comment !== "") { + str += "/*" + this.token.comment + "*/\n"; + } + if (this.token.toString() === "GOTO") { + if (this.children.length > 0) { + const children = this.children[0]; + str += "goto label_" + children.token.position + ";\n"; } - const libs = r2pipe_js_1.r2.callj("ilj"); - for (const lib of libs) { - const entry = { - base: 0, - size: 0, - path: lib, - name: fname(lib) - }; - res.push(entry); + else { + // console.log(JSON.stringify(this,null, 2)); + const pos = 0; + str += `goto label_${pos};\n`; } - return res; } + if (this.children.length > 0) { + str += ` (if (${this.rhs})\n`; + for (const children of this.children) { + if (children !== null) { + const x = children.toString(); + if (x != "") { + str += ` ${x}\n`; + } + } + } + str += " )\n"; + } + if (this.lhs !== undefined && this.rhs !== undefined) { + return str + ` ( ${this.lhs} ${this.token} ${this.rhs} )`; + // return str + `${this.lhs} ${this.token} ${this.rhs}`; + } + return str + this.token.toString(); } - getModuleByAddress(addr) { - } - getModuleByName(moduleName) { - } - codeSigningPolicy() { - return "optional"; +} +exports.EsilNode = EsilNode; +class EsilParser { + constructor(r2) { + this.cur = 0; + this.r2 = r2; + this.cur = 0; + this.stack = []; + this.nodes = []; + this.tokens = []; + this.root = new EsilNode(new EsilToken("function", 0), "block"); } - getTmpDir() { - return this.r2.call("e dir.tmp").trim(); + toJSON() { + if (this.stack.length > 0) { + // return JSON.stringify (this.stack, null, 2); + throw new Error("The ESIL stack is not empty"); + } + return JSON.stringify(this.root, null, 2); } - getHomeDir() { - return this.r2.call("e dir.home").trim(); + toEsil() { + return this.nodes.map((x) => x.toEsil()).join(","); } - platform() { - return this.r2.call("e asm.os").trim(); - } - getCurrentDir() { - return this.r2.call("pwd").trim(); - } - getCurrentThreadId() { - return +this.r2.call("dpq"); - } - pageSize() { - if (this.r2.callj("e asm.bits") === 64 && this.r2.call("e asm.arch").startsWith("arm")) { - return 16384; + optimizeFlags(node) { + if (node.rhs !== undefined) { + this.optimizeFlags(node.rhs); } - return 4096; - } - isDebuggerAttached() { - return this.r2.callj("e cfg.debug"); - } - setExceptionHandler() { - // do nothing - } - id() { - // - return this.r2.callj("dpq"); - } - pointerSize() { - return r2pipe_js_1.r2.callj("e asm.bits") / 8; - } -} -G.ProcessClass = ProcessClass; -class Assembler { - constructor(myr2) { - this.program = ""; - this.labels = {}; - this.endian = false; - this.pc = 0; - this.r2 = null; - this.r2 = (typeof myr2 === 'undefined') ? r2pipe_js_1.r2 : myr2; - this.program = ''; - this.labels = {}; - } - setProgramCounter(pc) { - this.pc = pc; - } - setEndian(big) { - this.endian = big; - } - toString() { - return this.program; - } - append(x) { - this.pc += x.length / 2; - this.program += x; - } - // api - label(s) { - const pos = this.pc; // this.#program.length / 4; - this.labels[s] = this.pc; - return pos; - } - asm(s) { - let hex = this.r2.cmd('""pa ' + s).trim(); - if (hex.length < 16) { - // ok + if (node.lhs !== undefined) { + this.optimizeFlags(node.lhs); } - else { - hex = "____"; - // console.error("Invalid instruction: " + s); + for (let i = 0; i < node.children.length; i++) { + this.optimizeFlags(node.children[i]); + } + const addr = node.toString(); + if (+addr > 4096) { + const cname = r2.cmd(`fd.@ ${addr}`); + const fname = cname.trim().split("\n")[0].trim(); + if (fname != "" && fname.indexOf("+") === -1) { + node.token.text = fname; + } } - this.append(hex); } -} -G.Assembler = Assembler; -class R2Papi { - constructor(r2) { - this.r2 = r2; + optimize(options) { + if (options.indexOf("flag") != -1) { + this.optimizeFlags(this.root); + } } toString() { - return "[object R2Papi]"; + return this.root.children.map((x) => x.toString()).join(";\n"); } - toJSON() { - return this.toString(); + reset() { + this.nodes = []; + this.stack = []; + this.tokens = []; + this.cur = 0; + this.root = new EsilNode(new EsilToken("function", 0), "block"); } - getBaseAddress() { - return new NativePointer(this.cmd("e bin.baddr")); + parseRange(from, to) { + let pos = from; + while (pos < this.tokens.length && pos < to) { + const token = this.peek(pos); + if (!token) { + // console.log("BREAK"); + break; + } + // console.log(pos, token); + this.cur = pos; + this.pushToken(token); + pos = this.cur; + pos++; + } + // console.log("done"); } - jsonToTypescript(name, a) { - let str = `interface ${name} {\n`; - if (a.length && a.length > 0) { - a = a[0]; + parseFunction(addr) { + const ep = this; + function parseAmount(n) { + // console.log("PDQ "+n); + const output = r2.cmd("pie " + n + " @e:scr.color=0"); + const lines = output.trim().split("\n"); + for (const line of lines) { + if (line.length === 0) { + console.log("Empty"); + continue; + } + // console.log("parse", r2.cmd("?v:$$")); + const kv = line.split(" "); + if (kv.length > 1) { + // line != "") { + // console.log("// @ " + kv[0]); + //ep.reset (); + r2.cmd(`s ${kv[0]}`); + ep.parse(kv[1], kv[0]); + ep.optimize("flags,labels"); + //console.log(ep.toString()); + } + } + // console.log(ep.toString()); } - for (let k of Object.keys(a)) { - const typ = typeof (a[k]); - const nam = k; - str += ` ${nam}: ${typ};\n`; + const oaddr = (r2.cmd("?v $$")).trim(); + // const func = r2.cmdj("pdrj"); // XXX this command changes the current seek + if (addr === undefined) { + addr = oaddr; } - return `${str}}\n`; - } - getBits() { - return this.cmd('-b'); - } - getArch() { - return this.cmd('-a'); - } - getCpu() { - return this.cmd('-e asm.cpu'); - } - // TODO: setEndian, setCpu, ... - setArch(arch, bits) { - this.cmd("-a " + arch); - if (bits !== undefined) { - this.cmd("-b " + bits); + const bbs = r2.cmdj(`afbj@${addr}`); // XXX this command changes the current seek + for (const bb of bbs) { + // console.log("bb_" + bb.addr + ":"); + r2.cmd(`s ${bb.addr}`); + parseAmount(bb.ninstr); } + r2.cmd(`s ${oaddr}`); } - setFlagSpace(name) { - this.cmd('fs ' + name); - } - setLogLevel(level) { - this.cmd('e log.level=' + level); - return this; - } - /** - * should return the id for the new map using the given file descriptor - */ - // rename to createMap or mapFile? - newMap(fd, vaddr, size, paddr, perm, name = "") { - this.cmd(`om ${fd} ${vaddr} ${size} ${paddr} ${perm} ${name}`); - } - at(a) { - return new NativePointer(a); - } - getShell() { - return new shell_js_1.R2PapiShell(this); - } - // Radare/Frida - version() { - return this.r2.cmd("?Vq").trim(); - } - // Process - platform() { - return this.r2.cmd("uname").trim(); - } - arch() { - return this.r2.cmd("uname -a").trim(); - } - bits() { - return this.r2.cmd("uname -b").trim(); - } - id() { - // getpid(); - return +this.r2.cmd("?vi:$p"); - } - // Other stuff - printAt(msg, x, y) { - // see pg, but pg is obrken :D + parse(expr, addr) { + const tokens = expr + .trim() + .split(",") + .map((x) => x.trim()); + const from = this.tokens.length; + for (const tok of tokens) { + const token = new EsilToken(tok, this.tokens.length); + if (addr !== undefined) { + token.addr = addr; + } + this.tokens.push(token); + } + const to = this.tokens.length; + this.parseRange(from, to); } - clearScreen() { - this.r2.cmd("!clear"); - return this; + peek(a) { + return this.tokens[a]; } - getConfig(key) { - if (key === '') { - return new Error('Empty key'); + pushToken(tok) { + if (this.isNumber(tok)) { + const node = new EsilNode(tok, "number"); + this.stack.push(node); + this.nodes.push(node); } - const exist = this.r2.cmd(`e~^${key} =`).trim(); - if (exist === '') { - return new Error('Config key does not exist'); + else if (this.isInternal(tok)) { + const node = new EsilNode(tok, "flag"); + this.stack.push(node); + this.nodes.push(node); } - return this.r2.call("e " + key).trim(); - } - setConfig(key, val) { - this.r2.call("e " + key + "=" + val); - return this; - } - getRegisterStateForEsil() { - return this.cmdj("dre").trim(); - } - getRegisters() { - // this.r2.log("winrar" + JSON.stringify(JSON.parse(this.r2.cmd("drj")),null, 2) ); - return this.cmdj("drj"); - } - resizeFile(newSize) { - this.cmd(`r ${newSize}`); - return this; - } - insertNullBytes(newSize, at) { - if (at === undefined) { - at = "$$"; + else if (this.isOperation(tok)) { + // run the operation login } - this.cmd(`r+${newSize}@${at}`); - return this; - } - removeBytes(newSize, at) { - if (at === undefined) { - at = "$$"; + else { + // assume it's a register, so just push the string + const node = new EsilNode(tok, "register"); + this.stack.push(node); + this.nodes.push(node); } - this.cmd(`r-${newSize}@${at}`); - return this; - } - seek(addr) { - this.cmd(`s ${addr}`); - return this; - } - currentSeek() { - return new NativePointer('$$'); + // we need a list of register names to do this check properly + // throw new Error ("Unknown token"); } - seekToRelativeOpcode(nth) { - this.cmd(`so ${nth}`); - return this.currentSeek(); + isNumber(expr) { + if (expr.toString().startsWith("0")) { + return true; + } + return +expr > 0; } - getBlockSize() { - return +this.cmd("b"); + isInternal(expr) { + const text = expr.toString(); + return text.startsWith("$") && text.length > 1; } - setBlockSize(a) { - this.cmd(`b ${a}`); - return this; - } - countFlags() { - return Number(this.cmd("f~?")); - } - countFunctions() { - return Number(this.cmd("aflc")); - } - analyzeFunctionsWithEsil(depth) { - this.cmd("aaef"); - } - analyzeProgramWithEsil(depth) { - this.cmd("aae"); - } - analyzeProgram(depth) { - if (depth === undefined) { - depth = 0; - } - switch (depth) { - case 0: - this.cmd("aa"); - break; - case 1: - this.cmd("aaa"); + parseUntil(start) { + const from = start + 1; + let pos = from; + const origStack = []; + const this_nodes_length = this.nodes.length; + this.stack.forEach((x) => origStack.push(x)); + while (pos < this.tokens.length) { + const token = this.peek(pos); + if (!token) { break; - case 2: - this.cmd("aaaa"); + } + if (token.toString() === "}") { break; - case 3: - this.cmd("aaaaa"); + } + if (token.toString() === "}{") { + // return token; break; + } + // console.log("peek ", this.tokens[pos]); + pos++; } - return this; + this.stack = origStack; + const to = pos; + this.parseRange(from, to); + const same = this.nodes.length == this_nodes_length; + // console.log("BLOCK ("+ ep.toString()); + if (same) { + return null; + } + return this.nodes[this.nodes.length - 1]; // this.tokens.length - 1]; } - enumerateThreads() { - // TODO: use apt/dpt to list threads at iterate over them to get the registers - const regs0 = this.cmdj("drj"); - const thread0 = { - context: regs0, - id: 0, - state: "waiting", - selected: true, - }; - return [thread0]; + getNodeFor(index) { + const tok = this.peek(index); + if (tok === undefined) { + return null; + } + for (const node of this.nodes) { + if (node.token.position === index) { + return node; + } + } + this.nodes.push(new EsilNode(new EsilToken("label", index), "label")); + return null; } - currentThreadId() { - if (+this.cmd("e cfg.debug")) { - return +this.cmd("dpt."); + findNodeFor(index) { + for (const node of this.nodes) { + if (node.token.position === index) { + return node; + } } - return this.id(); + return null; } - setRegisters(obj) { - for (let r of Object.keys(obj)) { - const v = obj[r]; - this.r2.cmd("dr " + r + "=" + v); + isOperation(expr) { + switch (expr.toString()) { + // 1pop1push + case "[1]": + case "[2]": + case "[4]": + case "[8]": + if (this.stack.length >= 1) { + const i1 = this.stack.pop(); + // TODO: MemoryReferenceNode(i1)); + const mn = new EsilNode(i1.token, "operation"); // expr.toString()); + this.stack.push(i1); // mn); + } + else { + throw new Error("Stack needs more items"); + } + return true; + // 1pop1push + case "!": + if (this.stack.length >= 1) { + const i0 = new EsilNode(new EsilToken("", expr.position), "none"); + const i1 = this.stack.pop(); + const nn = new EsilNode(expr, "operation"); + nn.setSides(i0, i1); + this.stack.push(nn); + } + else { + throw new Error("Stack needs more items"); + } + return true; + case "": + case "}": + case "}{": + // no pops or nothing, just does nothing + return true; + case "DUP": + if (this.stack.length < 1) { + throw new Error("goto cant pop"); + } + else { + const destNode = this.stack.pop(); + this.stack.push(destNode); + this.stack.push(destNode); + } + return true; + case "GOTO": + // take previous statement which should be const and add a label + { + const prev = this.peek(expr.position - 1); + if (prev !== null) { + // TODO: check stack + if (this.stack.length < 1) { + throw new Error("goto cant pop"); + } + const destNode = this.stack.pop(); + if (destNode !== null) { + const value = 0 | +destNode.toString(); + if (value > 0) { + const destToken = this.peek(value); + if (destToken !== undefined) { + destToken.label = "label_" + value; + destToken.comment = "hehe"; + const nn = new EsilNode(expr, "goto"); + const gn = this.getNodeFor(destToken.position); + if (gn != null) { + nn.children.push(gn); + } + this.root.children.push(nn); + } + else { + console.error("Cannot find goto node"); + } + } + else { + console.error("Cannot find dest node for goto"); + } + } + } + } + return true; + // controlflow + case "?{": // ESIL_TOKEN_IF + if (this.stack.length >= 1) { + const i0 = new EsilNode(new EsilToken("if", expr.position), "none"); + const i1 = this.stack.pop(); + const nn = new EsilNode(expr, "operation"); + nn.setSides(i0, i1); // left side can be ignored for now.. but we can express this somehow + const trueBlock = this.parseUntil(expr.position); + let falseBlock = null; + // nn.addChildren(trueBlock, falseBlock); + if (trueBlock !== null) { + nn.children.push(trueBlock); + this.nodes.push(trueBlock); + falseBlock = this.parseUntil(trueBlock.token.position + 1); + if (falseBlock !== null) { + nn.children.push(falseBlock); + this.nodes.push(falseBlock); + } + } + // console.log("true", trueBlock); + // console.log("false", falseBlock); + // this.stack.push(nn); + this.nodes.push(nn); + this.root.children.push(nn); + if (falseBlock !== null) { + this.cur = falseBlock.token.position; + } + } + else { + throw new Error("Stack needs more items"); + } + return true; + case "-": + if (this.stack.length >= 2) { + const i0 = this.stack.pop(); + const i1 = this.stack.pop(); + const nn = new EsilNode(expr, "operation"); + nn.setSides(i0, i1); + if (this.stack.length === 0) { + // this.root.children.push(nn); + } + this.stack.push(nn); + this.nodes.push(nn); + } + else { + throw new Error("Stack needs more items"); + } + return true; + // 2pop1push + case "<": + case ">": + case "^": + case "&": + case "|": + case "+": + case "*": + case "/": + case ">>=": + case "<<=": + case ">>>=": + case "<<<=": + case ">>>>=": + case "<<<<=": + if (this.stack.length >= 2) { + const i0 = this.stack.pop(); + const i1 = this.stack.pop(); + const nn = new EsilNode(expr, "operation"); + nn.setSides(i0, i1); + if (this.stack.length === 0) { + // this.root.children.push(nn); + } + this.stack.push(nn); + this.nodes.push(nn); + } + else { + throw new Error("Stack needs more items"); + } + return true; + // 2pop0push + case "=": + case ":=": + case "-=": + case "+=": + case "==": + case "=[1]": + case "=[2]": + case "=[4]": + case "=[8]": + if (this.stack.length >= 2) { + const i0 = this.stack.pop(); + const i1 = this.stack.pop(); + const nn = new EsilNode(expr, "operation"); + nn.setSides(i0, i1); + if (this.stack.length === 0) { + this.root.children.push(nn); + } + this.nodes.push(nn); + } + else { + throw new Error("Stack needs more items"); + } + return true; } + return false; } - hex(s) { - return this.r2.cmd("?v " + s).trim(); +} +exports.EsilParser = EsilParser; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Base64 = void 0; +class Base64 { + /** + * Encode the given input string using base64 + * + * @param {string} input string to encode + * @returns {string} base64 encoded string + */ + static encode(input) { + return (0, exports.b64)(input); } - step() { - this.r2.cmd("ds"); - return this; + /** + * Decode the given base64 string into plain text + * + * @param {string} input string encoded in base64 format + * @returns {string} base64 decoded string + */ + static decode(input) { + return (0, exports.b64)(input, true); } - stepOver() { - this.r2.cmd("dso"); - return this; +} +exports.Base64 = Base64; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.newAsyncR2PipeFromSync = exports.R2PipeSyncFromSync = void 0; +class R2PipeSyncFromSync { + constructor(r2p) { + this.r2p = r2p; } - math(expr) { - return +this.r2.cmd("?v " + expr); - } - stepUntil(dst) { - this.cmd(`dsu ${dst}`); + /** + * Run a command in the associated instance of radare2 and return the output as a string + * + * @param {string} command to be executed inside radare2. + * @returns {string} The output of the command execution + */ + cmd(command) { + return this.r2p.cmd(command); } - enumerateXrefsTo(s) { - return this.call("axtq " + s).trim().split(/\n/); + cmdAt(command, address) { + return this.r2p.cmdAt(command, address); } - // TODO: rename to searchXrefsTo ? - findXrefsTo(s, use_esil) { - if (use_esil) { - this.call("/r " + s); - } - else { - this.call("/re " + s); - } + cmdj(cmd) { + return this.r2p.cmdj(cmd); } - analyzeFunctionsFromCalls() { - this.call("aac"); - return this; + call(command) { + return this.r2p.call(command); } - analyzeFunctionsWithPreludes() { - this.call("aap"); - return this; + callj(cmd) { + return this.r2p.cmdj(cmd); } - analyzeObjCReferences() { - this.cmd("aao"); - return this; + callAt(command, address) { + return this.r2p.cmdAt(command, address); } - analyzeImports() { - this.cmd("af @ sym.imp.*"); - return this; + log(msg) { + return this.r2p.log(msg); } - searchDisasm(s) { - const res = this.callj("/ad " + s); - return res; + plugin(type, maker) { + return this.r2p.plugin(type, maker); } - searchString(s) { - const res = this.cmdj("/j " + s); - return res; + unload(type, name) { + return this.r2p.unload(type, name); } - searchBytes(data) { - function num2hex(data) { - return (data & 0xff).toString(16); - } - const s = data.map(num2hex).join(''); - const res = this.cmdj("/xj " + s); - return res; +} +exports.R2PipeSyncFromSync = R2PipeSyncFromSync; +function newAsyncR2PipeFromSync(r2p) { + const asyncR2Pipe = new R2PipeSyncFromSync(r2p); + return asyncR2Pipe; +} +exports.newAsyncR2PipeFromSync = newAsyncR2PipeFromSync; +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.R2AI = void 0; +/** + * Provides a way to script the interactions with different language models using javascript from inside radare2. + * + * @typedef R2AI + */ +class R2AI { + constructor(r2, num, model) { + /** + * Instance variable that informs if the `r2ai` plugin is loaded, must be true in order to use the rest of the methods of this class. + * + * @type {boolean} + */ + this.available = false; + /** + * Name of the model instantiated to be used for the subsequent calls. + * + * @type {string} + */ + this.model = ""; + this.r2 = r2; + this.available = false; } - binInfo() { - try { - return this.cmdj("ij~{bin}"); + checkAvailability() { + if (this.available) { + return true; } - catch (e) { - return {}; + this.available = r2pipe_js_1.r2.cmd("r2ai -h").trim() !== ""; + /* + if (this.available) { + if (num) { + r2.call(`r2ai -n ${num}`) + } + // r2.call('r2ai -e DEBUG=1') + if (model) { + this.model = model; + } } + */ + return this.available; } - // TODO: take a BinFile as argument instead of number - selectBinary(id) { - this.call(`ob ${id}`); + /** + * Reset conversation messages + */ + reset() { + this.checkAvailability(); + if (this.available) { + r2pipe_js_1.r2.call("r2ai -R"); + } } - openFile(name) { - const ofd = this.call('oqq').trim(); - this.call(`o ${name}`); - const nfd = this.call('oqq').trim(); - if (ofd === nfd) { - return new Error('Cannot open file'); + /** + * Set the role (system prompt) message for the language model to obey. + * + * @param {string} text containing the system prompt + * @returns {boolean} true if successful + */ + setRole(msg) { + if (this.available) { + r2pipe_js_1.r2.call(`r2ai -r ${msg}`); + return true; } - return parseInt(nfd); + return false; } - openFileNomap(name) { - const ofd = this.call('oqq').trim(); - this.call(`of ${name}`); - const nfd = this.call('oqq').trim(); - if (ofd === nfd) { - return new Error('Cannot open file'); + /** + * Set the Model name or path to the GGUF file to use. + * + * @param {string} model name or path to GGUF file + * @returns {boolean} true if successful + */ + setModel(modelName) { + if (this.available) { + r2pipe_js_1.r2.call(`r2ai -m ${this.model}`); + return true; } - return parseInt(nfd); + return false; } - currentFile(name) { - return this.call('o.').trim(); + /** + * Get the current selected model name. + * + * @returns {boolean} model name + */ + getModel() { + if (this.available) { + this.model = r2pipe_js_1.r2.call("r2ai -m").trim(); + } + return this.model; } - enumeratePlugins(type) { - switch (type) { - case "bin": - return this.callj("Lij"); - case "io": - return this.callj("Loj"); - case "core": - return this.callj("Lcj"); - case "arch": - return this.callj("LAj"); - case "anal": - return this.callj("Laj"); - case "lang": - return this.callj("Llj"); + /** + * Get a list of suggestions for model names to use. + * + * @returns {string[]} array of strings containing the model names known to work + */ + listModels() { + if (this.available) { + const models = r2pipe_js_1.r2.call("r2ai -M"); + return models + .replace(/-m /, "") + .trim() + .split(/\n/g) + .filter((x) => x.indexOf(":") !== -1); } return []; } - enumerateModules() { - return this.callj("dmmj"); - } - enumerateFiles() { - return this.callj("oj"); + /** + * Send message to the language model to be appended to the current conversation (see `.reset()`) + * + * @param {string} text sent from the user to the language model + * @returns {string} response from the language model + */ + query(msg) { + if (!this.available || msg == "") { + return ""; + } + const fmsg = msg.trim().replace(/\n/g, "."); + const response = r2pipe_js_1.r2.call(`r2ai ${fmsg}`); + return response.trim(); } - enumerateBinaries() { - return this.callj("obj"); +} +exports.R2AI = R2AI; +"use strict"; +// main r2papi file +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NativePointer = exports.NativeCallback = exports.NativeFunction = exports.R2PapiSync = exports.Assembler = exports.ProcessClass = exports.ModuleClass = exports.ThreadClass = void 0; +class ThreadClass { + constructor(r2) { + this.api = null; + this.api = r2; } - enumerateMaps() { - return this.callj("omj"); + backtrace() { + return r2pipe_js_1.r2.call("dbtj"); } - enumerateClasses() { - return this.callj("icj"); + sleep(seconds) { + return r2pipe_js_1.r2.call("sleep " + seconds); } - enumerateSymbols() { - return this.callj("isj"); +} +exports.ThreadClass = ThreadClass; +class ModuleClass { + constructor(r2) { + this.api = null; + this.api = r2; } - enumerateExports() { - return this.callj("iEj"); + fileName() { + return this.api.call("dpe").trim(); } - enumerateImports() { - return this.callj("iij"); + name() { + return "Module"; } - enumerateLibraries() { - return this.callj("ilj"); + findBaseAddress() { + return "TODO"; } - enumerateSections() { - return this.callj("iSj"); + getBaseAddress(name) { + return "TODO"; } - enumerateSegments() { - return this.callj("iSSj"); + getExportByName(name) { + const res = r2pipe_js_1.r2.call("iE,name/eq/" + name + ",vaddr/cols,:quiet"); + return ptr(res); } - enumerateEntrypoints() { - return this.callj("iej"); + findExportByName(name) { + return this.getExportByName(name); } - enumerateRelocations() { - return this.callj("irj"); + enumerateExports() { + // TODO: adjust to be the same output as Frida + return r2pipe_js_1.r2.callj("iEj"); } - enumerateFunctions() { - return this.cmdj("aflj"); + enumerateImports() { + // TODO: adjust to be the same output as Frida + return r2pipe_js_1.r2.callj("iij"); } - enumerateFlags() { - return this.cmdj("fj"); + enumerateSymbols() { + // TODO: adjust to be the same output as Frida + return r2pipe_js_1.r2.callj("isj"); } - skip() { - this.r2.cmd("dss"); + enumerateEntrypoints() { + // TODO: adjust to be the same output as Frida + return r2pipe_js_1.r2.callj("iej"); } - ptr(s) { - return new NativePointer(s, this); + enumerateRanges() { + // TODO: adjust to be the same output as Frida + return r2pipe_js_1.r2.callj("omj"); } - call(s) { - return this.r2.call(s); +} +exports.ModuleClass = ModuleClass; +class ProcessClass { + constructor(r2) { + this.r2 = null; + this.r2 = r2; } - callj(s) { - return JSON.parse(this.call(s)); + enumerateMallocRanges() { } + enumerateSystemRanges() { } + enumerateRanges() { } + enumerateThreads() { + return r2pipe_js_1.r2.callj("dptj"); } - cmd(s) { - return this.r2.cmd(s); + enumerateModules() { + r2pipe_js_1.r2.call("cfg.json.num=string"); // to handle 64bit values properly + if (r2pipe_js_1.r2.callj("e cfg.debug")) { + const modules = r2pipe_js_1.r2.callj("dmmj"); + const res = []; + for (const mod of modules) { + const entry = { + base: new NativePointer(mod.addr), + size: new NativePointer(mod.addr_end).sub(mod.addr), + path: mod.file, + name: mod.name + }; + res.push(entry); + } + return res; + } + else { + const fname = (x) => { + const y = x.split("/"); + return y[y.length - 1]; + }; + const bobjs = r2pipe_js_1.r2.callj("obj"); + const res = []; + for (const obj of bobjs) { + const entry = { + base: new NativePointer(obj.addr), + size: obj.size, + path: obj.file, + name: fname(obj.file) + }; + res.push(entry); + } + const libs = r2pipe_js_1.r2.callj("ilj"); + for (const lib of libs) { + const entry = { + base: 0, + size: 0, + path: lib, + name: fname(lib) + }; + res.push(entry); + } + return res; + } } - cmdj(s) { - return JSON.parse(this.cmd(s)); + getModuleByAddress(addr) { } + getModuleByName(moduleName) { } + codeSigningPolicy() { + return "optional"; } - log(s) { - return this.r2.log(s); + getTmpDir() { + return this.r2.call("e dir.tmp").trim(); } - clippy(msg) { - this.r2.log(this.r2.cmd("?E " + msg)); + getHomeDir() { + return this.r2.call("e dir.home").trim(); } - ascii(msg) { - this.r2.log(this.r2.cmd("?ea " + msg)); + platform() { + return this.r2.call("e asm.os").trim(); } -} -G.R2Papi = R2Papi; -// useful to call functions via dxc -class NativeFunction { - constructor() { + getCurrentDir() { + return this.r2.call("pwd").trim(); } -} -G.NativeFunction = NativeFunction; -// uhm not sure how to map this into r2 yet -class NativeCallback { - constructor() { + getCurrentThreadId() { + return +this.r2.call("dpq"); } -} -G.NativeCallback = NativeCallback; -// export const NULL = ptr("0");yet -class NativePointer { - constructor(s, api) { - if (api === undefined) { - this.api = G.R; - } - else { - this.api = api; + pageSize() { + if (this.r2.callj("e asm.bits") === 64 && + this.r2.call("e asm.arch").startsWith("arm")) { + return 16384; } - // this.api.r2.log("NP " + s); - this.addr = ("" + s).trim(); + return 4096; } - setFlag(name) { - this.api.call(`f ${name}=${this.addr}`); + isDebuggerAttached() { + return this.r2.callj("e cfg.debug"); } - unsetFlag() { - this.api.call(`f-${this.addr}`); + setExceptionHandler() { + // do nothing } - hexdump(length) { - let len = (length === undefined) ? "" : "" + length; - return this.api.cmd(`x${len}@${this.addr}`); + id() { + // + return this.r2.callj("dpq").trim(); } - functionGraph(format) { - if (format === "dot") { - return this.api.cmd(`agfd@ ${this.addr}`); - } - if (format === "json") { - return this.api.cmd(`agfj@${this.addr}`); + pointerSize() { + return r2pipe_js_1.r2.callj("e asm.bits") / 8; + } +} +exports.ProcessClass = ProcessClass; +/** + * Assembler and disassembler facilities to decode and encode instructions + * + * @typedef Assembler + */ +class Assembler { + constructor(myr2) { + this.program = ""; + this.labels = {}; + this.endian = false; + this.pc = ptr(0); + if (myr2 === undefined) { + this.r2 = (0, r2pipe_js_1.newAsyncR2PipeFromSync)(r2pipe_js_1.r2); } - if (format === "mermaid") { - return this.api.cmd(`agfm@${this.addr}`); + else { + this.r2 = myr2; } - return this.api.cmd(`agf@${this.addr}`); + this.program = ""; + this.labels = {}; } - readByteArray(len) { - return JSON.parse(this.api.cmd(`p8j ${len}@${this.addr}`)); + /** + * Change the address of the program counter, some instructions need to know where + * are they located before being encoded or decoded. + * + * @param {NativePointerValue} + */ + setProgramCounter(pc) { + this.pc = pc; } - readHexString(len) { - return this.api.cmd(`p8 ${len}@${this.addr}`).trim(); + setEndian(big) { + this.endian = big; } - and(a) { - const addr = this.api.call(`?v ${this.addr} & ${a}`).trim(); - return new NativePointer(addr); + toString() { + return this.program; } - or(a) { - const addr = this.api.call(`?v ${this.addr} | ${a}`).trim(); - return new NativePointer(addr); + append(x) { + // append text + this.pc = this.pc.add(x.length / 2); + this.program += x; } - add(a) { - const addr = this.api.call(`?v ${this.addr}+${a}`).trim(); - return new NativePointer(addr); + // api + label(s) { + const pos = this.pc; // this.#program.length / 4; + this.labels[s] = this.pc; + return pos; } - sub(a) { - const addr = this.api.call(`?v ${this.addr}-${a}`).trim(); - return new NativePointer(addr); + /** + * Encode (assemble) an instruction by taking the string representation. + * + * @param {string} the string representation of the instruction to assemble + * @returns {string} the hexpairs that represent the assembled instruciton + */ + encode(s) { + const output = this.r2.call(`pa ${s}`); + return output.trim(); } - writeByteArray(data) { - this.api.cmd("wx " + data.join("")); - return this; + /** + * Decode (disassemble) an instruction by taking the hexpairs string as input. + * TODO: should take an array of bytes too + * + * @param {string} the hexadecimal pairs of bytes to decode as an instruction + * @returns {string} the mnemonic and operands of the resulting decoding + */ + decode(s) { + const output = this.r2.call(`pad ${s}`); + return output.trim(); } - writeAssembly(instruction) { - this.api.cmd(`wa ${instruction} @ ${this.addr}`); - return this; +} +exports.Assembler = Assembler; +/** + * High level abstraction on top of the r2 command interface provided by r2pipe. + * + * @typedef R2Papi + */ +class R2PapiSync { + /** + * Create a new instance of the R2Papi class, taking an r2pipe interface as reference. + * + * @param {R2PipeSync} the r2pipe instance to use as backend. + * @returns {R2Papi} instance + */ + constructor(r2) { + this.r2 = r2; } - writeCString(s) { - this.api.call("w " + s); - return this; + toString() { + return "[object R2Papi]"; } - writeWideString(s) { - this.api.call("ww " + s); - return this; + toJSON() { + return this.toString(); } /** - * Check if it's a pointer to the address zero. Also known as null pointer. - * - * @returns {boolean} true if null - */ - isNull() { - return this.toNumber() == 0; + * Get the base address used by the current loaded binary + * + * @returns {NativePointer} address of the base of the binary + */ + getBaseAddress() { + return new NativePointer(this.cmd("e bin.baddr")); } - compare(a) { - if (typeof a === "string" || typeof a === "number") { - a = new NativePointer(a); + jsonToTypescript(name, a) { + let str = `interface ${name} {\n`; + if (a.length && a.length > 0) { + a = a[0]; } - return a.addr === this.addr || (new NativePointer(a.addr)).toNumber() === this.toNumber(); + for (const k of Object.keys(a)) { + const typ = typeof a[k]; + const nam = k; + str += ` ${nam}: ${typ};\n`; + } + return `${str}}\n`; } - pointsToNull() { - return this.readPointer().compare(0); + /** + * Get the general purpose register size of the targize architecture in bits + * + * @returns {number} the regsize + */ + getBits() { + return +this.cmd("-b"); } - toJSON() { - return this.api.cmd('?vi ' + this.addr.trim()).trim(); + /** + * Get the name of the arch plugin selected, which tends to be the same target architecture. + * Note that on some situations, this info will be stored protected bby the AirForce. + * When using the r2ghidra arch plugin the underlying arch is in `asm.cpu`: + * + * @returns {string} the name of the target architecture. + */ + getArch() { + return this.cmdTrim("-a"); } - toString() { - return this.api.cmd('?v ' + this.addr.trim()).trim(); + callTrim(x) { + const res = this.call(x); + return res.trim(); } - toNumber() { - return parseInt(this.toString()); + cmdTrim(x) { + const res = this.cmd(x); + return res.trim(); } - writePointer(p) { - this.api.cmd(`wvp ${p}@${this}`); // requires 5.8.2 + /** + * Get the name of the selected CPU for the current selected architecture. + * + * @returns {string} the value of asm.cpu + */ + getCpu() { + // return this.cmd('-c'); + return this.cmdTrim("-e asm.cpu"); // use arch.cpu } - readRelativePointer() { - return this.add(this.readS32()); + // TODO: setEndian, setCpu, ... + setArch(arch, bits) { + this.cmd("-a " + arch); + if (bits !== undefined) { + this.cmd("-b " + bits); + } } - readPointer() { - return new NativePointer(this.api.call("pvp@" + this.addr)); + setFlagSpace(name) { + this.cmd("fs " + name); } - readS8() { - return parseInt(this.api.cmd(`pv1d@${this.addr}`)); + demangleSymbol(lang, mangledName) { + return this.cmdTrim("iD " + lang + " " + mangledName); } - readU8() { - return parseInt(this.api.cmd(`pv1u@${this.addr}`)); + setLogLevel(level) { + this.cmd("e log.level=" + level); } - readU16() { - return parseInt(this.api.cmd(`pv2d@${this.addr}`)); + /** + * should return the id for the new map using the given file descriptor + */ + // rename to createMap or mapFile? + newMap(fd, vaddr, size, paddr, perm, name = "") { + this.cmd(`om ${fd} ${vaddr} ${size} ${paddr} ${perm} ${name}`); } - readU16le() { - return parseInt(this.api.cmd(`pv2d@${this.addr}@e:cfg.bigendian=false`)); // requires 5.8.9 + at(a) { + return new NativePointer(a); } - readU16be() { - return parseInt(this.api.cmd(`pv2d@${this.addr}@e:cfg.bigendian=true`)); // requires 5.8.9 + getShell() { + return new shell_js_1.R2Shell(this); } - readS16() { - return parseInt(this.api.cmd(`pv2d@${this.addr}`)); // requires 5.8.9 + // Radare/Frida + version() { + const v = this.r2.cmd("?Vq"); + return v.trim(); } - readS16le() { - return parseInt(this.api.cmd(`pv2d@${this.addr}@e:cfg.bigendian=false`)); // requires 5.8.9 + // Process + platform() { + const output = this.r2.cmd("uname"); + return output.trim(); } - readS16be() { - return parseInt(this.api.cmd(`pv2d@${this.addr}@e:cfg.bigendian=true`)); // requires 5.8.9 + arch() { + const output = this.r2.cmd("uname -a"); + return output.trim(); } - readS32() { - return parseInt(this.api.cmd(`pv4d@${this.addr}`)); // requires 5.8.9 + bits() { + const output = this.r2.cmd("uname -b"); + return output.trim(); } - readU32() { - return parseInt(this.api.cmd(`pv4u@${this.addr}`)); // requires 5.8.9 + id() { + // getpid(); + return +this.r2.cmd("?vi:$p"); } - readU32le() { - return parseInt(this.api.cmd(`pv4u@${this.addr}@e:cfg.bigendian=false`)); // requires 5.8.9 + // Other stuff + printAt(msg, x, y) { + // see pg, but pg is obrken :D } - readU32be() { - return parseInt(this.api.cmd(`pv4u@${this.addr}@e:cfg.bigendian=true`)); // requires 5.8.9 + clearScreen() { + this.r2.cmd("!clear"); + return this; } - readU64() { - // XXX: use bignum or string here - return parseInt(this.api.cmd(`pv8u@${this.addr}`)); + getConfig(key) { + if (key === "") { + return new Error("Empty key"); + } + const exist = this.r2.cmd(`e~^${key} =`); + if (exist.trim() === "") { + return new Error("Config key does not exist"); + } + const value = this.r2.call("e " + key); + return value.trim(); } - readU64le() { - return parseInt(this.api.cmd(`pv8u@${this.addr}@e:cfg.bigendian=false`)); // requires 5.8.9 + setConfig(key, val) { + this.r2.call("e " + key + "=" + val); + return this; } - readU64be() { - return parseInt(this.api.cmd(`pv8u@${this.addr}@e:cfg.bigendian=true`)); // requires 5.8.9 + getRegisterStateForEsil() { + const dre = this.cmdj("dre"); + return this.cmdj("dre"); } - writeInt(n) { - return this.writeU32(n); + getRegisters() { + // this.r2.log("winrar" + JSON.stringify(JSON.parse(this.r2.cmd("drj")),null, 2) ); + return this.cmdj("drj"); } - writeU8(n) { - this.api.cmd(`wv1 ${n}@${this.addr}`); - return true; + resizeFile(newSize) { + this.cmd(`r ${newSize}`); + return this; } - writeU16(n) { - this.api.cmd(`wv2 ${n}@${this.addr}`); - return true; + insertNullBytes(newSize, at) { + if (at === undefined) { + at = "$$"; + } + this.cmd(`r+${newSize}@${at}`); + return this; } - writeU16be(n) { - this.api.cmd(`wv2 ${n}@${this.addr}@e:cfg.bigendian=true`); - return true; + removeBytes(newSize, at) { + if (at === undefined) { + at = "$$"; + } + this.cmd(`r-${newSize}@${at}`); + return this; } - writeU16le(n) { - this.api.cmd(`wv2 ${n}@${this.addr}@e:cfg.bigendian=false`); - return true; + seek(addr) { + this.cmd(`s ${addr}`); + return this; } - writeU32(n) { - this.api.cmd(`wv4 ${n}@${this.addr}`); - return true; + currentSeek() { + return new NativePointer("$$"); } - writeU32be(n) { - this.api.cmd(`wv4 ${n}@${this.addr}@e:cfg.bigendian=true`); - return true; + seekToRelativeOpcode(nth) { + this.cmd(`so ${nth}`); + return this.currentSeek(); } - writeU32le(n) { - this.api.cmd(`wv4 ${n}@${this.addr}@e:cfg.bigendian=false`); - return true; + getBlockSize() { + return +this.cmd("b"); } - writeU64(n) { - this.api.cmd(`wv8 ${n}@${this.addr}`); - return true; + setBlockSize(a) { + this.cmd(`b ${a}`); + return this; } - writeU64be(n) { - this.api.cmd(`wv8 ${n}@${this.addr}@e:cfg.bigendian=true`); - return true; + countFlags() { + return Number(this.cmd("f~?")); } - writeU64le(n) { - this.api.cmd(`wv8 ${n}@${this.addr}@e:cfg.bigendian=false`); - return true; + countFunctions() { + return Number(this.cmd("aflc")); } - readInt32() { - return this.readU32(); + analyzeFunctionsWithEsil(depth) { + this.cmd("aaef"); } - readCString() { - return JSON.parse(this.api.cmd(`pszj@${this.addr}`)).string; + analyzeProgramWithEsil(depth) { + this.cmd("aae"); } - readWideString() { - return JSON.parse(this.api.cmd(`pswj@${this.addr}`)).string; + analyzeProgram(depth) { + if (depth === undefined) { + depth = 0; + } + switch (depth) { + case 0: + this.cmd("aa"); + break; + case 1: + this.cmd("aaa"); + break; + case 2: + this.cmd("aaaa"); + break; + case 3: + this.cmd("aaaaa"); + break; + } + return this; } - readPascalString() { - return JSON.parse(this.api.cmd(`pspj@${this.addr}`)).string; + enumerateThreads() { + // TODO: use apt/dpt to list threads at iterate over them to get the registers + const regs0 = this.cmdj("drj"); + const thread0 = { + context: regs0, + id: 0, + state: "waiting", + selected: true + }; + return [thread0]; } - instruction() { - const op = this.api.cmdj(`aoj@${this.addr}`)[0]; - return op; + currentThreadId() { + if (+this.cmd("e cfg.debug")) { + return +this.cmd("dpt."); + } + return this.id(); } - disassemble(length) { - let len = (length === undefined) ? "" : "" + length; - return this.api.cmd(`pd ${len}@${this.addr}`); + setRegisters(obj) { + for (const r of Object.keys(obj)) { + const v = obj[r]; + this.r2.cmd("dr " + r + "=" + v); + } } - analyzeFunction() { - this.api.cmd("af@" + this.addr); + hex(s) { + const output = this.r2.cmd("?v " + s); + return output.trim(); + } + step() { + this.r2.cmd("ds"); return this; } - analyzeFunctionRecursively() { - this.api.cmd("afr@" + this.addr); + stepOver() { + this.r2.cmd("dso"); return this; } - name() { - return this.api.cmd("fd " + this.addr).trim(); + math(expr) { + return +this.r2.cmd("?v " + expr); } - methodName() { - // TODO: @ should be optional here, as addr should be passable as argument imho - return this.api.cmd("ic.@" + this.addr).trim(); + stepUntil(dst) { + this.cmd(`dsu ${dst}`); } - symbolName() { - // TODO: @ should be optional here, as addr should be passable as argument imho - return this.api.cmd("isj.@" + this.addr).trim(); + enumerateXrefsTo(s) { + const output = this.call("axtq " + s); + return output.trim().split(/\n/); } - getFunction() { - return this.api.cmdj("afij@" + this.addr); + // TODO: rename to searchXrefsTo ? + findXrefsTo(s, use_esil) { + if (use_esil) { + this.call("/r " + s); + } + else { + this.call("/re " + s); + } } - basicBlock() { - const bb = this.api.cmdj("abj@" + this.addr); - return bb; + analyzeFunctionsFromCalls() { + this.call("aac"); + return this; } - functionBasicBlocks() { - return this.api.cmdj("afbj@" + this.addr); + autonameAllFunctions() { + this.call("aan"); + return this; } - xrefs() { - return this.api.cmdj("axtj@" + this.addr); + analyzeFunctionsWithPreludes() { + this.call("aap"); + return this; } -} -G.NativePointer = NativePointer; -Object.defineProperty(G, "__esModule", { value: true }); -Object.defineProperty(G, "__esModule", { value: true }); -G.Base64 = void 0; -class Base64 { - static encode(x) { - return (0, G.b64)(x); + analyzeObjCReferences() { + this.cmd("aao"); + return this; } - static decode(x) { - return (0, G.b64)(x, true); + analyzeImports() { + this.cmd("af @ sym.imp.*"); + return this; } -} -G.Base64 = Base64; -Object.defineProperty(G, "__esModule", { value: true }); -G.R2AI = void 0; -class R2AI { - constructor(num, model) { - this.available = false; - this.model = ""; - this.available = r2pipe_js_1.r2.cmd('r2ai -h').trim() !== ""; - if (this.available) { - if (num) { - r2pipe_js_1.r2.call(`r2ai -n ${num}`); - } - // r2.call('r2ai -e DEBUG=1') - if (model) { - this.model = model; - } - } - else { - throw new Error("ERROR: r2ai is not installed"); - } + searchDisasm(s) { + const res = this.callj("/ad " + s); + return res; } - reset() { - if (this.available) { - r2pipe_js_1.r2.call('r2ai -R'); - } + searchString(s) { + const res = this.cmdj("/j " + s); + return res; } - setRole(msg) { - if (this.available) { - r2pipe_js_1.r2.call(`r2ai -r ${msg}`); + searchBytes(data) { + function num2hex(data) { + return (data & 0xff).toString(16); } + const s = data.map(num2hex).join(""); + const res = this.cmdj("/xj " + s); + return res; } - setModel(modelName) { - if (this.available) { - r2pipe_js_1.r2.call(`r2ai -m ${this.model}`); + binInfo() { + try { + return this.cmdj("ij~{bin}"); } - } - getModel() { - if (this.available) { - return r2pipe_js_1.r2.call("r2ai -m"); + catch (e) { + return {}; } - return this.model; } - listModels() { - if (this.available) { - return r2pipe_js_1.r2.call("r2ai -M").trim().split(/\n/g); + // TODO: take a BinFile as argument instead of number + selectBinary(id) { + this.call(`ob ${id}`); + } + openFile(name) { + const ofd = this.call("oqq"); + this.call(`o ${name}`); + const nfd = this.call("oqq"); + if (ofd.trim() === nfd.trim()) { + return new Error("Cannot open file"); } - return []; + return parseInt(nfd); } - query(msg) { - if (!this.available || msg == '') { - return ''; + openFileNomap(name) { + const ofd = this.call("oqq"); + this.call(`of ${name}`); + const nfd = this.call("oqq"); + if (ofd.trim() === nfd.trim()) { + return new Error("Cannot open file"); } - const fmsg = msg.trim().replace(/\n/g, '.'); - return r2pipe_js_1.r2.call(`r2ai ${fmsg}`); + return parseInt(nfd); } -} -G.R2AI = R2AI; -// shell utilities on top of r2pipe -Object.defineProperty(G, "__esModule", { value: true }); -G.R2PapiShell = void 0; -class R2PapiShell { - constructor(papi) { - this.rp = papi; + currentFile(name) { + return (this.call("o.")).trim(); } - /** - * 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. - */ - mkdir(file, recursive) { - if (recursive === true) { - this.rp.call(`mkdir -p ${file}`); - } - else { - this.rp.call(`mkdir ${file}`); + enumeratePlugins(type) { + switch (type) { + case "bin": + return this.callj("Lij"); + case "io": + return this.callj("Loj"); + case "core": + return this.callj("Lcj"); + case "arch": + return this.callj("LAj"); + case "anal": + return this.callj("Laj"); + case "lang": + return this.callj("Llj"); } - return true; + return []; } - /** - * Deletes a file - */ - unlink(file) { - this.rp.call(`rm ${file}`); - return true; + enumerateModules() { + return this.callj("dmmj"); } - /** - * Change current directory - */ - chdir(path) { - this.rp.call(`cd ${path}`); - return true; + enumerateFiles() { + return this.callj("oj"); } - ls() { - return this.rp.call(`ls -q`).trim().split('\n'); + enumerateBinaries() { + return this.callj("obj"); } - fileExists(path) { - // TODO - return false; + enumerateMaps() { + return this.callj("omj"); } - /** - * Opens an URL or application - * calls `xdg-open` on linux, `start` on windows, `open` on Mac - */ - open(arg) { - this.rp.call(`open ${arg}`); + enumerateClasses() { + return this.callj("icj"); } - system(cmd) { - this.rp.call(`!${cmd}`); - return 0; + enumerateSymbols() { + return this.callj("isj"); } - run(path) { - this.rp.call(`rm ${path}`); - return 0; + enumerateExports() { + return this.callj("iEj"); } - mount(fstype, path) { - this.rp.call(`m ${fstype} ${path}`); - return true; + enumerateImports() { + return this.callj("iij"); } - umount(path) { - this.rp.call(`m-${path}`); + enumerateLibraries() { + return this.callj("ilj"); } - chdir2(path) { - if (path === undefined) { - path = "/"; - } - this.rp.call(`mdq ${path}`); - return true; + enumerateSections() { + return this.callj("iSj"); } - ls2(path) { - if (path === undefined) { - path = "/"; - } - return this.rp.call(`mdq ${path}`).trim().split('\n'); + enumerateSegments() { + return this.callj("iSSj"); } - enumerateMountpoints() { - return this.rp.cmdj("mlj"); + enumerateEntrypoints() { + return this.callj("iej"); } - isSymlink(file) { - return false; + enumerateRelocations() { + return this.callj("irj"); } - isDirectory(file) { - return false; + enumerateFunctions() { + return this.cmdj("aflj"); } -} -G.R2PapiShell = R2PapiShell; -Object.defineProperty(G, "__esModule", { value: true }); -G.EsilParser = G.EsilNode = G.EsilToken = void 0; -// ("this is just a comment"), -- comments are also part of the runtime -/* -=("//", { - =(obj, {}()) - =([obj, comment], 32) - if(eq([obj,comment], 32), - ret() - ) - ret(obj) -}) -*/ -class EsilToken { - constructor(text = "", position = 0) { - this.label = ""; - this.comment = ""; - this.text = ""; - this.addr = "0"; // for ut64 we use strings for numbers :< - this.position = 0; - this.text = text; - this.position = position; + enumerateFlags() { + return this.cmdj("fj"); } - toString() { - return this.text; + skip() { + this.r2.cmd("dss"); } -} -G.EsilToken = EsilToken; -class EsilNode { - constructor(token = new EsilToken(), type = "none") { - this.type = "none"; - this.token = token; - this.children = []; + ptr(s) { + return new NativePointer(s, this); } - setSides(lhs, rhs) { - this.lhs = lhs; - this.rhs = rhs; + call(s) { + return this.r2.call(s); } - addChildren(ths, fhs) { - if (ths !== undefined) { - this.children.push(ths); - } - if (fhs !== undefined) { - this.children.push(fhs); - } + callj(s) { + return JSON.parse(this.call(s)); } - toEsil() { - if (this.lhs !== undefined && this.rhs !== undefined) { - // XXX handle ?{ }{ } - let left = this.lhs.toEsil(); - if (left !== "") { - left += ","; - } - let right = this.rhs.toEsil(); - return `${right},${left}${this.token}`; - } - return ''; // this.token.text; + cmd(s) { + return this.r2.cmd(s); } - toString() { - let str = ""; - if (this.token.label !== "") { - str += this.token.label + ":\n"; - } - if (this.token.addr !== "0") { - // str += "// @ " + this.token.addr + "\n"; - } - if (this.token.comment !== "") { - str += "/*" + this.token.comment + "*/\n"; - } - if (this.token.toString() === "GOTO") { - if (this.children.length > 0) { - const children = this.children[0]; - str += "goto label_" + children.token.position + ";\n"; - } - else { - // console.log(JSON.stringify(this,null, 2)); - let pos = 0; - str += `goto label_${pos};\n`; - } - } - if (this.children.length > 0) { - str += ` (if (${this.rhs})\n`; - for (let children of this.children) { - if (children !== null) { - const x = children.toString(); - if (x != "") { - str += ` ${x}\n`; - } - } - } - str += " )\n"; - } - if (this.lhs !== undefined && this.rhs !== undefined) { - return str + ` ( ${this.lhs} ${this.token} ${this.rhs} )`; - // return str + `${this.lhs} ${this.token} ${this.rhs}`; - } - return str + this.token.toString(); + cmdj(s) { + return JSON.parse(this.cmd(s)); } -} -G.EsilNode = EsilNode; -class EsilParser { - constructor(r2) { - this.cur = 0; - this.r2 = r2; - this.cur = 0; - this.stack = []; - this.nodes = []; - this.tokens = []; - this.root = new EsilNode(new EsilToken("function", 0), "block"); + log(s) { + return this.r2.log(s); } - toJSON() { - if (this.stack.length > 0) { - // return JSON.stringify (this.stack, null, 2); - throw new Error("The ESIL stack is not empty"); - } - return JSON.stringify(this.root, null, 2); + clippy(msg) { + this.r2.log(this.r2.cmd("?E " + msg)); } - toEsil() { - return this.nodes - .map((x) => x.toEsil()) - .join(','); + ascii(msg) { + this.r2.log(this.r2.cmd("?ea " + msg)); } - optimizeFlags(node) { - if (node.rhs !== undefined) { - this.optimizeFlags(node.rhs); - } - if (node.lhs !== undefined) { - this.optimizeFlags(node.lhs); - } - for (let i = 0; i < node.children.length; i++) { - this.optimizeFlags(node.children[i]); - } - const addr = node.toString(); - if (+addr > 4096) { - const fname = r2.cmd(`fd.@ ${addr}`).trim().split("\n")[0].trim(); - if (fname != "" && fname.indexOf("+") === -1) { - node.token.text = fname; - } - } +} +exports.R2PapiSync = R2PapiSync; +// useful to call functions via dxc and to define and describe function signatures +class NativeFunction { + constructor() { } +} +exports.NativeFunction = NativeFunction; +// uhm not sure how to map this into r2 yet +class NativeCallback { + constructor() { } +} +exports.NativeCallback = NativeCallback; +/** + * Class providing a way to work with 64bit pointers from Javascript, this API mimics the same + * well-known promitive available in Frida, but it's baked by the current session of r2. + * + * It is also possible to use this class via the global `ptr` function. + * + * @typedef NativePointer + */ +class NativePointer { + constructor(s, api) { + this.api = api ?? exports.R; + this.addr = ("" + s).trim(); } - optimize(options) { - if (options.indexOf("flag") != -1) { - this.optimizeFlags(this.root); - } + /** + * Filter a string to be used as a valid flag name + * + * @param {string} name of the symbol name + * @returns {string} filtered name to be used as a flag + */ + filterFlag(name) { + return this.api.call(`fD ${name}`); } - toString() { - return this.root.children - .map((x) => x.toString()) - .join(';\n'); + /** + * Set a flag (name) at the offset pointed + * + * @param {string} name of the flag to set + * @returns {string} base64 decoded string + */ + setFlag(name) { + this.api.call(`f ${name}=${this.addr}`); } - reset() { - this.nodes = []; - this.stack = []; - this.tokens = []; - this.cur = 0; - this.root = new EsilNode(new EsilToken("function", 0), "block"); + /** + * Remove the flag in the current offset + * + */ + unsetFlag() { + this.api.call(`f-${this.addr}`); } - parseRange(from, to) { - let pos = from; - while (pos < this.tokens.length && pos < to) { - const token = this.peek(pos); - if (!token) { - // console.log("BREAK"); - break; - } - // console.log(pos, token); - this.cur = pos; - this.pushToken(token); - pos = this.cur; - pos++; - } - // console.log("done"); + /** + * Render an hexadecimal dump of the bytes contained in the range starting + * in the current pointer and given length. + * + * @param {number} length optional amount of bytes to dump, using blocksize + * @returns {string} string containing the hexadecimal dump of memory + */ + hexdump(length) { + const len = length === undefined ? "" : "" + length; + return this.api.cmd(`x${len}@${this.addr}`); } - parseFunction(addr) { - var ep = this; - function parseAmount(n) { - // console.log("PDQ "+n); - const lines = r2.cmd("pie " + n + " @e:scr.color=0").trim().split("\n"); - for (const line of lines) { - if (line.length === 0) { - console.log("Empty"); - continue; - } - // console.log("parse", r2.cmd("?v:$$")); - const kv = line.split(' '); - if (kv.length > 1) { // line != "") { - // console.log("// @ " + kv[0]); - //ep.reset (); - r2.cmd(`s ${kv[0]}`); - ep.parse(kv[1], kv[0]); - ep.optimize("flags,labels"); - //console.log(ep.toString()); - } - } - // console.log(ep.toString()); + functionGraph(format) { + if (format === "dot") { + return this.api.cmd(`agfd@ ${this.addr}`); } - const oaddr = r2.cmd("?v $$").trim(); - // const func = r2.cmdj("pdrj"); // XXX this command changes the current seek - if (addr === undefined) { - addr = oaddr; + if (format === "json") { + return this.api.cmd(`agfj@${this.addr}`); } - const bbs = r2.cmdj(`afbj@${addr}`); // XXX this command changes the current seek - for (let bb of bbs) { - // console.log("bb_" + bb.addr + ":"); - r2.cmd(`s ${bb.addr}`); - parseAmount(bb.ninstr); + if (format === "mermaid") { + return this.api.cmd(`agfm@${this.addr}`); } - r2.cmd(`s ${oaddr}`); + return this.api.cmd(`agf@${this.addr}`); } - parse(expr, addr) { - const tokens = expr.trim().split(',').map((x) => x.trim()); - const from = this.tokens.length; - for (let tok of tokens) { - const token = new EsilToken(tok, this.tokens.length); - if (addr !== undefined) { - token.addr = addr; - } - this.tokens.push(token); - } - const to = this.tokens.length; - this.parseRange(from, to); + readByteArray(len) { + return JSON.parse(this.api.cmd(`p8j ${len}@${this.addr}`)); } - peek(a) { - return this.tokens[a]; + readHexString(len) { + return (this.api.cmd(`p8 ${len}@${this.addr}`)).trim(); } - pushToken(tok) { - if (this.isNumber(tok)) { - const node = new EsilNode(tok, "number"); - this.stack.push(node); - this.nodes.push(node); - } - else if (this.isInternal(tok)) { - const node = new EsilNode(tok, "flag"); - this.stack.push(node); - this.nodes.push(node); - } - else if (this.isOperation(tok)) { - // run the operation login - } - else { - // assume it's a register, so just push the string - const node = new EsilNode(tok, "register"); - this.stack.push(node); - this.nodes.push(node); - } - // we need a list of register names to do this check properly - // throw new Error ("Unknown token"); + and(a) { + const addr = this.api.call(`?v ${this.addr} & ${a}`); + return new NativePointer(addr.trim()); } - isNumber(expr) { - if (expr.toString().startsWith("0")) { - return true; - } - return +expr > 0; + or(a) { + const addr = this.api.call(`?v ${this.addr} | ${a}`); + return new NativePointer(addr.trim()); } - isInternal(expr) { - const text = expr.toString(); - return text.startsWith("$") && text.length > 1; + add(a) { + const addr = this.api.call(`?v ${this.addr}+${a}`); + return new NativePointer(addr); } - parseUntil(start) { - const from = start + 1; - let pos = from; - const origStack = []; - const this_nodes_length = this.nodes.length; - this.stack.forEach((x) => origStack.push(x)); - while (pos < this.tokens.length) { - const token = this.peek(pos); - if (!token) { - break; - } - if (token.toString() === '}') { - break; - } - if (token.toString() === '}{') { - // return token; - break; - } - // console.log("peek ", this.tokens[pos]); - pos++; - } - this.stack = origStack; - const to = pos; - this.parseRange(from, to); - const same = this.nodes.length == this_nodes_length; - // console.log("BLOCK ("+ ep.toString()); - if (same) { - return null; - } - return this.nodes[this.nodes.length - 1]; // this.tokens.length - 1]; + sub(a) { + const addr = this.api.call(`?v ${this.addr}-${a}`); + return new NativePointer(addr); } - getNodeFor(index) { - const tok = this.peek(index); - if (tok === undefined) { - return null; + writeByteArray(data) { + this.api.cmd("wx " + data.join("")); + return this; + } + writeAssembly(instruction) { + this.api.cmd(`wa ${instruction} @ ${this.addr}`); + return this; + } + writeCString(s) { + this.api.call("w " + s); + return this; + } + writeWideString(s) { + this.api.call("ww " + s); + return this; + } + /** + * Check if it's a pointer to the address zero. Also known as null pointer. + * + * @returns {boolean} true if null + */ + isNull() { + return (this.toNumber()) == 0; + } + /** + * Compare current pointer with the passed one, and return -1, 0 or 1. + * + * * if (this < arg) return -1; + * * if (this > arg) return 1; + * * if (this == arg) return 0; + * + * @returns {number} returns -1, 0 or 1 depending on the comparison of the pointers + */ + compare(a) { + const bv = typeof a === "string" || typeof a === "number" + ? new NativePointer(a) + : a; + const dist = r2pipe_js_1.r2.call(`?vi ${this.addr} - ${bv.addr}`); + if (dist[0] === "-") { + return -1; } - for (let node of this.nodes) { - if (node.token.position === index) { - return node; - } + if (dist[0] === "0") { + return 0; } - this.nodes.push(new EsilNode(new EsilToken("label", index), "label")); - return null; + return 1; } - findNodeFor(index) { - for (let node of this.nodes) { - if (node.token.position === index) { - return node; - } - } - return null; + /** + * Check if it's a pointer to the address zero. Also known as null pointer. + * + * @returns {boolean} true if null + */ + pointsToNull() { + const value = this.readPointer(); + return (value.compare(0)) == 0; } - isOperation(expr) { - switch (expr.toString()) { - // 1pop1push - case "[1]": - case "[2]": - case "[4]": - case "[8]": - if (this.stack.length >= 1) { - const i1 = this.stack.pop(); - // TODO: MemoryReferenceNode(i1)); - const mn = new EsilNode(i1.token, "operation"); // expr.toString()); - this.stack.push(i1); // mn); - } - else { - throw new Error("Stack needs more items"); - } - return true; - // 1pop1push - case "!": - if (this.stack.length >= 1) { - const i0 = new EsilNode(new EsilToken("", expr.position), "none"); - const i1 = this.stack.pop(); - const nn = new EsilNode(expr, "operation"); - nn.setSides(i0, i1); - this.stack.push(nn); - } - else { - throw new Error("Stack needs more items"); - } - return true; - case "": - case "}": - case "}{": - // no pops or nothing, just does nothing - return true; - case "DUP": - if (true) { - if (this.stack.length < 1) { - throw new Error("goto cant pop"); - } - const destNode = this.stack.pop(); - this.stack.push(destNode); - this.stack.push(destNode); - } - return true; - case "GOTO": - // take previous statement which should be const and add a label - const prev = this.peek(expr.position - 1); - if (prev !== null) { - // TODO: check stack - if (this.stack.length < 1) { - throw new Error("goto cant pop"); - } - const destNode = this.stack.pop(); - if (destNode !== null) { - const value = 0 | +destNode.toString(); - if (value > 0) { - const destToken = this.peek(value); - if (destToken !== undefined) { - destToken.label = "label_" + value; - destToken.comment = "hehe"; - const nn = new EsilNode(expr, "goto"); - const gn = this.getNodeFor(destToken.position); - if (gn != null) { - nn.children.push(gn); - } - this.root.children.push(nn); - } - else { - console.error("Cannot find goto node"); - } - } - else { - console.error("Cannot find dest node for goto"); - } - } - } - return true; - // controlflow - case "?{": // ESIL_TOKEN_IF - if (this.stack.length >= 1) { - const i0 = new EsilNode(new EsilToken("if", expr.position), "none"); - const i1 = this.stack.pop(); - const nn = new EsilNode(expr, "operation"); - nn.setSides(i0, i1); // left side can be ignored for now.. but we can express this somehow - let trueBlock = this.parseUntil(expr.position); - let falseBlock = null; - // nn.addChildren(trueBlock, falseBlock); - if (trueBlock !== null) { - nn.children.push(trueBlock); - this.nodes.push(trueBlock); - falseBlock = this.parseUntil(trueBlock.token.position + 1); - if (falseBlock !== null) { - nn.children.push(falseBlock); - this.nodes.push(falseBlock); - } - } - // console.log("true", trueBlock); - // console.log("false", falseBlock); - // this.stack.push(nn); - this.nodes.push(nn); - this.root.children.push(nn); - if (falseBlock !== null) { - this.cur = falseBlock.token.position; - } - } - else { - throw new Error("Stack needs more items"); - } - return true; - case "-": - if (this.stack.length >= 2) { - const i0 = this.stack.pop(); - const i1 = this.stack.pop(); - const nn = new EsilNode(expr, "operation"); - nn.setSides(i0, i1); - if (this.stack.length === 0) { - // this.root.children.push(nn); - } - this.stack.push(nn); - this.nodes.push(nn); - } - else { - throw new Error("Stack needs more items"); - } - return true; - // 2pop1push - case "<": - case ">": - case "^": - case "&": - case "|": - case "+": - case "*": - case "/": - case ">>=": - case "<<=": - case ">>>=": - case "<<<=": - case ">>>>=": - case "<<<<=": - if (this.stack.length >= 2) { - const i0 = this.stack.pop(); - const i1 = this.stack.pop(); - const nn = new EsilNode(expr, "operation"); - nn.setSides(i0, i1); - if (this.stack.length === 0) { - // this.root.children.push(nn); - } - this.stack.push(nn); - this.nodes.push(nn); - } - else { - throw new Error("Stack needs more items"); - } - return true; - // 2pop0push - case "=": - case ":=": - case "-=": - case "+=": - case "==": - case "=[1]": - case "=[2]": - case "=[4]": - case "=[8]": - if (this.stack.length >= 2) { - const i0 = this.stack.pop(); - const i1 = this.stack.pop(); - const nn = new EsilNode(expr, "operation"); - nn.setSides(i0, i1); - if (this.stack.length === 0) { - this.root.children.push(nn); - } - this.nodes.push(nn); - } - else { - throw new Error("Stack needs more items"); - } - return true; - } - return false; + toJSON() { + const output = this.api.cmd("?vi " + this.addr.trim()); + return output.trim(); + } + toString() { + return (this.api.cmd("?v " + this.addr.trim())).trim(); + } + toNumber() { + return parseInt(this.toString()); + } + writePointer(p) { + } + readRelativePointer() { + return this.add(this.readS32()); + } + readPointer() { + const address = this.api.call("pvp@" + this.addr); + return new NativePointer(address); + } + readS8() { + return parseInt(this.api.cmd(`pv1d@${this.addr}`)); + } + readU8() { + return parseInt(this.api.cmd(`pv1u@${this.addr}`)); + } + readU16() { + return parseInt(this.api.cmd(`pv2d@${this.addr}`)); + } + readU16le() { + } + readU16be() { + } + readS16() { + } + readS16le() { + } + readS16be() { + } + readS32() { + // same as readInt32() + } + readU32() { + } + readU32le() { + } + readU32be() { + } + readU64() { + // XXX: use bignum or string here + return parseInt(this.api.cmd(`pv8u@${this.addr}`)); + } + readU64le() { + } + readU64be() { + } + writeInt(n) { + return this.writeU32(n); + } + /** + * Write a byte in the current offset, the value must be between 0 and 255 + * + * @param {string} n number to write in the pointed byte in the current address + * @returns {boolean} false if the operation failed + */ + writeU8(n) { + this.api.cmd(`wv1 ${n}@${this.addr}`); + return true; + } + writeU16(n) { + this.api.cmd(`wv2 ${n}@${this.addr}`); + return true; + } + writeU16be(n) { + this.api.cmd(`wv2 ${n}@${this.addr}@e:cfg.bigendian=true`); + return true; + } + writeU16le(n) { + this.api.cmd(`wv2 ${n}@${this.addr}@e:cfg.bigendian=false`); + return true; + } + writeU32(n) { + this.api.cmd(`wv4 ${n}@${this.addr}`); + return true; + } + writeU32be(n) { + this.api.cmd(`wv4 ${n}@${this.addr}@e:cfg.bigendian=true`); + return true; + } + writeU32le(n) { + this.api.cmd(`wv4 ${n}@${this.addr}@e:cfg.bigendian=false`); + return true; + } + writeU64(n) { + this.api.cmd(`wv8 ${n}@${this.addr}`); + return true; + } + writeU64be(n) { + this.api.cmd(`wv8 ${n}@${this.addr}@e:cfg.bigendian=true`); + return true; + } + writeU64le(n) { + this.api.cmd(`wv8 ${n}@${this.addr}@e:cfg.bigendian=false`); + return true; + } + readInt32() { + return this.readU32(); + } + readCString() { + const output = this.api.cmd(`pszj@${this.addr}`); + return JSON.parse(output).string; + } + readWideString() { + const output = this.api.cmd(`pswj@${this.addr}`); + return JSON.parse(output).string; + } + readPascalString() { + const output = this.api.cmd(`pspj@${this.addr}`); + return JSON.parse(output).string; + } + instruction() { + const output = this.api.cmdj(`aoj@${this.addr}`); + return output[0]; + } + disassemble(length) { + const len = length === undefined ? "" : "" + length; + return this.api.cmd(`pd ${len}@${this.addr}`); + } + analyzeFunction() { + this.api.cmd("af@" + this.addr); + return this; + } + analyzeFunctionRecursively() { + this.api.cmd("afr@" + this.addr); + return this; + } + name() { + return (this.api.cmd("fd " + this.addr)).trim(); + } + methodName() { + // TODO: @ should be optional here, as addr should be passable as argument imho + return (this.api.cmd("ic.@" + this.addr)).trim(); + } + symbolName() { + // TODO: @ should be optional here, as addr should be passable as argument imho + const name = this.api.cmd("isj.@" + this.addr); + return name.trim(); + } + getFunction() { + return this.api.cmdj("afij@" + this.addr); + } + basicBlock() { + return this.api.cmdj("abj@" + this.addr); + } + functionBasicBlocks() { + return this.api.cmdj("afbj@" + this.addr); + } + xrefs() { + return this.api.cmdj("axtj@" + this.addr); } } -G.EsilParser = EsilParser; -const r2pipe_js_1 = G; +exports.NativePointer = NativePointer; +var R2Papi=R2PapiSync;