frida-fs 4.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/index.js +75 -21
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -9,3 +9,13 @@ const fs = require('frida-fs');
|
|
|
9
9
|
|
|
10
10
|
fs.createReadStream('/etc/hosts').pipe(networkStream);
|
|
11
11
|
```
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
const fs = require('frida-fs');
|
|
15
|
+
|
|
16
|
+
for (const elm of fs.list("/proc/self/")) {
|
|
17
|
+
console.log(JSON.stringify(elm));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log(fs.readFileSync("/etc/hosts"));
|
|
21
|
+
```
|
package/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {Buffer} from 'buffer';
|
|
2
|
+
import process from 'process';
|
|
3
|
+
import {Readable} from 'readable-stream/lib/readable.js';
|
|
4
|
+
import {Writable} from 'readable-stream/lib/writable.js';
|
|
2
5
|
|
|
3
6
|
const {platform, pointerSize} = Process;
|
|
4
7
|
|
|
@@ -87,7 +90,7 @@ const SEEK_END = 2;
|
|
|
87
90
|
|
|
88
91
|
const EINTR = 4;
|
|
89
92
|
|
|
90
|
-
class ReadStream extends
|
|
93
|
+
class ReadStream extends Readable {
|
|
91
94
|
constructor(path) {
|
|
92
95
|
super({
|
|
93
96
|
highWaterMark: 4 * 1024 * 1024
|
|
@@ -99,8 +102,10 @@ class ReadStream extends stream.Readable {
|
|
|
99
102
|
const pathStr = Memory.allocUtf8String(path);
|
|
100
103
|
const fd = getApi().open(pathStr, constants.O_RDONLY, 0);
|
|
101
104
|
if (fd.value === -1) {
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
process.nextTick(() => {
|
|
106
|
+
this.emit('error', new Error(`Unable to open file (${getErrorString(fd.errno)})`));
|
|
107
|
+
this.push(null);
|
|
108
|
+
});
|
|
104
109
|
return;
|
|
105
110
|
}
|
|
106
111
|
|
|
@@ -127,6 +132,7 @@ class ReadStream extends stream.Readable {
|
|
|
127
132
|
.catch(error => {
|
|
128
133
|
this._readRequest = null;
|
|
129
134
|
this._closeInput();
|
|
135
|
+
this.emit('error', error);
|
|
130
136
|
this.push(null);
|
|
131
137
|
});
|
|
132
138
|
}
|
|
@@ -139,7 +145,7 @@ class ReadStream extends stream.Readable {
|
|
|
139
145
|
}
|
|
140
146
|
}
|
|
141
147
|
|
|
142
|
-
class WriteStream extends
|
|
148
|
+
class WriteStream extends Writable {
|
|
143
149
|
constructor(path) {
|
|
144
150
|
super({
|
|
145
151
|
highWaterMark: 4 * 1024 * 1024
|
|
@@ -153,8 +159,10 @@ class WriteStream extends stream.Writable {
|
|
|
153
159
|
const mode = constants.S_IRUSR | constants.S_IWUSR | constants.S_IRGRP | constants.S_IROTH;
|
|
154
160
|
const fd = getApi().open(pathStr, flags, mode);
|
|
155
161
|
if (fd.value === -1) {
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
process.nextTick(() => {
|
|
163
|
+
this.emit('error', new Error(`Unable to open file (${getErrorString(fd.errno)})`));
|
|
164
|
+
this.push(null);
|
|
165
|
+
});
|
|
158
166
|
return;
|
|
159
167
|
}
|
|
160
168
|
|
|
@@ -412,6 +420,24 @@ const statSpecs = {
|
|
|
412
420
|
'blksize': [ 48, 'S32' ],
|
|
413
421
|
}
|
|
414
422
|
},
|
|
423
|
+
'linux-32-stat64': {
|
|
424
|
+
size: 104,
|
|
425
|
+
fields: {
|
|
426
|
+
'dev': [ 0, 'U64' ],
|
|
427
|
+
'mode': [ 16, 'U32' ],
|
|
428
|
+
'nlink': [ 20, 'U32' ],
|
|
429
|
+
'ino': [ 96, 'U64' ],
|
|
430
|
+
'uid': [ 24, 'U32' ],
|
|
431
|
+
'gid': [ 28, 'U32' ],
|
|
432
|
+
'rdev': [ 32, 'U64' ],
|
|
433
|
+
'atime': [ 72, readTimespec32 ],
|
|
434
|
+
'mtime': [ 80, readTimespec32 ],
|
|
435
|
+
'ctime': [ 88, readTimespec32 ],
|
|
436
|
+
'size': [ 48, 'S64' ],
|
|
437
|
+
'blocks': [ 64, 'S64' ],
|
|
438
|
+
'blksize': [ 56, 'S32' ],
|
|
439
|
+
}
|
|
440
|
+
},
|
|
415
441
|
'linux-64': {
|
|
416
442
|
size: 144,
|
|
417
443
|
fields: {
|
|
@@ -431,9 +457,34 @@ const statSpecs = {
|
|
|
431
457
|
},
|
|
432
458
|
},
|
|
433
459
|
};
|
|
434
|
-
|
|
460
|
+
let cachedStatSpec = null;
|
|
435
461
|
const statBufSize = 256;
|
|
436
462
|
|
|
463
|
+
function getStatSpec() {
|
|
464
|
+
if (cachedStatSpec !== null)
|
|
465
|
+
return cachedStatSpec;
|
|
466
|
+
|
|
467
|
+
const api = getApi();
|
|
468
|
+
const stat64Impl = api.stat64 ?? api.__xstat64;
|
|
469
|
+
|
|
470
|
+
let platformId = `${platform}-${pointerSize * 8}`;
|
|
471
|
+
if (platformId === 'linux-32') {
|
|
472
|
+
if (stat64Impl !== undefined)
|
|
473
|
+
platformId += '-stat64';
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const statSpec = statSpecs[platformId];
|
|
477
|
+
if (statSpec === undefined)
|
|
478
|
+
throw new Error('Current OS is not yet supported; please open a PR');
|
|
479
|
+
|
|
480
|
+
statSpec._stat = stat64Impl ?? api.stat;
|
|
481
|
+
statSpec._lstat = api.lstat64 ?? api.__lxstat64 ?? api.lstat;
|
|
482
|
+
|
|
483
|
+
cachedStatSpec = statSpec;
|
|
484
|
+
|
|
485
|
+
return statSpec;
|
|
486
|
+
}
|
|
487
|
+
|
|
437
488
|
class Stats {
|
|
438
489
|
isFile() {
|
|
439
490
|
return (this.mode & S_IFMT) === S_IFREG;
|
|
@@ -465,21 +516,14 @@ class Stats {
|
|
|
465
516
|
}
|
|
466
517
|
|
|
467
518
|
function statSync(path) {
|
|
468
|
-
|
|
469
|
-
const impl = api.stat64 || api.stat;
|
|
470
|
-
return performStat(impl, path);
|
|
519
|
+
return performStat(getStatSpec()._stat, path);
|
|
471
520
|
}
|
|
472
521
|
|
|
473
522
|
function lstatSync(path) {
|
|
474
|
-
|
|
475
|
-
const impl = api.lstat64 || api.lstat;
|
|
476
|
-
return performStat(impl, path);
|
|
523
|
+
return performStat(getStatSpec()._lstat, path);
|
|
477
524
|
}
|
|
478
525
|
|
|
479
526
|
function performStat(impl, path) {
|
|
480
|
-
if (statSpec === null)
|
|
481
|
-
throw new Error('Current OS is not yet supported; please open a PR');
|
|
482
|
-
|
|
483
527
|
const buf = Memory.alloc(statBufSize);
|
|
484
528
|
const result = impl(Memory.allocUtf8String(path), buf);
|
|
485
529
|
if (result.value !== 0)
|
|
@@ -529,7 +573,7 @@ function statsHasField(name) {
|
|
|
529
573
|
}
|
|
530
574
|
|
|
531
575
|
function statsReadField(name) {
|
|
532
|
-
let field =
|
|
576
|
+
let field = getStatSpec().fields[name];
|
|
533
577
|
if (field === undefined) {
|
|
534
578
|
if (name === 'birthtime') {
|
|
535
579
|
return statsReadField.call(this, 'ctime');
|
|
@@ -612,11 +656,18 @@ const apiSpec = [
|
|
|
612
656
|
['unlink', SF, 'int', ['pointer']],
|
|
613
657
|
['stat', SF, 'int', ['pointer', 'pointer']],
|
|
614
658
|
['stat64', SF, 'int', ['pointer', 'pointer']],
|
|
659
|
+
['__xstat64', SF, 'int', ['int', 'pointer', 'pointer'], invokeXstat],
|
|
615
660
|
['lstat', SF, 'int', ['pointer', 'pointer']],
|
|
616
661
|
['lstat64', SF, 'int', ['pointer', 'pointer']],
|
|
662
|
+
['__lxstat64', SF, 'int', ['int', 'pointer', 'pointer'], invokeXstat],
|
|
617
663
|
['strerror', NF, 'pointer', ['int']],
|
|
618
664
|
];
|
|
619
665
|
|
|
666
|
+
function invokeXstat(impl, path, buf) {
|
|
667
|
+
const STAT_VER_LINUX = 3;
|
|
668
|
+
return impl(STAT_VER_LINUX, path, buf);
|
|
669
|
+
}
|
|
670
|
+
|
|
620
671
|
let cachedApi = null;
|
|
621
672
|
function getApi() {
|
|
622
673
|
if (cachedApi === null) {
|
|
@@ -634,13 +685,16 @@ function addApiPlaceholder(api, entry) {
|
|
|
634
685
|
Object.defineProperty(api, name, {
|
|
635
686
|
configurable: true,
|
|
636
687
|
get() {
|
|
637
|
-
const [, Ctor, retType, argTypes] = entry;
|
|
688
|
+
const [, Ctor, retType, argTypes, wrapper] = entry;
|
|
638
689
|
|
|
639
690
|
let impl = null;
|
|
640
691
|
const address = Module.findExportByName(null, name);
|
|
641
692
|
if (address !== null)
|
|
642
693
|
impl = new Ctor(address, retType, argTypes);
|
|
643
694
|
|
|
695
|
+
if (wrapper !== undefined)
|
|
696
|
+
impl = wrapper.bind(null, impl);
|
|
697
|
+
|
|
644
698
|
Object.defineProperty(api, name, { value: impl });
|
|
645
699
|
|
|
646
700
|
return impl;
|
|
@@ -649,11 +703,11 @@ function addApiPlaceholder(api, entry) {
|
|
|
649
703
|
}
|
|
650
704
|
|
|
651
705
|
export function createReadStream(path) {
|
|
652
|
-
|
|
706
|
+
return new ReadStream(path);
|
|
653
707
|
}
|
|
654
708
|
|
|
655
709
|
export function createWriteStream(path) {
|
|
656
|
-
|
|
710
|
+
return new WriteStream(path);
|
|
657
711
|
}
|
|
658
712
|
|
|
659
713
|
export const readdir = callbackify(readdirSync);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frida-fs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Create a stream from a filesystem resource",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -15,5 +15,8 @@
|
|
|
15
15
|
"bugs": {
|
|
16
16
|
"url": "https://github.com/nowsecure/frida-fs/issues"
|
|
17
17
|
},
|
|
18
|
-
"homepage": "https://github.com/nowsecure/frida-fs#readme"
|
|
18
|
+
"homepage": "https://github.com/nowsecure/frida-fs#readme",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"readable-stream": "^4.0.0"
|
|
21
|
+
}
|
|
19
22
|
}
|