Ejemplo n.º 1
0
Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *error_string)
{
	Module *module = new Module;
	kernelObjects.Create(module);
	memset(&module->nm, 0, sizeof(module->nm));

	u8 *newptr = 0;
	if (*(u32*)ptr == 0x4543537e) { // "~SCE"
		INFO_LOG(HLE, "~SCE module, skipping header");
		ptr += *(u32*)(ptr + 4);
	}

	if (*(u32*)ptr == 0x5053507e) { // "~PSP"
		// Decrypt module! YAY!
		INFO_LOG(HLE, "Decrypting ~PSP file");
		PSP_Header *head = (PSP_Header*)ptr;
		const u8 *in = ptr;
		u32 size = head->elf_size;
		if (head->psp_size > size)
		{
			size = head->psp_size;
		}
		newptr = new u8[head->elf_size + head->psp_size];
		ptr = newptr;
		int ret = pspDecryptPRX(in, (u8*)ptr, head->psp_size);
		if (ret == MISSING_KEY) {
			// This should happen for all "kernel" modules so disabling.
			// Reporting::ReportMessage("Missing PRX decryption key!");
			*error_string = "Missing key";
			delete [] newptr;
			module->isFake = true;
			strncpy(module->nm.name, head->modname, 28);
			module->nm.entry_addr = -1;
			module->nm.gp_value = -1;
			return module;
		}
		else if (ret <= 0)
		{
			ERROR_LOG(HLE, "Failed decrypting PRX! That's not normal! ret = %i\n", ret);
			Reporting::ReportMessage("Failed decrypting the PRX (ret = %i, size = %i, psp_size = %i)!", ret, head->elf_size, head->psp_size);
		}
	}

	if (*(u32*)ptr != 0x464c457f)
	{
		ERROR_LOG_REPORT(HLE, "Wrong magic number %08x", *(u32*)ptr);
		*error_string = "File corrupt";
		if (newptr) {
			delete [] newptr;
		}
		kernelObjects.Destroy<Module>(module->GetUID());
		return 0;
	}
	// Open ELF reader
	ElfReader reader((void*)ptr);

	if (!reader.LoadInto(loadAddress))
	{
		ERROR_LOG(HLE, "LoadInto failed");
		if (newptr)
		{
			delete [] newptr;
		}
		kernelObjects.Destroy<Module>(module->GetUID());
		return 0;
	}
	module->memoryBlockAddr = reader.GetVaddr();

	struct libent
	{
		u32 exportName; //default 0
		u16 bcdVersion;
		u16 moduleAttributes;
		u8 exportEntrySize;
		u8 numVariables;
		u16 numFunctions;
		u32 __entrytableAddr;
	};

	struct PspModuleInfo
	{
		// 0, 0, 1, 1 ?
		u16 moduleAttrs; //0x0000 User Mode, 0x1000 Kernel Mode
		u16 moduleVersion;
		// 28 bytes of module name, packed with 0's.
		char name[28];
		u32 gp;					 // ptr to MIPS GOT data	(global offset table)
		u32 libent;			 // ptr to .lib.ent section 
		u32 libentend;		// ptr to end of .lib.ent section 
		u32 libstub;			// ptr to .lib.stub section 
		u32 libstubend;	 // ptr to end of .lib.stub section 
	};

	SectionID sceModuleInfoSection = reader.GetSectionByName(".rodata.sceModuleInfo");
	PspModuleInfo *modinfo;
	if (sceModuleInfoSection != -1)
		modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSectionAddr(sceModuleInfoSection));
	else
		modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSegmentVaddr(0) + (reader.GetSegmentPaddr(0) & 0x7FFFFFFF) - reader.GetSegmentOffset(0));

	module->nm.gp_value = modinfo->gp;
	strncpy(module->nm.name, modinfo->name, 28);

	// Check for module blacklist - we don't allow games to load these modules from disc
	// as we have HLE implementations and the originals won't run in the emu because they
	// directly access hardware or for other reasons.
	for (u32 i = 0; i < ARRAY_SIZE(blacklistedModules); i++) {
		if (strcmp(modinfo->name, blacklistedModules[i]) == 0) {
			*error_string = "Blacklisted";
			if (newptr)
			{
				delete [] newptr;
			}
			module->isFake = true;
			module->nm.entry_addr = -1;
			return module;
		}
	}

	bool hasSymbols = false;
	bool dontadd = false;

	SectionID textSection = reader.GetSectionByName(".text");

	if (textSection != -1)
	{
		u32 textStart = reader.GetSectionAddr(textSection);
		u32 textSize = reader.GetSectionSize(textSection);

		if (!host->AttemptLoadSymbolMap())
		{
			hasSymbols = reader.LoadSymbols();
			if (!hasSymbols)
			{
				symbolMap.ResetSymbolMap();
				MIPSAnalyst::ScanForFunctions(textStart, textStart+textSize);
			}
		}
		else
		{
			dontadd = true;
		}
	}
	else if (host->AttemptLoadSymbolMap())
	{
		dontadd = true;
	}

	INFO_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub);

	struct PspLibStubEntry
	{
		u32 name;
		u16 version;
		u16 flags;
		u16 size;
		u16 numFuncs;
		// each symbol has an associated nid; nidData is a pointer
		// (in .rodata.sceNid section) to an array of longs, one
		// for each function, which identifies the function whose
		// address is to be inserted.
		//
		// The hash is the first 4 bytes of a SHA-1 hash of the function
		// name.	(Represented as a little-endian long, so the order
		// of the bytes is reversed.)
		u32 nidData;
		// the address of the function stubs where the function address jumps
		// should be filled in
		u32 firstSymAddr;
	};

	int numModules = (modinfo->libstubend - modinfo->libstub)/sizeof(PspLibStubEntry);

	DEBUG_LOG(LOADER,"Num Modules: %i",numModules);
	DEBUG_LOG(LOADER,"===================================================");

	PspLibStubEntry *entry = (PspLibStubEntry *)Memory::GetPointer(modinfo->libstub);

	int numSyms=0;
	for (int m = 0; m < numModules; m++) {
		const char *modulename;
		if (Memory::IsValidAddress(entry[m].name))
			modulename = (const char*)Memory::GetPointer(entry[m].name);
		else
			modulename = "(invalidname)";

		if (!Memory::IsValidAddress(entry[m].nidData)) {
			ERROR_LOG(LOADER, "Crazy niddata address %08x, skipping entire module", entry[m].nidData);
			continue;
		}
		u32 *nidDataPtr = (u32*)Memory::GetPointer(entry[m].nidData);
		// u32 *stubs = (u32*)Memory::GetPointer(entry[m].firstSymAddr);

		DEBUG_LOG(LOADER,"Importing Module %s, stubs at %08x",modulename,entry[m].firstSymAddr);

		for (int i=0; i<entry[m].numFuncs; i++)
		{
			u32 addrToWriteSyscall = entry[m].firstSymAddr+i*8;
			DEBUG_LOG(LOADER,"%s : %08x",GetFuncName(modulename, nidDataPtr[i]), addrToWriteSyscall);
			//write a syscall here
			if (Memory::IsValidAddress(addrToWriteSyscall))
				WriteSyscall(modulename, nidDataPtr[i], addrToWriteSyscall);
			if (!dontadd)
			{
				char temp[256];
				sprintf(temp,"zz_%s", GetFuncName(modulename, nidDataPtr[i]));
				symbolMap.AddSymbol(temp, addrToWriteSyscall, 8, ST_FUNCTION);
			}
			numSyms++;
		}
		DEBUG_LOG(LOADER,"-------------------------------------------------------------");
	}

	// Look at the exports, too.

	struct PspLibEntEntry
	{
		u32 name; /* ent's name (module name) address */
		u16 version;
		u16 flags;
		u8 size;
		u8 vcount;
		u16 fcount;
		u32 resident;
	};

	int numEnts = (modinfo->libentend - modinfo->libent)/sizeof(PspLibEntEntry);
	PspLibEntEntry *ent = (PspLibEntEntry *)Memory::GetPointer(modinfo->libent);
	for (int m=0; m<numEnts; m++)
	{
		const char *name;
		if (ent->size == 0)
			continue;

		if (ent->name == 0) {
			// ?
			name = module->nm.name;
		}
		else if (Memory::IsValidAddress(ent->name)) {
			name = (const char*)Memory::GetPointer(ent->name);
		}
		else {
			name = "invalid?";  // God Eater Burst
		}

		INFO_LOG(HLE,"Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident);
		
		// Seen 0x00060005 in God Eater Burst
		if (Memory::IsValidAddress(ent->resident)) 
		{
			u32 *residentPtr = (u32*)Memory::GetPointer(ent->resident);

			for (u32 j = 0; j < ent->fcount; j++)
			{
				u32 nid = residentPtr[j];
				u32 exportAddr = residentPtr[ent->fcount + ent->vcount + j];

				switch (nid)
				{
				case NID_MODULE_START:
					module->nm.module_start_func = exportAddr;
					break;
				case NID_MODULE_STOP:
					module->nm.module_stop_func = exportAddr;
					break;
				case NID_MODULE_REBOOT_BEFORE:
					module->nm.module_reboot_before_func = exportAddr;
					break;
				case NID_MODULE_REBOOT_PHASE:
					module->nm.module_reboot_phase_func = exportAddr;
					break;
				case NID_MODULE_BOOTSTART:
					module->nm.module_bootstart_func = exportAddr;
					break;
				default:
					ResolveSyscall(name, nid, exportAddr);
				}
			}

			for (u32 j = 0; j < ent->vcount; j++)
			{
				u32 nid = residentPtr[ent->fcount + j];
				u32 exportAddr = residentPtr[ent->fcount + ent->vcount + ent->fcount + j];

				switch (nid)
				{
				case NID_MODULE_INFO:
					break;
				case NID_MODULE_START_THREAD_PARAMETER:
					if (Memory::Read_U32(exportAddr) != 3)
						WARN_LOG_REPORT(LOADER, "Strange value at module_start_thread_parameter export: %08x", Memory::Read_U32(exportAddr));
					module->nm.module_start_thread_priority = Memory::Read_U32(exportAddr + 4);
					module->nm.module_start_thread_stacksize = Memory::Read_U32(exportAddr + 8);
					module->nm.module_start_thread_attr = Memory::Read_U32(exportAddr + 12);
					break;
				case NID_MODULE_STOP_THREAD_PARAMETER:
					if (Memory::Read_U32(exportAddr) != 3)
						WARN_LOG_REPORT(LOADER, "Strange value at module_stop_thread_parameter export: %08x", Memory::Read_U32(exportAddr));
					module->nm.module_stop_thread_priority = Memory::Read_U32(exportAddr + 4);
					module->nm.module_stop_thread_stacksize = Memory::Read_U32(exportAddr + 8);
					module->nm.module_stop_thread_attr = Memory::Read_U32(exportAddr + 12);
					break;
				case NID_MODULE_REBOOT_BEFORE_THREAD_PARAMETER:
					if (Memory::Read_U32(exportAddr) != 3)
						WARN_LOG_REPORT(LOADER, "Strange value at module_reboot_before_thread_parameter export: %08x", Memory::Read_U32(exportAddr));
					module->nm.module_reboot_before_thread_priority = Memory::Read_U32(exportAddr + 4);
					module->nm.module_reboot_before_thread_stacksize = Memory::Read_U32(exportAddr + 8);
					module->nm.module_reboot_before_thread_attr = Memory::Read_U32(exportAddr + 12);
					break;
				case NID_MODULE_SDK_VERSION:
					DEBUG_LOG(LOADER, "Module SDK: %08x", Memory::Read_U32(exportAddr));
					break;
				default:
					DEBUG_LOG(LOADER, "Unexpected variable with nid: %08x", nid);
					break;
				}
			}
		}

		if (ent->size > 4)
		{
			ent = (PspLibEntEntry*)((u8*)ent + ent->size * 4);
		}
		else
		{
			ent++;
		}
	}

	module->nm.entry_addr = reader.GetEntryPoint();
	
	// use module_start_func instead of entry_addr if entry_addr is 0
	if (module->nm.entry_addr == 0)
		module->nm.entry_addr = module->nm.module_start_func;

	if (newptr)
	{
		delete [] newptr;
	}
	return module;
}
Ejemplo n.º 2
0
Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *error_string)
{
	Module *module = new Module;
	kernelObjects.Create(module);

	u8 *newptr = 0;

	if (*(u32*)ptr == 0x5053507e) { // "~PSP"
		// Decrypt module! YAY!
		INFO_LOG(HLE, "Decrypting ~PSP file");
		PSP_Header *head = (PSP_Header*)ptr;
		const u8 *in = ptr;
		u32 size = head->elf_size;
		if (head->psp_size > size)
		{
			size = head->psp_size;
		}
		newptr = new u8[head->elf_size + head->psp_size];
		ptr = newptr;
		pspDecryptPRX(in, (u8*)ptr, head->psp_size);
	}

	if (*(u32*)ptr == 0x4543537e) { // "~SCE"
		ERROR_LOG(HLE, "Wrong magic number %08x (~SCE, kernel module?)",*(u32*)ptr);
		*error_string = "Kernel module?";
		if (newptr)
		{
			delete [] newptr;
		}
		kernelObjects.Destroy<Module>(module->GetUID());
		return 0;
	}
	
	if (*(u32*)ptr != 0x464c457f)
	{
		ERROR_LOG(HLE, "Wrong magic number %08x",*(u32*)ptr);
		*error_string = "File corrupt";
		if (newptr)
		{
			delete [] newptr;
		}
		kernelObjects.Destroy<Module>(module->GetUID());
		return 0;
	}
	// Open ELF reader
	ElfReader reader((void*)ptr);

	if (!reader.LoadInto(loadAddress))
	{
		ERROR_LOG(HLE, "LoadInto failed");
		if (newptr)
		{
			delete [] newptr;
		}
		kernelObjects.Destroy<Module>(module->GetUID());
		return 0;
	}

	struct libent
	{
		u32 exportName; //default 0
		u16 bcdVersion;
		u16 moduleAttributes;
		u8 exportEntrySize;
		u8 numVariables;
		u16 numFunctions;
		u32 __entrytableAddr;
	};

	struct PspModuleInfo
	{
		// 0, 0, 1, 1 ?
		u16 moduleAttrs; //0x0000 User Mode, 0x1000 Kernel Mode
		u16 moduleVersion;
		// 28 bytes of module name, packed with 0's.
		char name[28];
		u32 gp;					 // ptr to MIPS GOT data	(global offset table)
		u32 libent;			 // ptr to .lib.ent section 
		u32 libentend;		// ptr to end of .lib.ent section 
		u32 libstub;			// ptr to .lib.stub section 
		u32 libstubend;	 // ptr to end of .lib.stub section 
	};

	SectionID sceModuleInfoSection = reader.GetSectionByName(".rodata.sceModuleInfo");
	PspModuleInfo *modinfo;
	if (sceModuleInfoSection != -1)
		modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetSectionAddr(sceModuleInfoSection));
	else
		modinfo = (PspModuleInfo *)Memory::GetPointer(reader.GetVaddr() + (reader.GetSegmentPaddr(0) & 0x7FFFFFFF) - reader.GetSegmentOffset(0));

	// Check for module blacklist - we don't allow games to load these modules from disc
	// as we have HLE implementations and the originals won't run in the emu because they
	// directly access hardware or for other reasons.
	for (u32 i = 0; i < ARRAY_SIZE(blacklistedModules); i++) {
		if (strcmp(modinfo->name, blacklistedModules[i]) == 0) {
			*error_string = "Blacklisted";
			if (newptr)
			{
				delete [] newptr;
			}
			kernelObjects.Destroy<Module>(module->GetUID());
			return 0;
		}
	}

	bool hasSymbols = false;
	bool dontadd = false;

	SectionID textSection = reader.GetSectionByName(".text");

	if (textSection != -1)
	{
		u32 textStart = reader.GetSectionAddr(textSection);
		u32 textSize = reader.GetSectionSize(textSection);

		if (!host->AttemptLoadSymbolMap())
		{
			hasSymbols = reader.LoadSymbols();
			if (!hasSymbols)
			{
				symbolMap.ResetSymbolMap();
				MIPSAnalyst::ScanForFunctions(textStart, textStart+textSize);
			}
		}
		else
		{
			dontadd = true;
		}
	}

	module->gp_value = modinfo->gp;
	strncpy(module->name, modinfo->name, 28);

	INFO_LOG(LOADER,"Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent,modinfo->libstub);

	struct PspLibStubEntry
	{
		u32 name;
		u16 version;
		u16 flags;
		u16 size;
		u16 numFuncs;
		// each symbol has an associated nid; nidData is a pointer
		// (in .rodata.sceNid section) to an array of longs, one
		// for each function, which identifies the function whose
		// address is to be inserted.
		//
		// The hash is the first 4 bytes of a SHA-1 hash of the function
		// name.	(Represented as a little-endian long, so the order
		// of the bytes is reversed.)
		u32 nidData;
		// the address of the function stubs where the function address jumps
		// should be filled in
		u32 firstSymAddr;
	};

	int numModules = (modinfo->libstubend - modinfo->libstub)/sizeof(PspLibStubEntry);

	DEBUG_LOG(LOADER,"Num Modules: %i",numModules);
	DEBUG_LOG(LOADER,"===================================================");

	PspLibStubEntry *entry = (PspLibStubEntry *)Memory::GetPointer(modinfo->libstub);

	int numSyms=0;
	for (int m = 0; m < numModules; m++)
	{
		const char *modulename = (const char*)Memory::GetPointer(entry[m].name);
		u32 *nidDataPtr = (u32*)Memory::GetPointer(entry[m].nidData);
		// u32 *stubs = (u32*)Memory::GetPointer(entry[m].firstSymAddr);

		DEBUG_LOG(LOADER,"Importing Module %s, stubs at %08x",modulename,entry[m].firstSymAddr);

		for (int i=0; i<entry[m].numFuncs; i++)
		{
			u32 addrToWriteSyscall = entry[m].firstSymAddr+i*8;
			DEBUG_LOG(LOADER,"%s : %08x",GetFuncName(modulename, nidDataPtr[i]), addrToWriteSyscall);
			//write a syscall here
			WriteSyscall(modulename, nidDataPtr[i], addrToWriteSyscall);
			if (!dontadd)
			{
				char temp[256];
				sprintf(temp,"zz_%s", GetFuncName(modulename, nidDataPtr[i]));
				symbolMap.AddSymbol(temp, addrToWriteSyscall, 8, ST_FUNCTION);
			}
			numSyms++;
		}
		DEBUG_LOG(LOADER,"-------------------------------------------------------------");
	}

	// Look at the exports, too.

	struct PspLibEntEntry
	{
		u32 name; /* ent's name (module name) address */
		u16 version;
		u16 flags;
		u8 size;
		u8 vcount;
		u16 fcount;
		u32 resident;
	};

	int numEnts = (modinfo->libentend - modinfo->libent)/sizeof(PspLibEntEntry);
	PspLibEntEntry *ent = (PspLibEntEntry *)Memory::GetPointer(modinfo->libent);
	for (int m=0; m<numEnts; m++)
	{
		const char *name;
		if (ent->size == 0)
		{
			continue;
		}

		if (ent->name == 0)
		{
			// ?
			name = module->name;
		}
		else
		{
			name = (const char*)Memory::GetPointer(ent->name);
		}

		INFO_LOG(HLE,"Exporting ent %d named %s, %d funcs, %d vars, resident %08x", m, name, ent->fcount, ent->vcount, ent->resident);
		
		u32 *residentPtr = (u32*)Memory::GetPointer(ent->resident);

		for (u32 j = 0; j < ent->fcount; j++)
		{
			u32 nid = residentPtr[j];
			u32 exportAddr = residentPtr[ent->fcount + ent->vcount + j];
			ResolveSyscall(name, nid, exportAddr);
		}
		if (ent->size > 4)
		{
			ent = (PspLibEntEntry*)((u8*)ent + ent->size * 4);
		}
		else
		{
			ent++;
		}
	}

	module->entry_addr = reader.GetEntryPoint();

	if (newptr)
	{
		delete [] newptr;
	}
	return module;
}