Advertising (This ad goes away for registered users. You can Login or Register)

Reverse of TN HEN main function

Forum rules
Forum rule Nº 15 is strictly enforced in this subforum.
Post Reply
jigsaw
Posts: 255
Joined: Sat Dec 18, 2010 12:49 pm

Reverse of TN HEN main function

Post by jigsaw » Sat Dec 25, 2010 10:13 pm

Hi,

I reversed main function of TN HEN. It's basically what Davee described in his blog ( http://lolhax.org/2010/12/23/arcanum/#more-18 ) , with some extra effort for locating routine address via htmlviewer.
Is it allowed post reversed HEN here? :?

thx &
rgds,
-ql
Advertising
Last edited by jigsaw on Sun Dec 26, 2010 11:33 am, edited 1 time in total.

User avatar
m0skit0
Guru
Posts: 3817
Joined: Mon Sep 27, 2010 6:01 pm

Re: Is it OK to post reverse of TN HEN here?

Post by m0skit0 » Sun Dec 26, 2010 10:24 am

I don't see why it would be forbidden.
Advertising
I wanna lots of mov al,0xb
Image
"just not into this RA stuffz"

jigsaw
Posts: 255
Joined: Sat Dec 18, 2010 12:49 pm

Re: Is it OK to post reverse of TN HEN here?

Post by jigsaw » Sun Dec 26, 2010 11:32 am

OK here it goes. Only the main function where exploit happens. It's ready to be translated to c code since it's heavily commented.

Oh BTW, this is Chinese version coz the original TN version doesn't work on my PSP 3004.

Code: Select all

; ======================================================
; Subroutine sub_00000484 - Address 0x00000484 
; entry point, i.e., the main(void)
sub_00000484:		; Refs: 0x0000009C 
	0x00000484: 0x27BDFF48 'H..'' - addiu      $sp, $sp, -184
	0x00000488: 0x03A02021 '! ..' - addu       $a0, $sp, $zr
	0x0000048C: 0x00002821 '!(..' - addu       $a1, $zr, $zr
	0x00000490: 0x240600A8 '...$' - addiu      $a2, $zr, 168
	0x00000494: 0xAFBF00B4 '....' - sw         $ra, 180($sp)
	0x00000498: 0xAFB200B0 '....' - sw         $s2, 176($sp)
	0x0000049C: 0xAFB100AC '....' - sw         $s1, 172($sp)
	0x000004A0: 0x0C0001CD '....' - jal        sub_00000734 ; memset(sp, 0, 168) ; a struct, sizeof which is 168, on top of stack
	0x000004A4: 0xAFB000A8 '....' - sw         $s0, 168($sp)
	0x000004A8: 0x240200A8 '...$' - addiu      $v0, $zr, 168 ; v0 = 168
	0x000004AC: 0xAFA20000 '....' - sw         $v0, 0($sp) ; p->size = 168?
	0x000004B0: 0x03A02021 '! ..' - addu       $a0, $sp, $zr ; a0 is pointer to the struct
	0x000004B4: 0x24020013 '...$' - addiu      $v0, $zr, 19 ; v0 = 19;
	0x000004B8: 0x0C000B64 'd...' - jal        sceUtility_CDC3AA41 ; sceUtilityHtmlViewerInitStart
	0x000004BC: 0xAFA20010 '....' - sw         $v0, 16($sp) ; p->xx = 19;
	0x000004C0: 0x04400049 'I.@.' - bltz       $v0, loc_000005E8 ; goto out on failure
	0x000004C4: 0x3C04000F '...<' - lui        $a0, 0xF ; a0 = 0x000F0000
	0x000004C8: 0x0C000B80 '....' - jal        ThreadManForUser_CEADEB47 ; sceKernelDelayThread(1000000)
	0x000004CC: 0x34844240 '@B.4' - ori        $a0, $a0, 0x4240 ; 1,000,000
	0x000004D0: 0x3C020000 '...<' - lui        $v0, 0x0
; Data ref 0x000030C8 "sceVshHV" ; vsh html viewer. search for sceVshHVUtility_Module
	0x000004D4: 0x245030C8 '.0P$' - addiu      $s0, $v0, 12488
	0x000004D8: 0x3C120880 '...<' - lui        $s2, 0x880 ; s2 = 0x08800000
	0x000004DC: 0x3C110A00 '...<' - lui        $s1, 0xA00 ; s1 = 0x0A000000
	0x000004E0: 0x02402021 '! @.' - addu       $a0, $s2, $zr ; a0 = 0x08800000

loc_000004E4:		; Refs: 0x00000504 
	0x000004E4: 0x02002821 '!(..' - addu       $a1, $s0, $zr ; a1 = "sceVshHV"
	0x000004E8: 0x0C00020E '....' - jal        sub_00000838 ; strncmp
	0x000004EC: 0x24060008 '...$' - addiu      $a2, $zr, 8 ; a2 = 8
	0x000004F0: 0x54400004 '..@T' - bnel       $v0, $zr, loc_00000504 ; if (not match) goto 504;
	0x000004F4: 0x26520004 '..R&' - addiu      $s2, $s2, 4 ; s2 += 4; ; move forward 4 bytes
	0x000004F8: 0x16500005 '..P.' - bne        $s2, $s0, loc_00000510 ; match found, goto 510;
	0x000004FC: 0x00002821 '!(..' - addu       $a1, $zr, $zr ; a1 = 0;
	0x00000500: 0x26520004 '..R&' - addiu      $s2, $s2, 4

loc_00000504:		; Refs: 0x000004F0 
	0x00000504: 0x1651FFF7 '..Q.' - bne        $s2, $s1, loc_000004E4 ; search from 0x08800000 to 0x0A000000
	0x00000508: 0x02402021 '! @.' - addu       $a0, $s2, $zr ; a0 = s2;
	0x0000050C: 0x00002821 '!(..' - addu       $a1, $zr, $zr ; a1 = 0

loc_00000510:		; Refs: 0x000004F8 
	0x00000510: 0x3C060010 '...<' - lui        $a2, 0x10 ; a2 = 0x00100000
	0x00000514: 0x0C0001CD '....' - jal        sub_00000734 ; memset(0x08800000, 0, 0x00100000);
	0x00000518: 0x3C040880 '...<' - lui        $a0, 0x880 ; a0 = 0x08800000
	0x0000051C: 0x0C0001B4 '....' - jal        sub_000006D0 ; v0 = set_k1(0);
	0x00000520: 0x00002021 '! ..' - addu       $a0, $zr, $zr ; a0 = 0;
	0x00000524: 0x2642FD78 'x.B&' - addiu      $v0, $s2, -648 ; v0 = s2 - 648; s2 is where sceVshHV locates
	0x00000528: 0x0040F809 '..@.' - jalr       $v0, $ra; 648 bytes away from string sceVshHV. indirect call to sceUtility_private_2DC8380C, i.e., pspUtilityPowerUnregisterCallback
	0x0000052C: 0x3C040808 '...<' - lui        $a0, 0x808 ; a0 = 0x08080000
	0x00000530: 0x0C000117 '....' - jal        sub_0000045C ; ClearCaches()
	0x00000534: 0x3C110880 '...<' - lui        $s1, 0x880 ; s1 = 0x08800000
	0x00000538: 0x2404FFFF '...$' - addiu      $a0, $zr, -1
	0x0000053C: 0x3C030890 '...<' - lui        $v1, 0x890 ; v1 = 0x08900000
	0x00000540: 0x8E220000 '..".' - lw         $v0, 0($s1)

loc_00000544:		; Refs: 0x00000550 
	0x00000544: 0x10440006 '..D.' - beq        $v0, $a0, loc_00000560 ; j if (v0 == 0xFFFFFFFF)
	0x00000548: 0x3C020890 '...<' - lui        $v0, 0x890 ; v0 = 0x08900000
	0x0000054C: 0x26310004 '..1&' - addiu      $s1, $s1, 4 ; s1 += 4
	0x00000550: 0x5623FFFC '..#V' - bnel       $s1, $v1, loc_00000544 ; search 0xFFFFFFFF from 0x0880000 to 0x0890000. Note that 0xFFFFFFFF proves that power unregister works.
	0x00000554: 0x8E220000 '..".' - lw         $v0, 0($s1)
	0x00000558: 0x0800015A 'Z...' - j          loc_00000568
	0x0000055C: 0x00000000 '....' - sll        $zr, $zr, 0

loc_00000560:		; Refs: 0x00000544 
	0x00000560: 0x56220003 '.."V' - bnel       $s1, $v0, loc_00000570 ; if (s1 != 0x08900000) j. it means we found 0xFFFFFFFF before 0x08900000.
	0x00000564: 0x3C040000 '...<' - lui        $a0, 0x0

loc_00000568:		; Refs: 0x00000558 
	0x00000568: 0x0000000D '....' - break      0x0 ; breakpoint exception if not found. i.e., power_unregister fails.
	0x0000056C: 0x3C040000 '...<' - lui        $a0, 0x0

loc_00000570:		; Refs: 0x00000560 ;
	0x00000570: 0x00003021 '!0..' - addu       $a2, $zr, $zr ; callback arg is NULL
	0x00000574: 0x3C100880 '...<' - lui        $s0, 0x880 ; s0 = 0x08800000
; Data ref 0x000030D0 ... 0x00000000 0x00000000 0x00000000 0x00000000 
	0x00000578: 0x248430D0 '.0.$' - addiu      $a0, $a0, 12496 ; callback name is empty string
	0x0000057C: 0x0C000B7E '~...' - jal        ThreadManForUser_E81CAF8F ; sceKernelCreateCallback
	0x00000580: 0x00002821 '!(..' - addu       $a1, $zr, $zr ; callback function is NULL
	0x00000584: 0x3604CCB0 '...6' - ori        $a0, $s0, 0xCCB0 ; a0 =0x0880CCB0
	0x00000588: 0x00912023 '# ..' - subu       $a0, $a0, $s1 ; a0 -= s1. s1 is where we found 0xFFFFFFFF 
	0x0000058C: 0x00402821 '!(@.' - addu       $a1, $v0, $zr ; a1 is SceUID, the callback handler
	0x00000590: 0x2642FD90 '..B&' - addiu      $v0, $s2, -624 ; s2 is where sceVshVH locates
	0x00000594: 0x0040F809 '..@.' - jalr       $v0, $ra ; 624 bytes away from sceVshVH is indirect call to scePower_driver_1A41E0ED, i.e., pspUtilityPowerRegisterCallback
	0x00000598: 0x00042102 '.!..' - srl        $a0, $a0, 4 ; a0 = sysmem_addr
	0x0000059C: 0x0C000117 '....' - jal        sub_0000045C ; ClearCaches
	0x000005A0: 0x00000000 '....' - sll        $zr, $zr, 0
	0x000005A4: 0x3C020000 '...<' - lui        $v0, 0x0
	0x000005A8: 0x36030010 '...6' - ori        $v1, $s0, 0x10 ; v1 = 0x08800010
	0x000005AC: 0x36044234 '4B.6' - ori        $a0, $s0, 0x4234 ; a0 = 0x08804234
; Text ref sub_00000328 (0x00000328)
	0x000005B0: 0x24420328 '(.B$' - addiu      $v0, $v0, 808
	0x000005B4: 0xAC620000 '..b.' - sw         $v0, 0($v1) ; our callback stored to 0x08800010
	0x000005B8: 0x0C000117 '....' - jal        sub_0000045C ; ClearCaches
	0x000005BC: 0xAC900000 '....' - sw         $s0, 0($a0) ; store 0x08800000 to 0x08804234
	0x000005C0: 0x0C000183 '....' - jal        sub_0000060C ; disable interrupt
	0x000005C4: 0x00000000 '....' - sll        $zr, $zr, 0
	0x000005C8: 0x00408021 '!.@.' - addu       $s0, $v0, $zr ; s0 = old intr
	0x000005CC: 0x3C050880 '...<' - lui        $a1, 0x880 ; a1 = 0x08800000
	0x000005D0: 0x0C000B74 't...' - jal        sceSuspendForUser_EADB1BD7 ; sceKernelPowerLock. enter kernel mode
	0x000005D4: 0x00002021 '! ..' - addu       $a0, $zr, $zr
	0x000005D8: 0x0C00019C '....' - jal        sub_00000670 ; restore intr
	0x000005DC: 0x02002021 '! ..' - addu       $a0, $s0, $zr
	0x000005E0: 0x0C000B8C '....' - jal        LoadExecForUser_05572A5F ; sceKernelExitGame
	0x000005E4: 0x00000000 '....' - sll        $zr, $zr, 0

loc_000005E8:		; Refs: 0x000004C0 
	0x000005E8: 0x0C000B88 '....' - jal        ThreadManForUser_809CE29B ; sceKernelExitDeleteThread
	0x000005EC: 0x00002021 '! ..' - addu       $a0, $zr, $zr
	0x000005F0: 0x8FBF00B4 '....' - lw         $ra, 180($sp)
	0x000005F4: 0x00001021 '!...' - addu       $v0, $zr, $zr
	0x000005F8: 0x8FB200B0 '....' - lw         $s2, 176($sp)
	0x000005FC: 0x8FB100AC '....' - lw         $s1, 172($sp)
	0x00000600: 0x8FB000A8 '....' - lw         $s0, 168($sp)
	0x00000604: 0x03E00008 '....' - jr         $ra
	0x00000608: 0x27BD00B8 '...'' - addiu      $sp, $sp, 184


jigsaw
Posts: 255
Joined: Sat Dec 18, 2010 12:49 pm

Re: Reverse of TN HEN main function

Post by jigsaw » Sun Dec 26, 2010 6:02 pm

The C code goes. Note: It compiles but always halt PSP under HBL (6.20 OFW). No idea of how to fix it. :(
According to the debug message, it stops after calling sceUtility_private_2DC8380C, the first jalr, and halt after few seconds.
I checked the asm and cannot find major difference between TN HEN.
I'd appreciate If somebody could give it a try.

rgds,
-ql

Code: Select all


#include <stdio.h>
#include <string.h>

#include "pspsdk.h"
#include "pspkernel.h"
#include "pspdebug.h"
#include "psputility.h"
#include "psputilsforkernel.h"

PSP_MODULE_INFO("TEST", 0, 1, 0); /* not sure how to set it, but tried to keep align with TN HEN .rodata.sceModuleInfo */

#if 0
PSP_MAIN_THREAD_ATTR(0); /* no idea of what it is */
#endif

#define printf pspDebugScreenPrintf

/* prototype of sceUtility_private_2DC8380C, scePower_driver_CE5D389B */
typedef int (*func1_t)(unsigned int);

/* prototype of sceUtility_private_764F5A3C, scePower_driver_1A41E0ED */
typedef int (*func2_t)(unsigned int, SceUID);

static void
clear_cache(void)
{
	sceKernelIcacheInvalidateAll();
	sceKernelDcacheWritebackInvalidateAll();
}

static void
callback(void)
{
	printf("Hello World!\n");
}

int
main(void)
{
	const static char *cbname = "test";

	char buf[168];
	pspUtilityHtmlViewerParam *param = (pspUtilityHtmlViewerParam *) buf;
	unsigned int *p = (unsigned int *) buf;
	func1_t fp;
	func2_t fp2;
	SceUID sceuid;
	char *s;
	unsigned int intr;

	pspDebugScreenInit();

	memset(buf, 0, 168);
	*p = 168;
	p += 4;
	*p = 19;

	sceUtilityHtmlViewerInitStart(param);
	sceKernelDelayThread(1000000);

	printf("start...\n");
	s = (char *) 0x08800000U;

	do {
		if (!strncmp("sceVshHV", s, 8))
			break;
		s += 4;
	} while (s < (char *) 0x0A000000U);

	printf("find sceVshHV at %p\n", s);
	memset((void *) 0x08800000, 0, 0x00100000);
	pspSdkSetK1(0);
	fp = (func1_t) ((unsigned) s - 648U); /* sceUtility_private_2DC8380C. CRASH here */
	printf("power unregister at %p\n", fp); /* this line is never printed */
	fp(0x08080000);
	printf("power unregister done\n");
	clear_cache();

	p = (unsigned int *) 0x08800000;

	do {
		if (*p == 0xFFFFFFFF)
			goto found;
		p++;
	} while (p < (unsigned int *) 0x08900000);

	printf("0xFFFFFFFF not found. quit!\n");
	return 0;

found:
	printf("create callback\n");
	sceuid = sceKernelCreateCallback(cbname, 0, 0);
	fp2 = (func2_t) (s - 624U);
	printf("power register\n");
	fp2((0x0880CCB0 -(unsigned int) p) >> 4, sceuid); /* sceUtility_private_764F5A3C */
	clear_cache();

	p = (unsigned int *) 0x08800010;
	*p = (unsigned int) callback;
	p = (unsigned int *) 0x08804234;
	*p = 0x08800000;
	clear_cache();

	printf("suspend intr\n");
	intr = sceKernelCpuSuspendIntr();
	sceKernelPowerLock(0, 0x08800000);
	sceKernelCpuResumeIntr(intr);
	printf("resumed intr\n");
	sceKernelExitGame();
	sceKernelExitDeleteThread(0);

	return 0;
}



wololo
Site Admin
Posts: 3619
Joined: Wed Oct 15, 2008 12:42 am
Location: Japan

Re: Reverse of TN HEN main function

Post by wololo » Mon Dec 27, 2010 5:16 am

I'm always lost with function pointers, but could it be the way you wrote it?

I would try

Code: Select all

   pspSdkSetK1(0);
  void (* func1)(u32 arg1) = (void *)((u32)s - 648);
  func1(0x08080000);
instead of

Code: Select all

   pspSdkSetK1(0);
   fp = (func1_t) ((unsigned) s - 648U); /* sceUtility_private_2DC8380C. CRASH here */
   printf("power unregister at %p\n", fp); /* this line is never printed */
   fp(0x08080000);
If you need US PSN Codes, this technique is what I recommend.

Looking for guest bloggers and news hunters here at wololo.net, PM me!

JJS
Big Beholder
Posts: 1416
Joined: Mon Sep 27, 2010 2:18 pm
Contact:

Re: Reverse of TN HEN main function

Post by JJS » Mon Dec 27, 2010 7:33 am

I have also reversed the whole HEN launcher. The output of pspdecompiler was used as a basis for the C code, so you can attribute any weirdness to that ;). It should just build and run, I tested on a GO and on a 1000. It is based on the original version by TN.

The rebootex.bin is not compiled in unlike on the original, but has to be extracted from the data section (at 0x0000BB10) and placed as "ms0:/rebootex" on the memory stick.

Code: Select all

#include <pspsdk.h>
#include <pspdebug.h>
#include <psputility.h>
#include <pspkernel.h>
#include <psputilsforkernel.h>
#include <psppower.h>
#include <stdio.h>
#include <string.h>


#define REBOOTEX_SIZE (32000)


int global_model = 0; // 0x00018EF4
int (*func_decompressReboot)(u32 addr, u32 size, void *unk, void *unk2, void *unk3) = NULL; // 0x00018EF8

char global_rebootEx[REBOOTEX_SIZE] __attribute__((aligned(64))); // 0x0000BB10

unsigned int loadExecPatchAddresses_Go[] = { 0x00002F28, 0x00002F74 }; // 0x0000BB00
unsigned int loadExecPatchAddresses[] = { 0x00002CD8, 0x00002D24 }; // 0x0000BB08

#define MAKE_CALL(f) (0x0C000000 | (((unsigned int)(f) >> 2) & 0x03FFFFFF))



PSP_MODULE_INFO("hen", 0, 1, 1); 



// TN HEN got the rebootex.bin file compiled in, but here
// it is loaded separately from the memory stick
void helperLoadRebootEx()
{
	SceUID file = sceIoOpen("ms0:/rebootex", PSP_O_RDONLY, 0777);
	sceIoRead(file, global_rebootEx, REBOOTEX_SIZE);
	sceIoClose(file);
}



/** henPatchedRebootEx
* Subroutine at address 0x000002B4
*/
int henPatchedRebootEx(u32 addr, u32 size, void *unk, void *unk2, void *unk3)
{
	// Decompress rebootex
	int (*func_sceKernelGzipDecompress)(char*, unsigned int, char*, int*) = (void*)0x8800FA10;
	int uncompressedSize = func_sceKernelGzipDecompress((char*)0x88FC0000, 0x10000, global_rebootEx, NULL);

	// Zero some memory
	char* address = (char*)0x88FB0000;
	while (address < (char*)0x88FB0020)
	{
		*address = 0;
		address++;
	}

	*((unsigned int*)0x88FB0000) = global_model;
	*((unsigned int*)0x88FB0004) = uncompressedSize;

	return func_decompressReboot(addr, size, unk, unk2, unk3);
}




/** henKernelCallback
* Subroutine at address 0x00000360
*/
int henKernelCallback()
{
	// Find text entry of module "sceLoadExec"
	SceModule* (*func_sceKernelFindModuleByName)(char*) = (void*)0x8801EB78;
	SceModule* module = func_sceKernelFindModuleByName("sceLoadExec");
	// Get text_address member, it is at a different position than in the PSPSDK struct
	unsigned int* textAddress = *(unsigned int*)((unsigned int)module + 108);

	// Determine PSP model and chooce patch addresses accordingly
	int (*func_sceKernelGetModel)() = (void*)0x8800A1C4;
	global_model = func_sceKernelGetModel();

	unsigned int* patchSet;

	if (global_model == 4) // PSP Go
	{
		patchSet = &loadExecPatchAddresses_Go[0]; // 0x0000BB00
	}
	else
	{
		patchSet = &loadExecPatchAddresses[0]; // 0x0000BB08
	}

	unsigned int* patchAddress;

	// Patch call to rebootex decryption
	patchAddress = (unsigned int*)((unsigned int)textAddress + patchSet[0]);
	*patchAddress = MAKE_CALL(&henPatchedRebootEx); // sub_0002B4

	// Overwrite some instruction
	patchAddress = (unsigned int*)((unsigned int)textAddress + patchSet[1]);
	*patchAddress = 0x3C0188FC;

	// Patch hardcoded memory locations
	*((unsigned int *) 0x8800CCB0) = 0xACC24230;
	*((unsigned int *) 0x8800CCB4) = 0x0A003322;
	*((unsigned int *) 0x8800CCB8) = 0x00001021;
	*((unsigned int *) 0x8800CCBC) = 0x3C058801;
	func_decompressReboot = (void*)textAddress;

	// Unknown function call
	int (*func_unknown1)() = (void*)0x88000E98;
	func_unknown1();

	// Unknown function call
	int (*func_unknown2)() = (void*)0x88000744;
	func_unknown2();

	return 0;
}



/**	henClearCache
* Subroutine at address 0x00000494
*/
void henClearCache() // sub_00494
{
	sceKernelIcacheInvalidateAll();
	sceKernelDcacheWritebackInvalidateAll();
}



/** main()
* Subroutine at address 0x000004B0
*/
int main() // sub_004B0
{
	pspDebugScreenInit(); // sub_00F4C

	// Original TN HEN has the rebootex data compiled in
	helperLoadRebootEx();

	unsigned int firmwareVersion = sceKernelDevkitVersion ();

	if (firmwareVersion != 0x06020010)
	{
		pspDebugScreenPrintf("Error: %s.", "Incompatible firmware"); // sub_00F6C
		__asm__ ("break;");
	}

	pspUtilityHtmlViewerParam htmlParam;
	memset(&htmlParam, 0, sizeof(pspUtilityHtmlViewerParam)); // sub_01020
	htmlParam.base.size = sizeof(pspUtilityHtmlViewerParam); // = 0x000000A8
	htmlParam.base.accessThread = 0x13;

	SceUID loadResult = sceUtilityHtmlViewerInitStart(&htmlParam); //sceUtility_CDC3AA41
	if (loadResult < 0)
	{
		pspDebugScreenPrintf("Error: %s.", "Could not load module");
		__asm__ ("break;");
	}

	sceKernelDelayThread(1000000);

	// Search through all of user memory to find the values 0x56656373 0x56486873 = "sceVshHV" (from "sceVshHVUtility_Module")
	// Note: this performs the same function, it is not transcribed verbatim
	unsigned int* address_low = (unsigned int*)0x08800000;
	unsigned int* address_high = (unsigned int*)0x08800004;

	while (address_high < (unsigned int*)0x0A000000)
	{
		if ((*address_low == 0x56656373) && (*address_high == 0x56486873))
		{
			break;
		}

		address_low++;
		address_high++;
	}

	// String not found
	if (address_high == (unsigned int*)0x0A000000)
	{
		pspDebugScreenPrintf("Error: %s.", "Could not find module address"); // sub_00F6C(0x0000B428, 0x0000B464)
		__asm__ ("break;");
	}

	// Zero out a good chunk of the lower end of user memory
	memset((void*)0x08800000, 0, 0x100000); // sub_01020

	// Make function pointer from address_low and invalidate the cache
	int (*func_unknown1)(int) = (void*)((unsigned int)address_low - 0x288);

	// Call the function
	func_unknown1(0x08080000);

	henClearCache(); // sub_00494

	// Search for the 0xFFFFFFFF value in RAM between 0x08800000 and 0x08900000
	// Note: this performs the same function, it is not transcribed verbatim
	unsigned int* functionAddress;
	unsigned int* currentAddress = (unsigned int*)0x08800004;

	if (*(unsigned int*)0x08800000 == 0xFFFFFFFF)
	{
		functionAddress = (unsigned int*)0x00000CCB;
	}
	else
	{
		while (currentAddress < (int*)0x08900000)
		{
			if (*currentAddress == 0xFFFFFFFF)
			{
				break;
			}

			currentAddress++;
		}

		if (currentAddress == (unsigned int*)0x08900000)
		{
			pspDebugScreenPrintf("Error: %s.", "Could not initialize exploit"); // sub_00F6C(0x0000B428, 0x0000B484);
			__asm__ ("break;");
		}

		functionAddress = (unsigned int*)(((unsigned int)0x0880CCB0 - (unsigned int)currentAddress) >> 4);
	}

	SceUID callbackId = sceKernelCreateCallback("", 0, 0); // (0x0000B4C0, 0x00000000, 0x00000000);

	// Make function pointer
	int (*functionRegisterCallback)(void*, int) = (void*)(((int)address_low - 0xBC00 + 0xB990));

	// Register the callback
	functionRegisterCallback(functionAddress, callbackId);

	henClearCache(); // sub_00494

	*(unsigned int*)0x08800010 = (int)&henKernelCallback; // sub_00360;
	*(unsigned int*)0x08804234 = 0x08800000;

	henClearCache(); // sub_00494

	// Go into kernel mode
	sceKernelPowerLock(NULL, 0x08800000);

	sceKernelExitGame();
	return 1;
}

jigsaw
Posts: 255
Joined: Sat Dec 18, 2010 12:49 pm

Re: Reverse of TN HEN main function

Post by jigsaw » Mon Dec 27, 2010 8:24 am

Wololo wrote:I'm always lost with function pointers, but could it be the way you wrote it?

I would try

Code: Select all

   pspSdkSetK1(0);
  void (* func1)(u32 arg1) = (void *)((u32)s - 648);
  func1(0x08080000);
instead of

Code: Select all

   pspSdkSetK1(0);
   fp = (func1_t) ((unsigned) s - 648U); /* sceUtility_private_2DC8380C. CRASH here */
   printf("power unregister at %p\n", fp); /* this line is never printed */
   fp(0x08080000);
Sorry my mistake. It should crash at fp(0x08080000) instead of assigning fp value. I won't bet your fix will work but anyway I'll give it a try later today.

jigsaw
Posts: 255
Joined: Sat Dec 18, 2010 12:49 pm

Re: Reverse of TN HEN main function

Post by jigsaw » Mon Dec 27, 2010 8:47 am

Impressive. Yesterday I also worked out routines at 0x00000360 and 0x000002B4. Apparently the fix in Chinese version is in routine 0x00000360 (OK it may be in other places as well but I don't know).

But I would never figure out how it works coz I just don't know existence of rebootex which hides itself in data segment.

May I ask how you noticed rebootex.bin and found where to locate it?

I was really depressed when yesterday I found that 0x00000360 just call some random functions and place value in arbitrary addresses, which just doesn't make sense to me. But now I feel much better coz your code explains some of the mysterious functions.

And besides, could you please try to compile it till the first jalr in main, and see how it works?
That is, with this code, how far does it go (see below). Coz I'm confused why my code always stops at func_unknown1(0x08080000);
Is it because I use PSP_MODULE_INFO("hen", 0, 1, 0); while you use PSP_MODULE_INFO("hen", 0, 1, 1);
Or it could be some other issue, like wrong Makefile?

Code: Select all

int main() // sub_004B0
{
	pspDebugScreenInit(); // sub_00F4C
	pspUtilityHtmlViewerParam htmlParam;

	memset(&htmlParam, 0, sizeof(pspUtilityHtmlViewerParam)); // sub_01020
	htmlParam.base.size = sizeof(pspUtilityHtmlViewerParam); // = 0x000000A8
	htmlParam.base.accessThread = 0x13;

	SceUID loadResult = sceUtilityHtmlViewerInitStart(&htmlParam); //sceUtility_CDC3AA41
	if (loadResult < 0)
	{
		pspDebugScreenPrintf("Error: %s.", "Could not load module");
		__asm__ ("break;");
	}

	sceKernelDelayThread(1000000);

	// Search through all of user memory to find the values 0x56656373 0x56486873 = "sceVshHV" (from "sceVshHVUtility_Module")
	// Note: this performs the same function, it is not transcribed verbatim
	unsigned int* address_low = (unsigned int*)0x08800000;
	unsigned int* address_high = (unsigned int*)0x08800004;

	while (address_high < (unsigned int*)0x0A000000)
	{
		if ((*address_low == 0x56656373) && (*address_high == 0x56486873))
		{
			break;
		}

		address_low++;
		address_high++;
	}

	// String not found
	if (address_high == (unsigned int*)0x0A000000)
	{
		pspDebugScreenPrintf("Error: %s.", "Could not find module address"); // sub_00F6C(0x0000B428, 0x0000B464)
		__asm__ ("break;");
	}

	// Zero out a good chunk of the lower end of user memory
	memset((void*)0x08800000, 0, 0x100000); // sub_01020

	// Make function pointer from address_low and invalidate the cache
	int (*func_unknown1)(int) = (void*)((unsigned int)address_low - 0x288);

	// Call the function
	func_unknown1(0x08080000);

	henClearCache(); // sub_00494

	sceKernelExitGame();
	return 1;
}

jigsaw
Posts: 255
Joined: Sat Dec 18, 2010 12:49 pm

Re: Reverse of TN HEN main function

Post by jigsaw » Mon Dec 27, 2010 8:55 am

Hi JJS,

I noticed that you skipped set_k1(0) in your code. Is it purposely? Maybe that makes my code broken? But it does exist in TN HEN...getting confused.
I have to wait for another day to get back home and try it.

JJS
Big Beholder
Posts: 1416
Joined: Mon Sep 27, 2010 2:18 pm
Contact:

Re: Reverse of TN HEN main function

Post by JJS » Mon Dec 27, 2010 9:20 am

jigsaw wrote:I noticed that you skipped set_k1(0) in your code. Is it purposely?
This must be something that the patch added because I have not seen that $k1 is being modified in the original. I am actually not sure if you can touch k1 from user mode at all or if just doing this will crash the PSP.
jigsaw wrote:May I ask how you noticed rebootex.bin and found where to locate it?
The program follows the same pattern as ChickHEN, which is explained here. Without that it would have been much harder.
I am not so hot with the RE stuff, so there might also be mistakes in my code.
jigsaw wrote:Apparently the fix in Chinese version is in routine 0x00000360 (OK it may be in other places as well but I don't know).
I haven't looked at that version. But I guess it makes sense that the patch addresses are the same as on the GO for 04g models since they were introduced at the same time.
jigsaw wrote:Is it because I use PSP_MODULE_INFO("hen", 0, 1, 0); while you use PSP_MODULE_INFO("hen", 0, 1, 1);
The last two parameters are just the version number. It doesn't matter what it is set to.

The Makefile I use is the most basic thing imaginable:

Code: Select all

TARGET = hen

OBJS = hen.o

INCDIR = 
CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
LIBS = -lpsppower -lpsputility

LDFLAGS =

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = TN HEN loader for 6.20 RE

PSP_FW_VERSION = 371
BUILD_PRX = 1

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak

EDIT: I looked at the fixed version for the 04g and what I see is that it "fakes" the model number for it to "2" (03g), but uses the patch addresses for the GO. Edit again: I might be confused and that it only fakes the model number.

Post Reply

Return to “Programming and Security”