forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

[RESOLVED] Patching NIDS in Devhook

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
accepttheownage



Joined: 18 Jun 2006
Posts: 17

PostPosted: Thu Sep 28, 2006 9:36 am    Post subject: [RESOLVED] Patching NIDS in Devhook Reply with quote

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
View user's profile Send private message
mbf



Joined: 18 Aug 2006
Posts: 55

PostPosted: Thu Sep 28, 2006 10:37 am    Post subject: Reply with quote

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
View user's profile Send private message
accepttheownage



Joined: 18 Jun 2006
Posts: 17

PostPosted: Thu Sep 28, 2006 11:29 am    Post subject: Reply with quote

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
View user's profile Send private message
PSP250



Joined: 19 Nov 2005
Posts: 12

PostPosted: Thu Sep 28, 2006 12:21 pm    Post subject: Reply with quote

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
View user's profile Send private message
accepttheownage



Joined: 18 Jun 2006
Posts: 17

PostPosted: Thu Sep 28, 2006 12:41 pm    Post subject: Reply with quote

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
View user's profile Send private message
mbf



Joined: 18 Aug 2006
Posts: 55

PostPosted: Thu Sep 28, 2006 7:54 pm    Post subject: Reply with quote

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
View user's profile Send private message
accepttheownage



Joined: 18 Jun 2006
Posts: 17

PostPosted: Sat Sep 30, 2006 10:38 am    Post subject: Reply with quote

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
View user's profile Send private message
accepttheownage



Joined: 18 Jun 2006
Posts: 17

PostPosted: Mon Oct 02, 2006 1:02 pm    Post subject: Reply with quote

Nevermind, problem solved :)
Back to top
View user's profile Send private message
danzel



Joined: 04 Nov 2005
Posts: 182

PostPosted: Mon Oct 02, 2006 6:18 pm    Post subject: Reply with quote

What was the problem and fix then? Other people might like to know :)))
Back to top
View user's profile Send private message
accepttheownage



Joined: 18 Jun 2006
Posts: 17

PostPosted: Tue Oct 10, 2006 4:06 am    Post subject: Reply with quote

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
View user's profile Send private message
funpsp



Joined: 06 Dec 2006
Posts: 1

PostPosted: Wed Dec 06, 2006 1:39 am    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
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