PatchNID function

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

Moderators: cheriff, TyRaNiD

Post Reply
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

PatchNID function

Post by johnmph »

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


#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 &#40;&#40;modEntry->stub_top - modEntry->ent_top&#41; < 40&#41; return -1;

 // Trouver le SceModuleInfo
 modInfo = &#40;SceModuleInfo *&#41; &#40;&#40;*&#40;&#40;u32 *&#41; modEntry->stub_top&#41;&#41; - 0x38&#41;; // 0x38 = sizeof&#40;SceModuleInfo&#41; + 0x4

#if defined&#40;PATCH_INFO_SHOW&#41; || defined&#40;PATCH_INFO_FILE&#41;

 printf_patch&#40;"modInfo &#58; 0x%X\n",&#40;&#40;u32&#41; modInfo&#41;&#41;;
 printf_patch&#40;"modInfo->modname &#58; %s\n",modInfo->modname&#41;;
 printf_patch&#40;"modInfo->stub_top &#58; 0x%X\n",&#40;&#40;u32&#41; modInfo->stub_top&#41;&#41;;
 printf_patch&#40;"modInfo->stub_end &#58; 0x%X\n",&#40;&#40;u32&#41; modInfo->stub_end&#41;&#41;;

#endif

 // Parcourir la liste des stubs

 stubTable = &#40;SceLibraryStubTable *&#41; modInfo->stub_top;

 while &#40;stubTable < &#40;&#40;SceLibraryStubTable *&#41; modInfo->stub_end&#41;&#41;
 &#123;
#if defined&#40;PATCH_INFO_SHOW&#41; || defined&#40;PATCH_INFO_FILE&#41;

  printf_patch&#40;"stubTable &#58; 0x%X\n",&#40;&#40;u32&#41; stubTable&#41;&#41;;
  printf_patch&#40;"stubTable->libname &#58; %s\n",stubTable->libname&#41;;
  printf_patch&#40;"stubTable->stubcount &#58; %d\n",stubTable->stubcount&#41;;

#endif

  // Parcourir la table des NID
  for &#40;x=0;x<stubTable->stubcount;x++&#41;
  &#123;
   // Patcher l'adresse de la fonction si NID trouvé ou si nid = 0xFFFFFFFF &#40;code pour patcher tout les NID&#41;
   if &#40;&#40;stubTable->nidtable&#91;x&#93; == nid&#41; || &#40;nid == 0xFFFFFFFF&#41;&#41;
   &#123;
#if defined&#40;PATCH_INFO_SHOW&#41; || defined&#40;PATCH_INFO_FILE&#41;

    printf_patch&#40;"patched &#40;0x%X, NID %d&#41; &#58; 0x%X -> 0x%X\n",&#40;&#40;u32&#41; &&#40;&#40;u32 *&#41; stubTable->stubtable&#41;&#91;&#40;x << 0x1&#41; + 0x1&#93;&#41;,x,&#40;&#40;u32 *&#41; stubTable->stubtable&#41;&#91;&#40;x << 0x1&#41; + 0x1&#93;,&#40;&#40;u32&#41; patch&#41;&#41;;

#endif

	// &#40;x << 0x1&#41; + 0x1  -> 2 instructions par NID &#40;jr et nop&#41; et c'est la 2eme instruction qu'on patche
	&#40;&#40;u32 *&#41; stubTable->stubtable&#41;&#91;&#40;x << 0x1&#41; + 0x1&#93; = PATCH_JAL&#40;patch&#41;;		// JAL patch
    break;																		// un seul NID pareil par librairie ?
   &#125;
  &#125;

  // Mettre a jour le pointeur
  stubTable = &#40;SceLibraryStubTable *&#41; &#40;&#40;&#40;u32 *&#41; stubTable&#41; + stubTable->len&#41;;
 &#125;

 return 0;
&#125;

// Exemple d'appel

SceUID sceIoOpenPatched &#40;const char *path, int flags, SceMode mode&#41;
&#123;
 char pathPatch&#91;512&#93;;


 // Patcher le nom
 strPatchPath&#40;path,pathPatch&#41;;

#if defined&#40;PATCH_INFO_SHOW&#41; || defined&#40;PATCH_INFO_FILE&#41;

 printf_patch&#40;"SceIoOpenPatched &#58; %s -> %s\n",path,pathPatch&#41;;

#endif

 // Appeler la fonction normale
 return sceIoOpen&#40;pathPatch,flags,mode&#41;;
&#125;

... fonction appelante &#58;

 SceUID oid = sceKernelLoadModule&#40;pathPatch,flags,option&#41;;

 // Si erreur
 if &#40;oid & 0x80000000&#41; return oid;

 // Patcher les NID du module chargé
patchNID&#40;oid,0x109F50BC,&#40;u32 *&#41; sceIoOpenPatched&#41;;

 // Purger cache des instructions
 sceKernelIcacheClearAll&#40;&#41;;

Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

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!
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

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 ;-)
blasty
Posts: 9
Joined: Mon Aug 22, 2005 12:07 am

Post by blasty »

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!
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

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

// INCLUDES

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


// MODULE INITIALISATION

PSP_MODULE_INFO&#40;"FirmLaunch", 0x1000, 2, 0&#41;;
PSP_MAIN_THREAD_ATTR&#40;0x0&#41;;


// DEFINES

#define	printf			pspDebugScreenPrintf

#define PATCH_INFO_SHOW

// MIPS OPCODE

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


// FUNCTIONS CALLBACKS

int exit_callback &#40;int arg1, int arg2, void *common&#41;
&#123;
 sceKernelExitGame&#40;&#41;;
 return 0;
&#125;

int CallbackThread &#40;SceSize args, void *argp&#41;
&#123;
 int cbid;

 cbid = sceKernelCreateCallback&#40;"Exit Callback", exit_callback, NULL&#41;;
 sceKernelRegisterExitCallback&#40;cbid&#41;;

 sceKernelSleepThreadCB&#40;&#41;;
 return 0;
&#125;

int SetupCallbacks &#40;void&#41;
&#123;
 int thid = 0;

 thid = sceKernelCreateThread&#40;"update_thread", CallbackThread, 0x11, 0xFA0, PSP_THREAD_ATTR_USER, 0&#41;;

 if&#40;thid >= 0&#41; sceKernelStartThread&#40;thid, 0, 0&#41;;

 return thid;
&#125;

// FUNCTIONS

int patchStub &#40;u32 oid, u32 nid, u32 *patch&#41;
&#123;
 SceModule *modMem;
 SceLibraryStubTable *stubTable, *stubEnd;
 int x;


 // Trouver le pointeur memoire du module
 modMem = sceKernelFindModuleByUID&#40;oid&#41;;

#if defined&#40;PATCH_INFO_SHOW&#41;

 printf&#40;"modMem &#58; 0x%X\n",&#40;&#40;u32&#41; modMem&#41;&#41;;

#endif

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

 // Parcourir la liste des stubs
 stubTable = &#40;SceLibraryStubTable *&#41; &#40;&#40;u32 *&#41; modMem->stub_top&#41;;
 stubEnd = &#40;SceLibraryStubTable *&#41; &#40;&#40;&#40;u8 *&#41; modMem->stub_top&#41; + modMem->stub_size&#41;;

 while &#40;stubTable < stubEnd&#41;
 &#123;
#if defined&#40;PATCH_INFO_SHOW&#41;

  printf&#40;"stubTable &#58; 0x%X\n",&#40;&#40;u32&#41; stubTable&#41;&#41;;
  printf&#40;"stubTable->libname &#58; %s\n",stubTable->libname&#41;;
  printf&#40;"stubTable->stubcount &#58; %d\n",stubTable->stubcount&#41;;

#endif

  // Parcourir la table des NID
  for &#40;x=0;x<stubTable->stubcount;x++&#41;
  &#123;
   // Patcher l'adresse de la fonction si NID trouvé ou si nid = 0xFFFFFFFF &#40;code pour patcher tout les NID&#41;
   if &#40;&#40;stubTable->nidtable&#91;x&#93; == nid&#41; || &#40;nid == 0xFFFFFFFF&#41;&#41;
   &#123;
#if defined&#40;PATCH_INFO_SHOW&#41;

    printf&#40;"patched &#40;0x%X, NID %d&#41; &#58; 0x%X -> 0x%X\n",&#40;&#40;u32&#41; &&#40;&#40;u32 *&#41; stubTable->stubtable&#41;&#91;x << 0x1&#93;&#41;,x,&#40;&#40;u32 *&#41; stubTable->stubtable&#41;&#91;x << 0x1&#93;,&#40;&#40;u32&#41; patch&#41;&#41;;

#endif

	&#40;&#40;u32 *&#41; stubTable->stubtable&#41;&#91;x << 0x1&#93; = PATCH_J&#40;patch&#41;;					// J patch
	&#40;&#40;u32 *&#41; stubTable->stubtable&#41;&#91;&#40;x << 0x1&#41; + 0x1&#93; = PATCH_LUI&#40;0x0,0x0&#41;;		// LUI $zero, 0 &#40;delay slot instruction&#41;

    if &#40;nid != 0xFFFFFFFF&#41; break;												// un seul NID pareil par librairie ?
   &#125;
  &#125;

  // Mettre a jour le pointeur
  stubTable = &#40;SceLibraryStubTable *&#41; &#40;&#40;&#40;u32 *&#41; stubTable&#41; + stubTable->len&#41;;
 &#125;

 return 0;
&#125;

u32 LoadStartModule &#40;char *path, int start&#41;
&#123;
 u32 loadResult, startResult;
 int status;


 loadResult = sceKernelLoadModule&#40;path, 0, NULL&#41;;
 if &#40;loadResult & 0x80000000&#41; return -1;

 if &#40;start&#41;
 &#123;
  startResult = sceKernelStartModule&#40;loadResult, 0, NULL, &status, NULL&#41;;
  if &#40;loadResult != startResult&#41; return -2;
 &#125;

 return loadResult;
&#125;

SceUID sceIoOpenPatched &#40;const char *path, int flags, SceMode mode&#41;
&#123;
 char pathPatch&#91;512&#93;;


 // Patch name
 strcpy&#40;pathPatch,path&#41;;
 strcat&#40;pathPatch,".bak"&#41;;						// example &#58; ms0&#58;/temp.bin -> ms0&#58;/temp.bin.bak

 // Call normal function
 return sceIoOpen&#40;pathPatch,flags,mode&#41;;
&#125;

int main &#40;void&#41;
&#123;
 u32 oid;


 // Init SDK
 pspDebugInstallKprintfHandler&#40;NULL&#41;;
 pspDebugScreenSetTextColor&#40;0xFF&#41;;

 pspSdkInstallNoDeviceCheckPatch&#40;&#41;;
 pspSdkInstallNoPlainModuleCheckPatch&#40;&#41;;

 // Init display and HOME button
 pspDebugScreenInit&#40;&#41;;
 pspDebugScreenClear&#40;&#41;;
 SetupCallbacks&#40;&#41;;

 // Setup Pad
 sceCtrlSetSamplingCycle&#40;0&#41;;
 sceCtrlSetSamplingMode&#40;0&#41;;

 // Load a module
 oid = LoadStartModule&#40;"ms0&#58;/module.prx",1&#41;;

 // Patch NID module
 patchStub&#40;oid,0x109F50BC,&#40;u32 *&#41; sceIoOpenPatched&#41;;		// Replace sceIoOpen imported function of module.prx module by sceIoOpenPatched

 // Apply modifications to cache
 sceKernelDcacheWritebackAll&#40;&#41;;
 sceKernelIcacheClearAll&#40;&#41;;

 // Main loop
 for &#40;;;&#41; sceDisplayWaitVblankStart&#40;&#41;;

 // Exit program
 sceKernelExitGame&#40;&#41;;

 return 0;
&#125;
dankydoo
Posts: 11
Joined: Tue Mar 29, 2005 2:39 am

Post by dankydoo »

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