taiHEN  1.0
CFW framework for PS Vita
Data Structures | Macros | Typedefs
Hooks Interface

Patches functions. More...

Data Structures

struct  _tai_hook_user
 Internal structure. More...
 

Macros

#define TAI_CONTINUE(type, hook, ...)
 Calls the next function in the chain. More...
 

Typedefs

typedef uintptr_t tai_hook_ref_t
 Hook information. More...
 

Kernel Hooks

Hooks exports to kernel

SceUID taiHookFunctionAbs (SceUID pid, tai_hook_ref_t *p_hook, void *dest_func, const void *hook_func)
 Add a hook given an absolute address. More...
 
SceUID taiHookFunctionExportForKernel (SceUID pid, tai_hook_ref_t *p_hook, const char *module, uint32_t library_nid, uint32_t func_nid, const void *hook_func)
 Add a hook to a module function export. More...
 
SceUID taiHookFunctionImportForKernel (SceUID pid, tai_hook_ref_t *p_hook, const char *module, uint32_t import_library_nid, uint32_t import_func_nid, const void *hook_func)
 Add a hook to a module function import. More...
 
SceUID taiHookFunctionOffsetForKernel (SceUID pid, tai_hook_ref_t *p_hook, SceUID modid, int segidx, uint32_t offset, int thumb, const void *hook_func)
 Add a hook to a module manually with an offset. More...
 
int taiGetModuleInfoForKernel (SceUID pid, const char *module, tai_module_info_t *info)
 Gets information on a currently loaded module. More...
 
int taiHookReleaseForKernel (SceUID tai_uid, tai_hook_ref_t hook)
 Release a hook. More...
 

User Hooks

Hooks exports to user

SceUID taiHookFunctionExportForUser (tai_hook_ref_t *p_hook, tai_hook_args_t *args)
 Add a hook to a module function export for the calling process. More...
 
SceUID taiHookFunctionImportForUser (tai_hook_ref_t *p_hook, tai_hook_args_t *args)
 Add a hook to a module function import for the calling process. More...
 
SceUID taiHookFunctionOffsetForUser (tai_hook_ref_t *p_hook, tai_offset_args_t *args)
 Add a hook to a module manually with an offset for the calling process. More...
 
int taiGetModuleInfo (const char *module, tai_module_info_t *info)
 Gets information on a currently loaded module. More...
 
int taiHookRelease (SceUID tai_uid, tai_hook_ref_t hook)
 Release a hook for the calling process. More...
 
HELPER SceUID taiHookFunctionExport (tai_hook_ref_t *p_hook, const char *module, uint32_t library_nid, uint32_t func_nid, const void *hook_func)
 Helper function for taiHookFunctionExportForUser. More...
 
HELPER SceUID taiHookFunctionImport (tai_hook_ref_t *p_hook, const char *module, uint32_t import_library_nid, uint32_t import_func_nid, const void *hook_func)
 Helper function for taiHookFunctionImportForUser. More...
 
HELPER SceUID taiHookFunctionOffset (tai_hook_ref_t *p_hook, SceUID modid, int segidx, uint32_t offset, int thumb, const void *hook_func)
 Helper function for taiHookFunctionOffsetForUser. More...
 

Detailed Description

Patches functions.

A function hook allows a plugin to run code before and after a any function call. As an example, say we wish to hook sceIoOpenForDriver

static tai_hook_ref_t open_ref;
taiHookFunctionExportForKernel(KERNEL_PID, &open_ref, "SceIofilemgr", TAI_ANY_LIBRARY, 0x75192972, open_hook);

If we wish to log the path of any kernel file opens, we can write this

SceUID open_hook(const char *path, int flags, SceMode mode) {
printf("opened: %s\n", path);
return TAI_CONTINUE(SceUID, open_ref, path, flags, mode);
}

Note that it is the user's responsibility to ensure that the function prototype matches. What if we want to log the return values too?

SceUID open_hook(const char *path, int flags, SceMode mode) {
SceUID ret = TAI_CONTINUE(SceUID, open_ref, path, flags, mode);
printf("opened: %s, return: %x\n", path, ret);
return ret;
}

For a more complicated example, we can redirect a file open as follows

SceUID open_hook(const char *path, int flags, SceMode mode) {
SceUID ret;
if (strcmp(path, "ux0:id.dat") == 0) {
path = "ux0:id-redirect.dat";
printf("redirecting path\n");
}
ret = TAI_CONTINUE(SceUID, open_ref, path, flags, mode);
printf("opened: %s, return: %x\n", path, ret);
return ret;
}

Note that we use the TAI_CONTINUE macro in order to continue the chain. You should always do this because it ensures all hooks get their share of the pie. Consider this bad example

SceUID bad_open_hook(const char *path, int flags, SceMode mode) {
if (strcmp(path, "ux0:dontwant.bin") == 0) {
return SCE_KERNEL_ERROR_NOENT;
} else {
return TAI_CONTINUE(SceUID, open_ref, path, flags, mode);
}
}

This prevents any other hooks from running. This would break, for example, our logging hook above. Instead you should do

SceUID good_open_hook(const char *path, int flags, SceMode mode) {
SceUID ret;
ret = TAI_CONTINUE(SceUID, open_ref, path, flags, mode);
if (strcmp(path, "ux0:dontwant.bin") == 0) {
return SCE_KERNEL_ERROR_NOENT;
} else {
return ret;
}
}

Another common use case is the ability to call the original function. The recommended way of doing this is to make the original function call

SceUID recurse_open_hook(const char *path, int flags, SceMode mode) {
const char *log = "ux0:lastopen.txt";
SceUID ret;
SceUID fd;
ret = TAI_CONTINUE(SceUID, open_ref, path, flags, mode);
if (path != log && strncmp(path, "ux0:", 4) == 0) {
fd = sceIoOpenForDriver(log, SCE_O_WRONLY, 0);
sceIoWrite(fd, path, 256);
sceIoClose(fd);
}
return ret;
}

Note that calling the original sceIoOpenForDriver will recurse back to recurse_open_hook so it is very important to avoid an infinite recursion. In this case, we check that the parameter is not the same, but more complex checks may be needed for other function.

Macro Definition Documentation

§ TAI_CONTINUE

#define TAI_CONTINUE (   type,
  hook,
  ... 
)
Value:
({ \
struct _tai_hook_user *cur, *next; \
cur = (struct _tai_hook_user *)(hook); \
next = (struct _tai_hook_user *)cur->next; \
(next == NULL) ? \
((type(*)())cur->old)(__VA_ARGS__) \
: \
((type(*)())next->func)(__VA_ARGS__) \
; \
})
struct _tai_proc * next
Next process in this map bucket.
Internal structure.
Definition: taihen.h:220

Calls the next function in the chain.

Parameters
typeReturn type
hookThe hook continuing the call
Returns
Return value from the hook chain

Definition at line 345 of file taihen.h.

Typedef Documentation

§ tai_hook_ref_t

typedef uintptr_t tai_hook_ref_t

Hook information.

This reference is created on new hooks and is up to the caller to keep track of. The client is responsible for cleanup by passing the reference back to taiHEN when needed.

Definition at line 215 of file taihen.h.

Function Documentation

§ taiGetModuleInfo()

int taiGetModuleInfo ( const char *  module,
tai_module_info_t info 
)

Gets information on a currently loaded module.

You can use the macro TAI_MAIN_MODULE for module to specify the main module. This is usually the module that is loaded first and is usually the eboot.bin. This will only work if there is only one module loaded in the main memory space. Not all processes have this property! Make sure you check the return value.

See also
taiGetModuleInfoForKernel
Parameters
[in]moduleThe name of the module or TAI_MAIN_MODULE.
[out]infoThe information to fill
Returns
Zero on success, < 0 on error
  • TAI_ERROR_USER_MEMORY if info->size is too small or large or module is invalid
  • TAI_ERROR_INVALID_MODULE if TAI_MAIN_MODULE is specified and there are multiple main modules

Definition at line 209 of file taihen-user.c.

§ taiGetModuleInfoForKernel()

int taiGetModuleInfoForKernel ( SceUID  pid,
const char *  module,
tai_module_info_t info 
)

Gets information on a currently loaded module.

You should use this before calling taiHookFunctionOffsetForKernel in order to check that the module you wish to hook is currently loaded and that the module NID matches. The module NID changes in each version of the module.

Parameters
[in]pidThe pid of the caller (kernel should set to KERNEL_PID)
[in]moduleThe name of the module
[out]infoThe information to fill
Returns
Zero on success, < 0 on error
  • TAI_ERROR_INVALID_MODULE if module is TAI_MAIN_MODULE and pid is kernel

Definition at line 191 of file taihen.c.

§ taiHookFunctionAbs()

SceUID taiHookFunctionAbs ( SceUID  pid,
tai_hook_ref_t p_hook,
void *  dest_func,
const void *  hook_func 
)

Add a hook given an absolute address.

If target is the kernel, use KERNEL_PID as pid.

Parameters
[in]pidThe pid of the target
[out]p_hookA reference that can be used by the hook function
dest_funcThe function to patch (must be in the target address space)
[in]hook_funcThe hook function (must be in the target address space)
Returns
A tai patch reference on success, < 0 on error
  • TAI_ERROR_PATCH_EXISTS if the address is already patched
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to hook
  • TAI_ERROR_INVALID_KERNEL_ADDR if pid is kernel and address is in shared memory region

Definition at line 41 of file taihen.c.

§ taiHookFunctionExport()

HELPER SceUID taiHookFunctionExport ( tai_hook_ref_t p_hook,
const char *  module,
uint32_t  library_nid,
uint32_t  func_nid,
const void *  hook_func 
)

Helper function for taiHookFunctionExportForUser.

You can use the macro TAI_MAIN_MODULE for module to specify the main module. This is usually the module that is loaded first and is usually the eboot.bin. This will only work if there is only one module loaded in the main memory space. Not all processes have this property! Make sure you check the return value.

See also
taiHookFunctionExportForUser
Parameters
[out]p_hookA reference that can be used by the hook function
[in]moduleName of the target module or TAI_MAIN_MODULE.
[in]library_nidOptional. NID of the target library.
[in]func_nidThe function NID. If library_nid is TAI_ANY_LIBRARY, then the first export with the NID will be hooked.
[in]hook_funcThe hook function
Returns
{ description_of_the_return_value }

Definition at line 271 of file taihen.h.

§ taiHookFunctionExportForKernel()

SceUID taiHookFunctionExportForKernel ( SceUID  pid,
tai_hook_ref_t p_hook,
const char *  module,
uint32_t  library_nid,
uint32_t  func_nid,
const void *  hook_func 
)

Add a hook to a module function export.

If target is the kernel, use KERNEL_PID as pid. Since a module can have two libraries that export the same NID, you can optionally pass in the library NID of the one to hook. Otherwise, use TAI_ANY_LIBRARY and the first one found will be used.

Parameters
[in]pidThe pid of the target
[out]p_hookA reference that can be used by the hook function
[in]moduleName of the target module.
[in]library_nidOptional. NID of the target library.
[in]func_nidThe function NID. If library_nid is TAI_ANY_LIBRARY, then the first export with the NID will be hooked.
[in]hook_funcThe hook function (must be in the target address space)
Returns
A tai patch reference on success, < 0 on error
  • TAI_ERROR_PATCH_EXISTS if the address is already patched
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to hook
  • TAI_ERROR_INVALID_KERNEL_ADDR if pid is kernel and address is in shared memory region
  • TAI_ERROR_INVALID_MODULE if module is TAI_MAIN_MODULE and pid is kernel

Definition at line 72 of file taihen.c.

§ taiHookFunctionExportForUser()

SceUID taiHookFunctionExportForUser ( tai_hook_ref_t p_hook,
tai_hook_args_t args 
)

Add a hook to a module function export for the calling process.

See also
taiHookFunctionExportForKernel
Parameters
[out]p_hookA reference that can be used by the hook function
[in]argsCall arguments
Returns
A tai patch reference on success, < 0 on error
  • TAI_ERROR_PATCH_EXISTS if the address is already patched
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to hook
  • TAI_ERROR_NOT_IMPLEMENTED if address is in shared memory region
  • TAI_ERROR_USER_MEMORY if pointers are incorrect
  • TAI_ERROR_INVALID_MODULE if TAI_MAIN_MODULE is specified and there are multiple main modules

Definition at line 44 of file taihen-user.c.

§ taiHookFunctionImport()

HELPER SceUID taiHookFunctionImport ( tai_hook_ref_t p_hook,
const char *  module,
uint32_t  import_library_nid,
uint32_t  import_func_nid,
const void *  hook_func 
)

Helper function for taiHookFunctionImportForUser.

You can use the macro TAI_MAIN_MODULE for module to specify the main module. This is usually the module that is loaded first and is usually the eboot.bin. This will only work if there is only one module loaded in the main memory space. Not all processes have this property! Make sure you check the return value.

See also
taiHookFunctionImportForUser
Parameters
[out]p_hookA reference that can be used by the hook function
[in]moduleName of the target module or TAI_MAIN_MODULE.
[in]import_library_nidThe imported library from the target module
[in]import_func_nidThe function NID of the import
[in]hook_funcThe hook function

Definition at line 301 of file taihen.h.

§ taiHookFunctionImportForKernel()

SceUID taiHookFunctionImportForKernel ( SceUID  pid,
tai_hook_ref_t p_hook,
const char *  module,
uint32_t  import_library_nid,
uint32_t  import_func_nid,
const void *  hook_func 
)

Add a hook to a module function import.

If target is the kernel, use KERNEL_PID as pid. This will let you hook calls from one module to another without having to hook all calls to that module.

Parameters
[in]pidThe pid of the target
[out]p_hookA reference that can be used by the hook function
[in]moduleName of the target module.
[in]import_library_nidThe imported library from the target module
[in]import_func_nidThe function NID of the import
[in]hook_funcThe hook function (must be in the target address space)
Returns
A tai patch reference on success, < 0 on error
  • TAI_ERROR_PATCH_EXISTS if the address is already patched
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to hook
  • TAI_ERROR_INVALID_KERNEL_ADDR if pid is kernel and address is in shared memory region
  • TAI_ERROR_STUB_NOT_RESOLVED if the import has not been resolved yet. You should hook sceKernelLoadStartModule, sceSysmoduleLoadModule or whatever the application uses to start the imported module and add this hook after the module is loaded. Be sure to also hook module unloading to remove the hook BEFORE the imported module is unloaded!
  • TAI_ERROR_INVALID_MODULE if module is TAI_MAIN_MODULE and pid is kernel

Definition at line 115 of file taihen.c.

§ taiHookFunctionImportForUser()

SceUID taiHookFunctionImportForUser ( tai_hook_ref_t p_hook,
tai_hook_args_t args 
)

Add a hook to a module function import for the calling process.

See also
taiHookFunctionImportForKernel
Parameters
[out]p_hookA reference that can be used by the hook function
[in]argsCall arguments
Returns
A tai patch reference on success, < 0 on error
  • TAI_ERROR_PATCH_EXISTS if the address is already patched
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to hook
  • TAI_ERROR_NOT_IMPLEMENTED if address is in shared memory region. You should hook an import from another module instead.
  • TAI_ERROR_USER_MEMORY if pointers are incorrect
  • TAI_ERROR_STUB_NOT_RESOLVED if the import has not been resolved yet. You should hook sceKernelLoadStartModule, sceSysmoduleLoadModule or whatever the application uses to start the imported module and add this hook after the module is loaded. Be sure to also hook module unloading to remove the hook BEFORE the imported module is unloaded!
  • TAI_ERROR_INVALID_MODULE if TAI_MAIN_MODULE is specified and there are multiple main modules

Definition at line 105 of file taihen-user.c.

§ taiHookFunctionOffset()

HELPER SceUID taiHookFunctionOffset ( tai_hook_ref_t p_hook,
SceUID  modid,
int  segidx,
uint32_t  offset,
int  thumb,
const void *  hook_func 
)

Helper function for taiHookFunctionOffsetForUser.

See also
taiHookFunctionOffsetForUser
Parameters
[out]p_hookA reference that can be used by the hook function
[in]modidThe module UID from taiGetModuleInfo
[in]segidxThe ELF segment index containing the function to patch
[in]offsetThe offset from the start of the segment
[in]thumbSet to 1 if this is a Thumb function
[in]hook_funcThe hook function (must be in the target address space)

Definition at line 324 of file taihen.h.

§ taiHookFunctionOffsetForKernel()

SceUID taiHookFunctionOffsetForKernel ( SceUID  pid,
tai_hook_ref_t p_hook,
SceUID  modid,
int  segidx,
uint32_t  offset,
int  thumb,
const void *  hook_func 
)

Add a hook to a module manually with an offset.

If target is the kernel, use KERNEL_PID as pid. The caller is responsible for checking that the module is of the correct version!

Parameters
[in]pidThe pid of the target
[out]p_hookA reference that can be used by the hook function
[in]modidThe module UID from taiGetModuleInfoForKernel
[in]segidxThe ELF segment index containing the function to patch
[in]offsetThe offset from the start of the segment
[in]thumbSet to 1 if this is a Thumb function
[in]hook_funcThe hook function (must be in the target address space)
Returns
A tai patch reference on success, < 0 on error
  • TAI_ERROR_PATCH_EXISTS if the address is already patched
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to hook
  • TAI_ERROR_INVALID_KERNEL_ADDR if pid is kernel and address is in shared memory region

Definition at line 159 of file taihen.c.

§ taiHookFunctionOffsetForUser()

SceUID taiHookFunctionOffsetForUser ( tai_hook_ref_t p_hook,
tai_offset_args_t args 
)

Add a hook to a module manually with an offset for the calling process.

See also
taiHookFunctionOffsetForKernel
Parameters
[out]p_hookA reference that can be used by the hook function
[in]argsCall arguments
Returns
A tai patch reference on success, < 0 on error
  • TAI_ERROR_PATCH_EXISTS if the address is already patched
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to hook
  • TAI_ERROR_NOT_IMPLEMENTED if address is in shared memory region
  • TAI_ERROR_USER_MEMORY if pointers are incorrect

Definition at line 155 of file taihen-user.c.

§ taiHookRelease()

int taiHookRelease ( SceUID  tai_uid,
tai_hook_ref_t  hook 
)

Release a hook for the calling process.

See also
taiHookReleaseForKernel
Parameters
[in]tai_uidThe tai patch reference to free
[in]hookThe hook to free
Returns
Zero on success, < 0 on error
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to restore the function

Definition at line 246 of file taihen-user.c.

§ taiHookReleaseForKernel()

int taiHookReleaseForKernel ( SceUID  tai_uid,
tai_hook_ref_t  hook 
)

Release a hook.

Parameters
[in]tai_uidThe tai patch reference to free
[in]hookThe hook to free
Returns
Zero on success, < 0 on error
  • TAI_ERROR_HOOK_ERROR if an internal error occurred trying to restore the function

Definition at line 204 of file taihen.c.