Skip to content

Commit 65c99a7

Browse files
author
Your Name
committed
Improvements to source command to support macros and breakpoints
1 parent 408a81c commit 65c99a7

10 files changed

Lines changed: 64 additions & 36 deletions

File tree

.cshellrc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,15 @@ test malloc
1010
# show the first instruction of exit
1111
l exit 1
1212

13+
# set up a macro
14+
m test2
15+
l main
16+
q
17+
18+
# set up a breakpoint
19+
@f malloc 1 ?
20+
!= $eip 0
21+
q
22+
bt
23+
@f #1 #
24+
q

.devcontainer/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
FROM cshell AS frida-cshell
22
RUN apt-get update && \
33
apt-get install -y \
4-
nano
4+
nano \
5+
psmisc

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "frida-cshell",
3-
"version": "1.6.1",
3+
"version": "1.6.2",
44
"description": "Frida's CShell",
55
"scripts": {
66
"prepare": "npm run build && npm run version && npm run package && npm run copy",

src.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ return {
44
help: "test command",
55

66
usage: function() {
7-
Output.writeln("USAGE");
7+
Output.writeln("test command usage");
88
return Var.ZERO;
99
},
1010

11+
run: function(tokens) {
12+
return this.runSync(tokens);
13+
},
14+
1115
runSync: function(tokens) {
1216
if (tokens.length !== 1) return this.usage();
1317
const address = tokens[0].toVar().toPointer();

src/cmdlets/files/src.ts

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { CmdLet } from '../../commands/cmdlet.js';
2-
import { Command } from '../../commands/command.js';
2+
import { CharCode } from '../../io/char.js';
33
import { Input } from '../../io/input.js';
44
import { Output } from '../../io/output.js';
5-
import { Parser } from '../../io/parser.js';
65
import { Token } from '../../io/token.js';
6+
import { History } from '../../terminal/history.js';
77
import { Var } from '../../vars/var.js';
8-
import { Vars } from '../../vars/vars.js';
98

109
export class SrcCmdLet extends CmdLet {
1110
name = 'src';
@@ -19,55 +18,57 @@ src path - run commands from file
1918

2019
private static lastPath: string | null = null;
2120

22-
public static loadInitScript(path: string) {
21+
public static async loadInitScript(path: string) {
2322
this.lastPath = path;
2423
const src = new SrcCmdLet();
25-
src.runScript(path);
24+
await src.runScript(path);
2625
}
2726

28-
public runSync(tokens: Token[]): Var {
27+
public override runSync(_tokens: Token[]): Var {
28+
throw new Error("can't run in synchronous mode");
29+
}
30+
31+
public override async run(tokens: Token[]): Promise<Var> {
2932
const vars = this.transformOptional(tokens, [], [this.parseLiteral]);
3033
if (vars === null) return this.usage();
3134
// eslint-disable-next-line prefer-const
3235
let [_, [name]] = vars as [[], [string | null]];
3336
if (name === null) {
3437
if (SrcCmdLet.lastPath === null) throw new Error('path not initialized');
3538

36-
Output.writeln(`Loading: ${SrcCmdLet.lastPath}`);
37-
this.runScript(SrcCmdLet.lastPath);
39+
await this.runScript(SrcCmdLet.lastPath);
3840
return Var.ZERO;
3941
} else {
4042
if (name.length > 1 && name.startsWith('"') && name.endsWith('"')) {
4143
name = name.slice(1, name.length - 1);
4244
}
4345

44-
Output.writeln(`Loading: ${name}`);
4546
SrcCmdLet.lastPath = name;
46-
this.runScript(name);
47+
await this.runScript(name);
4748

4849
return Var.ZERO;
4950
}
5051
}
5152

52-
private runScript(path: string) {
53+
private async runScript(path: string) {
5354
try {
55+
Output.writeln(`Loading: ${Output.green(path)}`);
56+
5457
const initScript = File.readAllText(path);
5558
const lines = initScript.split('\n');
59+
60+
History.clearLine();
61+
Input.prompt();
62+
5663
for (const line of lines) {
5764
if (line.length === 0) continue;
5865
if (line.charAt(0) === '#') continue;
59-
60-
Output.writeln(`${Output.bold(Input.PROMPT)}${line}`);
61-
62-
if (line.trim().length === 0) continue;
63-
64-
const parser = new Parser(line.toString());
65-
const tokens = parser.tokenize();
66-
const ret = Command.runSync(tokens);
67-
Vars.setRet(ret);
68-
Output.writeRet();
69-
Output.writeln();
66+
Output.write(line);
67+
await Input.read(`${line}${String.fromCharCode(CharCode.CR)}`);
7068
}
69+
70+
Output.clearLine();
71+
Output.writeln(`Loaded: ${Output.green(path)}`);
7172
} catch (_) {
7273
/* Ignore the error */
7374
}

src/cmdlets/misc/macro.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ m name ${CmdLet.DELETE_CHAR} - delete a macro
112112

113113
public static runSync(macro: Macro): Var {
114114
let ret = Var.ZERO;
115-
for (const command of macro.commands) {
115+
for (const [idx, command] of macro.commands.entries()) {
116116
if (command.length === 0) continue;
117117
if (command.charAt(0) === '#') continue;
118118

@@ -124,8 +124,15 @@ m name ${CmdLet.DELETE_CHAR} - delete a macro
124124
const tokens = parser.tokenize();
125125
ret = Command.runSync(tokens);
126126
Vars.setRet(ret);
127-
Output.writeRet();
128-
Output.writeln();
127+
128+
/*
129+
* Don't print the return as the last command as we will print it as the
130+
* result of the macro command itself
131+
*/
132+
if (idx !== macro.commands.length - 1) {
133+
Output.writeRet();
134+
Output.writeln();
135+
}
129136
}
130137
return ret;
131138
}

src/commands/command.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ export class Command {
6060
const t0 = tokens[0] as Token;
6161
const v0 = t0.toVar();
6262
if (v0 === null) {
63+
const command = tokens.map(t => t.getLiteral()).join(' ');
6364
throw new Error(
64-
'request was not understood as an internal command or a detected symbol',
65+
`request was not understood as an internal command or a detected symbol: '${command}'`,
6566
);
6667
}
6768
const addr = v0.toPointer();

src/entrypoint.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ type InitParams = {
2222
};
2323

2424
rpc.exports = {
25-
init(stage: string, params: InitParams | null = null) {
25+
async init(stage: string, params: InitParams | null = null) {
2626
const debug = params?.debug ?? false;
2727
Output.setDebugging(debug);
2828
Output.debug(`init - stage: ${stage}, debug: ${debug}`);
2929
Output.banner();
3030
Process.setExceptionHandler(exceptionHandler);
31-
SrcCmdLet.loadInitScript(DEFAULT_SRC_PATH);
31+
await SrcCmdLet.loadInitScript(DEFAULT_SRC_PATH);
3232
Input.prompt();
3333
},
3434
/**

src/io/input.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,17 @@ export class Input {
160160
Output.clearLine();
161161
Output.writeln(`- ${line}`);
162162

163-
if (line === Input.QUIT_CHAR) {
163+
const trimmed = line.trim();
164+
165+
if (trimmed === Input.QUIT_CHAR) {
164166
/* Notify the commandlet we are done and exit edit mode */
165167
this.interceptLine = null;
166168
edit.saveLines();
167-
} else if (line === Input.CLEAR_CHAR) {
169+
} else if (trimmed === Input.CLEAR_CHAR) {
168170
/* Notify the commandlet we cleared and exit edit mode */
169171
this.interceptLine = null;
170172
edit.clearLines();
171-
} else if (line === Input.KEEP_CHAR) {
173+
} else if (trimmed === Input.KEEP_CHAR) {
172174
/* Notify the commandlet we aborted and exit edit mode */
173175
this.interceptLine = null;
174176
edit.cancelLines();

0 commit comments

Comments
 (0)