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 

PatchNID function

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



Joined: 23 Jul 2005
Posts: 119

PostPosted: Wed Nov 23, 2005 2:09 am    Post subject: PatchNID function Reply with quote

This is a small function which allow to change the function called by the NID (changes the syscall opcode) by a function of your choice (it must have the same parameters and return) :

Code:


#define PATCH_JAL(x)   0xC000000 | ((((u32) x) >> 0x2) & 0x3FFFFFF)         // JAL x

int patchNID (u32 oid, u32 nid, u32 *patch)
{
 SceModule *modEntry;
 SceModuleInfo *modInfo;
 SceLibraryStubTable *stubTable;
 int x;


 // Trouver le pointeur memoire du module
 modEntry = sceKernelFindModuleByUID(oid);

#if defined(PATCH_INFO_SHOW) || defined(PATCH_INFO_FILE)

 printf_patch("modEntry : 0x%X\n",((u32) modEntry));

#endif

 // Si mauvais module
 if ((((long) modEntry) & 0xFF000000) != 0x88000000) return -1;
 if ((modEntry->stub_top - modEntry->ent_top) < 40) return -1;

 // Trouver le SceModuleInfo
 modInfo = (SceModuleInfo *) ((*((u32 *) modEntry->stub_top)) - 0x38); // 0x38 = sizeof(SceModuleInfo) + 0x4

#if defined(PATCH_INFO_SHOW) || defined(PATCH_INFO_FILE)

 printf_patch("modInfo : 0x%X\n",((u32) modInfo));
 printf_patch("modInfo->modname : %s\n",modInfo->modname);
 printf_patch("modInfo->stub_top : 0x%X\n",((u32) modInfo->stub_top));
 printf_patch("modInfo->stub_end : 0x%X\n",((u32) modInfo->stub_end));

#endif

 // Parcourir la liste des stubs

 stubTable = (SceLibraryStubTable *) modInfo->stub_top;

 while (stubTable < ((SceLibraryStubTable *) modInfo->stub_end))
 {
#if defined(PATCH_INFO_SHOW) || defined(PATCH_INFO_FILE)

  printf_patch("stubTable : 0x%X\n",((u32) stubTable));
  printf_patch("stubTable->libname : %s\n",stubTable->libname);
  printf_patch("stubTable->stubcount : %d\n",stubTable->stubcount);

#endif

  // Parcourir la table des NID
  for (x=0;x<stubTable->stubcount;x++)
  {
   // Patcher l'adresse de la fonction si NID trouvé ou si nid = 0xFFFFFFFF (code pour patcher tout les NID)
   if ((stubTable->nidtable[x] == nid) || (nid == 0xFFFFFFFF))
   {
#if defined(PATCH_INFO_SHOW) || defined(PATCH_INFO_FILE)

    printf_patch("patched (0x%X, NID %d) : 0x%X -> 0x%X\n",((u32) &((u32 *) stubTable->stubtable)[(x << 0x1) + 0x1]),x,((u32 *) stubTable->stubtable)[(x << 0x1) + 0x1],((u32) patch));

#endif

   // (x << 0x1) + 0x1  -> 2 instructions par NID (jr et nop) et c'est la 2eme instruction qu'on patche
   ((u32 *) stubTable->stubtable)[(x << 0x1) + 0x1] = PATCH_JAL(patch);      // JAL patch
    break;                                                      // un seul NID pareil par librairie ?
   }
  }

  // Mettre a jour le pointeur
  stubTable = (SceLibraryStubTable *) (((u32 *) stubTable) + stubTable->len);
 }

 return 0;
}

// Exemple d'appel

SceUID sceIoOpenPatched (const char *path, int flags, SceMode mode)
{
 char pathPatch[512];


 // Patcher le nom
 strPatchPath(path,pathPatch);

#if defined(PATCH_INFO_SHOW) || defined(PATCH_INFO_FILE)

 printf_patch("SceIoOpenPatched : %s -> %s\n",path,pathPatch);

#endif

 // Appeler la fonction normale
 return sceIoOpen(pathPatch,flags,mode);
}

... fonction appelante :

 SceUID oid = sceKernelLoadModule(pathPatch,flags,option);

 // Si erreur
 if (oid & 0x80000000) return oid;

 // Patcher les NID du module chargé
patchNID(oid,0x109F50BC,(u32 *) sceIoOpenPatched);

 // Purger cache des instructions
 sceKernelIcacheClearAll();

Back to top
View user's profile Send private message
Fanjita



Joined: 28 Sep 2005
Posts: 217

PostPosted: Wed Nov 23, 2005 3:08 am    Post subject: Reply with quote

Doh! You posted this just a couple of days after I spent most of the weekend figuring out how to do the same thing :)
_________________
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
Back to top
View user's profile Send private message
johnmph



Joined: 23 Jul 2005
Posts: 119

PostPosted: Wed Nov 23, 2005 3:11 pm    Post subject: Reply with quote

Fanjita wrote:
Doh! You posted this just a couple of days after I spent most of the weekend figuring out how to do the same thing :)


oups, sorry ;-)
Back to top
View user's profile Send private message
blasty



Joined: 22 Aug 2005
Posts: 9

PostPosted: Thu Dec 01, 2005 3:23 am    Post subject: Reply with quote

I have compiled the example but I am having trouble getting it to work, could you post a slightly more detailed example? I'm not sure if I'm getting the loading of the module bit correct. When I run the program it never finds the NID. I got the NIDs from here

Any help would be appreciated. Thanks in advance!
Back to top
View user's profile Send private message
johnmph



Joined: 23 Jul 2005
Posts: 119

PostPosted: Thu Dec 01, 2005 8:21 am    Post subject: Reply with quote

blasty wrote:
I have compiled the example but I am having trouble getting it to work, could you post a slightly more detailed example? I'm not sure if I'm getting the loading of the module bit correct. When I run the program it never finds the NID. I got the NIDs from here

Any help would be appreciated. Thanks in advance!



I have modified a little the function, this is the new function with sample :

Code:

// INCLUDES

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


// MODULE INITIALISATION

PSP_MODULE_INFO("FirmLaunch", 0x1000, 2, 0);
PSP_MAIN_THREAD_ATTR(0x0);


// DEFINES

#define   printf         pspDebugScreenPrintf

#define PATCH_INFO_SHOW

// MIPS OPCODE

#define PATCH_J(x)         0x8000000 | ((((u32) x) >> 0x2) & 0x3FFFFFF)                        // J x
#define PATCH_LUI(x,y)      0x3C000000 | ((x & 0x1F) << 0x10) | (y & 0xFFFF)                     // LUI x, y


// FUNCTIONS CALLBACKS

int exit_callback (int arg1, int arg2, void *common)
{
 sceKernelExitGame();
 return 0;
}

int CallbackThread (SceSize args, void *argp)
{
 int cbid;

 cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
 sceKernelRegisterExitCallback(cbid);

 sceKernelSleepThreadCB();
 return 0;
}

int SetupCallbacks (void)
{
 int thid = 0;

 thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, PSP_THREAD_ATTR_USER, 0);

 if(thid >= 0) sceKernelStartThread(thid, 0, 0);

 return thid;
}

// FUNCTIONS

int patchStub (u32 oid, u32 nid, u32 *patch)
{
 SceModule *modMem;
 SceLibraryStubTable *stubTable, *stubEnd;
 int x;


 // Trouver le pointeur memoire du module
 modMem = sceKernelFindModuleByUID(oid);

#if defined(PATCH_INFO_SHOW)

 printf("modMem : 0x%X\n",((u32) modMem));

#endif

 // Si mauvais module
 if ((((long) modMem) & 0xFF000000) != 0x88000000) return -1;
 if ((modMem->stub_top - modMem->ent_top) < 40) return -1;

 // Parcourir la liste des stubs
 stubTable = (SceLibraryStubTable *) ((u32 *) modMem->stub_top);
 stubEnd = (SceLibraryStubTable *) (((u8 *) modMem->stub_top) + modMem->stub_size);

 while (stubTable < stubEnd)
 {
#if defined(PATCH_INFO_SHOW)

  printf("stubTable : 0x%X\n",((u32) stubTable));
  printf("stubTable->libname : %s\n",stubTable->libname);
  printf("stubTable->stubcount : %d\n",stubTable->stubcount);

#endif

  // Parcourir la table des NID
  for (x=0;x<stubTable->stubcount;x++)
  {
   // Patcher l'adresse de la fonction si NID trouvé ou si nid = 0xFFFFFFFF (code pour patcher tout les NID)
   if ((stubTable->nidtable[x] == nid) || (nid == 0xFFFFFFFF))
   {
#if defined(PATCH_INFO_SHOW)

    printf("patched (0x%X, NID %d) : 0x%X -> 0x%X\n",((u32) &((u32 *) stubTable->stubtable)[x << 0x1]),x,((u32 *) stubTable->stubtable)[x << 0x1],((u32) patch));

#endif

   ((u32 *) stubTable->stubtable)[x << 0x1] = PATCH_J(patch);               // J patch
   ((u32 *) stubTable->stubtable)[(x << 0x1) + 0x1] = PATCH_LUI(0x0,0x0);      // LUI $zero, 0 (delay slot instruction)

    if (nid != 0xFFFFFFFF) break;                                    // un seul NID pareil par librairie ?
   }
  }

  // Mettre a jour le pointeur
  stubTable = (SceLibraryStubTable *) (((u32 *) stubTable) + stubTable->len);
 }

 return 0;
}

u32 LoadStartModule (char *path, int start)
{
 u32 loadResult, startResult;
 int status;


 loadResult = sceKernelLoadModule(path, 0, NULL);
 if (loadResult & 0x80000000) return -1;

 if (start)
 {
  startResult = sceKernelStartModule(loadResult, 0, NULL, &status, NULL);
  if (loadResult != startResult) return -2;
 }

 return loadResult;
}

SceUID sceIoOpenPatched (const char *path, int flags, SceMode mode)
{
 char pathPatch[512];


 // Patch name
 strcpy(pathPatch,path);
 strcat(pathPatch,".bak");                  // example : ms0:/temp.bin -> ms0:/temp.bin.bak

 // Call normal function
 return sceIoOpen(pathPatch,flags,mode);
}

int main (void)
{
 u32 oid;


 // Init SDK
 pspDebugInstallKprintfHandler(NULL);
 pspDebugScreenSetTextColor(0xFF);

 pspSdkInstallNoDeviceCheckPatch();
 pspSdkInstallNoPlainModuleCheckPatch();

 // Init display and HOME button
 pspDebugScreenInit();
 pspDebugScreenClear();
 SetupCallbacks();

 // Setup Pad
 sceCtrlSetSamplingCycle(0);
 sceCtrlSetSamplingMode(0);

 // Load a module
 oid = LoadStartModule("ms0:/module.prx",1);

 // Patch NID module
 patchStub(oid,0x109F50BC,(u32 *) sceIoOpenPatched);      // Replace sceIoOpen imported function of module.prx module by sceIoOpenPatched

 // Apply modifications to cache
 sceKernelDcacheWritebackAll();
 sceKernelIcacheClearAll();

 // Main loop
 for (;;) sceDisplayWaitVblankStart();

 // Exit program
 sceKernelExitGame();

 return 0;
}
Back to top
View user's profile Send private message
dankydoo



Joined: 29 Mar 2005
Posts: 11

PostPosted: Sat Dec 03, 2005 9:14 am    Post subject: Reply with quote

John,

Interesting function!

I have a few questions on how it works, I am attempting to understand how all this works:

I Understand that you patch the first instruction of the given NID function to jump to the patched function. What I do not understand is how the unpatched function is called within the patched function? Wouldn't this result in a loop, or there are 2 different methods for calling a given functoin? I guess I do not really understand the difference on how an NID is resolved compared to a normal function call? ( I understand the code on how you are looping through the modules NIDs to find the correct one to patch)

Even further, why are syscalls needed? Why do we need to know the NID of the function when we can call it by name?

Also, how would you patch the function that is called by name in a similar manner to the patchNID function?

thanks for any help with this, I'd really like to understand these concepts...

dankydoo
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