 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
accepttheownage
Joined: 18 Jun 2006 Posts: 17
|
Posted: Thu Sep 28, 2006 9:36 am Post subject: [RESOLVED] Patching NIDS in Devhook |
|
|
Sample code:
| Code: | #include <pspkernel.h>
#include <psputilsforkernel.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <string.h>
PSP_MODULE_INFO("Api Hook", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
typedef int (*SCE_AUDIO_OUTPUT)(int channel, int vol, void *buf);
struct SyscallHeader
{
void *unk;
unsigned int basenum;
unsigned int topnum;
unsigned int size;
};
SCE_AUDIO_OUTPUT sceAudioOutput_Real, sceAudioOutputBlocking_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 NIDByName(const char *name)
{
u8 digest[20];
u32 nid;
if(sceKernelUtilsSha1Digest((u8 *) name, strlen(name), digest) >= 0)
{
nid = digest[0] | (digest[1] << 8) | (digest[2] << 16) | (digest[3] << 24);
return nid;
}
return 0;
}
u32 FindNID(char modname[27], u32 nid)
{
struct SceLibraryEntryTable *entry;
void *entTab;
int entLen;
SceModule *tmpmod, *pMod = NULL;
SceUID ids[100];
int count = 0;
int p;
memset(ids, 0, 100 * sizeof(SceUID));
sceKernelGetModuleIdList(ids, 100 * sizeof(SceUID), &count);
for(p = 0; p < count; p++)
{
tmpmod = sceKernelFindModuleByUID(ids[p]);
if(strcmp(tmpmod->modname, modname) == 0)
{
pMod = tmpmod;
}
}
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)
{
return vars[count+total];
}
}
}
i += (entry->len * 4);
}
}
return 0;
}
void *find_syscall_addr(u32 addr)
{
struct SyscallHeader *head;
u32 *syscalls;
void **ptr;
int size;
int i;
asm(
"cfc0 %0, $12\n"
: "=r"(ptr)
);
if(!ptr)
{
return NULL;
}
head = (struct SyscallHeader *) *ptr;
syscalls = (u32*) (*ptr + 0x10);
size = (head->size - 0x10);
for(i = 0; i < size; i++)
{
if(syscalls[i] == addr)
{
return &syscalls[i];
}
}
return NULL;
}
static void *apiHookAddr(u32 *addr, void *func)
{
if(!addr)
{
return NULL;
}
*addr = (u32) func;
sceKernelDcacheWritebackInvalidateRange(addr, sizeof(addr));
sceKernelIcacheInvalidateRange(addr, sizeof(addr));
return addr;
}
u32 PatchNID(char modname[27], const char *funcname, void *func)
{
u32 nidaddr = FindNID(modname, NIDByName(funcname));
if(nidaddr > 0x80000000)
{
if(!apiHookAddr(find_syscall_addr(nidaddr), func))
{
nidaddr = 0;
}
}
return nidaddr;
}
//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)
{
sceAudioOutput_Real = (void*) PatchNID("sceAudio_Driver", "sceAudioOutput", sceAudioOutput_patched);
sceAudioOutputBlocking_Real = (void*) PatchNID("sceAudio_Driver", "sceAudioOutputBlocking", sceAudioOutputBlocking_patched);
sceKernelCreateThread("hook_main_thread", main_thread, 100, 0x1000, 0, NULL);
return 0;
} |
Last edited by accepttheownage on Tue Oct 10, 2006 5:15 am; edited 1 time in total |
|
| Back to top |
|
 |
mbf
Joined: 18 Aug 2006 Posts: 55
|
Posted: Thu Sep 28, 2006 10:37 am Post subject: |
|
|
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. |
|
| Back to top |
|
 |
accepttheownage
Joined: 18 Jun 2006 Posts: 17
|
Posted: Thu Sep 28, 2006 11:29 am Post subject: |
|
|
| 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? |
|
| Back to top |
|
 |
PSP250
Joined: 19 Nov 2005 Posts: 12
|
Posted: Thu Sep 28, 2006 12:21 pm Post subject: |
|
|
The options you have are:- Hook into the export functions directly "redirecting" the actual export function's first instructions to your own (as noted by mbf)
- Hijack the resolved import table entry of all modules that import this function and redirect it to your own code
Regarding why it is crashing:
| Code: | sceAudioOutput_Real = (SCE_AUDIO_OUTPUT)_lw(offset);
_sw((u32)sceAudioOutput_patched, offset); |
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. |
|
| Back to top |
|
 |
accepttheownage
Joined: 18 Jun 2006 Posts: 17
|
Posted: Thu Sep 28, 2006 12:41 pm Post subject: |
|
|
| Is there any easy way I could refer to my function directly in the jump command? (I'm not very knowledgable in MIPS) |
|
| Back to top |
|
 |
mbf
Joined: 18 Aug 2006 Posts: 55
|
Posted: Thu Sep 28, 2006 7:54 pm Post subject: |
|
|
it's fairly easy to patch a jump. Check out this document page 545.
| Quote: | | 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 ;) |
|
| Back to top |
|
 |
accepttheownage
Joined: 18 Jun 2006 Posts: 17
|
Posted: Sat Sep 30, 2006 10:38 am Post subject: |
|
|
| Code: | #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? |
|
| Back to top |
|
 |
accepttheownage
Joined: 18 Jun 2006 Posts: 17
|
Posted: Mon Oct 02, 2006 1:02 pm Post subject: |
|
|
| Nevermind, problem solved :) |
|
| Back to top |
|
 |
danzel
Joined: 04 Nov 2005 Posts: 182
|
Posted: Mon Oct 02, 2006 6:18 pm Post subject: |
|
|
| What was the problem and fix then? Other people might like to know :))) |
|
| Back to top |
|
 |
accepttheownage
Joined: 18 Jun 2006 Posts: 17
|
Posted: Tue Oct 10, 2006 4:06 am Post subject: |
|
|
Sorry it took so long. Here's an updated sample that hooks only 2 audio functions.
| Code: | #include <pspkernel.h>
#include <psputilsforkernel.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <string.h>
PSP_MODULE_INFO("Api Hook", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
typedef int (*SCE_AUDIO_OUTPUT)(int channel, int vol, void *buf);
struct SyscallHeader
{
void *unk;
unsigned int basenum;
unsigned int topnum;
unsigned int size;
};
SCE_AUDIO_OUTPUT sceAudioOutput_Real, sceAudioOutputBlocking_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 NIDByName(const char *name)
{
u8 digest[20];
u32 nid;
if(sceKernelUtilsSha1Digest((u8 *) name, strlen(name), digest) >= 0)
{
nid = digest[0] | (digest[1] << 8) | (digest[2] << 16) | (digest[3] << 24);
return nid;
}
return 0;
}
u32 FindNID(char modname[27], u32 nid)
{
struct SceLibraryEntryTable *entry;
void *entTab;
int entLen;
SceModule *tmpmod, *pMod = NULL;
SceUID ids[100];
int count = 0;
int p;
memset(ids, 0, 100 * sizeof(SceUID));
sceKernelGetModuleIdList(ids, 100 * sizeof(SceUID), &count);
for(p = 0; p < count; p++)
{
tmpmod = sceKernelFindModuleByUID(ids[p]);
if(strcmp(tmpmod->modname, modname) == 0)
{
pMod = tmpmod;
}
}
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)
{
return vars[count+total];
}
}
}
i += (entry->len * 4);
}
}
return 0;
}
void *find_syscall_addr(u32 addr)
{
struct SyscallHeader *head;
u32 *syscalls;
void **ptr;
int size;
int i;
asm(
"cfc0 %0, $12\n"
: "=r"(ptr)
);
if(!ptr)
{
return NULL;
}
head = (struct SyscallHeader *) *ptr;
syscalls = (u32*) (*ptr + 0x10);
size = (head->size - 0x10);
for(i = 0; i < size; i++)
{
if(syscalls[i] == addr)
{
return &syscalls[i];
}
}
return NULL;
}
static void *apiHookAddr(u32 *addr, void *func)
{
if(!addr)
{
return NULL;
}
*addr = (u32) func;
sceKernelDcacheWritebackInvalidateRange(addr, sizeof(addr));
sceKernelIcacheInvalidateRange(addr, sizeof(addr));
return addr;
}
u32 PatchNID(char modname[27], const char *funcname, void *func)
{
u32 nidaddr = FindNID(modname, NIDByName(funcname));
if(nidaddr > 0x80000000)
{
if(!apiHookAddr(find_syscall_addr(nidaddr), func))
{
nidaddr = 0;
}
}
return nidaddr;
}
//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)
{
sceAudioOutput_Real = (void*) PatchNID("sceAudio_Driver", "sceAudioOutput", sceAudioOutput_patched);
sceAudioOutputBlocking_Real = (void*) PatchNID("sceAudio_Driver", "sceAudioOutputBlocking", sceAudioOutputBlocking_patched);
sceKernelCreateThread("hook_main_thread", main_thread, 100, 0x1000, 0, NULL);
return 0;
}
|
|
|
| Back to top |
|
 |
funpsp
Joined: 06 Dec 2006 Posts: 1
|
Posted: Wed Dec 06, 2006 1:39 am Post subject: |
|
|
Hi,
I get your last working source code to use the hook for function sceWlanGetEtherAddr, but like this i have error when I try to compil the source.
Errors like this:
Undefined main
multiple definition of _start or module_start.
How do you compile this source code ?
If I replace _start with main, my psp load the prx and black, nothing is working.
I use the psptoolchain 20060120.
Maybe you can give me your Makefile or something to get it working.
Thanks. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|