The most transparent way would be to patch directly the audio routines to make them jump to your own by replacing the first 2 instructions by a jump to your own + a nop, then jump back once you've altered the data and executed the original first 2 instructions. If those 2 first instructions are always the same, it would even be easier.
Also make sure your own code and the code you want to patch are in the same memory segment.
The code I have is basically doing the same thing, executing my function first then going back to the instruction that is stored in the variable and executing that. I think the problem may be that my code is not stored in the same memory segment as you said. Is there any way to ensure that it will be loaded in the same segment?
Assuming _sw sets a word at offset, this will "destroy" the first instruction of the exported function. The first instruction is not an address. It is a MIPS instruction. You need to create a jump instruction to your code and save the instruction that was intially at that location.
it's fairly easy to patch a jump. Check out this document page 545.
The 26-bit target address is shifted left two bits and combined with the high-order bits of the address of the delay slot. The program unconditionally jumps to this calculated address with a delay of one instruction.
Anyway, the address you get from libsFindExportAddrByNid() is the address of the original function.... why not patching the export table of the module you want to patch? If that's possible, It would be even easier and painless. But I guess it would only work for modules not loaded yet though.
EDIT: I meant that it would only let you hijack calls by modules/PRXs/EBOOTs not yet loaded. But just load your vhsext before the real one and you're in ;)
#include <pspkernel.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <string.h>
PSP_MODULE_INFO("Api Hook", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
#define J_OPCODE 0x08000000
#define NOP 0x00000000
typedef int (*SCE_AUDIO_OUTPUT)(int channel, int vol, void *buf);
typedef int (*SCE_AUDIO_OUTPUT_PANNED)(int channel, int leftvol, int rightvol, void *buf);
SCE_AUDIO_OUTPUT sceAudioOutput_Real, sceAudioOutputBlocking_Real;
SCE_AUDIO_OUTPUT_PANNED sceAudioOutputPanned_Real, sceAudioOutputPannedBlocking_Real;
int sceAudioOutput_patched(int channel, int vol, void *buf)
{
return sceAudioOutput_Real(channel, 0, buf);
}
int sceAudioOutputBlocking_patched(int channel, int vol, void *buf)
{
return sceAudioOutputBlocking_Real(channel, 0, buf);
}
u32 PatchNID(SceModule *pMod, u32 nid, u32 hook)
{
struct SceLibraryEntryTable *entry;
void *entTab;
int entLen;
if(pMod != NULL)
{
int i = 0;
entTab = pMod->ent_top;
entLen = pMod->ent_size;
while(i < entLen)
{
int count;
int total;
unsigned int *vars;
entry = (struct SceLibraryEntryTable *) (entTab + i);
total = entry->stubcount + entry->vstubcount;
vars = entry->entrytable;
if(entry->stubcount > 0)
{
for(count = 0; count < entry->stubcount; count++)
{
if(vars[count] == nid)
{
u32 orignid = vars[count+total];
vars[count+total] = hook;
return orignid;
}
}
}
i += (entry->len * 4);
}
}
else
{
return 0;
}
return 0;
}
//Keep our module running
int main_thread(SceSize args, void *argp) {
while(!sceKernelFindModuleByName("sceKernelLibrary"))
sceKernelDelayThread(100000);
sceKernelDelayThread(1000000);
while(1)
{
sceKernelDelayThread(20000);
}
return 0;
}
int module_start(SceSize args, void *argp) __attribute__((alias("_start")));
int _start(SceSize args, void *argp)
{
int thread_count = 0, counter = 0;
u32 AudioOutput, AudioOutputBlocking;
SceModule *mod_tmp = NULL, *audiomod = NULL;
SceUID thread_temp[100];
//Get a list of modules from running threads.
//For some reason I couldn't get a list of modules directly, maybe a problem with devhook?
sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread, thread_temp, 100, &thread_count);
for(counter=0; counter < thread_count; counter++)
{
SceKernelThreadInfo info;
info.size = sizeof(SceKernelThreadInfo);
sceKernelReferThreadStatus(thread_temp[counter], &info);
mod_tmp = sceKernelFindModuleByAddress((u32)info.entry);
//Find audio module based off of name, doesn't seem to work when I use the exact name =/
if(mod_tmp->modname[3] == 'A' && mod_tmp->modname[5] == 'd')
{
audiomod = mod_tmp;
}
}
AudioOutput = PatchNID(audiomod, 0x8C1009B2, (u32)sceAudioOutput_patched);
sceAudioOutput_Real = (SCE_AUDIO_OUTPUT)_lw(AudioOutput);
AudioOutputBlocking = PatchNID(audiomod, 0x136CAF51, (u32)sceAudioOutputBlocking_patched);
sceAudioOutputBlocking_Real = (SCE_AUDIO_OUTPUT)_lw(AudioOutputBlocking);
sceKernelDcacheWritebackAll();
sceKernelCreateThread("hook_main_thread", main_thread, 100, 0x1000, 0, NULL);
return 0;
}
That's my updated code. I load the module RIGHT after the audio module and patch the table directly but I still get sound in the menu and in game =/
Any ideas?