├── .gitignore ├── LICENSE ├── README.md ├── lib ├── callback.ts └── index.ts ├── package-lock.json ├── package.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | /dist/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 AeonLucid 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # frida-syscall-interceptor 2 | 3 | This project allows you to intercept syscalls on android, currently only supports Arm64. 4 | 5 | You need to use this in a frida typescript project. For an example on how to set one up, see [oleavr/frida-agent-example](https://github.com/oleavr/frida-agent-example). 6 | 7 | ## Issues 8 | 9 | - The original syscall won't be called anymore if you hook it, so you are required to create a fake implementation. 10 | 11 | ## Usage 12 | 13 | ```typescript 14 | // Add at the top. 15 | import { hookSyscall } from 'frida-syscall-interceptor'; 16 | 17 | // Somewhere in your code. 18 | let baseAddr = Module.findBaseAddress('libSomething.so')!; 19 | let address = baseAddr.add('0x1234'); 20 | 21 | hookSyscall(address, new NativeCallback(function (dirfd, pathname, mode, flags) { 22 | let path = pathname.readCString(); 23 | 24 | log(`Called faccessat hook`); 25 | log('- X0: ' + dirfd); 26 | log('- X1: ' + path); 27 | log('- X2: ' + mode); 28 | log('- X3: ' + flags); 29 | 30 | return 0; 31 | }, 'int', ['int', 'pointer', 'int', 'int'])); 32 | ``` -------------------------------------------------------------------------------- /lib/callback.ts: -------------------------------------------------------------------------------- 1 | export class SyscallCallback { 2 | 3 | frida: NativePointer; 4 | native: NativePointer; 5 | 6 | constructor (frida: NativePointer, native: NativePointer) { 7 | this.frida = frida; 8 | this.native = native; 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | import { SyscallCallback } from "./callback"; 2 | 3 | let callbacks: SyscallCallback[] = []; 4 | 5 | export function hookSyscall(syscallAddress: NativePointer, callback: NativeCallback) { 6 | const address = syscallAddress.sub(12); 7 | const instructions = address.readByteArray(12); 8 | 9 | if (instructions == null) { 10 | throw new Error(`Unable to read instructions at address ${address}.`); 11 | } 12 | 13 | Memory.patchCode(address, 16, function (code) { 14 | let writer = new Arm64Writer(code, { pc: address }); 15 | writer.putBranchAddress(createCallback(callback, instructions, address.add(16), syscallAddress)); 16 | writer.flush(); 17 | }); 18 | } 19 | 20 | function createCallback(callback: NativeCallback, instructions: ArrayBuffer, retAddress: NativePointer, syscallAddress: NativePointer) { 21 | // Create custom instructions. 22 | let frida = Memory.alloc(Process.pageSize); 23 | 24 | Memory.patchCode(frida, Process.pageSize, function (code) { 25 | let writer = new Arm64Writer(code, { pc: frida }); 26 | 27 | // Restore argument instructions. 28 | writer.putBytes(instructions); 29 | 30 | // Push all registers except x0. 31 | writer.putPushRegReg('x15', 'x1'); 32 | writer.putPushRegReg('x2', 'x3'); 33 | writer.putPushRegReg('x4', 'x5'); 34 | writer.putPushRegReg('x6', 'x7'); 35 | writer.putPushRegReg('x8', 'x9'); 36 | writer.putPushRegReg('x10', 'x11'); 37 | writer.putPushRegReg('x12', 'x13'); 38 | writer.putPushRegReg('x14', 'x15'); 39 | writer.putPushRegReg('x16', 'x17'); 40 | writer.putPushRegReg('x18', 'x19'); 41 | writer.putPushRegReg('x20', 'x21'); 42 | writer.putPushRegReg('x22', 'x23'); 43 | writer.putPushRegReg('x24', 'x25'); 44 | writer.putPushRegReg('x26', 'x27'); 45 | writer.putPushRegReg('x28', 'x29'); 46 | writer.putInstruction(0xd53b420f); 47 | writer.putPushRegReg('x30', 'x15'); 48 | 49 | // Call native. 50 | writer.putLdrRegAddress('x16', callback); 51 | writer.putBlrReg('x16'); 52 | 53 | // Pop all registers, except x0, so x0 from native call gets used. 54 | writer.putPopRegReg('x30', 'x15'); 55 | writer.putInstruction(0xd51b420f); 56 | writer.putPopRegReg('x28', 'x29'); 57 | writer.putPopRegReg('x26', 'x27'); 58 | writer.putPopRegReg('x24', 'x25'); 59 | writer.putPopRegReg('x22', 'x23'); 60 | writer.putPopRegReg('x20', 'x21'); 61 | writer.putPopRegReg('x18', 'x19'); 62 | writer.putPopRegReg('x16', 'x17'); 63 | writer.putPopRegReg('x14', 'x15'); 64 | writer.putPopRegReg('x12', 'x13'); 65 | writer.putPopRegReg('x10', 'x11'); 66 | writer.putPopRegReg('x8', 'x9'); 67 | writer.putPopRegReg('x6', 'x7'); 68 | writer.putPopRegReg('x4', 'x5'); 69 | writer.putPopRegReg('x2', 'x3'); 70 | writer.putPopRegReg('x15', 'x1'); 71 | 72 | // Call syscall. 73 | // writer.putInstruction(0xd4000001); 74 | 75 | writer.putBranchAddress(retAddress); 76 | writer.flush(); 77 | }); 78 | 79 | // Store callback so it doesn't get garbage collected. 80 | callbacks.push(new SyscallCallback(frida, callback)); 81 | 82 | // Return pointer to the instructions. 83 | return callbacks[callbacks.length - 1].frida; 84 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frida-syscall-interceptor", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/frida-gum": { 8 | "version": "14.5.0", 9 | "resolved": "https://registry.npmjs.org/@types/frida-gum/-/frida-gum-14.5.0.tgz", 10 | "integrity": "sha512-eMJ9Nvo+QoA+K//0+qByBgkWnnyrzmfz/Z0+hCUEmrXn6wGc5FCHfjARXP8fu1SH3WEPWTvXzOUJqmhfv96GNg==", 11 | "dev": true 12 | }, 13 | "@types/node": { 14 | "version": "13.1.1", 15 | "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.1.tgz", 16 | "integrity": "sha512-hx6zWtudh3Arsbl3cXay+JnkvVgCKzCWKv42C9J01N2T2np4h8w5X8u6Tpz5mj38kE3M9FM0Pazx8vKFFMnjLQ==", 17 | "dev": true 18 | }, 19 | "typescript": { 20 | "version": "3.7.4", 21 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", 22 | "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==", 23 | "dev": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frida-syscall-interceptor", 3 | "version": "1.0.0", 4 | "description": "Frida syscall interceptor", 5 | "main": "./dist/index.js", 6 | "types": "./dist/index.d.ts", 7 | "files": [ 8 | "/dist/" 9 | ], 10 | "scripts": { 11 | "prepare": "npm run build", 12 | "build": "tsc", 13 | "watch": "tsc -w" 14 | }, 15 | "devDependencies": { 16 | "@types/frida-gum": "^14.5.0", 17 | "@types/node": "^13.1.1", 18 | "typescript": "^3.7.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": ["esnext"], 5 | "strict": true, 6 | "module": "commonjs", 7 | "esModuleInterop": true, 8 | "declaration": true, 9 | "outDir": "./dist" 10 | }, 11 | "include": [ 12 | "lib/**/*" 13 | ] 14 | } 15 | --------------------------------------------------------------------------------