Titanox
A hooking framework, symbol rebinder and memory-manager for jailed IOS, All-In-One.
Install / Use
/learn @Ragekill3377/TitanoxREADME
Titanox
Donations
USDT-TRC20 address: TGtQav9ockH1gnb4oqpJLHZJgjv65aEsQj
BNB-BSC address: 0x6a42D5375e77FF896E5fDD5B494Df9f9cAA08D78
SOLANA/SOL: 3HQw2KHZDFL3nEpFxvN5YZGxCqjBsLK5jyhHLZoJsq2q
USDC/BSC: 0x6a42D5375e77FF896E5fDD5B494Df9f9cAA08D78
LITECOIN/LTC: LZr52LM5EaWv7RF8GJY635woqwpxZK3zMJ
TRON/TRX: TRRNssMpSvDkGYq7qPq22Ff6vgFT4dBNwu
-
Do not send NFTs to this/these address/addresses.
-> SEND SOLANA NFTs to:
3HQw2KHZDFL3nEpFxvN5YZGxCqjBsLK5jyhHLZoJsq2q
-> FOR ETHEREUM/ETH NFTs:
0x6a42D5375e77FF896E5fDD5B494Df9f9cAA08D78
PayPal: @HKTRC email: killrage441@gmail.com Name: Haroon Khan
Titanox is a hooking framework for iOS. It utilizes fishhook for symbol rebinding and MemX for memory related tasks. This library supports function hooking, method swizzling, memory patching etc. It does not have any external dependencies and can be used on non-jailbroken/non-rooted IOS devices with full functionailty!!!
Join for support!
experimental: This framework also uses breakpoint hooks. Inspired by The Ellekit Team.
Features
beta function: brk hooking.
-
Breakpoint hooks: Apply upto maximum 6 hooks via breakpoints at runtime. -> Undetected*
-
Static Inline Hook & Patch: -> Patch unlimited addresses UNDER MAINTENANCE -> Hook unlimited addresses -> Be able to call orig in hooks -> Unlimited -> Drawback: need to manually replace binary (From documents directory)
-
Function Hooking (by symbol): Hook functions and rebind symbols (fishhook). FUNCTIONS MUST BE EXPORTED!!!
-
Virtual Function hooking: You can hook any pure C++ class virtual function with this. A wrapper for @Aethereux 's MemX. -> Unlimited -> Must be virtual -> By address
-
Method Swizzling: Replace methods in Objective-C classes.
-
Memory Patching: Modify memory contents safely. -> Read -> Write -> Patch (Insipred from Dobby's CodePatch, made to work on stock IOS)
-
Bool-Hooking: Toggle bool values in memory, to the opposite of their original state. bool symbol must be exposed.
-
Is Hooked: Check if a function is already hooked. This is done automatically.
-
Base Address & VM Address Slide Get: Get
BaseAddressi.e header of the target library and thevm addrslide.
LOGS ARE SAVED TO DOCUMENT'S DIRECTORY AS TITANOX_LOGS.TXT. NO NEED TO USE NSLog or Console app to view logs! You can take logging from utils/utils.mm.
APIs:~
-
fishhook: A library for symbol rebinding used by @facebook. fishhook
-
MemX: A memory management library by @Aethereux. (Modified) MemX-Jailed
Documentation:~
Usage:~
Static Inline Hook (NEW):
A bit complex to use ->
-
Patch
-
Get patched binary
-
Replaced original binary with patched one
-
re-inject titanox + your tweak/library in the target, but this time the target must be the patched one
Required!
StaticInlineHook *hooker = [[StaticInlineHook alloc] initWithMachOName:@"hello.dylib"]; // whatever is name of target binary
Patching address (Need to activate later)
NSString *originalBytes = [hooker applyPatchAtVaddr:0x100003f20 // vm addr stuff
patchBytes:@"00008052C0035FD6"]; // mov & ret asm
Hook Function
void *runthishook = [hooker hookFunctionAtVaddr:0x100004000 withReplacement:(void *)&orig_target];
// you can call orig in the hook func
Activate patch
BOOL qw = [hooker activatePatchAtVaddr:0x100003f20 patchBytes:@"00008052C0035FD6"]; // make sure its same as addr patch init
if (qw) {
// worked
}
Deactivate patch
BOOL wq = [hooker deactivatePatchAtVaddr:0x100003f20 patchBytes:@"00008052C0035FD6"]; // must be same as init patch
if (wq) {
// worked
}
VMT (Virtual) Hook usage and helpers (NEW)
class QAZ {
public:
virtual int do_shit(int v) {
printf("%d\n", v);
return v;
}
virtual ~QAZ() = default;
};
int mt_do_shit(QAZ* s, int v) {
printf("Hooked value -> %d\n", v);
return 69420;
}
void messaround() {
QAZ* obj = new QAZ();
void* hook = [TitanoxHook vmthookCreateWithNewFunction:(void*)&my_do_shit index:0];
if (!hook) {
//Titanox will auto log what went wrong and where.
delete obj;
return;
}
[TitanoxHook vmthookSwap:hook instance:(void*)obj]; // THIS actually does the hook. swaps vtable
int res1 = obj->do_shit(5); // try calling with any value, will return 69420.
// reset to original vtable
[TitanoxHook vmthookReset:hook instance:(void*)obj];
int res2 = obj->do_shit(5);
NSLog(@"This should be 5 -> %d", res2);
[TitanoxHook vmthookDestroy:hook];
void* inv = [TitanoxHook vmtinvokerCreateWithInstance:(void*)obj index:0];
if (!inv) {
// again it will auto log.
delete obj;
return;
}
// Just cast invoker to func ptr with same signature e.g: int(*)(CPPClass*, int)
typedef int (*fn_t)(QAZ*, int);
fn_t func = *(fn_t*)&inv;
int res3 = func(obj, 10);
NSLog(@"direct invoker call: %d", res3);
// get rid of the caller
[TitanoxHook vmtinvokerDestroy:inv];
delete obj;
}
// You can call orig and hook as many funcs as you want safely.
// However, they must be virtual. If they aren't, use brk hooks.
// I'd reccommend using brk hooks as a last resort though.
// prioritise this
// Example: Let's say you can't get a class instance for some reason
// You can use brk hooks to hook it, get instance, unhook, and use that to hook whatever target function you have (virtual)
BRK Hook (Aarch64/arm64) FOR C/C++ FUNCTIONS BY ADDRESS
static void (*original_exit)(int) = NULL;
void hooked_exit(int status) {
NSLog(@"[HOOK] _exit called with status: %d", status);
// a bit difficult to call orig with brk hooks
// copy orig func data, strip PACs and use that (if it works)
return;
}
void hook_exit() {
original_exit = (void (*)(int)) dlsym(RTLD_DEFAULT, "_exit");
if (!original_exit) {
NSLog(@"[ERROR] Failed to find _exit symbol");
return;
}
if ([TitanoxHook addBreakpointAtAddress:(void *)original_exit withHook:(void *)hooked_exit]) {
NSLog(@"[HOOK] _exit hooked successfully");
} else {
NSLog(@"[ERROR] Failed to hook _exit");
}
}
void unhook_exit() {
if (!original_exit) {
NSLog(@"[ERROR] Cannot unhook _exit: original_exit is NULL");
return;
}
if ([TitanoxHook removeBreakpointAtAddress:(void *)original_exit]) {
NSLog(@"[HOOK] _exit unhooked successfully");
} else {
NSLog(@"[ERROR] Failed to unhook _exit");
}
}
HAS a limit to 6 hooks. Unhooking frees those slots.
Function Hooking by fishhook (static) C/C++ Functions by SYMBOL Hook a function by symbol using fishhook (Will hook in main task process):
[TitanoxHook hookStaticFunction:"_funcsym" withReplacement:newFunction outOldFunction:&oldFunction];
Hook a function in a specific library:(Will hook in target library/Binary specified in 'inLibrary'.) Full name is required. i.e extension if any e.g .dylib. It auto loads in the target if not loaded in! Can be the main executable or a loaded library in the application.**
[TitanoxHook hookFunctionByName:"_Zn5Get6Ten" inLibrary:"ShooterGame" withReplacement:newFunction outOldFunction:&oldFunction];
Method Swizzling Swizzle a method in an objc class:
[TitanoxHook swizzleMethod:@selector(originalMethod) withMethod:@selector(swizzledMethod) inClass:[TargetClass class]];
Method Overriding Over-ride a method in an objc class with a new implementation:
[TitanoxHook overrideMethodInClass:[TargetClass class]
selector:@selector(targetMethod)
withNewFunction:newFunction
oldFunctionPointer:&oldFunction];
Memory Modifications R/W memory at specified addresses.
mach_vm_address_t targetAddress = 0x102345678;
uint8_t buffer[16] = {0};
mach_vm_size_t size = sizeof(buffer);
if ([TitanoxHook readMemoryAt:targetAddress buffer:buffer size:size]) {
NSLog(@"worked.");
} else {
NSLog(@"failed to read.");
}
// OR
if ([TitanoxHook MemXreadMemory:targetAddress buffer:buffer length:size]) {
NSLog(@"worked");
} else {
NSLog(@"couldn't read.");
}
Read String
uintptr_t stringAddress = 0x102;
size_t maxLen = 64;
NSString *readString = [TitanoxHook MemXreadString:stringAddress maxLength:maxLen];
if (readString) {
NSLog(@"read string: %@", readString);
} else {
NSLog(@"failed to read string.");
}
Write
mach_vm_address_t targetAddress = 0x1000000000;
uint8_t data[] = {0xdead, 0xdead, 0xdead, 0xdead};
mach_vm_size_t size = sizeof(data);
if ([TitanoxHook writeMemoryAt:targetAddress data:data size:size]) {
NSLog(@"worked.");
} else {
NSLog(@"failed.");
}
// OR
NSNumber *value = @(12345);
NSString *type = @"int"; // type of data ("int", "long", "uintptr_t", etc.)
[TitanoxHook MemXwriteMemory:targetAddress value:value type:type];
Is Address Valid?
uintptr_t address = 0x100;
if ([TitanoxHook MemXisValidPointer:address]) {
NSLog(@"ptr 0x%lx is valid.", address);
} else {
NSLog(@"ptr 0x%lx is invalid.", address);
}
Change Memory protections with custom vm functions
mach_vm_address_t targetAddress = 0x449ef78;
mach_vm_size_t size = 0x1000; // this should be sizeof target addr but just an example here
vm_prot_t newProtection = VM_PROT_READ | VM_PROT_WRITE;
BOOL setMax = NO; // depends on your usage case
kern_return_t result = [TitanoxHook protectMemoryAt:targetAddress s
