taiHEN
1.0
CFW framework for PS Vita
|
Here are a couple of examples that demonstrate how to use the taiHEN APIs.
Configure the following user plugin to load on an application named "AppName" with the title id "ABCD01234".
We can build this as myplugin.suprx
and add it to ux0:tai/config.txt
under the section *ABCD01234
and it will be loaded when ABCD01234
is started and insert the hook.
The following example will log all file opens from applications. Compile it as kernellog.skprx
and add to *KERNEL
section in ux0:tai/config.txt
.
Consider one kernel plugin with the code above. Now consider a second kernel plugin as follows.
Now we have both filesystem filtering and logging.
This plugin will be loaded in kernel and changes the return value of a function that does a check to enable dynarec.
The above examples are all global hooks: every call regardless of origin will be hooked. You can also insert local hooks: a library import from a module. In this example, we have a user plugin loaded with "AppName" that only logs sceIoOpen
calls from that application.
Below are some common tasks and paradigms that might be of interest to people writing advanced hooks.
Currently taiHEN does not support hooking the exports of shared libraries (or the imports from shared libraries). Shared libraries are ones loaded in the 0xE0000000
address range and are mainly in modules that most applications import from (example being SceLibKernel
and SceGxm
). You can, however, hook imports of shared libraries as usual. So, if multiple non-shared modules import a function of interest, you must hook all of them (if desired).
Weak imports are imports of modules not loaded at application startup and are loaded by sceSysmoduleLoadModule
(in SceSysmodule
) or sceKernelLoadStartModule
(in SceLibKernel
) or some other function. They typically are loaded on-demand and unloaded when no longer needed to save memory. That means that your hooks must be created after the module is loaded and removed before the module is unloaded. To do this, you have to first hook the module load and unload imports and in those hooks, you create/remove the desired hook. In this example, we wish to hook sceScreenShotDisable
which is loaded by the game from sceSysmoduleLoadModule
.
You can specify suprx
to load with specific titles, but you cannot do so with skprx
. This is a limitation of the Vita kernel. A workaround is to use the taiHEN APIs to manually load and unload the kernel module directly. Please note this feature only works with unsafe homebrew enabled. Be aware that module_stop
of your user plugin is not automatically called so you should not use that to cleanup your kernel plugin. Instead, your kernel plugin's module_start
can return SCE_KERNEL_START_NO_RESIDENT
to be cleaned up automatically after running. In the case that it is not possible, you should be careful not to load the same kernel module twice.
It it important to remember to always clean up hooks and injections in module_stop
for kernel modules. You should be doing this for user modules as well, but patches in user-space will be cleaned up by taiHEN when the process exits. Patches in kernel will not be cleaned up automatically.
When writing a kernel module that exposes new syscalls, know that the syscall stack is only 4096 bytes. That means you might easily run out of space. You should use sceKernelRunWithStack
to increase the stack size if needed.
By default, the Vita does not allow unloading modules that exposes syscalls (you will get SCE_KERNEL_ERROR_MODULEMGR_IN_USE
). To get around this, you can hook an override function in the module manager. This hook will be released when the module is unloaded.
There is currently a bug in the implementation where a crash may happen if you are hooking a function while it is being used. Usually this doesn't happen (except by chance), but some functions might be called in a tight loop. A temporary workaround is listed in the issue tracker.