diff --git a/agent/src/android/filesystem.ts b/agent/src/android/filesystem.ts index aaf0eaf..40c78e1 100644 --- a/agent/src/android/filesystem.ts +++ b/agent/src/android/filesystem.ts @@ -1,4 +1,5 @@ -import * as fs from "fs"; +import * as fs from "frida-fs"; +import { Buffer } from "buffer"; import { hexStringToBytes } from "../lib/helpers.js"; import { IAndroidFilesystem } from "./lib/interfaces.js"; import { @@ -78,7 +79,9 @@ export const pwd = (): Promise => { }; // heavy lifting is done in frida-fs here. -export const readFile = (path: string): Buffer => { +export const readFile = (path: string): string | Buffer => { + if (fs.statSync(path).size == 0) + return Buffer.alloc(0); return fs.readFileSync(path); }; diff --git a/agent/src/generic/http.ts b/agent/src/generic/http.ts index 8bc7ff4..ad56d4f 100644 --- a/agent/src/generic/http.ts +++ b/agent/src/generic/http.ts @@ -1,4 +1,4 @@ -import * as fs from "fs"; +import * as fs from "frida-fs"; import * as httpLib from "http"; import * as url from "url"; import { colors as c } from "../lib/color.js"; @@ -11,19 +11,28 @@ const log = (m: string): void => { c.log(`[http server] ${m}`); }; -const dirListingHTML = (p: string): string => { +const dirListingHTML = (pwd: string, path: string): string => { let h = ` -

Index Of /

+

Index Of ${path}

{file_listing} `; h = h.replace(`{file_listing}`, () => { - return fs.readdirSync(p).map((f) => { - return `${f}`; + return fs.list(pwd + decodeURIComponent(path)).map((f) => { + if (f.name === '.') return; + + // Add a slash at the end if it is a directory. + var fname = f.name + (f.type == 4 ? '/' : ''); + + if (path !== '/') { + return `${fname}`; + } else if (fname !== '../') { + return `${fname}`; + } }).join("
"); }); @@ -49,16 +58,40 @@ export const start = (pwd: string, port: number = 9000): void => { log(`${c.redBright('Missing URL or request method.')}`); return; } - - const parsedUrl = new URL(req.url); - if (parsedUrl.pathname === "/") { - res.end(dirListingHTML(pwd)); - return; - } + try { + const parsedUrl = url.parse(req.url); + const fileLocation = pwd + decodeURIComponent(parsedUrl.path); + + if (fs.statSync(fileLocation).isDirectory()) { + res.end(dirListingHTML(pwd, parsedUrl.path)); + return; + } - res.setHeader("Content-type", "application/octet-stream"); - res.end(fs.readFileSync(pwd + parsedUrl.pathname)); + res.setHeader("Content-type", "application/octet-stream"); + + // Check that we are not reading an empty file + if (fs.statSync(fileLocation).size !== 0) { + const file = fs.readFileSync(fileLocation); + res.write(file, 'utf-8') + } + res.end(); + + } catch (error) { + if (error instanceof Error && error.message == "No such file or directory") { + res.statusCode = 404; + res.end("File not found") + } else { + if (error instanceof Error) { + log(c.redBright(`${error.stack}`)); + } else { + log(c.redBright(`${error}`)); + } + + res.statusCode = 500; + res.end("Internal Server Error") + } + } }); httpServer.listen(port); @@ -75,12 +108,12 @@ export const stop = (): void => { httpServer.close() .once("close", () => { log(c.blackBright(`Server closed.`)); - // httpServer = undefined; + httpServer = undefined; }); }; export const status = (): void => { - if (httpServer.listening) { + if (httpServer && httpServer.listening) { log(`Server is running on port ` + `${c.greenBright(listenPort.toString())} serving ${c.greenBright(servePath)}`); return; diff --git a/agent/src/ios/binary.ts b/agent/src/ios/binary.ts index 4939754..7a0fd8f 100644 --- a/agent/src/ios/binary.ts +++ b/agent/src/ios/binary.ts @@ -31,6 +31,9 @@ export const info = (): IBinaryModuleDictionary => { const imports: Set = new Set(a.enumerateImports().map((i) => i.name)); const fb = iosfilesystem.readFile(a.path); + if (typeof(fb) == 'string') { + return; + } try { const exe = macho.parse(fb); diff --git a/agent/src/ios/filesystem.ts b/agent/src/ios/filesystem.ts index cf10b07..deaf562 100644 --- a/agent/src/ios/filesystem.ts +++ b/agent/src/ios/filesystem.ts @@ -1,4 +1,5 @@ -import * as fs from "fs"; +import * as fs from "frida-fs"; +import { Buffer } from "buffer"; import { hexStringToBytes } from "../lib/helpers.js"; import { getNSFileManager } from "./lib/helpers.js"; import { @@ -87,7 +88,9 @@ export const pwd = (): string => { }; // heavy lifting is done in frida-fs here. -export const readFile = (path: string): Buffer => { +export const readFile = (path: string): string | Buffer => { + if (fs.statSync(path).size == 0) + return Buffer.alloc(0); return fs.readFileSync(path); }; diff --git a/agent/src/ios/keychain.ts b/agent/src/ios/keychain.ts index d408696..e3d797f 100644 --- a/agent/src/ios/keychain.ts +++ b/agent/src/ios/keychain.ts @@ -111,9 +111,7 @@ const enumerateKeychain = (): IKeychainData[] => { }); const keyChainData: IKeychainData[] = []; - keyChainData.concat(...itemClassResults).filter((n) => n !== undefined); - - return keyChainData; + return keyChainData.concat(...itemClassResults).filter((n) => n !== undefined); }; // print raw entries using some Frida magic diff --git a/agent/src/rpc/ios.ts b/agent/src/rpc/ios.ts index 47a8eb8..9e7836e 100644 --- a/agent/src/rpc/ios.ts +++ b/agent/src/rpc/ios.ts @@ -40,7 +40,7 @@ export const ios = { // ios filesystem iosFileCwd: (): string => iosfilesystem.pwd(), iosFileDelete: (path: string): boolean => iosfilesystem.deleteFile(path), - iosFileDownload: (path: string): Buffer => iosfilesystem.readFile(path), + iosFileDownload: (path: string): string | Buffer => iosfilesystem.readFile(path), iosFileExists: (path: string): boolean => iosfilesystem.exists(path), iosFileLs: (path: string): IIosFileSystem => iosfilesystem.ls(path), iosFilePathIsFile: (path: string): boolean => iosfilesystem.pathIsFile(path), diff --git a/objection/commands/filemanager.py b/objection/commands/filemanager.py index 89f9956..69956a0 100644 --- a/objection/commands/filemanager.py +++ b/objection/commands/filemanager.py @@ -44,7 +44,9 @@ def cd(args: list) -> None: return # moving one directory back - if path == '..': + device_path_separator = device_state.platform.path_separator + + if path == '..' or path == '..'+device_path_separator: split_path = os.path.split(current_dir) @@ -66,6 +68,10 @@ def cd(args: list) -> None: # assume the path does not exist by default does_exist = False + # normalise path to remove '../' + if '..'+device_path_separator in path: + path = os.path.normpath(path).replace('\\', device_path_separator) + # check for existence based on the runtime if device_state.platform == Ios: does_exist = _path_exists_ios(path) @@ -89,7 +95,13 @@ def cd(args: list) -> None: # see if its legit. else: - proposed_path = device_state.platform.path_separator.join([current_dir, path]) + proposed_path = device_path_separator.join([current_dir, path]) + + # normalise path to remove '../' + if '..'+device_path_separator in proposed_path: + proposed_path = os.path.normpath(proposed_path).replace('\\', device_path_separator) + if proposed_path == '//': + return # assume the proposed_path does not exist by default does_exist = False @@ -785,7 +797,10 @@ def list_folders_in_current_fm_directory() -> dict: file_name, file_type = entry if file_type == 'directory': - resp[file_name] = file_name + if ' ' in file_name: + resp[f"'{file_name}'"] = file_name + else: + resp[file_name] = file_name return resp @@ -816,6 +831,9 @@ def list_files_in_current_fm_directory() -> dict: file_name, file_type = entry if file_type == 'file': - resp[file_name] = file_name + if ' ' in file_name: + resp[f"'{file_name}'"] = file_name + else: + resp[file_name] = file_name return resp diff --git a/objection/utils/agent.py b/objection/utils/agent.py index cf2a4ed..64ecc7b 100644 --- a/objection/utils/agent.py +++ b/objection/utils/agent.py @@ -216,6 +216,8 @@ def set_target_pid(self): elif self.config.spawn: if self.config.uid is not None: + if self.device.query_system_parameters()['os']['id'] != 'android': + raise Exception('--uid flag can only be used on Android.') self.pid = self.device.spawn(self.config.name, uid=int(self.config.uid)) else: self.pid = self.device.spawn(self.config.name) @@ -245,9 +247,10 @@ def attach(self): raise Exception('A PID needs to be set before attach()') if self.config.uid is None: + debug_print(f'Attaching to PID: {self.pid}') self.session = self.device.attach(self.pid) else: - self.session = self.device.attach(self.pid, uid=self.config.uid) + self.session = self.device.attach(self.pid) self.session.on('detached', self.handlers.session_on_detached) diff --git a/requirements.txt b/requirements.txt index 1f678cf..2b309d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ requests Flask>=3.0.0 Pygments>=2.0.0 litecli>=1.3.0 +setuptools>=70.0.0