[RESOLVED] Patching NIDS in Devhook

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
accepttheownage
Posts: 17
Joined: Sun Jun 18, 2006 6:56 am

[RESOLVED] Patching NIDS in Devhook

Post by accepttheownage »

Sample code:

Code: Select all

#include <pspkernel.h> 
#include <psputilsforkernel.h> 
#include <pspsdk.h> 
#include <pspctrl.h> 
#include <string.h> 

PSP_MODULE_INFO&#40;"Api Hook", 0x1000, 1, 1&#41;; 
PSP_MAIN_THREAD_ATTR&#40;0&#41;; 

typedef int &#40;*SCE_AUDIO_OUTPUT&#41;&#40;int channel, int vol, void *buf&#41;; 

struct SyscallHeader 
&#123; 
        void *unk; 
        unsigned int basenum; 
        unsigned int topnum; 
        unsigned int size; 
&#125;; 

SCE_AUDIO_OUTPUT sceAudioOutput_Real, sceAudioOutputBlocking_Real; 

int sceAudioOutput_patched&#40;int channel, int vol, void *buf&#41; 
&#123; 
    return sceAudioOutput_Real&#40;channel, 0, buf&#41;; 
&#125; 

int sceAudioOutputBlocking_patched&#40;int channel, int vol, void *buf&#41; 
&#123; 
    return sceAudioOutputBlocking_Real&#40;channel, 0, buf&#41;; 
&#125; 

u32 NIDByName&#40;const char *name&#41; 
&#123; 
        u8 digest&#91;20&#93;; 
        u32 nid; 

        if&#40;sceKernelUtilsSha1Digest&#40;&#40;u8 *&#41; name, strlen&#40;name&#41;, digest&#41; >= 0&#41; 
        &#123; 
                nid = digest&#91;0&#93; | &#40;digest&#91;1&#93; << 8&#41; | &#40;digest&#91;2&#93; << 16&#41; | &#40;digest&#91;3&#93; << 24&#41;; 
                return nid; 
        &#125; 

        return 0; 
&#125; 

u32 FindNID&#40;char modname&#91;27&#93;, u32 nid&#41; 
&#123; 
        struct SceLibraryEntryTable *entry; 
        void *entTab; 
        int entLen; 

        SceModule *tmpmod, *pMod = NULL; 
        SceUID ids&#91;100&#93;; 
        int count = 0; 
        int p; 

        memset&#40;ids, 0, 100 * sizeof&#40;SceUID&#41;&#41;; 

        sceKernelGetModuleIdList&#40;ids, 100 * sizeof&#40;SceUID&#41;, &count&#41;; 

        for&#40;p = 0; p < count; p++&#41; 
        &#123; 
            tmpmod = sceKernelFindModuleByUID&#40;ids&#91;p&#93;&#41;; 

            if&#40;strcmp&#40;tmpmod->modname, modname&#41; == 0&#41; 
            &#123; 
                pMod = tmpmod; 
            &#125; 
        &#125; 

        if&#40;pMod != NULL&#41; 
        &#123; 
                int i = 0; 

                entTab = pMod->ent_top; 
                entLen = pMod->ent_size; 
                while&#40;i < entLen&#41; 
                &#123; 
                        int count; 
                        int total; 
                        unsigned int *vars; 

                        entry = &#40;struct SceLibraryEntryTable *&#41; &#40;entTab + i&#41;; 

                        total = entry->stubcount + entry->vstubcount; 
                        vars = entry->entrytable; 

                        if&#40;entry->stubcount > 0&#41; 
                        &#123; 
                                for&#40;count = 0; count < entry->stubcount; count++&#41; 
                                &#123; 
                                    if&#40;vars&#91;count&#93; == nid&#41; 
                                    &#123; 
                                        return vars&#91;count+total&#93;; 
                                    &#125; 
                                &#125; 
                        &#125; 
                        i += &#40;entry->len * 4&#41;; 
                &#125; 
        &#125; 

        return 0; 
&#125; 

void *find_syscall_addr&#40;u32 addr&#41; 
&#123; 
        struct SyscallHeader *head; 
        u32 *syscalls; 
        void **ptr; 
        int size; 
        int i; 

        asm&#40; 
                        "cfc0 %0, $12\n" 
                        &#58; "=r"&#40;ptr&#41; 
           &#41;; 

        if&#40;!ptr&#41; 
        &#123; 
                return NULL; 
        &#125; 

        head = &#40;struct SyscallHeader *&#41; *ptr; 
        syscalls = &#40;u32*&#41; &#40;*ptr + 0x10&#41;; 
        size = &#40;head->size - 0x10&#41;; 

        for&#40;i = 0; i < size; i++&#41; 
        &#123; 
                if&#40;syscalls&#91;i&#93; == addr&#41; 
                &#123; 
                        return &syscalls&#91;i&#93;; 
                &#125; 
        &#125; 

        return NULL; 
&#125; 


static void *apiHookAddr&#40;u32 *addr, void *func&#41; 
&#123; 
        if&#40;!addr&#41; 
        &#123; 
                return NULL; 
        &#125; 
        *addr = &#40;u32&#41; func; 
        sceKernelDcacheWritebackInvalidateRange&#40;addr, sizeof&#40;addr&#41;&#41;; 
        sceKernelIcacheInvalidateRange&#40;addr, sizeof&#40;addr&#41;&#41;; 

        return addr; 
&#125; 

u32 PatchNID&#40;char modname&#91;27&#93;, const char *funcname, void *func&#41; 
&#123; 
        u32 nidaddr = FindNID&#40;modname, NIDByName&#40;funcname&#41;&#41;; 

        if&#40;nidaddr > 0x80000000&#41; 
        &#123; 
                if&#40;!apiHookAddr&#40;find_syscall_addr&#40;nidaddr&#41;, func&#41;&#41; 
                &#123; 
                        nidaddr = 0; 
                &#125; 
        &#125; 

        return nidaddr; 
&#125; 

//Keep our module running 
int main_thread&#40;SceSize args, void *argp&#41; &#123; 
    while&#40;!sceKernelFindModuleByName&#40;"sceKernelLibrary"&#41;&#41; 
        sceKernelDelayThread&#40;100000&#41;; 

    sceKernelDelayThread&#40;1000000&#41;; 

    while&#40;1&#41; 
    &#123; 
        sceKernelDelayThread&#40;20000&#41;; 
    &#125; 
    return 0; 
&#125; 


int module_start&#40;SceSize args, void *argp&#41; __attribute__&#40;&#40;alias&#40;"_start"&#41;&#41;&#41;; 
int _start&#40;SceSize args, void *argp&#41; 
&#123; 
    sceAudioOutput_Real = &#40;void*&#41; PatchNID&#40;"sceAudio_Driver", "sceAudioOutput", sceAudioOutput_patched&#41;; 
    sceAudioOutputBlocking_Real = &#40;void*&#41; PatchNID&#40;"sceAudio_Driver", "sceAudioOutputBlocking", sceAudioOutputBlocking_patched&#41;; 

    sceKernelCreateThread&#40;"hook_main_thread", main_thread, 100, 0x1000, 0, NULL&#41;; 

    return 0; 
&#125; 
Last edited by accepttheownage on Tue Oct 10, 2006 5:15 am, edited 1 time in total.
mbf
Posts: 55
Joined: Fri Aug 18, 2006 7:43 pm

Post by mbf »

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.
accepttheownage
Posts: 17
Joined: Sun Jun 18, 2006 6:56 am

Post by accepttheownage »

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?
PSP250
Posts: 12
Joined: Sat Nov 19, 2005 2:41 am

Post by PSP250 »

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: Select all

sceAudioOutput_Real = &#40;SCE_AUDIO_OUTPUT&#41;_lw&#40;offset&#41;;
_sw&#40;&#40;u32&#41;sceAudioOutput_patched, offset&#41;; 
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.
accepttheownage
Posts: 17
Joined: Sun Jun 18, 2006 6:56 am

Post by accepttheownage »

Is there any easy way I could refer to my function directly in the jump command? (I'm not very knowledgable in MIPS)
mbf
Posts: 55
Joined: Fri Aug 18, 2006 7:43 pm

Post by mbf »

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 ;)
accepttheownage
Posts: 17
Joined: Sun Jun 18, 2006 6:56 am

Post by accepttheownage »

Code: Select all

#include <pspkernel.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <string.h>

PSP_MODULE_INFO&#40;"Api Hook", 0x1000, 1, 1&#41;;
PSP_MAIN_THREAD_ATTR&#40;0&#41;;

#define J_OPCODE    0x08000000
#define NOP         0x00000000

typedef int &#40;*SCE_AUDIO_OUTPUT&#41;&#40;int channel, int vol, void *buf&#41;;
typedef int &#40;*SCE_AUDIO_OUTPUT_PANNED&#41;&#40;int channel, int leftvol, int rightvol, void *buf&#41;;

SCE_AUDIO_OUTPUT sceAudioOutput_Real, sceAudioOutputBlocking_Real;
SCE_AUDIO_OUTPUT_PANNED sceAudioOutputPanned_Real, sceAudioOutputPannedBlocking_Real;

int sceAudioOutput_patched&#40;int channel, int vol, void *buf&#41;
&#123;
    return sceAudioOutput_Real&#40;channel, 0, buf&#41;;
&#125;

int sceAudioOutputBlocking_patched&#40;int channel, int vol, void *buf&#41;
&#123;
    return sceAudioOutputBlocking_Real&#40;channel, 0, buf&#41;;
&#125;


u32 PatchNID&#40;SceModule *pMod, u32 nid, u32 hook&#41;
&#123;
        struct SceLibraryEntryTable *entry;
        void *entTab;
        int entLen;


        if&#40;pMod != NULL&#41;
        &#123;
                int i = 0;

                entTab = pMod->ent_top;
                entLen = pMod->ent_size;
                while&#40;i < entLen&#41;
                &#123;
                        int count;
                        int total;
                        unsigned int *vars;

                        entry = &#40;struct SceLibraryEntryTable *&#41; &#40;entTab + i&#41;;

                        total = entry->stubcount + entry->vstubcount;
                        vars = entry->entrytable;

                        if&#40;entry->stubcount > 0&#41;
                        &#123;
                                for&#40;count = 0; count < entry->stubcount; count++&#41;
                                &#123;
                                    if&#40;vars&#91;count&#93; == nid&#41;
                                    &#123;
                                        u32 orignid = vars&#91;count+total&#93;;
                                        vars&#91;count+total&#93; = hook;
                                        return orignid;
                                    &#125;
                                &#125;
                        &#125;
                        i += &#40;entry->len * 4&#41;;
                &#125;
        &#125;
        else
        &#123;
                return 0;
        &#125;

        return 0;
&#125;


//Keep our module running
int main_thread&#40;SceSize args, void *argp&#41; &#123;
    while&#40;!sceKernelFindModuleByName&#40;"sceKernelLibrary"&#41;&#41;
        sceKernelDelayThread&#40;100000&#41;;

    sceKernelDelayThread&#40;1000000&#41;;

    while&#40;1&#41;
    &#123;
        sceKernelDelayThread&#40;20000&#41;;
    &#125;
    return 0;
&#125;


int module_start&#40;SceSize args, void *argp&#41; __attribute__&#40;&#40;alias&#40;"_start"&#41;&#41;&#41;;
int _start&#40;SceSize args, void *argp&#41;
&#123;
    int thread_count = 0, counter = 0;
    u32 AudioOutput, AudioOutputBlocking;
    SceModule *mod_tmp = NULL, *audiomod = NULL;
    SceUID thread_temp&#91;100&#93;;

    //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&#40;SCE_KERNEL_TMID_Thread, thread_temp, 100, &thread_count&#41;;

    for&#40;counter=0; counter < thread_count; counter++&#41;
    &#123;
        SceKernelThreadInfo info;
        info.size = sizeof&#40;SceKernelThreadInfo&#41;;

        sceKernelReferThreadStatus&#40;thread_temp&#91;counter&#93;, &info&#41;;

        mod_tmp = sceKernelFindModuleByAddress&#40;&#40;u32&#41;info.entry&#41;;

        //Find audio module based off of name, doesn't seem to work when I use the exact name =/
        if&#40;mod_tmp->modname&#91;3&#93; == 'A' && mod_tmp->modname&#91;5&#93; == 'd'&#41;
        &#123;
            audiomod = mod_tmp;
        &#125;
    &#125;

    AudioOutput = PatchNID&#40;audiomod, 0x8C1009B2, &#40;u32&#41;sceAudioOutput_patched&#41;;
    sceAudioOutput_Real = &#40;SCE_AUDIO_OUTPUT&#41;_lw&#40;AudioOutput&#41;;
    AudioOutputBlocking = PatchNID&#40;audiomod, 0x136CAF51, &#40;u32&#41;sceAudioOutputBlocking_patched&#41;;
    sceAudioOutputBlocking_Real = &#40;SCE_AUDIO_OUTPUT&#41;_lw&#40;AudioOutputBlocking&#41;;

    sceKernelDcacheWritebackAll&#40;&#41;;

    sceKernelCreateThread&#40;"hook_main_thread", main_thread, 100, 0x1000, 0, NULL&#41;;

    return 0;
&#125;
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?
accepttheownage
Posts: 17
Joined: Sun Jun 18, 2006 6:56 am

Post by accepttheownage »

Nevermind, problem solved :)
danzel
Posts: 182
Joined: Fri Nov 04, 2005 11:03 pm

Post by danzel »

What was the problem and fix then? Other people might like to know :)))
accepttheownage
Posts: 17
Joined: Sun Jun 18, 2006 6:56 am

Post by accepttheownage »

Sorry it took so long. Here's an updated sample that hooks only 2 audio functions.

Code: Select all

#include <pspkernel.h>
#include <psputilsforkernel.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <string.h>

PSP_MODULE_INFO&#40;"Api Hook", 0x1000, 1, 1&#41;;
PSP_MAIN_THREAD_ATTR&#40;0&#41;;

typedef int &#40;*SCE_AUDIO_OUTPUT&#41;&#40;int channel, int vol, void *buf&#41;;

struct SyscallHeader
&#123;
        void *unk;
        unsigned int basenum;
        unsigned int topnum;
        unsigned int size;
&#125;;

SCE_AUDIO_OUTPUT sceAudioOutput_Real, sceAudioOutputBlocking_Real;

int sceAudioOutput_patched&#40;int channel, int vol, void *buf&#41;
&#123;
    return sceAudioOutput_Real&#40;channel, 0, buf&#41;;
&#125;

int sceAudioOutputBlocking_patched&#40;int channel, int vol, void *buf&#41;
&#123;
    return sceAudioOutputBlocking_Real&#40;channel, 0, buf&#41;;
&#125;

u32 NIDByName&#40;const char *name&#41;
&#123;
        u8 digest&#91;20&#93;;
        u32 nid;

        if&#40;sceKernelUtilsSha1Digest&#40;&#40;u8 *&#41; name, strlen&#40;name&#41;, digest&#41; >= 0&#41;
        &#123;
                nid = digest&#91;0&#93; | &#40;digest&#91;1&#93; << 8&#41; | &#40;digest&#91;2&#93; << 16&#41; | &#40;digest&#91;3&#93; << 24&#41;;
                return nid;
        &#125;

        return 0;
&#125;

u32 FindNID&#40;char modname&#91;27&#93;, u32 nid&#41;
&#123;
        struct SceLibraryEntryTable *entry;
        void *entTab;
        int entLen;

        SceModule *tmpmod, *pMod = NULL;
        SceUID ids&#91;100&#93;;
        int count = 0;
        int p;

        memset&#40;ids, 0, 100 * sizeof&#40;SceUID&#41;&#41;;

        sceKernelGetModuleIdList&#40;ids, 100 * sizeof&#40;SceUID&#41;, &count&#41;;

        for&#40;p = 0; p < count; p++&#41;
        &#123;
            tmpmod = sceKernelFindModuleByUID&#40;ids&#91;p&#93;&#41;;

            if&#40;strcmp&#40;tmpmod->modname, modname&#41; == 0&#41;
            &#123;
                pMod = tmpmod;
            &#125;
        &#125;

        if&#40;pMod != NULL&#41;
        &#123;
                int i = 0;

                entTab = pMod->ent_top;
                entLen = pMod->ent_size;
                while&#40;i < entLen&#41;
                &#123;
                        int count;
                        int total;
                        unsigned int *vars;

                        entry = &#40;struct SceLibraryEntryTable *&#41; &#40;entTab + i&#41;;

                        total = entry->stubcount + entry->vstubcount;
                        vars = entry->entrytable;

                        if&#40;entry->stubcount > 0&#41;
                        &#123;
                                for&#40;count = 0; count < entry->stubcount; count++&#41;
                                &#123;
                                    if&#40;vars&#91;count&#93; == nid&#41;
                                    &#123;
                                        return vars&#91;count+total&#93;;
                                    &#125;
                                &#125;
                        &#125;
                        i += &#40;entry->len * 4&#41;;
                &#125;
        &#125;

        return 0;
&#125;

void *find_syscall_addr&#40;u32 addr&#41;
&#123;
        struct SyscallHeader *head;
        u32 *syscalls;
        void **ptr;
        int size;
        int i;

        asm&#40;
                        "cfc0 %0, $12\n"
                        &#58; "=r"&#40;ptr&#41;
           &#41;;

        if&#40;!ptr&#41;
        &#123;
                return NULL;
        &#125;

        head = &#40;struct SyscallHeader *&#41; *ptr;
        syscalls = &#40;u32*&#41; &#40;*ptr + 0x10&#41;;
        size = &#40;head->size - 0x10&#41;;

        for&#40;i = 0; i < size; i++&#41;
        &#123;
                if&#40;syscalls&#91;i&#93; == addr&#41;
                &#123;
                        return &syscalls&#91;i&#93;;
                &#125;
        &#125;

        return NULL;
&#125;


static void *apiHookAddr&#40;u32 *addr, void *func&#41;
&#123;
        if&#40;!addr&#41;
        &#123;
                return NULL;
        &#125;
        *addr = &#40;u32&#41; func;
        sceKernelDcacheWritebackInvalidateRange&#40;addr, sizeof&#40;addr&#41;&#41;;
        sceKernelIcacheInvalidateRange&#40;addr, sizeof&#40;addr&#41;&#41;;

        return addr;
&#125;

u32 PatchNID&#40;char modname&#91;27&#93;, const char *funcname, void *func&#41;
&#123;
        u32 nidaddr = FindNID&#40;modname, NIDByName&#40;funcname&#41;&#41;;

        if&#40;nidaddr > 0x80000000&#41;
        &#123;
                if&#40;!apiHookAddr&#40;find_syscall_addr&#40;nidaddr&#41;, func&#41;&#41;
                &#123;
                        nidaddr = 0;
                &#125;
        &#125;

        return nidaddr;
&#125;

//Keep our module running
int main_thread&#40;SceSize args, void *argp&#41; &#123;
    while&#40;!sceKernelFindModuleByName&#40;"sceKernelLibrary"&#41;&#41;
        sceKernelDelayThread&#40;100000&#41;;

    sceKernelDelayThread&#40;1000000&#41;;

    while&#40;1&#41;
    &#123;
        sceKernelDelayThread&#40;20000&#41;;
    &#125;
    return 0;
&#125;


int module_start&#40;SceSize args, void *argp&#41; __attribute__&#40;&#40;alias&#40;"_start"&#41;&#41;&#41;;
int _start&#40;SceSize args, void *argp&#41;
&#123;
    sceAudioOutput_Real = &#40;void*&#41; PatchNID&#40;"sceAudio_Driver", "sceAudioOutput", sceAudioOutput_patched&#41;;
    sceAudioOutputBlocking_Real = &#40;void*&#41; PatchNID&#40;"sceAudio_Driver", "sceAudioOutputBlocking", sceAudioOutputBlocking_patched&#41;;

    sceKernelCreateThread&#40;"hook_main_thread", main_thread, 100, 0x1000, 0, NULL&#41;;

    return 0;
&#125;
funpsp
Posts: 1
Joined: Wed Dec 06, 2006 1:24 am

Post by funpsp »

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.
Post Reply