SkillAgentSearch skills...

Interruptor

Human-friendly cross-platform system call tracing and hooking library based on Frida's Stalker

Install / Use

/learn @FrenchYeti/Interruptor

README

Interruptor

ci

Work In Progess

The home for Interruptor, a human-friendly interrupts hook library based on Frida's Stalker

Interruptor is the interrupts/systemcall hooking system from Dexcalibur.

Quick start for Android app (could not work as is with obfuscated app) :

frida --codeshare FrenchYeti/android-arm64-strace -U -f YOUR_BINARY

If you like it, please consider to buy :moneybag: Dexcalibur Pro or :sparkling_heart: sponsor me. Sponsor encourage me to free parts of Dexcalibur Pro and spend more free time on such projects :)

The purpose of this library is to provide to Frida users, a rich API able to produce strace-like trace + hook + configurable syscall args API.

It provides by default some useful features such as :

  • File Descriptor lookup (to retrieve path)
  • Bitmap parsing to have humean-friendly output
  • Syscall hook using Frida's Interceptor style
  • Better api to trace/change syscall args before/after
  • Filterable modules and syscalls
  • Coverage generation

Full documentation of the API is now available

1. How to use it

Interruptor can be used by following different approach. I Hope you will be able to find the best one for you :

  • A. Interruptor as NPM package in your hooking project
  • B. Importing minified file per architecture/os
  • C. Using Frida's CodeShare (not yet configurable, less suitable for tampering)
  • C. From source

Case A : Using Interruptor package

See it on NPM

It is the BEST and more reliable way to use Interruptor

This method require Frida >= 16.x is you write your hook in Typescript.

Basically, create a new folder for your hooks or move into your workspace :

mkdir my_workspace && cd my_workspace

And install the package :

npm install @reversense/interruptor

After successful install, you can create a basic script (script.ts) like it (TypeScript) :

import target from '@reversense/interruptor/index.linux.arm64.js';

const Interruptor = target.LinuxArm64({});

Interruptor.newAgentTracer({
    followThread: true,
    scope: {
        syscalls: {
            exclude:  [/clock_gettime/]
        },
        modules: {
            exclude: [/linker/]
        }
    },
    onStart: function(){
        console.log("Entering into lib")
    }
}).start();

Then, just launch your frida script like this :

frida -U -l ./script.ts -f <YOUR_APP>

May be you noted TS script is passed directly to frida instead of frida-compile, such thing is possible with Frida >= 16.x .

Case B : From minified files

Requirements :

  • frida

Download latest release for your architecture into your working directory, and do:

import target from './index.linux.arm64.min.js';
import {DebugUtils} from "./src/common/DebugUtils.js";

const Interruptor = target.LinuxArm64({});

Interruptor.newAgentTracer({
    followThread: true,
    scope: {
        syscalls: {
            exclude:  [/clock_gettime/]
        },
        modules: {
            exclude: [/linker/]
        }
    }
}).start();

Time to deploy hooks can be configured to be when a particular library is loaded. See options below.

Case C : Using Frida's Codeshare (not yet configurable)

Warning : this methods don't allow you to configure Interruptor. So, tracing of obfuscated or multi-threaded application could fail.

This method is only provided for linux/arm64 and training purpose.

frida --codeshare FrenchYeti/android-arm64-strace -f YOUR_BINARY

Case D : From source

Requirements :

  • frida

Don't be afraid by dependencies : Interruptor has only common dev dependencies to provide types and unit test features.

Download or clone the repository, and install it

git clone https://github.com/FrenchYeti/interruptor
cd interruptor
npm install
npm run build

When it is done, just copy one of examples into repository root folder :

cp ./examples/android/simple_trace.ts .

And finally :

frida -U -l ./simple_strace.arm64.ts -f <PACKAGE> 

2. Examples

2.A Simple tracing

With recent version (> 0.2)

Simple tracing without hook from attach moment, with excluded module and syscall (by name)

import target from '@reversense/interruptor/index.linux.arm64.js';

const Interruptor = target.LinuxArm64({});

// better results, when app is loaded
Java.perform(()=>{
    Interruptor.newAgentTracer({
        scope: {
            syscalls: { exclude:  ["clock_gettime"] },
            modules: { exclude: [/linker64/] }
        }
    }).start();
});

With version <= 0.2

Simple tracing without hook from attach moment, with excluded module and syscall (by name)

var Interruptor = require('./android-arm64-strace.min.js').target.LinuxArm64();

// better results, when app is loaded
Java.perform(()=>{
    Interruptor.newAgentTracer({
        exclude: {
            modules: ["linker64"],
            syscalls: ["clock_gettime"]
        }
    }).start();
});

Output :

Output :

	------- [TID=4407][libutils.so][0x76d9fd6388] Thread routine start -------
	[INTERRUPTOR][STARTING] Tracing thread 4407 []
	[STARTING TRACE] UID=1 Thread 4407
 [TID=4407] [/system/lib64/libc.so +0x630]   setpriority (   which = NULL ,  who = 0x0 ,  ioprio = 0x0  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x928]   openat (   dfd = AT_FDCWD  ,  filename = /proc/4407/timerslack_ns ,  flags = O_RDONLY | O_WRONLY | O_CLOEXEC ,  mode =   )    > (FD) 0x1f
 [TID=4407] [/system/lib64/libc.so +0x990]   write (   fd = 31  /proc/4407/timerslack_ns   ,  buf = 50000 ,  size = 0x5  )    > 0x5
 [TID=4407] [/system/lib64/libc.so +0x6d0]   close (   fd = 31  /proc/4407/timerslack_ns    )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x270]   prctl (   opt = PR_SET_NAME ,  arg2 = 0x7651d1d560 ,  arg3 = 0x0 ,  arg4 = 0x0 ,  arg5 = 0x0  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x1b0]   mprotect (   addr = 0x7641dae000 ,  size = 0x1000 ,  prot = PROT_NONE  )    > 0 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0xf0]   madvise (   addr = 0x7641dae000 ,  size = 0xfb000 ,  behavior = MADV_DONTNEED  )    > 0 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0x928]   openat (   dfd = AT_FDCWD  ,  filename = /dev/ashmem ,  flags = O_RDONLY | O_RDWR | O_CLOEXEC ,  mode =   )    > (FD) 0x1f
 [TID=4407] [/system/lib64/libc.so +0xd90]   fstat (   fd = 31  /dev/ashmem   ,  *statbuf = 0x7641ea9e68  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x910]   ioctl (   fd = 31  /dev/ashmem   ,  cmd = 0x41007701 ,  arg = 0x7641ea9f38  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x910]   ioctl (   fd = 31  /dev/ashmem   ,  cmd = 0x40087703 ,  arg = 0x2000  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x180]   mmap (   start_addr = 0x0 ,  size = 0x2000 ,  prot = PROT_READ | PROT_WRITE ,  flags = MAP_PRIVATE ,  fd = undefined ,  offset = 0x0  )    > 0x76599ee000 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0x6d0]   close (   fd = 31  /dev/ashmem    )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x1b0]   mprotect (   addr = 0x12f80000 ,  size = 0x40000 ,  prot = PROT_READ | PROT_WRITE  )    > 0 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0x8e0]   getpriority (   which = NULL ,  who = 0x0  )    > 0x14
 [TID=4407] [/system/lib64/libc.so +0x270]   prctl (   opt = PR_SET_NAME ,  arg2 = 0x7641eaa148 ,  arg3 = 0x343a7265646e6942 ,  arg4 = 0x315f363833 ,  arg5 = 0x28  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0xf70]   getuid (  )    > 10089
 [TID=4407] [/system/lib64/libc.so +0x910]   ioctl (   fd = 12  undefined   ,  cmd = 0xc0306201 ,  arg = 0x7641eaa2b8  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x180]   mmap (   start_addr = 0x0 ,  size = 0xfe000 ,  prot = PROT_READ | PROT_WRITE ,  flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE ,  fd = undefined ,  offset = 0x0  )    > 0x7641263000 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0x1b0]   mprotect (   addr = 0x7641263000 ,  size = 0x1000 ,  prot = PROT_NONE  )    > 0 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0x270]   prctl (   opt = PR_SET_VMA ,  arg2 = 0x0 ,  arg3 = 0x7641263000 ,  arg4 = 0x1000 ,  arg5 = 0x76de1b64c5  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x180]   mmap (   start_addr = 0x0 ,  size = 0x5000 ,  prot = PROT_NONE ,  flags = MAP_PRIVATE | MAP_ANONYMOUS ,  fd = undefined ,  offset = 0x0  )    > 0x76599e9000 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0x270]   prctl (   opt = PR_SET_VMA ,  arg2 = 0x0 ,  arg3 = 0x76599e9000 ,  arg4 = 0x5000 ,  arg5 = 0x76de1b62f9  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x1b0]   mprotect (   addr = 0x76599ea000 ,  size = 0x3000 ,  prot = PROT_READ | PROT_WRITE  )    > 0 SUCCESS
 [TID=4407] [/system/lib64/libc.so +0x270]   prctl (   opt = PR_SET_VMA ,  arg2 = 0x0 ,  arg3 = 0x76599ea000 ,  arg4 = 0x3000 ,  arg5 = 0x76de1b633b  )    > 0x0
 [TID=4407] [/system/lib64/libc.so +0x1ca8]   clone (   unsigned long = 0x3d0f00 ,  unsigned long = 0x76413604e0 ,  int * = 0x7641360500 ,  int * = 0x7641360588 ,  unsigned long = 0x7641360500  )    > 0x1139
 [TID=4407] [/system/lib64/libc.so +0x2c]   futex (   word = 0x7641360570 ,  op = FUTEX_WAKE_PRIVATE ,  u32 val = 0x1 ,  *utime = 0x0 ,  u32 *uaddr2 = 0x0 ,  u32 val3[ = 0x0  )    > 0x1
 [TID=4407] [/system/lib64/libc.so +0x2c]   futex (   word = 0x7659b1c248 ,  op = FUTEX_WAKE_PRIVATE ,  u32 val = 0x7fffffff ,  *utime = 0x0 ,  u32 *uaddr2 = 0x0 ,  u32 val3[ = 0x0  )    > 0x0

	------- [TID=4409][libutils.so][0x76d9fd6388] Thread routine start -------
	[INTERRUPTOR][STARTING] Tracing thread 4409 []
	[STARTING TRACE] UID=2 Thread 4409
 [TID=4409] [/system/lib64/libc.so +0x630]   setpriority (   which = NULL ,  who = 0x0 ,  ioprio = 0x0  )    > 0x0
 [TID=4409] [/system/lib64/libc.so +0x928]   ope
View on GitHub
GitHub Stars356
CategoryDevelopment
Updated1mo ago
Forks47

Languages

TypeScript

Security Score

85/100

Audited on Feb 1, 2026

No findings