Skip to content

Commit 1b908d5

Browse files
Tidy banner
1 parent 44587e5 commit 1b908d5

File tree

5 files changed

+128
-29
lines changed

5 files changed

+128
-29
lines changed

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.9.0",
3+
"version": "1.9.1",
44
"description": "Frida's CShell",
55
"scripts": {
66
"prepare": "npm run version && npm run build && npm run package && npm run copy",

src/entrypoint.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import { Exception } from './misc/exception.js';
1414
import { Version } from './misc/version.js';
1515
import { Format } from './misc/format.js';
1616

17-
export const DEFAULT_SRC_PATH: string = `${Process.getHomeDir()}/.cshellrc`;
17+
export const HOME_DIR: string = Process.getHomeDir();
18+
export const DEFAULT_SRC_PATH: string = HOME_DIR.endsWith('/')
19+
? `${HOME_DIR}.cshellrc`
20+
: `${HOME_DIR}/.cshellrc`;
1821

1922
type InitParams = {
2023
debug: boolean;
@@ -23,8 +26,8 @@ type InitParams = {
2326
rpc.exports = {
2427
async init(stage: string, params: InitParams | null = null) {
2528
if (params != null) {
26-
Output.writeln(`params: ${JSON.stringify(params)}`);
2729
Output.setDebugging(params.debug);
30+
Output.debug(`params: ${JSON.stringify(params)}`);
2831
}
2932
Output.debug(`init - stage: ${stage}`);
3033
Output.banner();

src/io/output.ts

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Vars } from '../vars/vars.js';
33
import { DEFAULT_SRC_PATH } from '../entrypoint.js';
44
import { Format } from '../misc/format.js';
55
import { APP_VERSION, GIT_COMMIT_HASH } from '../version.js';
6+
import { Endian } from '../misc/endian.js';
67

78
export class Output {
89
private static readonly shell: string[] = [
@@ -31,35 +32,90 @@ export class Output {
3132
private static suppressed: boolean = false;
3233

3334
public static banner() {
34-
this.shell
35-
.map((s, i) => {
36-
return { shell: s, label: this.label[i] };
37-
})
38-
.forEach(r => {
39-
this.writeln(this.blue(`${r.shell.padEnd(21, ' ')}${r.label}`));
40-
});
35+
const banner: [string, string][] = this.shell.map((s, i) => [
36+
(s as string).trimEnd(),
37+
(this.label[i] as string).trimEnd(),
38+
]);
39+
40+
const metadata: [string, string][] = Object.entries({
41+
cshell: APP_VERSION,
42+
commit: GIT_COMMIT_HASH,
43+
frida: Frida.version,
44+
runtime: Script.runtime,
45+
arch: Process.arch,
46+
endian: Endian.get(),
47+
pid: Process.id.toString(),
48+
binary: Process.enumerateModules()[0]?.name ?? null,
49+
script: DEFAULT_SRC_PATH,
50+
}).filter(([_key, value]) => value !== null) as [string, string][];
51+
52+
const [maxShellLength, maxLabelLength] = banner.reduce(
53+
([maxShell, maxLabel], [shell, label]) => [
54+
Math.max(maxShell, shell.length),
55+
Math.max(maxLabel, label.length),
56+
],
57+
[0, 0],
58+
);
4159

42-
this.writeln();
43-
this.writeln(
44-
this.bold(
45-
[
46-
`CSHELL: v${APP_VERSION}`,
47-
`COMMIT: ${GIT_COMMIT_HASH}`,
48-
`FRIDA: ${Frida.version}`,
49-
`RUNTIME: ${Script.runtime}`,
50-
].join('\n'),
51-
),
60+
const [maxKeyLength, maxValueLength] = metadata.reduce(
61+
([maxKey, maxVal], [key, value]) => [
62+
Math.max(maxKey, key.length),
63+
Math.max(maxVal, value.length),
64+
],
65+
[0, 0],
66+
);
67+
68+
const bannerSpacer = ' '.repeat(3);
69+
70+
const metaPrefix: string = '| ';
71+
const metaSpacer: string = ' | ';
72+
const metaSuffix: string = ' |';
73+
74+
const maxBannerLineLength =
75+
maxShellLength + bannerSpacer.length + maxLabelLength;
76+
const maxMetaLineLength =
77+
metaPrefix.length +
78+
maxKeyLength +
79+
metaSpacer.length +
80+
maxValueLength +
81+
metaSuffix.length;
82+
const bannerIndent = ' '.repeat(
83+
Math.max(0, maxMetaLineLength - maxBannerLineLength) / 2,
5284
);
53-
this.writeln(`init script: ${Output.bold(DEFAULT_SRC_PATH)}`);
5485

55-
this.writeln('Attached to:');
56-
this.writeln(`\tPID: ${this.green(Process.id.toString())}`);
86+
const metaSeperator = this.red(
87+
[
88+
'+-',
89+
'-'.repeat(maxKeyLength),
90+
'-+-',
91+
'-'.repeat(maxValueLength),
92+
'-+',
93+
].join(''),
94+
);
5795

58-
const modules = Process.enumerateModules();
59-
if (modules.length === 0) return;
96+
banner.forEach(([shell, label]) => {
97+
this.write(bannerIndent);
98+
this.write(this.blue(shell.padEnd(maxShellLength, ' ')));
99+
this.write(bannerSpacer);
100+
this.write(this.blue(label.padEnd(maxLabelLength, ' ')));
101+
this.writeln();
102+
});
60103

61-
const first = modules[0] as Module;
62-
this.writeln(`\tName: ${this.green(first.name)}`);
104+
this.writeln();
105+
106+
this.writeln(metaSeperator);
107+
108+
for (const [key, value] of metadata) {
109+
this.write(this.red(metaPrefix));
110+
this.write(this.green(key.toUpperCase().padStart(maxKeyLength, ' ')));
111+
this.write(this.red(metaSpacer));
112+
this.write(this.bold(this.yellow(value.padEnd(maxValueLength, ' '))));
113+
this.write(this.red(metaSuffix));
114+
this.writeln();
115+
}
116+
this.writeln(metaSeperator);
117+
118+
this.writeln();
63119
}
64120

65121
public static debug(buffer: string | null) {

src/misc/endian.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
export enum Endianness {
2+
Big = 'big',
3+
Little = 'little',
4+
}
5+
6+
export class Endian {
7+
private static endianness: Endianness | null = null;
8+
private static readonly TEST_VALUE_SIZE: number = 4;
9+
private static readonly TEST_VALUE: number = 0x12345678;
10+
11+
private static readonly LITTLE_ENDIAN_TEST: Uint8Array = new Uint8Array([
12+
0x78, 0x56, 0x34, 0x12,
13+
]);
14+
15+
private static readonly BIG_ENDIAN_TEST: Uint8Array = new Uint8Array([
16+
0x12, 0x34, 0x56, 0x78,
17+
]);
18+
19+
public static get(): Endianness | null {
20+
if (Endian.endianness !== null) {
21+
return Endian.endianness;
22+
}
23+
const mem = Memory.alloc(Endian.TEST_VALUE_SIZE);
24+
mem.writeU32(Endian.TEST_VALUE);
25+
const buffer = mem.readByteArray(Endian.TEST_VALUE_SIZE);
26+
if (buffer === null) {
27+
return null;
28+
}
29+
const bytes = new Uint8Array(buffer);
30+
const matches = (a: Uint8Array, b: Uint8Array) =>
31+
a.every((v, i) => v === b[i]);
32+
33+
if (matches(Endian.LITTLE_ENDIAN_TEST, bytes)) {
34+
return (Endian.endianness = Endianness.Little);
35+
} else if (matches(Endian.BIG_ENDIAN_TEST, bytes)) {
36+
return (Endian.endianness = Endianness.Big);
37+
}
38+
return null;
39+
}
40+
}

0 commit comments

Comments
 (0)