├── henkaku
├── .gitignore
├── config.h
├── user.yml
├── kernel.yml
├── LICENSE
├── henkaku.h
├── taihen.json
├── CMakeLists.txt
├── henkaku_settings.xml
├── system_settings.xml
├── kernel.c
├── language.h
└── user.c
├── installer
├── .gitignore
├── res
│ └── pkg
│ │ ├── bg0.png
│ │ ├── icon0.png
│ │ ├── startup.png
│ │ └── template.xml
├── src
│ ├── kernel2.yml
│ ├── kernel_exports.yml
│ ├── user_exports.yml
│ ├── enso.h
│ ├── sha256.h
│ ├── kernel2.c
│ ├── user.c
│ ├── pspdebug.h
│ ├── crc32.c
│ ├── sha256.c
│ ├── scr_printf.c
│ ├── font.c
│ └── main.c
├── LICENSE
└── CMakeLists.txt
├── enso
├── .gitignore
├── fat.tpl
├── first.x
├── second.x
├── Makefile
├── README.md
├── LICENSE
├── gen.py
├── first.c
├── nsbl.h
├── second.c
└── logo.h
└── README.md
/henkaku/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/installer/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/enso/.gitignore:
--------------------------------------------------------------------------------
1 | *.bin
2 | *.o
3 | first
4 | second
5 | fat.bin
6 |
--------------------------------------------------------------------------------
/enso/fat.tpl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheOfficialFloW/update365/HEAD/enso/fat.tpl
--------------------------------------------------------------------------------
/installer/res/pkg/bg0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheOfficialFloW/update365/HEAD/installer/res/pkg/bg0.png
--------------------------------------------------------------------------------
/installer/res/pkg/icon0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheOfficialFloW/update365/HEAD/installer/res/pkg/icon0.png
--------------------------------------------------------------------------------
/installer/res/pkg/startup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheOfficialFloW/update365/HEAD/installer/res/pkg/startup.png
--------------------------------------------------------------------------------
/henkaku/config.h:
--------------------------------------------------------------------------------
1 | #define BETA_RELEASE 0
2 | #define ENSO_RELEASE 1
3 | #define HENKAKU_RELEASE 1
4 | #define PSN_PASSPHRASE ""
5 |
--------------------------------------------------------------------------------
/henkaku/user.yml:
--------------------------------------------------------------------------------
1 | HENkakuUser:
2 | attributes: 0
3 | version:
4 | major: 1
5 | minor: 1
6 | main:
7 | start: module_start
8 | stop: module_stop
9 |
--------------------------------------------------------------------------------
/installer/src/kernel2.yml:
--------------------------------------------------------------------------------
1 | kernel2:
2 | attributes: 0
3 | version:
4 | major: 1
5 | minor: 1
6 | main:
7 | start: module_start
8 | stop: module_stop
9 |
--------------------------------------------------------------------------------
/installer/src/kernel_exports.yml:
--------------------------------------------------------------------------------
1 | kernel:
2 | attributes: 0
3 | version:
4 | major: 1
5 | minor: 1
6 | main:
7 | start: module_start
8 | stop: module_stop
9 |
--------------------------------------------------------------------------------
/installer/src/user_exports.yml:
--------------------------------------------------------------------------------
1 | user:
2 | attributes: 0
3 | version:
4 | major: 1
5 | minor: 1
6 | main:
7 | start: module_start
8 | stop: module_stop
9 |
--------------------------------------------------------------------------------
/henkaku/kernel.yml:
--------------------------------------------------------------------------------
1 | HENkaku:
2 | attributes: 0
3 | version:
4 | major: 1
5 | minor: 1
6 | main:
7 | start: module_start
8 | stop: module_stop
9 | modules:
10 | HENkaku:
11 | syscall: true
12 | functions:
13 | - henkaku_reload_config
14 |
--------------------------------------------------------------------------------
/enso/first.x:
--------------------------------------------------------------------------------
1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
2 | OUTPUT_ARCH(arm)
3 |
4 | ENTRY(start)
5 |
6 | SECTIONS
7 | {
8 | . = 0x51167220;
9 | .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) }
10 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
11 | .data : { *(.data .data.* .gnu.linkonce.d.*) }
12 | .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) }
13 | }
14 |
--------------------------------------------------------------------------------
/enso/second.x:
--------------------------------------------------------------------------------
1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
2 | OUTPUT_ARCH(arm)
3 |
4 | ENTRY(start)
5 |
6 | SECTIONS
7 | {
8 | . = 0x51e00000;
9 | .text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) }
10 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
11 | .data : { *(.data .data.* .gnu.linkonce.d.*) }
12 | .bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) }
13 | }
14 |
--------------------------------------------------------------------------------
/enso/Makefile:
--------------------------------------------------------------------------------
1 | CC=arm-vita-eabi-gcc
2 | CFLAGS=-Os -fno-builtin-printf -fPIC -fno-builtin-memset -Wall -Wextra -Wno-unused-variable -DFW_365
3 | OBJCOPY=arm-vita-eabi-objcopy
4 | LDFLAGS=-nodefaultlibs -nostdlib
5 |
6 | fat.bin: first.bin second.bin
7 | ./gen.py fat.tpl first.bin second.bin fat.bin
8 |
9 | first.bin: first
10 | $(OBJCOPY) -O binary $^ $@
11 |
12 | second.bin: second
13 | $(OBJCOPY) -O binary $^ $@
14 |
15 | first: first.o
16 | $(CC) -o $@ $^ $(LDFLAGS) -T first.x
17 |
18 | second: second.o
19 | $(CC) -o $@ $^ $(LDFLAGS) -T second.x
20 |
21 | clean:
22 | -rm -f first first.bin second second.bin fat.bin *.o
23 |
--------------------------------------------------------------------------------
/installer/src/enso.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // user prototypes
4 | int ensoCheckOs0(void);
5 | int ensoCheckMBR(void);
6 | int ensoCheckBlocks(void);
7 | int ensoWriteConfig(void);
8 | int ensoWriteBlocks(void);
9 | int ensoWriteMBR(void);
10 | int ensoCheckRealMBR(void);
11 | int ensoUninstallMBR(void);
12 | int ensoCleanUpBlocks(void);
13 |
14 | // kernel prototypes
15 | int k_ensoCheckOs0(void);
16 | int k_ensoCheckMBR(void);
17 | int k_ensoCheckBlocks(void);
18 | int k_ensoWriteConfig(void);
19 | int k_ensoWriteBlocks(void);
20 | int k_ensoWriteMBR(void);
21 | int k_ensoCheckRealMBR(void);
22 | int k_ensoUninstallMBR(void);
23 | int k_ensoCleanUpBlocks(void);
24 |
25 | enum {
26 | E_PREVIOUS_INSTALL = 1,
27 | E_MBR_BUT_UNKNOWN = 2,
28 | E_UNKNOWN_DATA = 3,
29 | };
30 |
31 | #define BLOCKS_OUTPUT "ux0:data/blocks.bin"
32 |
--------------------------------------------------------------------------------
/enso/README.md:
--------------------------------------------------------------------------------
1 | You need [vitasdk](https://vitasdk.org/).
2 |
3 | 1. `make` the payload
4 | 2. Copy `fat.bin` to `installer/res`
5 | 3. CMake the installer `mkdir build && cd build && cmake .. && make`
6 |
7 | Firmware specific offsets are in first.c and nsbl.h. Logo is raw framebuffer data gzipped. If you make this too big (bigger than original logo size), you WILL perma-brick your Vita.
8 |
9 | The source is for advanced users only. Users should download the [prebuilt package](https://enso.henkaku.xyz/). If something goes wrong, you WILL perma-brick your Vita. There is no recovery, even if you have a hardware mod. The only possible recovery is if you have a hardware mod and you dump the eMMC _before_ getting bricked, then you can restore the dump. Dumps are device-specific and encrypted with a device-specific key.
10 |
11 | Again, even if you just change the logo, there's a good chance you will perma-brick your Vita. You have been warned.
12 |
--------------------------------------------------------------------------------
/installer/res/pkg/template.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | bg0.png
6 |
7 |
8 |
9 | startup.png
10 |
11 |
12 |
13 |
14 |
15 | HENkaku Ensō
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 3.65 Updater
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | v1.0
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/enso/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 molecule
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/henkaku/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 molecule
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/installer/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 molecule
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/henkaku/henkaku.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @brief Internal functions and defines
3 | */
4 | #ifndef HENKAKU_HEADER
5 | #define HENKAKU_HEADER
6 |
7 | #include
8 |
9 | // TODO: Move to sdk
10 | int sceClibPrintf(const char *fmt, ...);
11 | int sceClibSnprintf(char *buf, size_t len, const char *fmt, ...);
12 |
13 | int henkaku_reload_config(void);
14 | int taiReloadConfig(void);
15 |
16 | /** Logging function */
17 | #ifdef ENABLE_LOGGING
18 | #ifdef __VITA_KERNEL__
19 | #define LOG(fmt, ...) printf("[%s:%d] " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
20 | #else
21 | #define LOG(fmt, ...) sceClibPrintf("[%s:%d] " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
22 | #endif
23 | #else
24 | #define LOG(fmt, ...)
25 | #endif
26 |
27 | /** Config */
28 | typedef struct {
29 | uint32_t magic;
30 | uint32_t version;
31 | uint32_t use_psn_spoofing;
32 | uint32_t allow_unsafe_hb;
33 | uint32_t use_spoofed_version;
34 | uint32_t spoofed_version;
35 | } __attribute__((packed)) henkaku_config_t;
36 |
37 | #define HENKAKU_CONFIG_MAGIC (0x4C434C4D)
38 | #define CONFIG_PATH "ur0:tai/henkaku_config.bin"
39 | #define OLD_CONFIG_PATH "ux0:temp/app_work/MLCL00001/rec/config.bin"
40 | #define SPOOF_VERSION (0x3670000)
41 |
42 | #endif // HENKAKU_HEADER
43 |
--------------------------------------------------------------------------------
/installer/src/sha256.h:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Filename: sha256.h
3 | * Author: Brad Conte (brad AT bradconte.com)
4 | * Copyright:
5 | * Disclaimer: This code is presented "as is" without any guarantees.
6 | * Details: Defines the API for the corresponding SHA1 implementation.
7 | *********************************************************************/
8 |
9 | #ifndef SHA256_H
10 | #define SHA256_H
11 |
12 | /*************************** HEADER FILES ***************************/
13 | #include
14 |
15 | /****************************** MACROS ******************************/
16 | #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
17 |
18 | /**************************** DATA TYPES ****************************/
19 | typedef unsigned char BYTE; // 8-bit byte
20 | typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines
21 |
22 | typedef struct {
23 | BYTE data[64];
24 | WORD datalen;
25 | unsigned long long bitlen;
26 | WORD state[8];
27 | } SHA256_CTX;
28 |
29 | /*********************** FUNCTION DECLARATIONS **********************/
30 | void sha256_init(SHA256_CTX *ctx);
31 | void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
32 | void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
33 |
34 | #endif // SHA256_H
35 |
--------------------------------------------------------------------------------
/henkaku/taihen.json:
--------------------------------------------------------------------------------
1 | {
2 | "taihen": {
3 | "nid": 910080232,
4 | "modules": {
5 | "taihen": {
6 | "nid": 540875304,
7 | "kernel": false,
8 | "functions": {
9 | "taiHookFunctionExportForUser": 2269553102,
10 | "taiHookFunctionImportForUser": 1399025245,
11 | "taiHookFunctionOffsetForUser": 87368282,
12 | "taiGetModuleInfo": 2777256836,
13 | "taiHookRelease": 472967065,
14 | "taiInjectAbs": 1247316228,
15 | "taiInjectDataForUser": 3458578876,
16 | "taiInjectRelease": 564447398
17 | },
18 | "variables": {
19 | }
20 | },
21 | "taihenForKernel": {
22 | "nid": 3487819968,
23 | "kernel": true,
24 | "functions": {
25 | "taiHookFunctionAbs": 3605329551,
26 | "taiHookFunctionExportForKernel": 1171062720,
27 | "taiHookFunctionImportForKernel": 1159321730,
28 | "taiHookFunctionOffsetForKernel": 2402393463,
29 | "taiGetModuleInfoForKernel": 1855132055,
30 | "taiHookReleaseForKernel": 3525736650,
31 | "taiInjectAbsForKernel": 4230976111,
32 | "taiInjectDataForKernel": 2678390840,
33 | "taiInjectReleaseForKernel": 1371225801,
34 | "taiLoadPluginsForTitleForKernel": 2621581546
35 | },
36 | "variables": {
37 | }
38 | },
39 | "taihenUnsafe": {
40 | "nid": 2998301478,
41 | "kernel": false,
42 | "functions": {
43 | "taiLoadKernelModule": 3603990244,
44 | "taiStartKernelModuleForUser": 2850755214,
45 | "taiLoadStartKernelModuleForUser": 2559617235,
46 | "taiLoadStartModuleForPidForUser": 3897797579,
47 | "taiStopUnloadKernelModuleForUser": 1277030648,
48 | "taiUnloadKernelModule": 1275696130,
49 | "taiMemcpyUserToKernel": 4138861294,
50 | "taiMemcpyKernelToUser": 2310758437
51 | },
52 | "variables": {
53 | }
54 | }
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/enso/gen.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 |
3 | from sys import argv, exit
4 | import struct
5 |
6 | def p32(x):
7 | return struct.pack("= 0x180:
29 | print "your first payload is too big!"
30 | exit(-1)
31 | if len(second_bin) >= 0x2000:
32 | print "your second payload is too big!"
33 | exit(-1)
34 |
35 | temp_store = 0x511671A0
36 | pivot = 0x5101504C # e890b672 ldm r0, {r1, r4, r5, r6, r9, sl, ip, sp, pc}
37 | pop_pc = 0x5100155F
38 | pop_r0_pc = 0x5100E4D1
39 | pop_r1_r2_r4_r6_pc = 0x51024C53
40 | blx_r3_pop_r3_pc = 0x510058AF
41 | pop_r3_pc = 0x510058B1
42 | flush_icache = 0x51014691 # ICIALLUIS
43 | clean_dcache = 0x510146DD
44 | debug_printf = 0x51012D45
45 |
46 | pivot_args = [0, 0, 0, 0, 0, 0, 0, temp_store + 0x40, pop_pc]
47 | rop = [
48 | pop_r0_pc,
49 | temp_store, # r0
50 |
51 | pop_r1_r2_r4_r6_pc,
52 | 0x800, # r1
53 | 0, # r2
54 | 0, # r4
55 | 0, # r6
56 |
57 | pop_r3_pc,
58 | clean_dcache, # r3
59 |
60 | blx_r3_pop_r3_pc,
61 | flush_icache, # r3
62 |
63 | blx_r3_pop_r3_pc,
64 | 0, # r3
65 | temp_store + 0x80|1,
66 | ]
67 |
68 | BASE = 0x5400
69 |
70 | # write pivot_args to temp_store
71 | ins(fat_tpl, BASE, pivot_args)
72 | # write rop to temp_store + 0x40
73 | ins(fat_tpl, BASE + 0x40, rop)
74 | # write payload to temp_store + 0x80
75 | ins(fat_tpl, BASE + 0x80, first_bin)
76 | # write second payload starting from block 5
77 | ins(fat_tpl, 5 * 0x200, second_bin)
78 | # write func ptr
79 | ins(fat_tpl, BASE + 0x638, [pivot])
80 | # write R0 arg to func ptr
81 | ins(fat_tpl, BASE + 0x63C, [temp_store])
82 |
83 | with open(argv[4], "wb") as fout:
84 | fout.write(fat_tpl)
85 |
86 |
87 | if __name__ == "__main__":
88 | main()
89 |
--------------------------------------------------------------------------------
/installer/src/kernel2.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | #define MOD_LIST_SIZE 128
11 |
12 | int module_get_export_func(SceUID pid, const char *modname, uint32_t libnid, uint32_t funcnid, uintptr_t *func);
13 |
14 | int (* _ksceKernelGetModuleList)(SceUID pid, int flags1, int flags2, SceUID *modids, size_t *num);
15 | int (* _ksceKernelGetModuleInfo)(SceUID pid, SceUID modid, SceKernelModuleInfo *info);
16 |
17 | void _start() __attribute__ ((weak, alias("module_start")));
18 | int module_start(SceSize args, void *argp) {
19 | int ret;
20 | SceKernelModuleInfo info;
21 | SceUID modlist[MOD_LIST_SIZE];
22 | int count = MOD_LIST_SIZE;
23 | int i;
24 |
25 | ret = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0xC445FA63, 0x97CF7B4E, (uintptr_t *)&_ksceKernelGetModuleList);
26 | if (ret < 0)
27 | ret = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0x92C9FFC2, 0xB72C75A4, (uintptr_t *)&_ksceKernelGetModuleList);
28 | if (ret < 0)
29 | return SCE_KERNEL_START_FAILED;
30 |
31 | ret = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0xC445FA63, 0xD269F915, (uintptr_t *)&_ksceKernelGetModuleInfo);
32 | if (ret < 0)
33 | ret = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0x92C9FFC2, 0xDAA90093, (uintptr_t *)&_ksceKernelGetModuleInfo);
34 | if (ret < 0)
35 | return SCE_KERNEL_START_FAILED;
36 |
37 | ret = _ksceKernelGetModuleList(KERNEL_PID, 0x7FFFFFFF, 1, modlist, &count);
38 | if (ret < 0)
39 | return SCE_KERNEL_START_FAILED;
40 |
41 | info.size = sizeof(SceKernelModuleInfo);
42 | ret = _ksceKernelGetModuleInfo(KERNEL_PID, modlist[1], &info);
43 | if (ret < 0)
44 | return SCE_KERNEL_START_FAILED;
45 |
46 | // second last kernel module must be either taihen or HENkaku
47 | if (strcmp(info.module_name, "taihen") != 0 && strcmp(info.module_name, "HENkaku") != 0)
48 | return SCE_KERNEL_START_FAILED;
49 |
50 | ret = _ksceKernelGetModuleList(ksceKernelGetProcessId(), 0x7FFFFFFF, 1, modlist, &count);
51 | if (ret < 0)
52 | return SCE_KERNEL_START_FAILED;
53 |
54 | info.size = sizeof(SceKernelModuleInfo);
55 | ret = _ksceKernelGetModuleInfo(ksceKernelGetProcessId(), modlist[0], &info);
56 | if (ret < 0)
57 | return SCE_KERNEL_START_FAILED;
58 |
59 | // last user module must be SceAppUtil
60 | if (strcmp(info.module_name, "SceAppUtil") != 0)
61 | return SCE_KERNEL_START_FAILED;
62 |
63 | return SCE_KERNEL_START_SUCCESS;
64 | }
65 |
66 | int module_stop(SceSize args, void *argp) {
67 | return SCE_KERNEL_STOP_SUCCESS;
68 | }
--------------------------------------------------------------------------------
/henkaku/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
4 | if(DEFINED ENV{VITASDK})
5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
6 | else()
7 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
8 | endif()
9 | endif()
10 |
11 | project(HENkaku)
12 | include("${VITASDK}/share/vita.cmake" REQUIRED)
13 |
14 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -fshort-wchar -O3 -std=gnu99")
15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -fno-exceptions")
16 |
17 | include_directories(
18 | )
19 |
20 | link_directories(
21 | ${CMAKE_CURRENT_BINARY_DIR}/henkaku-stubs
22 | )
23 |
24 | if (NOT ${RELEASE})
25 | add_definitions(-DENABLE_LOGGING)
26 | endif()
27 |
28 | # Builds
29 | function(ADD_RESOURCES out_var)
30 | set(result)
31 | foreach(in_f ${ARGN})
32 | set(out_f "${CMAKE_CURRENT_BINARY_DIR}/${in_f}.o")
33 | get_filename_component(out_dir ${out_f} DIRECTORY)
34 | add_custom_command(OUTPUT ${out_f}
35 | COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
36 | COMMAND ${CMAKE_LINKER} -r -b binary -o ${out_f} ${in_f}
37 | DEPENDS ${in_f}
38 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
39 | COMMENT "Building resource ${out_f}"
40 | VERBATIM
41 | )
42 | list(APPEND result ${out_f})
43 | endforeach()
44 | set(${out_var} "${result}" PARENT_SCOPE)
45 | endfunction()
46 |
47 | file(GLOB res_files RELATIVE ${CMAKE_SOURCE_DIR} *.xml)
48 | add_resources(xml_res ${res_files})
49 |
50 | add_executable(user
51 | ${xml_res}
52 | user.c
53 | )
54 |
55 | add_executable(kernel
56 | kernel.c
57 | )
58 |
59 | target_link_libraries(user
60 | taihen_stub
61 | HENkaku_stub
62 | SceLibKernel_stub
63 | SceIofilemgr_stub
64 | SceRegistryMgr_stub
65 | ScePower_stub
66 | SceVshBridge_stub
67 | )
68 |
69 | target_link_libraries(kernel
70 | gcc
71 | taihenForKernel_stub
72 | SceSysmemForDriver_stub
73 | SceSysclibForDriver_stub
74 | SceIofilemgrForDriver_stub
75 | SceDebugForDriver_stub
76 | SceModulemgrForDriver_stub
77 | SceThreadmgrForDriver_stub
78 | SceSysrootForKernel_stub
79 | )
80 |
81 | add_dependencies(user henkaku-stubs)
82 |
83 | set_target_properties(kernel
84 | PROPERTIES LINK_FLAGS "-nostdlib"
85 | COMPILE_FLAGS "-D__VITA_KERNEL__"
86 | )
87 |
88 | set_target_properties(user
89 | PROPERTIES LINK_FLAGS "-nostdlib"
90 | )
91 |
92 | vita_create_self(henkaku.skprx kernel
93 | UNSAFE
94 | CONFIG ${CMAKE_SOURCE_DIR}/kernel.yml
95 | )
96 | vita_create_stubs(henkaku-stubs kernel ${CMAKE_SOURCE_DIR}/kernel.yml
97 | KERNEL
98 | )
99 | vita_create_self(henkaku.suprx user
100 | UNSAFE
101 | CONFIG ${CMAKE_SOURCE_DIR}/user.yml
102 | )
103 |
104 | install(DIRECTORY ${CMAKE_BINARY_DIR}/henkaku-stubs/
105 | DESTINATION lib
106 | FILES_MATCHING PATTERN "*.a"
107 | )
108 |
--------------------------------------------------------------------------------
/henkaku/henkaku_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
18 |
19 |
20 |
24 |
25 |
26 |
32 |
33 |
34 |
38 |
41 |
44 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
62 |
63 |
64 |
68 |
69 |
70 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/enso/first.c:
--------------------------------------------------------------------------------
1 | /* first.c -- fixup environment and exec second payload
2 | *
3 | * Copyright (C) 2017 molecule
4 | *
5 | * This software may be modified and distributed under the terms
6 | * of the MIT license. See the LICENSE file for details.
7 | */
8 | #include
9 | #include "nsbl.h"
10 |
11 | // ALL OFFSETS ARE SPECIFIC TO 3.65
12 |
13 | #define SECOND_PAYLOAD_OFFSET (5)
14 | #define SECOND_PAYLOAD_SIZE (0x4000)
15 |
16 | void go(void) {
17 | printf("first\n");
18 | // first payload reinits os0 device and reads second payload from emmc
19 | // this is because we only have 0x180 bytes for first payload
20 |
21 | memset((char*)0x511673A0, 0, 0x600); // clean after us
22 |
23 | // we need to patch call to read block 1 instead of block 0 as the master block
24 | // now that we store a copy of real partition table in block 1
25 | *(uint16_t*)0x510202CE = 0x2101; // movs r1, #1
26 |
27 | clean_dcache((void *)0x510202C0, 0x20);
28 | flush_icache();
29 |
30 | // reinit os0_dev
31 | int (*fat_init_dev)() = (void*)0x5101FF21;
32 | char *os0_dev = (void*)0x51167784;
33 | int ret = fat_init_dev(os0_dev, 0x110000, 0x510010FD, 0x51028010); // os0_dev, flags, read_block, some_storage
34 |
35 | // TODO: what do these do? but we need them for some reason
36 | *(uint32_t*)(os0_dev + 0x2C) = 0;
37 | *(uint32_t*)(os0_dev + 0x78) = 0x1A000100;
38 | *(uint32_t*)(os0_dev + 0x84) = 0x1A001000;
39 | *(uint32_t*)(os0_dev + 0x90) = 0x0001002B;
40 |
41 | // restore corrupted boot args with our copy
42 | memcpy(boot_args, (*sysroot_ctx_ptr)->boot_args, sizeof(*boot_args));
43 |
44 | // allocate buffer for code
45 | SceKernelAllocMemBlockKernelOpt opt;
46 | int blk;
47 | void *base;
48 | void (*f)();
49 | memset(&opt, 0, sizeof(opt));
50 | opt.size = sizeof(opt);
51 | opt.attr = 0xA0400000;
52 | blk = sceKernelAllocMemBlock("", 0x1020D006, SECOND_PAYLOAD_SIZE, NULL);
53 | f = NULL;
54 | if (blk >= 0) {
55 | if (sceKernelGetMemBlockBase(blk, &base) >= 0) {
56 | // read code buffer
57 | if (read_block_os0(0x51028010, SECOND_PAYLOAD_OFFSET, SECOND_PAYLOAD_SIZE/512, base) >= 0) {
58 | // TODO: perhaps add some simple integrity check here?
59 | if (sceKernelRemapBlock(blk, 0x1020D005) >= 0) {
60 | clean_dcache(base, SECOND_PAYLOAD_SIZE);
61 | flush_icache();
62 | f = (void*)(base + 1);
63 | }
64 | }
65 | }
66 | }
67 |
68 | // fallback: if for some reason we weren't able to allocate/read the payload, then don't run it
69 | if (f != NULL) {
70 | f();
71 | }
72 |
73 | // restore context and resume boot
74 |
75 | uint32_t *sp = *(uint32_t**)(0x51030100 + 0x220); // sp top for core 0
76 | uint32_t *old_sp = sp - 0x11d;
77 |
78 | // r0: 0x51167784 os0_dev
79 | // r1: 0xfffffffe
80 | // r2: sp - 0x110
81 | // r3: 0
82 |
83 | __asm__ volatile (
84 | "movw r0, #0x7784\n"
85 | "movt r0, #0x5116\n"
86 | "movw r1, #0xfffe\n"
87 | "movt r1, #0xffff\n"
88 | "mov r2, %0\n"
89 | "mov r3, #0\n"
90 | "mov sp, %1\n"
91 | "mov r4, %2\n"
92 | "bx r4\n" :: "r" (sp - 0x110), "r" (old_sp), "r" (0x5101F779) : "r0", "r1", "r2", "r3", "r4"
93 | );
94 | }
95 |
96 | __attribute__ ((section (".text.start"), naked)) void start(void) {
97 | __asm__ volatile (
98 | "mov r0, #0\n"
99 | "movt r0, #0x51f0\n"
100 | "mov sp, r0\n"
101 | "b go\n"
102 | );
103 | }
104 |
--------------------------------------------------------------------------------
/installer/src/user.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | static tai_hook_ref_t sceSblSsUpdateMgrGetBootModeRef;
11 | static tai_hook_ref_t sceSblSsUpdateMgrSendCommandRef;
12 | static tai_hook_ref_t sceIoRemoveRef;
13 |
14 | static SceUID hooks[6];
15 |
16 | static char ux0_data_patch[] = "ux0:/data";
17 | static char ud0_psp2update_ensoswu_self_patch[] = "ud0:/PSP2UPDATE/ensoswu.self";
18 | static char ud0_psp2update_ensoupdat_pup_patch[] = "ud0:/PSP2UPDATE/ENSOUPDAT.PUP";
19 |
20 | int sceSblSsUpdateMgrGetBootModePatched(int *mode) {
21 | int ret;
22 | ret = TAI_CONTINUE(int, sceSblSsUpdateMgrGetBootModeRef, mode);
23 | *mode = 0x40; // GUI
24 | return ret;
25 | }
26 |
27 | int sceSblSsUpdateMgrSendCommandPatched(int cmd, int arg) {
28 | if (cmd == 0 || cmd == 1) {
29 | sceKernelPowerUnlock(0);
30 | }
31 |
32 | return TAI_CONTINUE(int, sceSblSsUpdateMgrSendCommandRef, cmd, arg);
33 | }
34 |
35 | // when launching with ksceAppMgrLaunchAppByPath the whole directory is blocked,
36 | // so we will get an error when trying to remove a file
37 | int sceIoRemovePatched(const char *file) {
38 | TAI_CONTINUE(int, sceIoRemoveRef, file);
39 | return 0; // always return ok
40 | }
41 |
42 | void _start() __attribute__ ((weak, alias("module_start")));
43 | int module_start(SceSize args, void *argp) {
44 | int res;
45 | tai_module_info_t info;
46 |
47 | // lock system
48 | res = sceKernelPowerLock(0);
49 | res |= sceShellUtilInitEvents(0);
50 | res |= sceShellUtilLock(0xFFF);
51 | res |= sceAppMgrDestroyOtherApp();
52 | if (res < 0)
53 | return SCE_KERNEL_START_FAILED;
54 |
55 | info.size = sizeof(tai_module_info_t);
56 | if (taiGetModuleInfo("ScePsp2Swu", &info) < 0)
57 | return SCE_KERNEL_START_FAILED;
58 |
59 | hooks[0] = taiHookFunctionImport(&sceSblSsUpdateMgrGetBootModeRef, "ScePsp2Swu", 0x31406C49, 0x8E834565, sceSblSsUpdateMgrGetBootModePatched);
60 | if (hooks[0] < 0)
61 | return SCE_KERNEL_START_FAILED;
62 |
63 | hooks[1] = taiHookFunctionImport(&sceSblSsUpdateMgrSendCommandRef, "ScePsp2Swu", 0x31406C49, 0x1825D954, sceSblSsUpdateMgrSendCommandPatched);
64 | if (hooks[1] < 0)
65 | return SCE_KERNEL_START_FAILED;
66 |
67 | hooks[2] = taiHookFunctionImport(&sceIoRemoveRef, "ScePsp2Swu", 0xCAE9ACE6, 0xE20ED0F3, sceIoRemovePatched);
68 | if (hooks[2] < 0)
69 | return SCE_KERNEL_START_FAILED;
70 |
71 | hooks[3] = taiInjectData(info.modid, 0, 0x2EB408, ux0_data_patch, sizeof(ux0_data_patch));
72 | if (hooks[3] < 0)
73 | return SCE_KERNEL_START_FAILED;
74 |
75 | hooks[4] = taiInjectData(info.modid, 0, 0x2EB428, ud0_psp2update_ensoswu_self_patch, sizeof(ud0_psp2update_ensoswu_self_patch));
76 | if (hooks[4] < 0)
77 | return SCE_KERNEL_START_FAILED;
78 |
79 | hooks[5] = taiInjectData(info.modid, 0, 0x2EB448, ud0_psp2update_ensoupdat_pup_patch, sizeof(ud0_psp2update_ensoupdat_pup_patch));
80 | if (hooks[5] < 0)
81 | return SCE_KERNEL_START_FAILED;
82 |
83 | return SCE_KERNEL_START_SUCCESS;
84 | }
85 |
86 | int module_stop(SceSize args, void *argp) {
87 | if (hooks[5] >= 0)
88 | taiInjectRelease(hooks[5]);
89 | if (hooks[4] >= 0)
90 | taiInjectRelease(hooks[4]);
91 | if (hooks[3] >= 0)
92 | taiInjectRelease(hooks[3]);
93 | if (hooks[2] >= 0)
94 | taiHookRelease(hooks[2], sceIoRemoveRef);
95 | if (hooks[1] >= 0)
96 | taiHookRelease(hooks[1], sceSblSsUpdateMgrSendCommandRef);
97 | if (hooks[0] >= 0)
98 | taiHookRelease(hooks[0], sceSblSsUpdateMgrGetBootModeRef);
99 |
100 | return SCE_KERNEL_STOP_SUCCESS;
101 | }
--------------------------------------------------------------------------------
/henkaku/system_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
36 |
37 |
38 |
42 |
43 |
44 |
48 |
49 |
50 |
54 |
55 |
56 |
60 |
61 |
62 |
66 |
67 |
68 |
72 |
73 |
74 |
78 |
79 |
80 |
84 |
85 |
86 |
90 |
91 |
92 |
96 |
97 |
98 |
102 |
103 |
104 |
108 |
109 |
110 |
114 |
115 |
116 |
120 |
121 |
122 |
126 |
127 |
128 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/installer/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8)
2 |
3 | if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
4 | if(DEFINED ENV{VITASDK})
5 | set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
6 | else()
7 | message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
8 | endif()
9 | endif()
10 |
11 | set(SHORT_NAME updater)
12 | project(${SHORT_NAME})
13 | include("${VITASDK}/share/vita.cmake" REQUIRED)
14 |
15 | set(VITA_APP_NAME "3.65 HENkaku Ensō Updater")
16 | set(VITA_TITLEID "UPDATE365")
17 |
18 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
19 | set(VITA_MAKE_FSELF_FLAGS "${VITA_MAKE_FSELF_FLAGS} -a 0x2808000000000000")
20 |
21 | link_directories(
22 | ${CMAKE_BINARY_DIR}/kernel_stubs
23 | ${CMAKE_BINARY_DIR}/user_stubs
24 | )
25 |
26 | # Builds
27 | function(ADD_RESOURCES out_var)
28 | set(result)
29 | foreach(in_f ${ARGN})
30 | set(out_f "${CMAKE_CURRENT_BINARY_DIR}/${in_f}.o")
31 | get_filename_component(out_dir ${out_f} DIRECTORY)
32 | add_custom_command(OUTPUT ${out_f}
33 | COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
34 | COMMAND ${CMAKE_LINKER} -r -b binary -o ${out_f} ${in_f}
35 | DEPENDS ${in_f}
36 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
37 | COMMENT "Building resource ${out_f}"
38 | VERBATIM
39 | )
40 | list(APPEND result ${out_f})
41 | endforeach()
42 | set(${out_var} "${result}" PARENT_SCOPE)
43 | endfunction()
44 |
45 | file(GLOB res_files RELATIVE
46 | ${CMAKE_SOURCE_DIR}
47 | res/fat.bin
48 | res/taihen.skprx
49 | res/henkaku.skprx
50 | res/henkaku.suprx
51 | )
52 | add_resources(enso_res ${res_files})
53 |
54 | add_executable(${SHORT_NAME}
55 | src/main.c
56 | src/sha256.c
57 | src/scr_printf.c
58 | src/font.c
59 | )
60 |
61 | add_dependencies(${SHORT_NAME} kernel.skprx)
62 |
63 | target_link_libraries(${SHORT_NAME}
64 | taihen_stub
65 | SceAppMgr_stub
66 | SceCtrl_stub
67 | SceDisplay_stub
68 | SceHttp_stub
69 | SceNet_stub
70 | SceNetCtl_stub
71 | ScePower_stub
72 | SceSblUpdateMgr_stub
73 | SceSsl_stub
74 | SceSysmodule_stub
75 | SceVshBridge_stub
76 | )
77 |
78 | vita_create_self(${SHORT_NAME}.self ${SHORT_NAME} UNSAFE)
79 |
80 | add_executable(kernel
81 | ${enso_res}
82 | src/kernel.c
83 | src/crc32.c
84 | )
85 | set_target_properties(kernel
86 | PROPERTIES LINK_FLAGS
87 | -nostdlib
88 | )
89 | target_link_libraries(kernel
90 | k
91 | gcc
92 | SceAppMgrForDriver_stub
93 | SceThreadmgrForDriver_stub
94 | SceModulemgrForDriver_stub
95 | SceSblAIMgrForDriver_stub
96 | SceIofilemgrForDriver_stub
97 | SceSysmemForDriver_stub
98 | SceSysrootForKernel_stub
99 | taihenForKernel_stub
100 | taihenModuleUtils_stub
101 | )
102 | vita_create_self(kernel.skprx kernel
103 | CONFIG ${CMAKE_SOURCE_DIR}/src/kernel_exports.yml
104 | UNSAFE
105 | )
106 | vita_create_stubs(kernel_stubs kernel ${CMAKE_SOURCE_DIR}/src/kernel_exports.yml KERNEL)
107 |
108 | add_executable(kernel2
109 | src/kernel2.c
110 | )
111 | set_target_properties(kernel2
112 | PROPERTIES LINK_FLAGS
113 | -nostdlib
114 | )
115 | target_link_libraries(kernel2
116 | gcc
117 | taihenForKernel_stub
118 | taihenModuleUtils_stub
119 | SceSysclibForDriver_stub
120 | SceThreadmgrForDriver_stub
121 | )
122 | vita_create_self(kernel2.skprx kernel2
123 | CONFIG ${CMAKE_SOURCE_DIR}/src/kernel2.yml
124 | UNSAFE
125 | )
126 |
127 | add_executable(user
128 | src/user.c
129 | )
130 | set_target_properties(user
131 | PROPERTIES LINK_FLAGS
132 | -nostartfiles
133 | )
134 | target_link_libraries(user
135 | taihen_stub
136 | SceAppMgr_stub
137 | SceShellSvc_stub
138 | )
139 | vita_create_self(user.suprx user
140 | CONFIG ${CMAKE_SOURCE_DIR}/src/user_exports.yml
141 | UNSAFE
142 | )
143 | vita_create_stubs(user_stubs user ${CMAKE_SOURCE_DIR}/src/user_exports.yml)
144 |
145 | add_dependencies(user kernel_stubs)
146 | add_dependencies(${SHORT_NAME} user_stubs)
147 | add_dependencies(${SHORT_NAME} kernel.skprx)
148 | add_dependencies(${SHORT_NAME} kernel2.skprx)
149 | add_dependencies(${SHORT_NAME} user.suprx)
150 |
151 | vita_create_vpk(${SHORT_NAME}.vpk ${VITA_TITLEID} ${SHORT_NAME}.self
152 | VERSION ${VITA_VERSION}
153 | NAME ${VITA_APP_NAME}
154 | FILE ${CMAKE_BINARY_DIR}/kernel.skprx kernel.skprx
155 | FILE ${CMAKE_BINARY_DIR}/kernel2.skprx kernel2.skprx
156 | FILE ${CMAKE_BINARY_DIR}/user.suprx user.suprx
157 | FILE ${CMAKE_SOURCE_DIR}/res/pkg/icon0.png sce_sys/icon0.png
158 | FILE ${CMAKE_SOURCE_DIR}/res/pkg/template.xml sce_sys/livearea/contents/template.xml
159 | FILE ${CMAKE_SOURCE_DIR}/res/pkg/bg0.png sce_sys/livearea/contents/bg0.png
160 | FILE ${CMAKE_SOURCE_DIR}/res/pkg/startup.png sce_sys/livearea/contents/startup.png
161 | )
162 |
--------------------------------------------------------------------------------
/installer/src/pspdebug.h:
--------------------------------------------------------------------------------
1 | /*
2 | * PSP Software Development Kit - http://www.psvdev.org
3 | * -----------------------------------------------------------------------
4 | * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
5 | *
6 | * pspdebug.h - Prototypes for the psvDebug library
7 | *
8 | * Copyright (c) 2005 Marcus R. Brown
9 | * Copyright (c) 2005 James Forshaw
10 | * Copyright (c) 2005 John Kelley
11 | *
12 | * $Id: pspdebug.h 2450 2009-01-04 23:53:02Z oopo $
13 | */
14 | #ifndef __DEBUG_H__
15 | #define __DEBUG_H__
16 |
17 | #ifdef __cplusplus
18 | extern "C" {
19 | #endif
20 |
21 | /** @defgroup Debug Debug Utility Library */
22 |
23 | /** @addtogroup Debug */
24 | /*@{*/
25 |
26 | /**
27 | * Initialise the debug screen
28 | */
29 | void psvDebugScreenInit(void);
30 |
31 | /**
32 | * Extended debug screen init
33 | *
34 | * @param vram_base - Base address of frame buffer, if NULL then sets a default
35 | * @param mode - Colour mode
36 | * @param setup - Setup the screen if 1
37 | */
38 | void psvDebugScreenInitEx(void *vram_base, int mode, int setup);
39 |
40 | /**
41 | * Do a printf to the debug screen.
42 | *
43 | * @param fmt - Format string to print
44 | * @param ... - Arguments
45 | */
46 | void psvDebugScreenPrintf(const char *fmt, ...) __attribute__((format(printf,1,2)));
47 |
48 | /**
49 | * Enable or disable background colour writing (defaults to enabled)
50 | *
51 | * @param enable - Set 1 to to enable background color, 0 for disable
52 | */
53 | void psvDebugScreenEnableBackColor(int enable);
54 |
55 | /**
56 | * Set the background color for the text
57 | * @note To reset the entire screens bg colour you need to call psvDebugScreenClear
58 | *
59 | * @param color - A 32bit RGB colour
60 | */
61 | void psvDebugScreenSetBackColor(uint32_t color);
62 |
63 | /**
64 | * Set the text color
65 | *
66 | * @param color - A 32 bit RGB color
67 | */
68 | void psvDebugScreenSetTextColor(uint32_t color);
69 |
70 | /**
71 | * Set the color mode (you must have switched the frame buffer appropriately)
72 | *
73 | * @param mode - Color mode
74 | */
75 | void psvDebugScreenSetColorMode(int mode);
76 |
77 | /**
78 | * Draw a single character to the screen.
79 | *
80 | * @param x - The x co-ordinate to draw to (pixel units)
81 | * @param y - The y co-ordinate to draw to (pixel units)
82 | * @param color - The text color to draw
83 | * @param ch - The character to draw
84 | */
85 | void psvDebugScreenPutChar(int x, int y, uint32_t color, uint8_t ch);
86 |
87 | /**
88 | * Set the current X and Y co-ordinate for the screen (in character units)
89 | */
90 | void psvDebugScreenSetXY(int x, int y);
91 |
92 | /**
93 | * Set the video ram offset used for the screen
94 | *
95 | * @param offset - Offset in bytes
96 | */
97 | void psvDebugScreenSetOffset(int offset);
98 |
99 | /**
100 | * Set the video ram base used for the screen
101 | *
102 | * @param base - Base address in bytes
103 | */
104 | void psvDebugScreenSetBase(uint32_t* base);
105 |
106 | /**
107 | * Get the current X co-ordinate (in character units)
108 | *
109 | * @return The X co-ordinate
110 | */
111 | int psvDebugScreenGetX(void);
112 |
113 | /**
114 | * Get the current Y co-ordinate (in character units)
115 | *
116 | * @return The Y co-ordinate
117 | */
118 | int psvDebugScreenGetY(void);
119 |
120 | /**
121 | * Clear the debug screen.
122 | */
123 | void psvDebugScreenClear(void);
124 |
125 | /**
126 | * Print non-nul terminated strings.
127 | *
128 | * @param buff - Buffer containing the text.
129 | * @param size - Size of the data
130 | *
131 | * @return The number of characters written
132 | */
133 | int psvDebugScreenPrintData(const char *buff, int size);
134 |
135 | /**
136 | * Print a string
137 | *
138 | * @param str - String
139 | *
140 | * @return The number of characters written
141 | */
142 | int psvDebugScreenPuts(const char *str);
143 |
144 | /**
145 | * Get a MIPS stack trace (might work :P)
146 | *
147 | * @param results - List of points to store the results of the trace, (up to max)
148 | * @param max - Maximum number of back traces
149 | *
150 | * @return The number of frames stored in results.
151 | */
152 | int psvDebugGetStackTrace(unsigned int* results, int max);
153 |
154 | /**
155 | * Enable the clear line function that allows debug to clear the screen
156 | */
157 | void psvDebugScreenClearLineEnable(void);
158 |
159 | /**
160 | * Disable the clear line function that causes flicker on constant refreshes
161 | */
162 | void psvDebugScreenClearLineDisable(void);
163 |
164 | /*@}*/
165 |
166 | #ifdef __cplusplus
167 | }
168 | #endif
169 |
170 | #endif
--------------------------------------------------------------------------------
/installer/src/crc32.c:
--------------------------------------------------------------------------------
1 | /*-
2 | * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
3 | * code or tables extracted from it, as desired without restriction.
4 | *
5 | * First, the polynomial itself and its table of feedback terms. The
6 | * polynomial is
7 | * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
8 | *
9 | * Note that we take it "backwards" and put the highest-order term in
10 | * the lowest-order bit. The X^32 term is "implied"; the LSB is the
11 | * X^31 term, etc. The X^0 term (usually shown as "+1") results in
12 | * the MSB being 1
13 | *
14 | * Note that the usual hardware shift register implementation, which
15 | * is what we're using (we're merely optimizing it by doing eight-bit
16 | * chunks at a time) shifts bits into the lowest-order term. In our
17 | * implementation, that means shifting towards the right. Why do we
18 | * do it this way? Because the calculated CRC must be transmitted in
19 | * order from highest-order term to lowest-order term. UARTs transmit
20 | * characters in order from LSB to MSB. By storing the CRC this way
21 | * we hand it to the UART in the order low-byte to high-byte; the UART
22 | * sends each low-bit to hight-bit; and the result is transmission bit
23 | * by bit from highest- to lowest-order term without requiring any bit
24 | * shuffling on our part. Reception works similarly
25 | *
26 | * The feedback terms table consists of 256, 32-bit entries. Notes
27 | *
28 | * The table can be generated at runtime if desired; code to do so
29 | * is shown later. It might not be obvious, but the feedback
30 | * terms simply represent the results of eight shift/xor opera
31 | * tions for all combinations of data and CRC register values
32 | *
33 | * The values must be right-shifted by eight bits by the "updcrc
34 | * logic; the shift must be unsigned (bring in zeroes). On some
35 | * hardware you could probably optimize the shift in assembler by
36 | * using byte-swap instructions
37 | * polynomial $edb88320
38 | *
39 | *
40 | * CRC32 code derived from work by Gary S. Brown.
41 | */
42 |
43 | #include
44 | #include
45 |
46 | static uint32_t crc32_tab[] = {
47 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
48 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
49 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
50 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
51 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
52 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
53 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
54 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
55 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
56 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
57 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
58 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
59 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
60 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
61 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
62 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
63 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
64 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
65 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
66 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
67 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
68 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
69 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
70 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
71 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
72 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
73 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
74 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
75 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
76 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
77 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
78 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
79 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
80 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
81 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
82 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
83 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
84 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
85 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
86 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
87 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
88 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
89 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
90 | };
91 |
92 | uint32_t
93 | crc32(uint32_t crc, const void *buf, size_t size)
94 | {
95 | const uint8_t *p;
96 |
97 | p = buf;
98 | crc = crc ^ ~0U;
99 |
100 | while (size--)
101 | crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
102 |
103 | return crc ^ ~0U;
104 | }
105 |
--------------------------------------------------------------------------------
/installer/src/sha256.c:
--------------------------------------------------------------------------------
1 | /*********************************************************************
2 | * Filename: sha256.c
3 | * Author: Brad Conte (brad AT bradconte.com)
4 | * Copyright:
5 | * Disclaimer: This code is presented "as is" without any guarantees.
6 | * Details: Implementation of the SHA-256 hashing algorithm.
7 | SHA-256 is one of the three algorithms in the SHA2
8 | specification. The others, SHA-384 and SHA-512, are not
9 | offered in this implementation.
10 | Algorithm specification can be found here:
11 | * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
12 | This implementation uses little endian byte order.
13 | *********************************************************************/
14 |
15 | /*************************** HEADER FILES ***************************/
16 | #include
17 | #include
18 | #include "sha256.h"
19 |
20 | /****************************** MACROS ******************************/
21 | #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
22 | #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
23 |
24 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
25 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
26 | #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
27 | #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
28 | #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
29 | #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
30 |
31 | /**************************** VARIABLES *****************************/
32 | static const WORD k[64] = {
33 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
34 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
35 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
36 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
37 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
38 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
39 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
40 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
41 | };
42 |
43 | /*********************** FUNCTION DEFINITIONS ***********************/
44 | void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
45 | {
46 | WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
47 |
48 | for (i = 0, j = 0; i < 16; ++i, j += 4)
49 | m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
50 | for ( ; i < 64; ++i)
51 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
52 |
53 | a = ctx->state[0];
54 | b = ctx->state[1];
55 | c = ctx->state[2];
56 | d = ctx->state[3];
57 | e = ctx->state[4];
58 | f = ctx->state[5];
59 | g = ctx->state[6];
60 | h = ctx->state[7];
61 |
62 | for (i = 0; i < 64; ++i) {
63 | t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
64 | t2 = EP0(a) + MAJ(a,b,c);
65 | h = g;
66 | g = f;
67 | f = e;
68 | e = d + t1;
69 | d = c;
70 | c = b;
71 | b = a;
72 | a = t1 + t2;
73 | }
74 |
75 | ctx->state[0] += a;
76 | ctx->state[1] += b;
77 | ctx->state[2] += c;
78 | ctx->state[3] += d;
79 | ctx->state[4] += e;
80 | ctx->state[5] += f;
81 | ctx->state[6] += g;
82 | ctx->state[7] += h;
83 | }
84 |
85 | void sha256_init(SHA256_CTX *ctx)
86 | {
87 | ctx->datalen = 0;
88 | ctx->bitlen = 0;
89 | ctx->state[0] = 0x6a09e667;
90 | ctx->state[1] = 0xbb67ae85;
91 | ctx->state[2] = 0x3c6ef372;
92 | ctx->state[3] = 0xa54ff53a;
93 | ctx->state[4] = 0x510e527f;
94 | ctx->state[5] = 0x9b05688c;
95 | ctx->state[6] = 0x1f83d9ab;
96 | ctx->state[7] = 0x5be0cd19;
97 | }
98 |
99 | void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
100 | {
101 | WORD i;
102 |
103 | for (i = 0; i < len; ++i) {
104 | ctx->data[ctx->datalen] = data[i];
105 | ctx->datalen++;
106 | if (ctx->datalen == 64) {
107 | sha256_transform(ctx, ctx->data);
108 | ctx->bitlen += 512;
109 | ctx->datalen = 0;
110 | }
111 | }
112 | }
113 |
114 | void sha256_final(SHA256_CTX *ctx, BYTE hash[])
115 | {
116 | WORD i;
117 |
118 | i = ctx->datalen;
119 |
120 | // Pad whatever data is left in the buffer.
121 | if (ctx->datalen < 56) {
122 | ctx->data[i++] = 0x80;
123 | while (i < 56)
124 | ctx->data[i++] = 0x00;
125 | }
126 | else {
127 | ctx->data[i++] = 0x80;
128 | while (i < 64)
129 | ctx->data[i++] = 0x00;
130 | sha256_transform(ctx, ctx->data);
131 | memset(ctx->data, 0, 56);
132 | }
133 |
134 | // Append to the padding the total message's length in bits and transform.
135 | ctx->bitlen += ctx->datalen * 8;
136 | ctx->data[63] = ctx->bitlen;
137 | ctx->data[62] = ctx->bitlen >> 8;
138 | ctx->data[61] = ctx->bitlen >> 16;
139 | ctx->data[60] = ctx->bitlen >> 24;
140 | ctx->data[59] = ctx->bitlen >> 32;
141 | ctx->data[58] = ctx->bitlen >> 40;
142 | ctx->data[57] = ctx->bitlen >> 48;
143 | ctx->data[56] = ctx->bitlen >> 56;
144 | sha256_transform(ctx, ctx->data);
145 |
146 | // Since this implementation uses little endian byte ordering and SHA uses big endian,
147 | // reverse all the bytes when copying the final state to the output hash.
148 | for (i = 0; i < 4; ++i) {
149 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
150 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
151 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
152 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
153 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
154 | hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
155 | hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
156 | hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 3.65 HENkaku Ensō Updater
2 |
3 | ## This software is outdated, please use the [real enso installer](https://github.com/TheOfficialFloW/enso/releases)
4 |
5 | Custom Firmware 3.65 HENkaku Ensō is a port of [henkaku](https://github.com/henkaku) to the latest possible firmware that does still have the bootloader vulnerability.
6 |
7 | ## Pros and cons
8 | ### Pros
9 | - You will be able to access the PSN store, activate your device and download your purchased games again (only as long as Sony doesn't decide to release a new update that prevents you from doing that).
10 | - You will be able to play all games that were released for firmwares 3.61-3.65.
11 | ### Cons
12 | - You will not be able to downgrade back to 3.60 if you find that this custom firmware doesn't suit you.
13 | - You can lose the ability to run homebrews, if you modify the OS and end up in a semi-brick where you are forced to reinstall the firmware. This should however not happen to a regular user, but I'd rather not install applications that modify read-only partitions like `os0:` or `vs0:`.
14 | - Some applications may not work on the new firmware and need to be ported.
15 |
16 | ## Instructions
17 | 1) If you are on a firmware below 3.60, update to 3.60 and install [henkaku](https://henkaku.xyz/).
18 | 2) Update [VitaShell](https://github.com/TheOfficialFloW/VitaShell/releases) to v1.82 or later (if you get an error when trying to install the vpk, simply rename the vpk to zip and manually copy the `eboot.bin` file to `ux0:app/VITASHELL/eboot.bin`).
19 | 3) Make a CMA backup of VitaShell. **This is very important, since if you lose VitaShell, this is the way you restore it**.
20 | 4) Download [updater.vpk](https://github.com/TheOfficialFloW/update365/releases/download/v1.0/updater.vpk) and [PSP2UPDAT.PUP](https://github.com/TheOfficialFloW/update365/releases/download/v1.0/PSP2UPDAT.PUP).
21 | 5) Install `updater.vpk` using `VitaShell` and put the `PSP2UPDAT.PUP` file at `ux0:app/UPDATE365/PSP2UPDAT.PUP`.
22 | 6) If you have already been using 3.60 HENkaku (Enso), uninstall all plugins and uninstall the enso patch. It is recommended to first unlink the Memory Card in `HENkaku Settings` (**NOT FORMAT**) just before you uninstall enso, so that your Memory Card won't be restricted afterwards due to the spoofed version at `ux0:id.dat`. Uninstalling all plugins and the enso patch is extremely important, as they can interfere with the update process if enabled (the updater will notice you in case you have not uninstalled them correctly).
23 | 7) Reboot your device, start HENkaku and directly launch the updater, without launching anything else before like VitaShell or Adrenaline (since they start kernel modules). Also make sure that your battery is at least at 50%.
24 | 8) Follow the instructions on screen and enjoy the update process.
25 | 9) When the updater finishes flashing the new firmware, custom modules will be written to `vs0:tai` and the bootloader hack injected to the eMMC. You should now be on 3.65 HENkaku Ensō.
26 |
27 | ## FAQ
28 | - "Are Adrenaline, DownloadEnabler, NoNpDrm and SD2VITA compatible on 3.65?" - Yes they have all been updated and are available under my repositories.
29 | - "Is it risky to perform this update?" - All my betatesters have successfully updated and have no issues so far. The updater has been designed carefully, so you don't need to worry.
30 | - "Will I lose the hack if I format my Memory Card or restore the systems settings?" - No, you can nearly do everything with your device and you will not lose HENkaku. You must just NOT reinstall the 3.65 PUP.
31 | - "I have installed a bad plugin and now my device doesn't boot anymore" - Try to enter the `Safe Mode` and choose `2. Rebuild Database`. This will allow you to boot the device with plugins disabled and fresh `config.txt` files.
32 | - "Will I be able to hack my device that is on 3.65/3.67?" - Not with this software. I will release my exploit chain by the end of this year or next, so you have to be patient.
33 | - "I have lost molecularShell/VitaShell!" - You proceeded through the updater without carefully reading it. Congratulations! You can simply restore it by using CMA and [psvimgtools](https://github.com/yifanlu/psvimgtools), but since you didn't made a backup as it was CLEARLY stated in the updater, it's your own fault and you will now have to figure out yourself how to solve this problem.
34 | - "I forgot to unlink the Memory Card before uninstalling enso now I can't use it!" - simply start HENkaku again through the browser, open settings app and then choose HENkaku Settings.
35 | - "I have only got a SD2VITA but no Memory Card, how can I update?" - If you are using a PS Vita Slim or PSTV, you can just use the Internal Storage to update, otherwise you can't. When you use SD2VITA you have to use a plugin for that. But plugins are dangerous since they can interfere with the update process which can lead to a brick in the worst case. An other reason is that I want to prevent this scenario: Imagine an user forgets to update the SD2VITA plugin and updates to 3.65, then realizes that the driver is unsupported. He will then be forced to buy a Memory Card in order to do anything with the new custom firmware.
36 |
37 | ## Donation
38 | If you like my work and want to support future projects, you can make a small donation with via bitcoin `361jRJtjppd2iyaAhBGjf9GUCWnunxtZ49`. Thank you!
39 |
40 | ## Compiling
41 | Compile `enso`, `henkaku` and [taihen](https://github.com/TheOfficialFloW/taiHEN), then put the binaries `fat.bin`, `henkaku.suprx`, `henkaku.skprx` and `taihen.skprx` at `installer/res`. Then you can compile the installer. It is however very dangerous to do this by yourself if you don't know what you're doing. One mistake means a bricked device. If you want to only compile the installer, then simply open `updater.vpk` as zip file and use the three binaries from there.
42 |
43 | ## Credits
44 | - [molecule](https://twitter.com/TeamMolecule) for their original work.
45 | - [Mathieulh](https://twitter.com/Mathieulh) for providing his devkit.
46 | - [Freakler](https://twitter.com/freakler94) for his LiveArea design.
47 |
--------------------------------------------------------------------------------
/installer/src/scr_printf.c:
--------------------------------------------------------------------------------
1 | /*
2 | * PSP Software Development Kit - http://www.psvdev.org
3 | * -----------------------------------------------------------------------
4 | * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
5 | *
6 | * scr_printf.c - Debug screen functions.
7 | *
8 | * Copyright (c) 2005 Marcus R. Brown
9 | * Copyright (c) 2005 James Forshaw
10 | * Copyright (c) 2005 John Kelley
11 | *
12 | * $Id: scr_printf.c 2450 2009-01-04 23:53:02Z oopo $
13 | */
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | #include "pspdebug.h"
20 |
21 | #define PSV_SCREEN_WIDTH 960
22 | #define PSV_SCREEN_HEIGHT 544
23 | #define PSV_LINE_SIZE 960
24 |
25 | /* baseado nas libs do Duke... */
26 |
27 | void _psvDebugScreenClearLine( int Y);
28 |
29 | static int X = 0, Y = 0;
30 | static int MX=68, MY=34;
31 | static uint32_t bg_col = 0, fg_col = 0xFFFFFFFF;
32 | static int bg_enable = 1;
33 | static void* g_vram_base = NULL;
34 | static int g_vram_offset = 0;
35 | static int g_vram_mode = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8;
36 | static int init = 0;
37 | static int clearline_en = 1;
38 |
39 | static void clear_screen_32(uint32_t color)
40 | {
41 | int x;
42 | uint32_t *vram = g_vram_base;
43 | vram += (g_vram_offset>>2);
44 |
45 | for(x = 0; x < (PSV_LINE_SIZE * PSV_SCREEN_HEIGHT); x++)
46 | {
47 | *vram++ = color;
48 | }
49 | }
50 |
51 | static void clear_screen(uint32_t color)
52 | {
53 | if(g_vram_mode == SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
54 | {
55 | clear_screen_32(color);
56 | }
57 | }
58 |
59 | #define ALIGN(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
60 |
61 | void psvDebugScreenInitEx(void *vram_base, int mode, int setup)
62 | {
63 | switch(mode)
64 | {
65 | case SCE_DISPLAY_PIXELFORMAT_A8B8G8R8:
66 | break;
67 | default: mode = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8;
68 | };
69 |
70 | X = Y = 0;
71 | /* Place vram in uncached memory */
72 | if(vram_base == NULL)
73 | {
74 | int block = sceKernelAllocMemBlock("", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, ALIGN(PSV_LINE_SIZE * PSV_SCREEN_HEIGHT * 4, 256 * 1024), NULL);
75 | sceKernelGetMemBlockBase(block, &vram_base);
76 | }
77 | g_vram_base = vram_base;
78 | g_vram_offset = 0;
79 | g_vram_mode = mode;
80 | if(setup)
81 | {
82 | SceDisplayFrameBuf framebuf;
83 | framebuf.size = sizeof(SceDisplayFrameBuf);
84 | framebuf.base = (void *)g_vram_base;
85 | framebuf.pitch = PSV_LINE_SIZE;
86 | framebuf.width = PSV_SCREEN_WIDTH;
87 | framebuf.height = PSV_SCREEN_HEIGHT;
88 | framebuf.pixelformat = mode;
89 | sceDisplaySetFrameBuf(&framebuf, 1);
90 | }
91 | clear_screen(bg_col);
92 | init = 1;
93 | }
94 |
95 | void psvDebugScreenInit()
96 | {
97 | X = Y = 0;
98 | psvDebugScreenInitEx(NULL, SCE_DISPLAY_PIXELFORMAT_A8B8G8R8, 1);
99 | }
100 |
101 | void psvDebugScreenEnableBackColor(int enable)
102 | {
103 | bg_enable = enable;
104 | }
105 |
106 | void psvDebugScreenSetBackColor(uint32_t colour)
107 | {
108 | bg_col = colour;
109 | }
110 |
111 | void psvDebugScreenSetTextColor(uint32_t colour)
112 | {
113 | fg_col = colour;
114 | }
115 |
116 | void psvDebugScreenSetColorMode(int mode)
117 | {
118 | switch(mode)
119 | {
120 | case SCE_DISPLAY_PIXELFORMAT_A8B8G8R8:
121 | break;
122 | default: mode = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8;
123 | };
124 |
125 | g_vram_mode = mode;
126 | }
127 |
128 | int psvDebugScreenGetX()
129 | {
130 | return X;
131 | }
132 |
133 | int psvDebugScreenGetY()
134 | {
135 | return Y;
136 | }
137 |
138 | void psvDebugScreenClear()
139 | {
140 | int y;
141 |
142 | if(!init)
143 | {
144 | return;
145 | }
146 |
147 | for(y=0;y=0 ) X=x;
159 | if( y=0 ) Y=y;
160 | }
161 |
162 | void psvDebugScreenSetOffset(int offset)
163 | {
164 | g_vram_offset = offset;
165 | }
166 |
167 | void psvDebugScreenSetBase(uint32_t* base)
168 | {
169 | g_vram_base = base;
170 | }
171 |
172 | extern uint8_t msx[];
173 |
174 | static void debug_put_char_32(int x, int y, uint32_t color, uint32_t bgc, uint8_t ch)
175 | {
176 | int i,j, l;
177 | uint8_t *font;
178 | uint32_t *vram_ptr;
179 | uint32_t *vram;
180 |
181 | if(!init)
182 | {
183 | return;
184 | }
185 |
186 | x *= 2;
187 | y *= 2;
188 |
189 | vram = g_vram_base;
190 | vram += (g_vram_offset >> 2) + x;
191 | vram += (y * PSV_LINE_SIZE);
192 |
193 | font = &msx[ (int)ch * 8];
194 | for (i=l=0; i < 8; i++, l+= 8, font++)
195 | {
196 | vram_ptr = vram;
197 | for (j=0; j < 8; j++)
198 | {
199 | if ((*font & (128 >> j))) {
200 | vram_ptr[0] = color;
201 | vram_ptr[1] = color;
202 | vram_ptr[0 + PSV_LINE_SIZE] = color;
203 | vram_ptr[1 + PSV_LINE_SIZE] = color;
204 | } else if(bg_enable) {
205 | vram_ptr[0] = bgc;
206 | vram_ptr[1] = bgc;
207 | vram_ptr[0 + PSV_LINE_SIZE] = bgc;
208 | vram_ptr[1 + PSV_LINE_SIZE] = bgc;
209 | }
210 |
211 | vram_ptr += 2;
212 | }
213 | vram += 2 * PSV_LINE_SIZE;
214 | }
215 | }
216 |
217 | void
218 | psvDebugScreenPutChar( int x, int y, uint32_t color, uint8_t ch)
219 | {
220 | if(g_vram_mode == SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)
221 | {
222 | debug_put_char_32(x, y, color, bg_col, ch);
223 | }
224 | }
225 |
226 | void _psvDebugScreenClearLine( int Y)
227 | {
228 | if(clearline_en)
229 | {
230 | int i;
231 | if(bg_enable)
232 | {
233 | for (i=0; i < MX; i++)
234 | {
235 | psvDebugScreenPutChar( i*7 , Y * 8, bg_col, 219);
236 | }
237 | }
238 | }
239 | return;
240 | }
241 |
242 | void psvDebugScreenClearLineEnable(void)
243 | {
244 | clearline_en = 1;
245 | return;
246 | }
247 |
248 | void psvDebugScreenClearLineDisable(void)
249 | {
250 | clearline_en = 0;
251 | return;
252 | }
253 |
254 | /* Print non-nul terminated strings */
255 | int psvDebugScreenPrintData(const char *buff, int size)
256 | {
257 | int i;
258 | int j;
259 | char c;
260 |
261 | if(!init)
262 | {
263 | return 0;
264 | }
265 |
266 | for (i = 0; i < size; i++)
267 | {
268 | c = buff[i];
269 | switch (c)
270 | {
271 | case '\r':
272 | X = 0;
273 | break;
274 | case '\n':
275 | X = 0;
276 | Y ++;
277 | if (Y == MY)
278 | Y = 0;
279 | _psvDebugScreenClearLine(Y);
280 | break;
281 | case '\t':
282 | for (j = 0; j < 5; j++) {
283 | psvDebugScreenPutChar( X*7 , Y * 8, fg_col, ' ');
284 | X++;
285 | }
286 | break;
287 | default:
288 | psvDebugScreenPutChar( X*7 , Y * 8, fg_col, c);
289 | X++;
290 | if (X == MX)
291 | {
292 | X = 0;
293 | Y++;
294 | if (Y == MY)
295 | Y = 0;
296 | _psvDebugScreenClearLine(Y);
297 | }
298 | }
299 | }
300 |
301 | return i;
302 | }
303 |
304 | int psvDebugScreenPuts(const char *str)
305 | {
306 | return psvDebugScreenPrintData(str, sceClibStrnlen(str, 2048));
307 | }
308 |
309 | void psvDebugScreenPrintf(const char *format, ...)
310 | {
311 | va_list opt;
312 | char buff[2048];
313 | int bufsz;
314 |
315 | va_start(opt, format);
316 | bufsz = sceClibVsnprintf( buff, (size_t) sizeof(buff), format, opt);
317 | (void) psvDebugScreenPrintData(buff, bufsz);
318 | }
319 |
--------------------------------------------------------------------------------
/installer/src/font.c:
--------------------------------------------------------------------------------
1 | /*
2 | * PSP Software Development Kit - http://www.pspdev.org
3 | * -----------------------------------------------------------------------
4 | * Licensed under the BSD license, see LICENSE in PSPSDK root for details.
5 | *
6 | * font.c - Debug Font.
7 | *
8 | * Copyright (c) 2005 Marcus R. Brown
9 | * Copyright (c) 2005 James Forshaw
10 | * Copyright (c) 2005 John Kelley
11 | *
12 | * $Id: font.c 540 2005-07-08 19:35:10Z warren $
13 | */
14 |
15 | unsigned char msx[]=
16 | "\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x42\xa5\x81\xa5\x99\x42\x3c"
17 | "\x3c\x7e\xdb\xff\xff\xdb\x66\x3c\x6c\xfe\xfe\xfe\x7c\x38\x10\x00"
18 | "\x10\x38\x7c\xfe\x7c\x38\x10\x00\x10\x38\x54\xfe\x54\x10\x38\x00"
19 | "\x10\x38\x7c\xfe\xfe\x10\x38\x00\x00\x00\x00\x30\x30\x00\x00\x00"
20 | "\xff\xff\xff\xe7\xe7\xff\xff\xff\x38\x44\x82\x82\x82\x44\x38\x00"
21 | "\xc7\xbb\x7d\x7d\x7d\xbb\xc7\xff\x0f\x03\x05\x79\x88\x88\x88\x70"
22 | "\x38\x44\x44\x44\x38\x10\x7c\x10\x30\x28\x24\x24\x28\x20\xe0\xc0"
23 | "\x3c\x24\x3c\x24\x24\xe4\xdc\x18\x10\x54\x38\xee\x38\x54\x10\x00"
24 | "\x10\x10\x10\x7c\x10\x10\x10\x10\x10\x10\x10\xff\x00\x00\x00\x00"
25 | "\x00\x00\x00\xff\x10\x10\x10\x10\x10\x10\x10\xf0\x10\x10\x10\x10"
26 | "\x10\x10\x10\x1f\x10\x10\x10\x10\x10\x10\x10\xff\x10\x10\x10\x10"
27 | "\x10\x10\x10\x10\x10\x10\x10\x10\x00\x00\x00\xff\x00\x00\x00\x00"
28 | "\x00\x00\x00\x1f\x10\x10\x10\x10\x00\x00\x00\xf0\x10\x10\x10\x10"
29 | "\x10\x10\x10\x1f\x00\x00\x00\x00\x10\x10\x10\xf0\x00\x00\x00\x00"
30 | "\x81\x42\x24\x18\x18\x24\x42\x81\x01\x02\x04\x08\x10\x20\x40\x80"
31 | "\x80\x40\x20\x10\x08\x04\x02\x01\x00\x10\x10\xff\x10\x10\x00\x00"
32 | "\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20\x20\x20\x00\x00\x20\x00"
33 | "\x50\x50\x50\x00\x00\x00\x00\x00\x50\x50\xf8\x50\xf8\x50\x50\x00"
34 | "\x20\x78\xa0\x70\x28\xf0\x20\x00\xc0\xc8\x10\x20\x40\x98\x18\x00"
35 | "\x40\xa0\x40\xa8\x90\x98\x60\x00\x10\x20\x40\x00\x00\x00\x00\x00"
36 | "\x10\x20\x40\x40\x40\x20\x10\x00\x40\x20\x10\x10\x10\x20\x40\x00"
37 | "\x20\xa8\x70\x20\x70\xa8\x20\x00\x00\x20\x20\xf8\x20\x20\x00\x00"
38 | "\x00\x00\x00\x00\x00\x20\x20\x40\x00\x00\x00\x78\x00\x00\x00\x00"
39 | "\x00\x00\x00\x00\x00\x60\x60\x00\x00\x00\x08\x10\x20\x40\x80\x00"
40 | "\x70\x88\x98\xa8\xc8\x88\x70\x00\x20\x60\xa0\x20\x20\x20\xf8\x00"
41 | "\x70\x88\x08\x10\x60\x80\xf8\x00\x70\x88\x08\x30\x08\x88\x70\x00"
42 | "\x10\x30\x50\x90\xf8\x10\x10\x00\xf8\x80\xe0\x10\x08\x10\xe0\x00"
43 | "\x30\x40\x80\xf0\x88\x88\x70\x00\xf8\x88\x10\x20\x20\x20\x20\x00"
44 | "\x70\x88\x88\x70\x88\x88\x70\x00\x70\x88\x88\x78\x08\x10\x60\x00"
45 | "\x00\x00\x20\x00\x00\x20\x00\x00\x00\x00\x20\x00\x00\x20\x20\x40"
46 | "\x18\x30\x60\xc0\x60\x30\x18\x00\x00\x00\xf8\x00\xf8\x00\x00\x00"
47 | "\xc0\x60\x30\x18\x30\x60\xc0\x00\x70\x88\x08\x10\x20\x00\x20\x00"
48 | "\x70\x88\x08\x68\xa8\xa8\x70\x00\x20\x50\x88\x88\xf8\x88\x88\x00"
49 | "\xf0\x48\x48\x70\x48\x48\xf0\x00\x30\x48\x80\x80\x80\x48\x30\x00"
50 | "\xe0\x50\x48\x48\x48\x50\xe0\x00\xf8\x80\x80\xf0\x80\x80\xf8\x00"
51 | "\xf8\x80\x80\xf0\x80\x80\x80\x00\x70\x88\x80\xb8\x88\x88\x70\x00"
52 | "\x88\x88\x88\xf8\x88\x88\x88\x00\x70\x20\x20\x20\x20\x20\x70\x00"
53 | "\x38\x10\x10\x10\x90\x90\x60\x00\x88\x90\xa0\xc0\xa0\x90\x88\x00"
54 | "\x80\x80\x80\x80\x80\x80\xf8\x00\x88\xd8\xa8\xa8\x88\x88\x88\x00"
55 | "\x88\xc8\xc8\xa8\x98\x98\x88\x00\x70\x88\x88\x88\x88\x88\x70\x00"
56 | "\xf0\x88\x88\xf0\x80\x80\x80\x00\x70\x88\x88\x88\xa8\x90\x68\x00"
57 | "\xf0\x88\x88\xf0\xa0\x90\x88\x00\x70\x88\x80\x70\x08\x88\x70\x00"
58 | "\xf8\x20\x20\x20\x20\x20\x20\x00\x88\x88\x88\x88\x88\x88\x70\x00"
59 | "\x88\x88\x88\x88\x50\x50\x20\x00\x88\x88\x88\xa8\xa8\xd8\x88\x00"
60 | "\x88\x88\x50\x20\x50\x88\x88\x00\x88\x88\x88\x70\x20\x20\x20\x00"
61 | "\xf8\x08\x10\x20\x40\x80\xf8\x00\x70\x40\x40\x40\x40\x40\x70\x00"
62 | "\x00\x00\x80\x40\x20\x10\x08\x00\x70\x10\x10\x10\x10\x10\x70\x00"
63 | "\x20\x50\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x00"
64 | "\x40\x20\x10\x00\x00\x00\x00\x00\x00\x00\x70\x08\x78\x88\x78\x00"
65 | "\x80\x80\xb0\xc8\x88\xc8\xb0\x00\x00\x00\x70\x88\x80\x88\x70\x00"
66 | "\x08\x08\x68\x98\x88\x98\x68\x00\x00\x00\x70\x88\xf8\x80\x70\x00"
67 | "\x10\x28\x20\xf8\x20\x20\x20\x00\x00\x00\x68\x98\x98\x68\x08\x70"
68 | "\x80\x80\xf0\x88\x88\x88\x88\x00\x20\x00\x60\x20\x20\x20\x70\x00"
69 | "\x10\x00\x30\x10\x10\x10\x90\x60\x40\x40\x48\x50\x60\x50\x48\x00"
70 | "\x60\x20\x20\x20\x20\x20\x70\x00\x00\x00\xd0\xa8\xa8\xa8\xa8\x00"
71 | "\x00\x00\xb0\xc8\x88\x88\x88\x00\x00\x00\x70\x88\x88\x88\x70\x00"
72 | "\x00\x00\xb0\xc8\xc8\xb0\x80\x80\x00\x00\x68\x98\x98\x68\x08\x08"
73 | "\x00\x00\xb0\xc8\x80\x80\x80\x00\x00\x00\x78\x80\xf0\x08\xf0\x00"
74 | "\x40\x40\xf0\x40\x40\x48\x30\x00\x00\x00\x90\x90\x90\x90\x68\x00"
75 | "\x00\x00\x88\x88\x88\x50\x20\x00\x00\x00\x88\xa8\xa8\xa8\x50\x00"
76 | "\x00\x00\x88\x50\x20\x50\x88\x00\x00\x00\x88\x88\x98\x68\x08\x70"
77 | "\x00\x00\xf8\x10\x20\x40\xf8\x00\x18\x20\x20\x40\x20\x20\x18\x00"
78 | "\x20\x20\x20\x00\x20\x20\x20\x00\xc0\x20\x20\x10\x20\x20\xc0\x00"
79 | "\x40\xa8\x10\x00\x00\x00\x00\x00\x00\x00\x20\x50\xf8\x00\x00\x00"
80 | "\x70\x88\x80\x80\x88\x70\x20\x60\x90\x00\x00\x90\x90\x90\x68\x00"
81 | "\x10\x20\x70\x88\xf8\x80\x70\x00\x20\x50\x70\x08\x78\x88\x78\x00"
82 | "\x48\x00\x70\x08\x78\x88\x78\x00\x20\x10\x70\x08\x78\x88\x78\x00"
83 | "\x20\x00\x70\x08\x78\x88\x78\x00\x00\x70\x80\x80\x80\x70\x10\x60"
84 | "\x20\x50\x70\x88\xf8\x80\x70\x00\x50\x00\x70\x88\xf8\x80\x70\x00"
85 | "\x20\x10\x70\x88\xf8\x80\x70\x00\x50\x00\x00\x60\x20\x20\x70\x00"
86 | "\x20\x50\x00\x60\x20\x20\x70\x00\x40\x20\x00\x60\x20\x20\x70\x00"
87 | "\x50\x00\x20\x50\x88\xf8\x88\x00\x20\x00\x20\x50\x88\xf8\x88\x00"
88 | "\x10\x20\xf8\x80\xf0\x80\xf8\x00\x00\x00\x6c\x12\x7e\x90\x6e\x00"
89 | "\x3e\x50\x90\x9c\xf0\x90\x9e\x00\x60\x90\x00\x60\x90\x90\x60\x00"
90 | "\x90\x00\x00\x60\x90\x90\x60\x00\x40\x20\x00\x60\x90\x90\x60\x00"
91 | "\x40\xa0\x00\xa0\xa0\xa0\x50\x00\x40\x20\x00\xa0\xa0\xa0\x50\x00"
92 | "\x90\x00\x90\x90\xb0\x50\x10\xe0\x50\x00\x70\x88\x88\x88\x70\x00"
93 | "\x50\x00\x88\x88\x88\x88\x70\x00\x20\x20\x78\x80\x80\x78\x20\x20"
94 | "\x18\x24\x20\xf8\x20\xe2\x5c\x00\x88\x50\x20\xf8\x20\xf8\x20\x00"
95 | "\xc0\xa0\xa0\xc8\x9c\x88\x88\x8c\x18\x20\x20\xf8\x20\x20\x20\x40"
96 | "\x10\x20\x70\x08\x78\x88\x78\x00\x10\x20\x00\x60\x20\x20\x70\x00"
97 | "\x20\x40\x00\x60\x90\x90\x60\x00\x20\x40\x00\x90\x90\x90\x68\x00"
98 | "\x50\xa0\x00\xa0\xd0\x90\x90\x00\x28\x50\x00\xc8\xa8\x98\x88\x00"
99 | "\x00\x70\x08\x78\x88\x78\x00\xf8\x00\x60\x90\x90\x90\x60\x00\xf0"
100 | "\x20\x00\x20\x40\x80\x88\x70\x00\x00\x00\x00\xf8\x80\x80\x00\x00"
101 | "\x00\x00\x00\xf8\x08\x08\x00\x00\x84\x88\x90\xa8\x54\x84\x08\x1c"
102 | "\x84\x88\x90\xa8\x58\xa8\x3c\x08\x20\x00\x00\x20\x20\x20\x20\x00"
103 | "\x00\x00\x24\x48\x90\x48\x24\x00\x00\x00\x90\x48\x24\x48\x90\x00"
104 | "\x28\x50\x20\x50\x88\xf8\x88\x00\x28\x50\x70\x08\x78\x88\x78\x00"
105 | "\x28\x50\x00\x70\x20\x20\x70\x00\x28\x50\x00\x20\x20\x20\x70\x00"
106 | "\x28\x50\x00\x70\x88\x88\x70\x00\x50\xa0\x00\x60\x90\x90\x60\x00"
107 | "\x28\x50\x00\x88\x88\x88\x70\x00\x50\xa0\x00\xa0\xa0\xa0\x50\x00"
108 | "\xfc\x48\x48\x48\xe8\x08\x50\x20\x00\x50\x00\x50\x50\x50\x10\x20"
109 | "\xc0\x44\xc8\x54\xec\x54\x9e\x04\x10\xa8\x40\x00\x00\x00\x00\x00"
110 | "\x00\x20\x50\x88\x50\x20\x00\x00\x88\x10\x20\x40\x80\x28\x00\x00"
111 | "\x7c\xa8\xa8\x68\x28\x28\x28\x00\x38\x40\x30\x48\x48\x30\x08\x70"
112 | "\x00\x00\x00\x00\x00\x00\xff\xff\xf0\xf0\xf0\xf0\x0f\x0f\x0f\x0f"
113 | "\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00"
114 | "\x00\x00\x00\x3c\x3c\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00"
115 | "\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x0f\x0f\x0f\x0f\xf0\xf0\xf0\xf0"
116 | "\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\x03\x03\x03\x03\x03\x03\x03\x03"
117 | "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x11\x22\x44\x88\x11\x22\x44\x88"
118 | "\x88\x44\x22\x11\x88\x44\x22\x11\xfe\x7c\x38\x10\x00\x00\x00\x00"
119 | "\x00\x00\x00\x00\x10\x38\x7c\xfe\x80\xc0\xe0\xf0\xe0\xc0\x80\x00"
120 | "\x01\x03\x07\x0f\x07\x03\x01\x00\xff\x7e\x3c\x18\x18\x3c\x7e\xff"
121 | "\x81\xc3\xe7\xff\xff\xe7\xc3\x81\xf0\xf0\xf0\xf0\x00\x00\x00\x00"
122 | "\x00\x00\x00\x00\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x00\x00\x00\x00"
123 | "\x00\x00\x00\x00\xf0\xf0\xf0\xf0\x33\x33\xcc\xcc\x33\x33\xcc\xcc"
124 | "\x00\x20\x20\x50\x50\x88\xf8\x00\x20\x20\x70\x20\x70\x20\x20\x00"
125 | "\x00\x00\x00\x50\x88\xa8\x50\x00\xff\xff\xff\xff\xff\xff\xff\xff"
126 | "\x00\x00\x00\x00\xff\xff\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0"
127 | "\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\xff\xff\xff\xff\x00\x00\x00\x00"
128 | "\x00\x00\x68\x90\x90\x90\x68\x00\x30\x48\x48\x70\x48\x48\x70\xc0"
129 | "\xf8\x88\x80\x80\x80\x80\x80\x00\xf8\x50\x50\x50\x50\x50\x98\x00"
130 | "\xf8\x88\x40\x20\x40\x88\xf8\x00\x00\x00\x78\x90\x90\x90\x60\x00"
131 | "\x00\x50\x50\x50\x50\x68\x80\x80\x00\x50\xa0\x20\x20\x20\x20\x00"
132 | "\xf8\x20\x70\xa8\xa8\x70\x20\xf8\x20\x50\x88\xf8\x88\x50\x20\x00"
133 | "\x70\x88\x88\x88\x50\x50\xd8\x00\x30\x40\x40\x20\x50\x50\x50\x20"
134 | "\x00\x00\x00\x50\xa8\xa8\x50\x00\x08\x70\xa8\xa8\xa8\x70\x80\x00"
135 | "\x38\x40\x80\xf8\x80\x40\x38\x00\x70\x88\x88\x88\x88\x88\x88\x00"
136 | "\x00\xf8\x00\xf8\x00\xf8\x00\x00\x20\x20\xf8\x20\x20\x00\xf8\x00"
137 | "\xc0\x30\x08\x30\xc0\x00\xf8\x00\x18\x60\x80\x60\x18\x00\xf8\x00"
138 | "\x10\x28\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xa0\x40"
139 | "\x00\x20\x00\xf8\x00\x20\x00\x00\x00\x50\xa0\x00\x50\xa0\x00\x00"
140 | "\x00\x18\x24\x24\x18\x00\x00\x00\x00\x30\x78\x78\x30\x00\x00\x00"
141 | "\x00\x00\x00\x00\x30\x00\x00\x00\x3e\x20\x20\x20\xa0\x60\x20\x00"
142 | "\xa0\x50\x50\x50\x00\x00\x00\x00\x40\xa0\x20\x40\xe0\x00\x00\x00"
143 | "\x00\x38\x38\x38\x38\x38\x38\x00\x00\x00\x00\x00\x00\x00\x00";
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/enso/nsbl.h:
--------------------------------------------------------------------------------
1 | /* nsbl.h -- imported data from non-secure bootloader
2 | *
3 | * Copyright (C) 2017 molecule
4 | *
5 | * This software may be modified and distributed under the terms
6 | * of the MIT license. See the LICENSE file for details.
7 | */
8 | #ifndef NSBL_HEADER
9 | #define NSBL_HEADER
10 |
11 | #include
12 |
13 | #define NULL ((void *)0)
14 |
15 | typedef struct SceModuleExports {
16 | uint16_t size; // size of this structure; 0x20 for Vita 1.x
17 | uint8_t lib_version[2]; //
18 | uint16_t attribute; // ?
19 | uint16_t num_functions; // number of exported functions
20 | uint16_t num_vars; // number of exported variables
21 | uint16_t unk;
22 | uint32_t num_tls_vars; // number of exported TLS variables? <-- pretty sure wrong // yifanlu
23 | uint32_t lib_nid; // NID of this specific export list; one PRX can export several names
24 | char *lib_name; // name of the export module
25 | uint32_t *nid_table; // array of 32-bit NIDs for the exports, first functions then vars
26 | void **entry_table; // array of pointers to exported functions and then variables
27 | } __attribute__((packed)) SceModuleExports;
28 |
29 | #define EI_NIDENT 16
30 | typedef struct Elf32_Ehdr {
31 | unsigned char e_ident[EI_NIDENT]; /* ident bytes */
32 | uint16_t e_type; /* file type */
33 | uint16_t e_machine; /* target machine */
34 | uint32_t e_version; /* file version */
35 | uint32_t e_entry; /* start address */
36 | uint32_t e_phoff; /* phdr file offset */
37 | uint32_t e_shoff; /* shdr file offset */
38 | uint32_t e_flags; /* file flags */
39 | uint16_t e_ehsize; /* sizeof ehdr */
40 | uint16_t e_phentsize; /* sizeof phdr */
41 | uint16_t e_phnum; /* number phdrs */
42 | uint16_t e_shentsize; /* sizeof shdr */
43 | uint16_t e_shnum; /* number shdrs */
44 | uint16_t e_shstrndx; /* shdr string index */
45 | } __attribute__((packed)) Elf32_Ehdr;
46 |
47 | typedef struct {
48 | uint32_t p_type; /* entry type */
49 | uint32_t p_offset; /* file offset */
50 | uint32_t p_vaddr; /* virtual address */
51 | uint32_t p_paddr; /* physical address */
52 | uint32_t p_filesz; /* file size */
53 | uint32_t p_memsz; /* memory size */
54 | uint32_t p_flags; /* entry flags */
55 | uint32_t p_align; /* memory/file alignment */
56 | } __attribute__((packed)) Elf32_Phdr;
57 |
58 | typedef struct SceModuleSelfSectionInfo {
59 | uint64_t offset;
60 | uint64_t size;
61 | uint32_t compressed; // 2=compressed
62 | uint32_t unknown1;
63 | uint32_t encrypted; // 1=encrypted
64 | uint32_t unknown2;
65 | } __attribute__((packed)) SceModuleSelfSectionInfo;
66 |
67 | #ifdef FW_365
68 |
69 | // firmware specific internal structures
70 |
71 | typedef struct SceBootArgs {
72 | uint16_t version;
73 | uint16_t size;
74 | uint32_t fw_version;
75 | uint32_t ship_version;
76 | uint32_t field_C;
77 | uint32_t field_10;
78 | uint32_t field_14;
79 | uint32_t field_18;
80 | uint32_t field_1C;
81 | uint32_t field_20;
82 | uint32_t field_24;
83 | uint32_t field_28;
84 | uint8_t debug_flags[8];
85 | uint32_t field_34;
86 | uint32_t field_38;
87 | uint32_t field_3C;
88 | uint32_t field_40;
89 | uint32_t field_44;
90 | uint32_t field_48;
91 | uint32_t aslr_seed;
92 | uint32_t field_50;
93 | uint32_t field_54;
94 | uint32_t field_58;
95 | uint32_t field_5C;
96 | uint32_t dram_base;
97 | uint32_t dram_size;
98 | uint32_t field_68;
99 | uint32_t boot_type_indicator_1;
100 | uint8_t serial[0x10];
101 | uint32_t secure_kernel_enp_addr;
102 | uint32_t secure_kernel_enp_size;
103 | uint32_t field_88;
104 | uint32_t field_8C;
105 | uint32_t kprx_auth_sm_self_addr;
106 | uint32_t kprx_auth_sm_self_size;
107 | uint32_t prog_rvk_srvk_addr;
108 | uint32_t prog_rvk_srvk_size;
109 | uint16_t model;
110 | uint16_t device_type;
111 | uint16_t device_config;
112 | uint16_t retail_type;
113 | uint32_t field_A8;
114 | uint32_t field_AC;
115 | uint8_t session_id[0x10];
116 | uint32_t field_C0;
117 | uint32_t boot_type_indicator_2;
118 | uint32_t field_C8;
119 | uint32_t field_CC;
120 | uint32_t resume_context_addr;
121 | uint32_t field_D4;
122 | uint32_t field_D8;
123 | uint32_t field_DC;
124 | uint32_t field_E0;
125 | uint32_t field_E4;
126 | uint32_t field_E8;
127 | uint32_t field_EC;
128 | uint32_t field_F0;
129 | uint32_t field_F4;
130 | uint32_t bootldr_revision;
131 | uint32_t magic;
132 | uint8_t session_key[0x20];
133 | uint8_t unused[0xE0];
134 | } __attribute__((packed)) SceBootArgs;
135 |
136 | typedef struct SceSysrootContext {
137 | uint32_t reserved[27];
138 | SceBootArgs *boot_args;
139 | } __attribute__((packed)) SceSysrootContext;
140 |
141 | typedef struct SceModuleLoadList {
142 | const char *filename;
143 | } __attribute__((packed)) SceModuleLoadList;
144 |
145 | typedef struct SceObject {
146 | uint32_t field_0;
147 | void *obj_data;
148 | char data[];
149 | } __attribute__((packed)) SceObject;
150 |
151 | typedef struct SceModuleSegment {
152 | uint32_t p_filesz;
153 | uint32_t p_memsz;
154 | uint16_t p_flags;
155 | uint16_t p_align_bits;
156 | void *buf;
157 | int32_t buf_blkid;
158 | } __attribute__((packed)) SceModuleSegment;
159 |
160 | typedef struct SceModuleObject {
161 | struct SceModuleObject *next;
162 | uint16_t exeflags;
163 | uint8_t status;
164 | uint8_t field_7;
165 | uint32_t min_sysver;
166 | int32_t modid;
167 | int32_t user_modid;
168 | int32_t pid;
169 | uint16_t modattribute;
170 | uint16_t modversion;
171 | uint32_t modid_name;
172 | SceModuleExports *ent_top_user;
173 | SceModuleExports *ent_end_user;
174 | uint32_t stub_start_user;
175 | uint32_t stub_end_user;
176 | uint32_t module_nid;
177 | uint32_t modinfo_field_38;
178 | uint32_t modinfo_field_3C;
179 | uint32_t modinfo_field_40;
180 | uint32_t exidx_start_user;
181 | uint32_t exidx_end_user;
182 | uint32_t extab_start_user;
183 | uint32_t extab_end_user;
184 | uint16_t num_export_libs;
185 | uint16_t num_import_libs;
186 | uint32_t field_54;
187 | uint32_t field_58;
188 | uint32_t field_5C;
189 | uint32_t field_60;
190 | void *imports;
191 | const char *path;
192 | uint32_t total_loadable;
193 | struct SceModuleSegment segments[3];
194 | void *type_6FFFFF00_buf;
195 | uint32_t type_6FFFFF00_bufsz;
196 | void *module_start;
197 | void *module_init;
198 | void *module_stop;
199 | uint32_t field_C0;
200 | uint32_t field_C4;
201 | uint32_t field_C8;
202 | uint32_t field_CC;
203 | uint32_t field_D0;
204 | struct SceObject *prev_loaded;
205 | } __attribute__((packed)) SceModuleObject;
206 |
207 | typedef struct SceKernelAllocMemBlockKernelOpt {
208 | uint32_t size;
209 | uint32_t field_4;
210 | uint32_t attr;
211 | uint32_t field_C;
212 | uint32_t paddr;
213 | uint32_t alignment;
214 | uint32_t field_18;
215 | uint32_t field_1C;
216 | uint32_t mirror_blkid;
217 | int32_t pid;
218 | uint32_t field_28;
219 | uint32_t field_2C;
220 | uint32_t field_30;
221 | uint32_t field_34;
222 | uint32_t field_38;
223 | uint32_t field_3C;
224 | uint32_t field_40;
225 | uint32_t field_44;
226 | uint32_t field_48;
227 | uint32_t field_4C;
228 | uint32_t field_50;
229 | uint32_t field_54;
230 | } __attribute__((packed)) SceKernelAllocMemBlockKernelOpt;
231 |
232 | typedef struct SceModuleDecryptContext {
233 | void *header;
234 | uint32_t header_len;
235 | Elf32_Ehdr *elf_ehdr;
236 | Elf32_Phdr *elf_phdr;
237 | uint8_t type;
238 | uint8_t init_completed;
239 | uint8_t field_12;
240 | uint8_t field_13;
241 | SceModuleSelfSectionInfo *section_info;
242 | void *header_buffer;
243 | uint32_t sbl_ctx;
244 | uint32_t field_20;
245 | uint32_t fd;
246 | int32_t pid;
247 | uint32_t max_size;
248 | } __attribute__((packed)) SceModuleDecryptContext;
249 |
250 | // firmware specific function offsets
251 | #ifdef DEBUG
252 | static int (*printf)(const char *fmt, ...) = (void*)0x51013919;
253 | #else
254 | #define printf(...)
255 | #endif
256 | static void *(*memset)(void *dst, int ch, int sz) = (void*)0x51013C41;
257 | static void *(*memcpy)(void *dst, const void *src, int sz) = (void *)0x51013BC1;
258 | static void *(*memmove)(void *dst, const void *src, int sz) = (void *)0x5102152D;
259 | static void (*clean_dcache)(void *dst, int len) = (void*)0x510146DD;
260 | static int (*read_block_os0)() = (void*)0x510010FD;
261 | static void (*flush_icache)() = (void*)0x51014691;
262 | static int (*strncmp)(const char *s1, const char *s2, int len) = (void *)0x51013CA0;
263 | static SceObject *(*get_obj_for_uid)(int uid) = (void *)0x51017785;
264 | static int (*module_load)(const SceModuleLoadList *list, int *uids, int count, int) = (void *)0x51001551;
265 | static int (*sceKernelAllocMemBlock)(const char *name, int type, int size, SceKernelAllocMemBlockKernelOpt *opt) = (void *)0x51007161;
266 | static int (*sceKernelGetMemBlockBase)(int32_t uid, void **basep) = (void *)0x510057E1;
267 | static int (*sceKernelRemapBlock)(int32_t uid, int type) = (void *)0x51007171;
268 |
269 | // firmware specific patch offsets
270 |
271 | static SceBootArgs *boot_args = (void *)0x51167528;
272 | static SceSysrootContext **sysroot_ctx_ptr = (void *)0x51138A3C;
273 | static void **module_load_func_ptr = (void *)0x510277A8;
274 |
275 | // sysstate patches
276 | #define SCEDISPLAY_LOGO_OFFSET (0x8990)
277 | #define SBLAUTHMGR_OFFSET_PATCH_ARG (168)
278 | #define SYSSTATE_IS_MANUFACTURING_MODE_OFFSET (0x1500)
279 | #define SYSSTATE_IS_DEV_MODE_OFFSET (0xE28)
280 | #define SYSSTATE_RET_CHECK_BUG (0xD92)
281 | static const uint8_t sysstate_ret_patch[] = {0x13, 0x22, 0xc8, 0xf2, 0x01, 0x02};
282 | #define SYSSTATE_SD0_STRING (0x2448)
283 | static const char ur0_path[] = "vs0:";
284 | #define SYSSTATE_SD0_PSP2CONFIG_STRING (0x2396)
285 | static const char ur0_psp2config_path[] = "vs0:tai/boot_config.txt";
286 | #define SYSSTATE_FINAL_CALL (0x130)
287 | #define SYSSTATE_FINAL (0x18C9)
288 |
289 | #else
290 | #error "No firmware defined or firmware not supported."
291 | #endif
292 |
293 | #endif
294 |
--------------------------------------------------------------------------------
/enso/second.c:
--------------------------------------------------------------------------------
1 | /* second.c -- bootloader patches
2 | *
3 | * Copyright (C) 2017 molecule
4 | *
5 | * This software may be modified and distributed under the terms
6 | * of the MIT license. See the LICENSE file for details.
7 | */
8 | #include
9 | #include "nsbl.h"
10 | #include "logo.h"
11 |
12 | #define unlikely(expr) __builtin_expect(!!(expr), 0)
13 |
14 | #define DACR_OFF(stmt) \
15 | do { \
16 | unsigned prev_dacr; \
17 | __asm__ volatile( \
18 | "mrc p15, 0, %0, c3, c0, 0 \n" \
19 | : "=r" (prev_dacr) \
20 | ); \
21 | __asm__ volatile( \
22 | "mcr p15, 0, %0, c3, c0, 0 \n" \
23 | : : "r" (0xFFFF0000) \
24 | ); \
25 | stmt; \
26 | __asm__ volatile( \
27 | "mcr p15, 0, %0, c3, c0, 0 \n" \
28 | : : "r" (prev_dacr) \
29 | ); \
30 | } while (0)
31 |
32 | #define INSTALL_HOOK_THUMB(func, addr) \
33 | do { \
34 | unsigned *target; \
35 | target = (unsigned*)(addr); \
36 | *target++ = 0xC004F8DF; /* ldr.w ip, [pc, #4] */ \
37 | *target++ = 0xBF004760; /* bx ip; nop */ \
38 | *target = (unsigned)func; \
39 | } while (0)
40 |
41 | #define INSTALL_RET_THUMB(addr, ret) \
42 | do { \
43 | unsigned *target; \
44 | target = (unsigned*)(addr); \
45 | *target = 0x47702000 | (ret); /* movs r0, #ret; bx lr */ \
46 | } while (0)
47 |
48 | // sdstor restore globals
49 | static int (*sdstor_read_sector_async)(void* ctx, int sector, char* buffer, int nSectors) = NULL;
50 | static int (*sdstor_read_sector)(void* ctx, int sector, char* buffer, int nSectors) = NULL;
51 | static void *(*get_sd_context_part_validate_mmc)(int sd_ctx_index) = NULL;
52 |
53 | // debug globals
54 | #ifdef DEBUG
55 | static int (*set_crash_flag)(int) = NULL;
56 | #endif
57 |
58 | // sigpatch globals
59 | static int g_sigpatch_disabled = 0;
60 | static int g_homebrew_decrypt = 0;
61 | static int (*sbl_parse_header)(uint32_t ctx, const void *header, int len, void *args) = NULL;
62 | static int (*sbl_set_up_buffer)(uint32_t ctx, int segidx) = NULL;
63 | static int (*sbl_decrypt)(uint32_t ctx, void *buf, int sz) = NULL;
64 |
65 | // sysstate final function
66 | static void __attribute__((noreturn)) (*sysstate_final)(void) = NULL;
67 |
68 | // utility functions
69 |
70 | #if 0
71 | static int hex_dump(const char *addr, unsigned int size)
72 | {
73 | unsigned int i;
74 | for (i = 0; i < (size >> 4); i++)
75 | {
76 | printf("0x%08X: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", addr, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
77 | addr += 0x10;
78 | }
79 | return 0;
80 | }
81 | #endif
82 |
83 | static void **get_export_func(SceModuleObject *mod, uint32_t lib_nid, uint32_t func_nid) {
84 | for (SceModuleExports *ent = mod->ent_top_user; ent != mod->ent_end_user; ent++) {
85 | if (ent->lib_nid == lib_nid) {
86 | for (int i = 0; i < ent->num_functions; i++) {
87 | if (ent->nid_table[i] == func_nid) {
88 | return &ent->entry_table[i];
89 | }
90 | }
91 | }
92 | }
93 | return NULL;
94 | }
95 |
96 | static int is_safe_mode(void) {
97 | SceBootArgs *boot_args = (*sysroot_ctx_ptr)->boot_args;
98 | uint32_t v;
99 |
100 | if (boot_args->debug_flags[7] != 0xFF) {
101 | return 1;
102 | }
103 |
104 | v = boot_args->boot_type_indicator_2 & 0x7F;
105 | if (v == 0xB || (v == 4 && boot_args->resume_context_addr)) {
106 | v = ~boot_args->field_CC;
107 | if (((v >> 8) & 0x54) == 0x54 && (v & 0xC0) == 0) {
108 | return 1;
109 | } else {
110 | return 0;
111 | }
112 | } else if (v == 4) {
113 | return 0;
114 | }
115 |
116 | if (v == 0x1F || (uint32_t)(v - 0x18) <= 1) {
117 | return 1;
118 | } else {
119 | return 0;
120 | }
121 | }
122 |
123 | static int is_update_mode(void) {
124 | SceBootArgs *boot_args = (*sysroot_ctx_ptr)->boot_args;
125 |
126 | if (boot_args->debug_flags[4] != 0xFF) {
127 | return 1;
128 | } else {
129 | return 0;
130 | }
131 | }
132 |
133 | static inline int skip_patches(void) {
134 | return is_safe_mode() || is_update_mode();
135 | }
136 |
137 | // sdif patches for MBR redirection
138 |
139 | static int sdstor_read_sector_patched(void* ctx, int sector, char* buffer, int nSectors) {
140 | int ret;
141 | #ifndef NO_MBR_REDIRECT
142 | if (unlikely(sector == 0 && nSectors > 0)) {
143 | printf("read sector 0 for %d at context 0x%08X\n", nSectors, ctx);
144 | if (get_sd_context_part_validate_mmc(0) == ctx) {
145 | printf("patching sector 0 read to sector 1\n");
146 | ret = sdstor_read_sector(ctx, 1, buffer, 1);
147 | if (ret >= 0 && nSectors > 1) {
148 | ret = sdstor_read_sector(ctx, 1, buffer + 0x200, nSectors-1);
149 | }
150 | return ret;
151 | }
152 | }
153 | #endif
154 |
155 | return sdstor_read_sector(ctx, sector, buffer, nSectors);
156 | }
157 |
158 | static int sdstor_read_sector_async_patched(void* ctx, int sector, char* buffer, int nSectors) {
159 | int ret;
160 | #ifndef NO_MBR_REDIRECT
161 | if (unlikely(sector == 0 && nSectors > 0)) {
162 | printf("read sector async 0 for %d at context 0x%08X\n", nSectors, ctx);
163 | if (get_sd_context_part_validate_mmc(0) == ctx) {
164 | printf("patching sector 0 read to sector 1\n");
165 | ret = sdstor_read_sector_async(ctx, 1, buffer, 1);
166 | if (ret >= 0 && nSectors > 1) {
167 | ret = sdstor_read_sector_async(ctx, 1, buffer + 0x200, nSectors-1);
168 | }
169 | return ret;
170 | }
171 | }
172 | #endif
173 |
174 | return sdstor_read_sector_async(ctx, sector, buffer, nSectors);
175 | }
176 |
177 | // sigpatches for bootup
178 |
179 | static int sbl_parse_header_patched(uint32_t ctx, const void *header, int len, void *args) {
180 | int ret = sbl_parse_header(ctx, header, len, args);
181 | if (unlikely(!g_sigpatch_disabled)) {
182 | DACR_OFF(
183 | g_homebrew_decrypt = (ret < 0);
184 | );
185 | if (g_homebrew_decrypt) {
186 | *(uint32_t *)(args + SBLAUTHMGR_OFFSET_PATCH_ARG) = 0x40;
187 | ret = 0;
188 | }
189 | }
190 | return ret;
191 | }
192 |
193 | static int sbl_set_up_buffer_patched(uint32_t ctx, int segidx) {
194 | if (unlikely(!g_sigpatch_disabled)) {
195 | if (g_homebrew_decrypt) {
196 | return 2; // always compressed!
197 | }
198 | }
199 | return sbl_set_up_buffer(ctx, segidx);
200 | }
201 |
202 | static int sbl_decrypt_patched(uint32_t ctx, void *buf, int sz) {
203 | if (unlikely(!g_sigpatch_disabled)) {
204 | if (g_homebrew_decrypt) {
205 | return 0;
206 | }
207 | }
208 | return sbl_decrypt(ctx, buf, sz);
209 | }
210 |
211 | static void __attribute__((noreturn)) sysstate_final_hook(void) {
212 | printf("after kernel load! disabling temporary sigpatches\n");
213 |
214 | DACR_OFF(
215 | g_sigpatch_disabled = 1;
216 | );
217 |
218 | sysstate_final();
219 | }
220 |
221 | // main function to hook stuff
222 |
223 | #define HOOK_EXPORT(name, lib_nid, func_nid) do { \
224 | void **func = get_export_func(mod, lib_nid, func_nid); \
225 | printf(#name ": 0x%08X\n", *func); \
226 | DACR_OFF( \
227 | name = *func; \
228 | *func = name ## _patched; \
229 | ); \
230 | } while (0)
231 | #define FIND_EXPORT(name, lib_nid, func_nid) do { \
232 | void **func = get_export_func(mod, lib_nid, func_nid); \
233 | printf(#name ": 0x%08X\n", *func); \
234 | DACR_OFF( \
235 | name = *func; \
236 | ); \
237 | } while (0)
238 | static int module_load_patched(const SceModuleLoadList *list, int *uids, int count, int unk) {
239 | int ret;
240 | SceObject *obj;
241 | SceModuleObject *mod;
242 | int skip;
243 | int sysmem_idx = -1, display_idx = -1, sdif_idx = -1, authmgr_idx = -1, sysstate_idx = -1;
244 |
245 | skip = skip_patches();
246 | for (int i = 0; i < count; i++) {
247 | if (!list[i].filename) {
248 | continue; // wtf sony why don't you sanitize input
249 | }
250 | printf("before start %s\n", list[i].filename);
251 | if (!skip && strncmp(list[i].filename, "display.skprx", 13) == 0) {
252 | display_idx = i;
253 | } else if (strncmp(list[i].filename, "sdif.skprx", 10) == 0) {
254 | sdif_idx = i; // never skip MBR redirection patches
255 | } else if (!skip && strncmp(list[i].filename, "authmgr.skprx", 13) == 0) {
256 | authmgr_idx = i;
257 | } else if (!skip && strncmp(list[i].filename, "sysstatemgr.skprx", 17) == 0) {
258 | sysstate_idx = i;
259 | }
260 | #ifdef DEBUG
261 | if (strncmp(list[i].filename, "sysmem.skprx", 12) == 0) {
262 | sysmem_idx = i;
263 | }
264 | #endif
265 | }
266 | ret = module_load(list, uids, count, unk);
267 | #ifdef DEBUG
268 | // get sysmem functions
269 | if (sysmem_idx >= 0) {
270 | obj = get_obj_for_uid(uids[sysmem_idx]);
271 | if (obj != NULL) {
272 | mod = (SceModuleObject *)&obj->data;
273 | FIND_EXPORT(set_crash_flag, 0x13D793B7, 0xA465A31A);
274 | FIND_EXPORT(printf, 0x88758561, 0x391B74B7);
275 | } else {
276 | printf("module data invalid for sysmem.skprx!\n");
277 | }
278 | }
279 | #endif
280 | // patch logo
281 | if (display_idx >= 0) {
282 | obj = get_obj_for_uid(uids[display_idx]);
283 | if (obj != NULL) {
284 | mod = (SceModuleObject *)&obj->data;
285 | printf("logo at offset: %x\n", mod->segments[0].buf + SCEDISPLAY_LOGO_OFFSET);
286 | DACR_OFF(
287 | memcpy(mod->segments[0].buf + SCEDISPLAY_LOGO_OFFSET, logo_data, logo_len);
288 | );
289 | // no cache flush needed because this is just data
290 | } else {
291 | printf("module data invalid for display.skprx!\n");
292 | }
293 | }
294 | // patch sdif
295 | if (sdif_idx >= 0) {
296 | obj = get_obj_for_uid(uids[sdif_idx]);
297 | if (obj != NULL) {
298 | mod = (SceModuleObject *)&obj->data;
299 | HOOK_EXPORT(sdstor_read_sector_async, 0x96D306FA, 0x6F8D529B);
300 | HOOK_EXPORT(sdstor_read_sector, 0x96D306FA, 0xB9593652);
301 | FIND_EXPORT(get_sd_context_part_validate_mmc, 0x96D306FA, 0x6A71987F);
302 | } else {
303 | printf("module data invalid for sdif.skprx!\n");
304 | }
305 | }
306 | // patch authmgr
307 | if (authmgr_idx >= 0) {
308 | obj = get_obj_for_uid(uids[authmgr_idx]);
309 | if (obj != NULL) {
310 | mod = (SceModuleObject *)&obj->data;
311 | HOOK_EXPORT(sbl_parse_header, 0x7ABF5135, 0xF3411881);
312 | HOOK_EXPORT(sbl_set_up_buffer, 0x7ABF5135, 0x89CCDA2C);
313 | HOOK_EXPORT(sbl_decrypt, 0x7ABF5135, 0xBC422443);
314 | } else {
315 | printf("module data invalid for authmgr.skprx!\n");
316 | }
317 | }
318 | // patch sysstate to load unsigned boot configs
319 | if (sysstate_idx >= 0) {
320 | obj = get_obj_for_uid(uids[sysstate_idx]);
321 | if (obj != NULL) {
322 | mod = (SceModuleObject *)&obj->data;
323 | DACR_OFF(
324 | INSTALL_RET_THUMB(mod->segments[0].buf + SYSSTATE_IS_MANUFACTURING_MODE_OFFSET, 1);
325 | *(uint32_t *)(mod->segments[0].buf + SYSSTATE_IS_DEV_MODE_OFFSET) = 0x20012001;
326 | memcpy(mod->segments[0].buf + SYSSTATE_RET_CHECK_BUG, sysstate_ret_patch, sizeof(sysstate_ret_patch));
327 | memcpy(mod->segments[0].buf + SYSSTATE_SD0_STRING, ur0_path, sizeof(ur0_path));
328 | memcpy(mod->segments[0].buf + SYSSTATE_SD0_PSP2CONFIG_STRING, ur0_psp2config_path, sizeof(ur0_psp2config_path));
329 | // this patch actually corrupts two words of data, but they are only used in debug printing and seem to be fine
330 | INSTALL_HOOK_THUMB(sysstate_final_hook, mod->segments[0].buf + SYSSTATE_FINAL_CALL);
331 | sysstate_final = mod->segments[0].buf + SYSSTATE_FINAL;
332 | );
333 | } else {
334 | printf("module data invalid for sysstatemgr.skprx!\n");
335 | }
336 | }
337 | return ret;
338 | }
339 | #undef HOOK_EXPORT
340 | #undef FIND_EXPORT
341 |
342 | void go(void) {
343 | printf("second\n");
344 |
345 | // patch module_load/module_start
346 | *module_load_func_ptr = module_load_patched;
347 | printf("module_load_patched: 0x%08X\n", module_load_patched);
348 | }
349 |
350 | __attribute__ ((section (".text.start"))) void start(void) {
351 | go();
352 | }
353 |
--------------------------------------------------------------------------------
/henkaku/kernel.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "henkaku.h"
11 | #include "config.h"
12 |
13 | #define OFFSET_PATCH_ARG (168)
14 | #define OFFSET_PATCH_AUTHID (152)
15 |
16 | typedef struct {
17 | uint32_t magic; /* 53434500 = SCE\0 */
18 | uint32_t version; /* header version 3*/
19 | uint16_t sdk_type; /* */
20 | uint16_t header_type; /* 1 self, 2 unknown, 3 pkg */
21 | uint32_t metadata_offset; /* metadata offset */
22 | uint64_t header_len; /* self header length */
23 | uint64_t elf_filesize; /* ELF file length */
24 | uint64_t self_filesize; /* SELF file length */
25 | uint64_t unknown; /* UNKNOWN */
26 | uint64_t self_offset; /* SELF offset */
27 | uint64_t appinfo_offset; /* app info offset */
28 | uint64_t elf_offset; /* ELF #1 offset */
29 | uint64_t phdr_offset; /* program header offset */
30 | uint64_t shdr_offset; /* section header offset */
31 | uint64_t section_info_offset; /* section info offset */
32 | uint64_t sceversion_offset; /* version offset */
33 | uint64_t controlinfo_offset; /* control info offset */
34 | uint64_t controlinfo_size; /* control info size */
35 | uint64_t padding;
36 | } __attribute__((packed)) self_header_t;
37 |
38 | typedef struct {
39 | uint64_t authid; /* auth id */
40 | uint32_t vendor_id; /* vendor id */
41 | uint32_t self_type; /* app type */
42 | uint64_t padding; /* UNKNOWN */
43 | } __attribute__((packed)) app_info_t;
44 |
45 | static henkaku_config_t config;
46 |
47 | static SceUID g_hooks[7];
48 |
49 | const char taihen_config_recovery_header[] =
50 | "# This file is used as an alternative if ux0:tai/config.txt is not found.\n";
51 |
52 | const char taihen_config_header[] =
53 | "# For users plugins, you must refresh taiHEN from HENkaku Settings for\n"
54 | "# changes to take place.\n"
55 | "# For kernel plugins, you must reboot for changes to take place.\n";
56 |
57 | const char taihen_config[] =
58 | "*KERNEL\n"
59 | "# henkaku.skprx is hard-coded to load and is not listed here\n"
60 | "*main\n"
61 | "# main is a special titleid for SceShell\n";
62 |
63 | static tai_hook_ref_t g_parse_headers_hook;
64 | static int parse_headers_patched(int ctx, const void *headers, size_t len, void *args) {
65 | self_header_t *self;
66 | app_info_t *info;
67 | int ret;
68 |
69 | ret = TAI_CONTINUE(int, g_parse_headers_hook, ctx, headers, len, args);
70 | if (len >= sizeof(self_header_t) && len >= sizeof(app_info_t)) {
71 | self = (self_header_t *)headers;
72 | if (self->appinfo_offset <= len - sizeof(app_info_t)) {
73 | info = (app_info_t *)(headers + self->appinfo_offset);
74 | LOG("authid: 0x%llx\n", info->authid);
75 | if (ret < 0 && config.allow_unsafe_hb) {
76 | LOG("is homebrew!");
77 | if ((info->authid & 0xFFFFFFFFFFFFFFFCLL) == 0x2F00000000000000LL) {
78 | if (info->authid & 1) {
79 | // we just give extended permissions
80 | *(uint32_t *)(args + OFFSET_PATCH_ARG) = 0x40;
81 | }
82 | } else {
83 | // we give authid + extended permissions
84 | *(uint32_t *)(args + OFFSET_PATCH_ARG) = 0x40;
85 | *(uint64_t *)(args + OFFSET_PATCH_AUTHID) = info->authid;
86 | }
87 | }
88 | }
89 | }
90 | return ret;
91 | }
92 |
93 | static tai_hook_ref_t g_start_preloaded_modules_hook;
94 | static int start_preloaded_modules_patched(SceUID pid) {
95 | int ret;
96 | char titleid[32];
97 |
98 | ret = TAI_CONTINUE(int, g_start_preloaded_modules_hook, pid);
99 |
100 | ksceKernelGetProcessTitleId(pid, titleid, 32);
101 | LOG("title started: %s, pid: %x, loading henkaku.suprx", titleid, pid);
102 |
103 | if (strcmp(titleid, "main") == 0 ||
104 | strcmp(titleid, "NPXS10015") == 0 ||
105 | strcmp(titleid, "NPXS10016") == 0) {
106 | ksceKernelLoadStartModuleForPid(pid, "vs0:tai/henkaku.suprx", 0, NULL, 0, NULL, NULL);
107 | }
108 |
109 | return ret;
110 | }
111 |
112 | static tai_hook_ref_t g_some_sysroot_check_hook;
113 | static int some_sysroot_check_patched(void) {
114 | TAI_CONTINUE(int, g_some_sysroot_check_hook);
115 | return 1;
116 | }
117 |
118 | static tai_hook_ref_t g_some_process_check_patched_hook;
119 | static int some_process_check_patched(void) {
120 | TAI_CONTINUE(int, g_some_process_check_patched_hook);
121 | return 0;
122 | }
123 |
124 | static tai_hook_ref_t g_some_power_auth_check_hook;
125 | static int some_power_auth_check_patched(void) {
126 | // this function may be called in the process of looping
127 | // see: https://github.com/yifanlu/taiHEN/issues/12
128 | // for now, we mark this as a FIXME and do this check manually
129 | if (g_some_power_auth_check_hook) {
130 | TAI_CONTINUE(int, g_some_power_auth_check_hook);
131 | }
132 | return 1;
133 | }
134 |
135 | static tai_hook_ref_t g_sceKernelGetSystemSwVersion_hook;
136 | static int sceKernelGetSystemSwVersion_patched(SceKernelFwInfo *info) {
137 | int ret;
138 | int ver_major;
139 | int ver_minor;
140 | ret = TAI_CONTINUE(int, g_sceKernelGetSystemSwVersion_hook, info);
141 | info->version = config.spoofed_version;
142 | ver_major = ((config.spoofed_version >> 24) & 0xF) + 10 * (config.spoofed_version >> 28);
143 | ver_minor = ((config.spoofed_version >> 16) & 0xF) + 10 * ((config.spoofed_version >> 20) & 0xF);
144 | snprintf(info->versionString, 16, "%d.%02d", ver_major, ver_minor);
145 | return ret;
146 | }
147 |
148 | static tai_hook_ref_t g_sceSblUsGetSpkgInfo_hook;
149 | static int sceSblUsGetSpkgInfo_patched(int r0, uintptr_t out) {
150 | int ver;
151 | int ret;
152 | ret = TAI_CONTINUE(int, g_sceSblUsGetSpkgInfo_hook, r0, out);
153 | if (r0 == 1 || r0 == 9 || r0 == 10 || r0 == 21 || r0 == 22) {
154 | ver = config.spoofed_version;
155 | ksceKernelMemcpyKernelToUser(out+4, &ver, 4);
156 | }
157 | return ret;
158 | }
159 |
160 | static int load_config_kernel(void) {
161 | SceUID fd;
162 | int rd;
163 | fd = ksceIoOpen(CONFIG_PATH, SCE_O_RDONLY, 0);
164 | if (fd < 0) {
165 | fd = ksceIoOpen(OLD_CONFIG_PATH, SCE_O_RDONLY, 0);
166 | }
167 | if (fd >= 0) {
168 | rd = ksceIoRead(fd, &config, sizeof(config));
169 | ksceIoClose(fd);
170 | if (rd == sizeof(config)) {
171 | if (config.magic == HENKAKU_CONFIG_MAGIC) {
172 | /* if (config.version >= 8) {
173 | return 0;
174 | } else {
175 | LOG("config version too old");
176 | }*/
177 | return 0;
178 | } else {
179 | LOG("config incorrect magic: %x", config.magic);
180 | }
181 | } else {
182 | LOG("config not right size: %d", rd);
183 | }
184 | } else {
185 | LOG("config file not found");
186 | }
187 | // default config
188 | config.magic = HENKAKU_CONFIG_MAGIC;
189 | config.version = HENKAKU_RELEASE;
190 | config.use_psn_spoofing = 1;
191 | config.allow_unsafe_hb = 0;
192 | config.use_spoofed_version = 1;
193 | config.spoofed_version = SPOOF_VERSION;
194 | return 0;
195 | }
196 |
197 | // user export
198 | int henkaku_reload_config(void) {
199 | int state;
200 | int tid;
201 | int ret;
202 | ENTER_SYSCALL(state);
203 | tid = ksceKernelCreateThread("configwrite", (SceKernelThreadEntry)load_config_kernel, 64, 0x1000, 0, 0, NULL);
204 | LOG("ksceKernelCreateThread: %x", tid);
205 | ret = ksceKernelStartThread(tid, 0, NULL);
206 | LOG("ksceKernelStartThread: %x", ret);
207 | ksceKernelWaitThreadEnd(tid, &ret, NULL);
208 | ksceKernelDeleteThread(tid);
209 | EXIT_SYSCALL(state);
210 | return ret;
211 | }
212 |
213 | int write_taihen_config(const char *path, int recovery) {
214 | int fd;
215 |
216 | // write default config
217 | ksceIoRemove(path);
218 | fd = ksceIoOpen(path, SCE_O_TRUNC | SCE_O_CREAT | SCE_O_WRONLY, 6);
219 | if (recovery) {
220 | ksceIoWrite(fd, taihen_config_recovery_header, sizeof(taihen_config_recovery_header) - 1);
221 | }
222 | ksceIoWrite(fd, taihen_config_header, sizeof(taihen_config_header) - 1);
223 | ksceIoWrite(fd, taihen_config, sizeof(taihen_config) - 1);
224 | ksceIoClose(fd);
225 |
226 | return 0;
227 | }
228 |
229 | void _start() __attribute__ ((weak, alias ("module_start")));
230 | int module_start(SceSize argc, const void *args) {
231 | SceUID shell_pid;
232 | SceIoStat stat;
233 | LOG("loading HENkaku config for kernel");
234 | if (ksceIoGetstat("ur0:shell/db/dbr.db-err", &stat) >= 0) {
235 | ksceIoMkdir("ux0:tai", 6);
236 | ksceIoMkdir("ur0:tai", 6);
237 | write_taihen_config("ux0:tai/config.txt", 0);
238 | write_taihen_config("ur0:tai/config.txt", 1);
239 | }
240 | load_config_kernel();
241 | // this hook enables extended permissions for unsafe homebrew + blocking unsafe homebrew if requested
242 | g_hooks[0] = taiHookFunctionImportForKernel(KERNEL_PID,
243 | &g_parse_headers_hook,
244 | "SceKernelModulemgr",
245 | 0x7ABF5135, // SceSblAuthMgrForKernel
246 | 0xF3411881,
247 | parse_headers_patched);
248 | LOG("parse_headers_hook: %x", g_hooks[0]);
249 | // this hooks loads hardcodes henkaku.suprx loading for SceShell and SceSettings
250 | g_hooks[1] = taiHookFunctionExportForKernel(KERNEL_PID,
251 | &g_start_preloaded_modules_hook,
252 | "SceKernelModulemgr",
253 | 0xC445FA63, // SceModulemgrForKernel
254 | 0x432DCC7A,
255 | start_preloaded_modules_patched);
256 | if (g_hooks[1] < 0) {
257 | g_hooks[1] = taiHookFunctionExportForKernel(KERNEL_PID,
258 | &g_start_preloaded_modules_hook,
259 | "SceKernelModulemgr",
260 | 0x92C9FFC2, // SceModulemgrForKernel
261 | 0x998C7AE9,
262 | start_preloaded_modules_patched);
263 | }
264 | LOG("start_preloaded_modules_hook: %x", g_hooks[1]);
265 | // the next two hooks enable dynarec by patching a system check and a process check
266 | g_hooks[2] = taiHookFunctionExportForKernel(KERNEL_PID,
267 | &g_some_sysroot_check_hook,
268 | "SceSysmem",
269 | 0x3691DA45, // SceSysrootForKernel
270 | 0xF8769E86,
271 | some_sysroot_check_patched);
272 | LOG("some_sysroot_check_hook: %x", g_hooks[2]);
273 | g_hooks[3] = taiHookFunctionExportForKernel(KERNEL_PID,
274 | &g_some_process_check_patched_hook,
275 | "SceSysmem",
276 | 0x63A519E5, // SceSysmemForKernel
277 | 0xD514BB56,
278 | some_process_check_patched);
279 | if (g_hooks[3] < 0) {
280 | g_hooks[3] = taiHookFunctionExportForKernel(KERNEL_PID,
281 | &g_some_process_check_patched_hook,
282 | "SceSysmem",
283 | 0x02451F0F, // SceSysmemForKernel
284 | 0x4E6D8BC3,
285 | some_process_check_patched);
286 | }
287 | LOG("some_process_check_patched_hook: %x", g_hooks[3]);
288 | // this hook patches an auth check in ScePower for enabling overclocking in safe homebrew
289 | g_some_power_auth_check_hook = 0;
290 | g_hooks[4] = taiHookFunctionImportForKernel(KERNEL_PID,
291 | &g_some_power_auth_check_hook,
292 | "ScePower",
293 | 0x9AD8E213, // SceSblACMgrForDriver
294 | 0x8612B243,
295 | some_power_auth_check_patched);
296 | LOG("some_power_auth_check_hook: %x", g_hooks[4]);
297 | if (config.use_spoofed_version) {
298 | // this hook spoofs the system version for the API access
299 | g_hooks[5] = taiHookFunctionExportForKernel(KERNEL_PID,
300 | &g_sceKernelGetSystemSwVersion_hook,
301 | "SceKernelModulemgr",
302 | 0xD4A60A52, // SceModulemgrForDriver
303 | 0x5182E212,
304 | sceKernelGetSystemSwVersion_patched);
305 | LOG("sceKernelGetSystemSwVersion_hook: %x", g_hooks[5]);
306 | // this hook spoofs the system version for internal access
307 | g_hooks[6] = taiHookFunctionExportForKernel(KERNEL_PID,
308 | &g_sceSblUsGetSpkgInfo_hook,
309 | "SceSblUpdateMgr",
310 | 0x31406C49, // SceSblSsUpdateMgr
311 | 0x8E3EC2E1,
312 | sceSblUsGetSpkgInfo_patched);
313 | LOG("sceSblUsGetSpkgInfo_hook: %x", g_hooks[6]);
314 | } else {
315 | LOG("skipping version spoofing");
316 | }
317 | if (argc == 4) {
318 | shell_pid = *(SceUID *)args;
319 | LOG("loading shell plugins");
320 | // normally this would be done automatically by taiHEN
321 | // but since our exploit runs AFTER SceShell is loaded,
322 | // we have to do this manually
323 | taiLoadPluginsForTitleForKernel(shell_pid, "main", 0);
324 | LOG("shell plugins loaded");
325 | }
326 | return SCE_KERNEL_START_SUCCESS;
327 | }
328 |
329 | int module_stop(SceSize argc, const void *args) {
330 | taiHookReleaseForKernel(g_hooks[0], g_parse_headers_hook);
331 | taiHookReleaseForKernel(g_hooks[1], g_start_preloaded_modules_hook);
332 | taiHookReleaseForKernel(g_hooks[2], g_some_sysroot_check_hook);
333 | taiHookReleaseForKernel(g_hooks[3], g_some_process_check_patched_hook);
334 | taiHookReleaseForKernel(g_hooks[4], g_some_power_auth_check_hook);
335 | if (config.use_spoofed_version) {
336 | taiHookReleaseForKernel(g_hooks[5], g_sceKernelGetSystemSwVersion_hook);
337 | taiHookReleaseForKernel(g_hooks[6], g_sceSblUsGetSpkgInfo_hook);
338 | }
339 | return SCE_KERNEL_STOP_SUCCESS;
340 | }
341 |
--------------------------------------------------------------------------------
/henkaku/language.h:
--------------------------------------------------------------------------------
1 | /**
2 | * @brief Language container for HENkaku Settings
3 | */
4 | #ifndef LANGUAGE_HEADER
5 | #define LANGUAGE_HEADER
6 |
7 | typedef struct {
8 | wchar_t *msg_henkaku_settings;
9 | wchar_t *msg_enable_psn_spoofing;
10 | wchar_t *msg_enable_unsafe_homebrew;
11 | wchar_t *msg_unsafe_homebrew_description;
12 | wchar_t *msg_enable_version_spoofing;
13 | wchar_t *msg_spoofed_version;
14 | wchar_t *msg_button_behavior;
15 | wchar_t *msg_button_enter;
16 | wchar_t *msg_button_cancel;
17 | wchar_t *msg_reload_taihen_config;
18 | wchar_t *msg_reload_taihen_config_success;
19 | wchar_t *msg_reboot_device;
20 | wchar_t *msg_content_downloader;
21 | wchar_t *msg_unlink_memory_card;
22 | wchar_t *msg_unlink_memory_card_success;
23 | wchar_t *msg_unlink_memory_card_error;
24 | } language_container_t;
25 |
26 | // by Nzaki0716 & SnyFbSx & kirisame0017
27 | language_container_t language_japanese = {
28 | L"HENkakuの設定",
29 | L"PSNの偽装を有効化",
30 | L"リスクのあるユーザープログラムを有効化",
31 | L"リスクのあるユーザープログラムは誤った操作や設定、または悪意のあるコードにより端末に修復不可能なダメージを与えることがあります。\nこれらをインストールする際は注意してください。",
32 | L"バージョンの偽装を有効化",
33 | L"偽装バージョンの確認",
34 | L"○ボタンの動作設定",
35 | L"決定",
36 | L"キャンセル",
37 | L"taiHEN config.txtのリロード",
38 | L"taiHEN config.txtのリロードが完了しました。",
39 | L"端末の再起動",
40 | L"コンテンツ ダウンローダー",
41 | L"メモリーカードとのリンクを解除する",
42 | L"ux0:id.datが削除されました。メモリーカードはこのVita以外でも使用できるようになりました。",
43 | L"ux0のマウントに失敗しました。メモリーカードは挿入されていますか?",
44 | };
45 |
46 | // by molecule
47 | language_container_t language_english_us = {
48 | L"HENkaku Settings",
49 | L"Enable PSN spoofing",
50 | L"Enable Unsafe Homebrew",
51 | L"Unsafe homebrews can damage your device permanently, if they are misused, misconfigured, or malicious.\nPlease take caution when installing them.",
52 | L"Enable Version Spoofing",
53 | L"Spoofed Version",
54 | L"○ Button Behavior",
55 | L"Enter",
56 | L"Cancel",
57 | L"Reload taiHEN config.txt",
58 | L"taiHEN config.txt has been successfully reloaded.",
59 | L"Reboot Device",
60 | L"Content Downloader",
61 | L"Unlink Memory Card",
62 | L"ux0:id.dat has been deleted. This memory card can now be used on any Vita.",
63 | L"Failed to mount ux0. Is a memory card inserted?",
64 | };
65 |
66 | // by jokira & devnoname120 & CelesteBlue-dev & chronoss09 & francl35
67 | language_container_t language_french = {
68 | L"Paramètres de HENkaku",
69 | L"Activer le spoof du PSN",
70 | L"Autoriser l'installation de homebrews non sécurisés",
71 | L"Les homebrews non sécurisés peuvent endommager votre système de façon permanente s'ils sont mal utilisés, mal configurés, ou malveillants.\nPrenez garde en activant ce paramètre.",
72 | L"Activer le spoof de version",
73 | L"Version spoofée",
74 | L"Action du bouton ○",
75 | L"Valider",
76 | L"Annuler",
77 | L"Recharger le fichier config.txt de taiHEN",
78 | L"Le fichier config.txt de taiHEN a bien été rechargé.",
79 | L"Redémarrer la console",
80 | L"Téléchargement de contenu",
81 | L"Délier la carte mémoire",
82 | L"ux0:id.dat a été supprimé. Cette carte mémoire peut être utilisée sur n'importe quelle Vita.",
83 | L"Le montage de ux0 a échoué. Y a-t-il une carte mémoire insérée?",
84 | };
85 |
86 | // by EricWeichhart & iamn0tdev & WZ-JK
87 | language_container_t language_spanish = {
88 | L"Ajustes de HENkaku",
89 | L"Activar Spoofing para PSN",
90 | L"Activar Homebrew inseguro",
91 | L"Homebrews inseguros pueden dañar tu dispositivo permanentemente si son maliciosos, erróneamente usados o configurados incorrectamente.\nPor favor, tenga precaución al instalarlos.",
92 | L"Activar Spoofing de versión",
93 | L"Versión para Spoofing",
94 | L"Comportamiento del botón ○",
95 | L"Aceptar",
96 | L"Cancelar",
97 | L"Recargar taiHEN config.txt",
98 | L"taiHEN config.txt ha sido recargado correctamente.",
99 | L"Reiniciar dispositivo",
100 | L"Descargador de Contenido",
101 | L"Desvincular la Tarjeta de Memoria",
102 | L"El ux0:id.dat ha sido eliminado. Esta tarjeta de memoria ahora se puede utilizar en cualquier Vita.",
103 | L"Ha habido un fallo al montar el ux0. ¿Se ha insertado una tarjeta de memoria?",
104 | };
105 |
106 | // by Ziusun
107 | language_container_t language_german = {
108 | L"HENkaku-Einstellungen",
109 | L"PSN-Zugang aktivieren",
110 | L"Unsichere Homebrew zulassen",
111 | L"Unsichere Homebrew kann das Gerät dauerhaft beschädigen, sollte sie unsachgemäß eingesetzt und konfiguriert werden oder schadhaft sein.\nDie Installation bitte immer mit größter Sorgfalt vornehmen.",
112 | L"Andere Firmware vortäuschen",
113 | L"Aktuelle Firmware",
114 | L"Funktion der ○-Taste",
115 | L"Bestätigen",
116 | L"Abbrechen",
117 | L"Die config.txt von taiHEN aktualisieren",
118 | L"Die config.txt von taiHEN wurde erfolgreich aktualisiert.",
119 | L"Gerät neustarten",
120 | L"Inhaltsdownloader",
121 | L"Speicherkarte entkoppeln",
122 | L"Der Dateieintrag ux0:id.dat wurde gelöscht. Diese Speicherkarte kann jetzt mit jeder Playstation Vita verwendet werden.",
123 | L"Die Partition ux0: konnte nicht gemountet werden. Ist eine Speicherkarte eingesteckt?",
124 | };
125 |
126 | // by blackjack4it & Checcolino & Rufis01
127 | language_container_t language_italian = {
128 | L"Impostazioni Henkaku",
129 | L"Abilita lo Spoof PSN",
130 | L"Abilita Homebrews non sicuri",
131 | L"Gli Homebrews non sicuri possono danneggiare irrimediabilmente la tua console, se usati/configurati non correttamente o sospetti.\nFai molta attenzione prima di procedere alla loro installazione.",
132 | L"Abilita lo Spoof della versione corrente",
133 | L"Versione corrente (Spoof)",
134 | L"Comportamento del tasto ○",
135 | L"OK",
136 | L"Annulla",
137 | L"Ricarica taiHEN config.txt",
138 | L"TaiHEN config.txt ricaricato correttamente.",
139 | L"Riavvia dispositivo",
140 | L"Scarica contenuto",
141 | L"Disassocia Memory Card",
142 | L"ux0:id.dat è stato cancellato. Adesso questa Memory Card può essere usata su qualsiasi PS Vita.",
143 | L"Impossibile montare ux0. La Memory Card è inserita?",
144 | };
145 |
146 | // by ConsoleHax & 2dook & jja2000
147 | language_container_t language_dutch = {
148 | L"HENkaku Instellingen",
149 | L"Activeer PSN spoofing",
150 | L"Onveilige Homebrew toestaan",
151 | L"Onveilige homebrew kan uw toestel permanent beschadigen indien deze onjuist geconfigureerd of kwaadaardig zijn.\nLet op met wat u installeert.",
152 | L"Schakel Versie Spoofing in",
153 | L"Spoofed Versie",
154 | L"Gedrag van de ○-knop",
155 | L"Enter",
156 | L"Annuleren",
157 | L"Herlaad taiHEN config.txt",
158 | L"taiHEN config.txt is succesvol herladen.",
159 | L"Herstart apparaat",
160 | L"Inhoud downloader",
161 | L"Geheugenkaart loskoppelen",
162 | L"ux0:id.dat is verwijderd. Deze geheugenkaart kan nu op elke Vita gebruikt worden.",
163 | L"Aankoppelen van ux0 is mislukt. Is er wel een geheugenkaart aanwezig?",
164 | };
165 |
166 | // by gnmmarechal & menelkir & bosshunter
167 | language_container_t language_portuguese_pt = {
168 | L"Definições do HENkaku",
169 | L"Ativar spoof da PSN",
170 | L"Permitir aplicações inseguras",
171 | L"Aplicações inseguras podem danificar o sistema permanentemente, se forem mal usadas, configuradas ou maliciosas.\nTenha cuidado ao instalá-las.",
172 | L"Ativar spoof da versão",
173 | L"Versão do spoof",
174 | L"Ação do botão ○",
175 | L"Entrar",
176 | L"Cancelar",
177 | L"Recarrege o ficheiro config.txt do taiHEN",
178 | L"O ficheiro taiHEN config.txt foi recarregado com sucesso.",
179 | L"Reiniciar o dispositivo",
180 | L"Descarregar Conteúdo",
181 | L"Desassociar Cartão de Memória",
182 | L"ux0:id.dat foi eliminado. Este cartão de memória pode agora ser usado em qualquer Vita.",
183 | L"Falha ao montar ux0. O cartão de memória está inserido?",
184 | };
185 |
186 | // by Tenek & MuskratDesman & dec0dOS
187 | language_container_t language_russian = {
188 | L"Настройки HENkaku",
189 | L"Включить спуфинг PSN",
190 | L"Включить небезопасные приложения",
191 | L"Небезопасные приложения могут повредить ваше устройство навсегда, если они используются неправильно, неправильно настроены или вредоносны.\nПожалуйста, проявляйте осторожность при их установке.",
192 | L"Включить подмену версии",
193 | L"Поддельная версия",
194 | L"Поведение кнопки ○",
195 | L"Ввод",
196 | L"Отмена",
197 | L"Перезагрузить taiHEN config.txt",
198 | L"taiHEN config.txt был успешно перезагружен.",
199 | L"Перезапустить устройство",
200 | L"Загрузчик контента",
201 | L"Отвязать карту памяти",
202 | L"ux0:id.dat был удален. Эта карта памяти теперь может быть использована на любой PSVita.",
203 | L"Ошибка при монтировании ux0. Проверьте, вставлена ли карта памяти",
204 | };
205 |
206 | // by TriggerHavoc
207 | language_container_t language_korean = {
208 | L"HENkaku 설정",
209 | L"PSN 스푸핑 활성화",
210 | L"안전하지 않은 홈브류 활성화",
211 | L"만약 홈브류가 오설정, 또는 악성코드등 오용된다면, 안전하지 않은 홈브류 활성화 옵션은 당신의 디바이스에 영구적으로 피해를 줄 수 있습니다.\n홈브류를 설치할 때 주의해주세요.",
212 | L"버전 스푸핑 활성화",
213 | L"스푸핑 버전",
214 | L"○ 버튼 설정",
215 | L"확인",
216 | L"취소",
217 | L"taiHEN config.txt를 다시 로드하기",
218 | L"taiHEN config.txt를 성공적으로 로드했습니다.",
219 | L"기기 재부팅",
220 | L"컨텐츠 다운로더",
221 | L"메모리 카드 언링크",
222 | L"ux0:id.dat 파일이 삭제되었습니다. 이제 이 메모리 카드는 모든 비타에서 사용하실 수 있습니다.",
223 | L"ux0에 마운트 할 수 없습니다. 메모리 카드가 올바르게 삽입되어 있습니까?",
224 | };
225 |
226 | // by iTZQing & FlexingTiger & magpte
227 | language_container_t language_chinese_t = {
228 | L"HENkaku設置",
229 | L"啟用PSN偽裝",
230 | L"啟用不安全自制軟件",
231 | L"如果不安全自制軟件被誤用、配置出現錯誤或軟件本身是惡意程序,可能會永久性損壞你的設備。\n請謹慎安裝!",
232 | L"啟用版本偽裝",
233 | L"偽裝版本",
234 | L"○鍵配置",
235 | L"確定",
236 | L"取消",
237 | L"重載taiHEN config.txt",
238 | L"重載taiHEN config.txt成功",
239 | L"重啟設備",
240 | L"下載內容管理器",
241 | L"解除記憶卡關聯",
242 | L"已刪除ux0:id.dat,現在這張記憶卡可應用到任意PSV上",
243 | L"掛載ux0失敗,請檢查記憶卡是否插入",
244 | };
245 |
246 | // by iTZQing & FlexingTiger & magpte
247 | language_container_t language_chinese_s = {
248 | L"HENkaku设置",
249 | L"启用PSN伪装",
250 | L"启用不安全自制软件",
251 | L"如果不安全自制软件被误用、配置出现错误或软件本身是恶意程序,可能会永久性损坏你的设备。\n请谨慎安装!",
252 | L"启用版本伪装",
253 | L"伪装版本",
254 | L"○键配置",
255 | L"确定",
256 | L"取消",
257 | L"重载taiHEN config.txt",
258 | L"重载taiHEN config.txt成功",
259 | L"重启设备",
260 | L"下载内容管理器",
261 | L"解除存储卡关联",
262 | L"已删除ux0:id.dat,现在这张存储卡可用在任意PSV上",
263 | L"挂载ux0失败,请检查存储卡是否插入",
264 | };
265 |
266 | // by v5000a & poppamies
267 | language_container_t language_finnish = {
268 | L"HENkakun Asetukset",
269 | L"Ota PSN spooffaaminen käyttöön",
270 | L"Salli vaaralliset homebrew-ohjelmat",
271 | L"Vaaralliset homebrew-ohjelmat voivat vahingoittaa laitettasi pysyvästi, mikäli niitä käytetään väärin, ne konfiguroidaan väärin, tai ne ovat haittaohjelmia.\nOle varovainen asentaessasi niitä.",
272 | L"Ota version spooffaaminen käyttöön",
273 | L"Spooffattu versio",
274 | L"○-näppäimen toiminto",
275 | L"Valitse",
276 | L"Peruuta",
277 | L"Lataa taiHEN config.txt uudelleen",
278 | L"taiHEN config.txt uudelleenladattiin onnistuneesti.",
279 | L"Käynnistä laite uudelleen",
280 | L"Sisällönlataaja",
281 | L"Irrota muistikortti",
282 | L"ux0:id.dat on poistettu. Voit nyt käyttää tätä muistikorttia millä tahansa Vitalla.",
283 | L"ux0:n liittäminen epäonnistui. Onko muistikortti laitteessa?",
284 | };
285 |
286 | // by MrOrbital & GizmoTheGreen & Wassburgare
287 | language_container_t language_swedish = {
288 | L"HENkaku-inställningar",
289 | L"Aktivera fejkad PSN-inloggning",
290 | L"Tillåt osäkra homebrews",
291 | L"Osäkra homebrews kan skada din enhet permanent om de används felaktigt, är felkonfigurerade eller innehåller skadlig kod.\nVar försiktig vid installation av sådana.",
292 | L"Aktivera fejkad version",
293 | L"Fejkad version",
294 | L"○-knappens beteende",
295 | L"Välj",
296 | L"Avbryt",
297 | L"Ladda om taiHEN config.txt",
298 | L"taiHEN config.txt har laddats om.",
299 | L"Starta om enhet",
300 | L"Innehållsnedladdare",
301 | L"Avlänka minneskort",
302 | L"ux0:id.dat har tagits bort. Det här minneskortet kan nu användas i valfri Vita.",
303 | L"Misslyckades med att montera ux0. Har du satt i ett minneskort?",
304 | };
305 |
306 | // by coestergaard & andrsnDK
307 | language_container_t language_danish = {
308 | L"HENkaku indstillinger",
309 | L"Aktiver PSN spoofing",
310 | L"Tillad usikre homebrews",
311 | L"Usikre homebrews kan skade din enhed permanent, hvis de bruges forkert, er fejlkonfigurerede eller indeholder skadelig kode.\nVær forsigtig når du installerer disse.",
312 | L"Aktiver version spoofing",
313 | L"Spoofed version",
314 | L"○ knap funktion",
315 | L"Vælg",
316 | L"Afbryd",
317 | L"Genindlæs taiHEN config.txt",
318 | L"taiHEN config.txt er blevet genindlæst.",
319 | L"Genstart enhed",
320 | L"Indholdshenter",
321 | L"Fjern link til hukommelseskort",
322 | L"ux0:id.dat er blevet slettet. Dette hukommelseskort kan nu bruges på en vilkårlig Vita.",
323 | L"Kunne ikke montere ux0. Er der indsat et hukommelseskort?",
324 | };
325 |
326 | // by baniel105 & irchagaming & Promises
327 | language_container_t language_norwegian = {
328 | L"HENkaku Instillinger",
329 | L"Aktiver forfalsket PSN-innlogging",
330 | L"Tillat usikker Homebrew",
331 | L"Usikre Homebrews kan ødelegge enhenten din permanent, hvis de er misbrukt, feilkonfigerert, eller inneholder skadelig programvare.\nVær forsiktig ved installasjon.",
332 | L"Aktiver forfalsket versjon",
333 | L"Forfalsket versjon",
334 | L"Funksjon på ○-knapp",
335 | L"Velg",
336 | L"Avbryt",
337 | L"Last på nytt taiHEN config.txt",
338 | L"taiHEN config.txt har blitt lastet.",
339 | L"Start enheten på nytt",
340 | L"Innholds Nedlaster",
341 | L"Lås opp Minnekort",
342 | L"ux0:id.dat er slettet. Dette minnekortet kan brukest på hvilken som helst Vita.",
343 | L"Klarte ikkje montere av ux0. Har du satt i eit minnekort?",
344 | };
345 |
346 | // by Grzybojad & szczuru & ItsYogSothoth & szczuru
347 | language_container_t language_polish = {
348 | L"Ustawienia HENkaku",
349 | L"Włącz fałszowanie PSN/SEN (spoofing)",
350 | L"Zezwól na podejrzane Homebrew",
351 | L"Podejrzane aplikacje mogą zawierać złośliwe oprogramowanie, przez co mogą trwale uszkodzić twoje urządzenie, jeżeli zostaną niepoprawnie użyte, bądź źle skonfigurowane.\nProszę zachować ostrożność przy ich instalacji.",
352 | L"Włącz fałszowanie wersji oprogramowania (spoofing)",
353 | L"Fałszowana wersja",
354 | L"Akcja przycisku ○",
355 | L"OK",
356 | L"Anuluj",
357 | L"Załaduj ponownie config.txt taiHEN",
358 | L"config.txt taiHEN został pomyślnie załadowany ponownie.",
359 | L"Uruchom ponownie konsolę",
360 | L"Pobieranie zawartości",
361 | L"Odłącz kartę pamięci",
362 | L"Plik ux0:id.dat został usunięty z karty pamięci. Można jej teraz używać z każdym systemem PS Vita.",
363 | L"Błąd podczas montowania partycji ux0, czy karta pamięci jest włożona?",
364 | };
365 |
366 | // by GrayJack & haouingvalt & menelkir
367 | language_container_t language_portuguese_br = {
368 | L"Configurações do HENkaku",
369 | L"Habilitar mimetização da PSN ",
370 | L"Habilitar softwares 'homebrew' inseguros",
371 | L"Softwares 'homebrew' inseguros podem danificar o seu aparelho permanentemente caso sejam usados ou configurados incorretamente, ou até mesmo maliciosos.\nPor favor, tenha cuidado ao instalá-los.",
372 | L"Habilitar mimetização de Versão",
373 | L"Versão a mimetizar",
374 | L"Ação do botão ○",
375 | L"Entrar",
376 | L"Cancelar",
377 | L"Recarrege o arquivo config.txt do taiHEN",
378 | L"taiHEN config.txt foi recarregado com sucesso.",
379 | L"Reiniciar o dispositivo",
380 | L"Baixar Conteúdo",
381 | L"Desassociar o Cartão de Memória",
382 | L"ux0:id.dat foi deletado. Agora este cartão de memória pode ser usado em qualquer Vita.",
383 | L"Falha ao montar ux0. O cartão de memória está inserido?",
384 | };
385 |
386 | // by molecule
387 | language_container_t language_english_gb = {
388 | L"HENkaku Settings",
389 | L"Enable PSN spoofing",
390 | L"Enable Unsafe Homebrew",
391 | L"Unsafe homebrews can damage your device permanently, if they are misused, misconfigured, or malicious.\nPlease take caution when installing them.",
392 | L"Enable Version Spoofing",
393 | L"Spoofed Version",
394 | L"○ Button Behaviour",
395 | L"Enter",
396 | L"Cancel",
397 | L"Reload taiHEN config.txt",
398 | L"taiHEN config.txt has been successfully reloaded.",
399 | L"Reboot Device",
400 | L"Content Downloader",
401 | L"Unlink Memory Card",
402 | L"ux0:id.dat has been deleted. This memory card can now be used on any Vita.",
403 | L"Failed to mount ux0. Is a memory card inserted?",
404 | };
405 |
406 | // by Chronicl3
407 | language_container_t language_turkish = {
408 | L"HENkaku Ayarları",
409 | L"PSN spoofing Etkinleştir",
410 | L"Yabancı Uygulamalara İzin Ver ",
411 | L"Bilinmeyen kaynaklardan uygulama yüklerken dikkatli olunuz.\nKötü niyetli,yanlış yapılandırılmış uygulamalar cihazınıza kalıcı zararlar verebilir.",
412 | L"Versiyon Spoofing Etkinleştir",
413 | L"Spoofed Versiyon",
414 | L"○ Düğmesi Davranışı",
415 | L"Gir",
416 | L"İptal",
417 | L"taiHEN config.txt'yi yeniden yükle",
418 | L"taiHEN config.txt başarılı bir şekilde yeniden yüklendi.",
419 | L"Cihazı yeniden başlat",
420 | L"İçerik İndiricisi",
421 | L"Hafıza Kartı Bağlantısını Kaldır",
422 | L"ux0:id.dat silindi.Bu hafıza kartı şuan herhangi bir vita da kullanılabilir.",
423 | L"ux0 dizin okuma başarısız oldu.Hafıza kartınız takılı mı?",
424 | };
425 |
426 | #endif // LANGUAGE_HEADER
427 |
--------------------------------------------------------------------------------
/enso/logo.h:
--------------------------------------------------------------------------------
1 | static const unsigned char logo_data[] = {
2 | 0x1f, 0x8b, 0x08, 0x00, 0x6f, 0xed, 0x0f, 0x59, 0x02, 0x03, 0xed, 0xdc,
3 | 0x41, 0x6e, 0x03, 0x21, 0x10, 0x44, 0x51, 0xdf, 0xff, 0xd2, 0xce, 0x09,
4 | 0x22, 0xdb, 0x63, 0x18, 0x37, 0x55, 0xef, 0x49, 0xb3, 0x0c, 0xd0, 0xec,
5 | 0xbe, 0x48, 0xf2, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
13 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x3d,
59 | 0x9f, 0xcf, 0x97, 0x1f, 0x00, 0x00, 0x00, 0x24, 0xf6, 0xae, 0x16, 0x06,
60 | 0x00, 0x00, 0xa0, 0xb9, 0x7d, 0x75, 0x30, 0x00, 0x00, 0x00, 0x2d, 0xdd,
61 | 0xab, 0x81, 0x01, 0x00, 0x00, 0x68, 0x6a, 0x5f, 0x0d, 0x0c, 0x00, 0x00,
62 | 0x40, 0x4b, 0xfb, 0x6a, 0x60, 0x00, 0x00, 0x00, 0x5a, 0xda, 0x57, 0x03,
63 | 0x03, 0x00, 0x00, 0xd0, 0xd2, 0xbe, 0x1a, 0x18, 0x00, 0x00, 0x00, 0xfd,
64 | 0x0b, 0x00, 0x00, 0x00, 0x39, 0xed, 0xab, 0x81, 0x01, 0x00, 0x00, 0x68,
65 | 0xea, 0x5f, 0x0d, 0x0c, 0x00, 0x00, 0x40, 0x43, 0xfb, 0xea, 0x5f, 0x00,
66 | 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00,
67 | 0x38, 0xa5, 0x7d, 0x35, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x17, 0x00, 0x00,
68 | 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0,
69 | 0xbf, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0xfd, 0x0b, 0x00, 0x00, 0x80, 0xfe,
70 | 0xd5, 0xbf, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0xfd, 0x0b, 0x00, 0x00, 0x80,
71 | 0x06, 0xd6, 0xbe, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0,
72 | 0xbf, 0x00, 0x00, 0x00, 0x70, 0x76, 0x03, 0x03, 0x00, 0x00, 0x40, 0x7a,
73 | 0xff, 0x02, 0x00, 0x00, 0x40, 0x7a, 0x03, 0x03, 0x00, 0x00, 0x80, 0xfe,
74 | 0x05, 0x00, 0x00, 0x80, 0xf3, 0x1b, 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b,
75 | 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b, 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b,
76 | 0x18, 0x00, 0x00, 0x00, 0x92, 0x3b, 0x18, 0x00, 0x00, 0x00, 0x92, 0x3b,
77 | 0x18, 0x00, 0x00, 0x00, 0xd2, 0x1b, 0x18, 0x00, 0x00, 0x00, 0xf4, 0x2f,
78 | 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0, 0xbf, 0x00, 0x00,
79 | 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0x40, 0xff, 0x02, 0x00, 0x00, 0x80,
80 | 0xfe, 0x05, 0x00, 0x00, 0x00, 0xfd, 0x0b, 0x00, 0x00, 0x80, 0xfe, 0xd5,
81 | 0xbf, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xd0, 0xbf, 0x00,
82 | 0x00, 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0x40, 0xff, 0x02, 0x00, 0x00,
83 | 0x80, 0xfe, 0x05, 0x00, 0x00, 0x00, 0xfd, 0x0b, 0x00, 0x00, 0x00, 0xfa,
84 | 0x17, 0x00, 0x00, 0x00, 0xfd, 0xab, 0x7f, 0x01, 0x00, 0x00, 0xd0, 0xbf,
85 | 0xfa, 0x17, 0x00, 0x00, 0x00, 0xfd, 0x0b, 0x00, 0x00, 0x00, 0xfa, 0x17,
86 | 0x00, 0x00, 0x00, 0xf4, 0x2f, 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00,
87 | 0x00, 0xd0, 0xbf, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01, 0x00, 0x00, 0x40,
88 | 0xff, 0x02, 0x00, 0x00, 0xd0, 0xdd, 0xb8, 0x57, 0x3f, 0x00, 0x00, 0x00,
89 | 0x48, 0x6d, 0x5e, 0x3d, 0x0c, 0x00, 0x00, 0x40, 0x6b, 0xf7, 0x6a, 0x60,
90 | 0x00, 0x00, 0x00, 0x5a, 0xba, 0x57, 0x07, 0x03, 0x00, 0x00, 0xd0, 0xd4,
91 | 0xbd, 0x3a, 0x18, 0x00, 0x00, 0x80, 0xb6, 0xf6, 0xd5, 0xc0, 0x00, 0x00,
92 | 0x00, 0xb4, 0xb4, 0xaf, 0x06, 0x06, 0x00, 0x00, 0xa0, 0xa1, 0x7b, 0x75,
93 | 0x30, 0x00, 0x00, 0x00, 0x6d, 0xed, 0xab, 0x81, 0x01, 0x00, 0x00, 0x68,
94 | 0x69, 0x5f, 0x0d, 0x0c, 0x00, 0x00, 0x40, 0x4b, 0xfb, 0x6a, 0x60, 0x00,
95 | 0x00, 0x00, 0xa6, 0xb6, 0xa6, 0x06, 0x06, 0x00, 0x00, 0x60, 0x62, 0xfb,
96 | 0x3a, 0x2b, 0x00, 0x00, 0x00, 0xa9, 0xfd, 0xeb, 0xdc, 0x00, 0x00, 0x00,
97 | 0x68, 0x5f, 0xe7, 0x07, 0x00, 0x00, 0x40, 0x3b, 0x9a, 0x03, 0x00, 0x00,
98 | 0x80, 0xc9, 0xdd, 0xa8, 0xe5, 0x01, 0x00, 0x00, 0xd0, 0xbe, 0x66, 0x02,
99 | 0x00, 0x00, 0xe0, 0xec, 0x56, 0xd4, 0xf5, 0x00, 0x00, 0x00, 0x68, 0x5f,
100 | 0xf3, 0x01, 0x00, 0x00, 0xa0, 0x0d, 0xcd, 0x09, 0x00, 0x00, 0xc0, 0xe4,
101 | 0x2e, 0x34, 0x2b, 0x00, 0x00, 0x00, 0xe9, 0x4d, 0x68, 0x5e, 0x00, 0x00,
102 | 0x00, 0xd2, 0x5b, 0xb0, 0xb1, 0x7f, 0x35, 0x30, 0x00, 0x00, 0x40, 0x5f,
103 | 0xff, 0x9a, 0x1b, 0x00, 0x00, 0x00, 0x1d, 0x68, 0x6e, 0x00, 0x00, 0x00,
104 | 0xce, 0xef, 0x40, 0xb3, 0x03, 0x00, 0x00, 0xa0, 0x01, 0xcd, 0x0e, 0x00,
105 | 0x00, 0x80, 0x06, 0x3c, 0x7d, 0x76, 0x0d, 0x0c, 0x00, 0x00, 0xa0, 0xff,
106 | 0xcc, 0x0f, 0x00, 0x00, 0x80, 0xfe, 0x33, 0x3f, 0x00, 0x00, 0x00, 0xfa,
107 | 0xcf, 0xfc, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0xf3, 0x03, 0x00, 0x00, 0xa0,
108 | 0xff, 0xcc, 0x0f, 0x00, 0x00, 0xc0, 0xea, 0xfe, 0x73, 0x07, 0xfa, 0x17,
109 | 0x00, 0x00, 0x40, 0xfb, 0xb9, 0x03, 0x00, 0x00, 0x00, 0xb4, 0x9f, 0x3b,
110 | 0x00, 0x00, 0x00, 0x40, 0xfb, 0xb9, 0x03, 0x00, 0x00, 0x00, 0xb4, 0x9f,
111 | 0x3b, 0x00, 0x00, 0x00, 0x40, 0xfb, 0xb9, 0x03, 0x00, 0x00, 0x00, 0xd6,
112 | 0xb6, 0x5f, 0x6a, 0xff, 0xe9, 0x5f, 0x00, 0x00, 0x00, 0xfd, 0xab, 0x7f,
113 | 0xf5, 0x2f, 0x00, 0x00, 0x80, 0xfe, 0x35, 0x3f, 0x00, 0x00, 0x00, 0xfa,
114 | 0xcf, 0xfc, 0x00, 0x00, 0x00, 0xe8, 0x3f, 0xf3, 0x03, 0x00, 0x00, 0xa0,
115 | 0xff, 0xcc, 0x0f, 0x00, 0x00, 0xc0, 0x2f, 0x1b, 0x50, 0xff, 0x02, 0x00,
116 | 0x00, 0xa0, 0x7f, 0xcd, 0x0e, 0x00, 0x00, 0x80, 0x06, 0x34, 0x3b, 0x00,
117 | 0x00, 0x00, 0xa7, 0x34, 0x60, 0x52, 0x07, 0xfa, 0xdd, 0x67, 0x00, 0x00,
118 | 0x00, 0xfd, 0xab, 0x7f, 0xf5, 0x2f, 0x00, 0x00, 0x40, 0x7b, 0xff, 0x26,
119 | 0xb4, 0x60, 0xe3, 0xcc, 0x00, 0x00, 0x00, 0x3c, 0xf4, 0xaf, 0xf6, 0x05,
120 | 0x00, 0x00, 0xd0, 0xbf, 0x61, 0x4d, 0xe8, 0xed, 0x17, 0x00, 0x00, 0x40,
121 | 0xff, 0xa6, 0x77, 0x61, 0xcb, 0x9c, 0x00, 0x00, 0x00, 0xf4, 0xb6, 0xa1,
122 | 0xf6, 0x05, 0x00, 0x00, 0x40, 0xff, 0xea, 0x5f, 0x00, 0x00, 0x00, 0x0d,
123 | 0x7c, 0x7e, 0x23, 0x6a, 0x5f, 0x00, 0x00, 0x00, 0x56, 0x74, 0xe2, 0xe4,
124 | 0x5e, 0x4c, 0x9b, 0x07, 0x00, 0x00, 0x00, 0x0d, 0x9c, 0xde, 0xf2, 0x00,
125 | 0x00, 0x00, 0x68, 0x47, 0xed, 0x0b, 0x00, 0x00, 0x40, 0x53, 0x43, 0x6a,
126 | 0x5f, 0x00, 0x00, 0x00, 0xee, 0x6e, 0xc9, 0xbb, 0x9a, 0x72, 0xd5, 0x39,
127 | 0xf5, 0x2f, 0x00, 0x00, 0x80, 0xfe, 0x9d, 0xd8, 0x96, 0xd3, 0xcf, 0x07,
128 | 0x00, 0x00, 0x40, 0x6f, 0x03, 0x4f, 0xfd, 0x00, 0x00, 0x00, 0x40, 0xfb,
129 | 0x02, 0x00, 0x00, 0xa0, 0x81, 0xb5, 0x2f, 0x00, 0x00, 0x00, 0x1a, 0x58,
130 | 0xfb, 0x02, 0x00, 0x00, 0xa0, 0x83, 0x35, 0x30, 0x00, 0x00, 0x00, 0xfa,
131 | 0x57, 0x03, 0x03, 0x00, 0x00, 0xa0, 0x83, 0xf5, 0x2f, 0x00, 0x00, 0x00,
132 | 0x3a, 0x58, 0x03, 0x03, 0x00, 0x00, 0xa0, 0x81, 0xf5, 0x2f, 0x00, 0x00,
133 | 0x00, 0x19, 0x1d, 0x7c, 0xe5, 0x2c, 0x00, 0x00, 0x00, 0x30, 0xbd, 0x87,
134 | 0x57, 0xed, 0x0d, 0x00, 0x00, 0x00, 0x13, 0xba, 0x78, 0xf7, 0x3e, 0x00,
135 | 0x00, 0x00, 0xd0, 0xd2, 0xda, 0x00, 0x00, 0x00, 0xd0, 0xd0, 0xbf, 0x1a,
136 | 0x18, 0x00, 0x00, 0x80, 0x96, 0x06, 0x06, 0x00, 0x00, 0x00, 0x0d, 0x0c,
137 | 0x00, 0x00, 0x00, 0x79, 0xfd, 0xab, 0x8f, 0x01, 0x00, 0x00, 0x48, 0x6f,
138 | 0x60, 0xef, 0xc5, 0x00, 0x00, 0x00, 0x68, 0x60, 0x1d, 0x0c, 0x00, 0x00,
139 | 0x40, 0x6f, 0xff, 0x6a, 0x60, 0x00, 0x00, 0x00, 0x34, 0x30, 0x00, 0x00,
140 | 0x00, 0x64, 0xf5, 0xaf, 0x06, 0x06, 0x00, 0x00, 0xa0, 0xa5, 0x7f, 0x35,
141 | 0x30, 0x00, 0x00, 0x00, 0x0d, 0xed, 0xab, 0x81, 0x01, 0x00, 0x00, 0x38,
142 | 0xa1, 0x7f, 0xef, 0x5c, 0x0b, 0x00, 0x00, 0x00, 0xee, 0x6e, 0xdf, 0x29,
143 | 0xeb, 0x02, 0x00, 0x00, 0xc0, 0xae, 0xfe, 0x9d, 0xb8, 0x36, 0x00, 0x00,
144 | 0x00, 0x4c, 0xea, 0x53, 0x0d, 0x0c, 0x00, 0x00, 0xc0, 0xf4, 0xfe, 0x3d,
145 | 0x6d, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0xb4, 0x49, 0xf5, 0x2f, 0x00, 0x00,
146 | 0x00, 0x0d, 0xfd, 0x7b, 0xfa, 0x7e, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01,
147 | 0x00, 0x00, 0xd0, 0xbf, 0xfa, 0x17, 0x00, 0x00, 0x80, 0x8e, 0xfe, 0x4d,
148 | 0xda, 0x13, 0x00, 0x00, 0x00, 0xfd, 0xab, 0x7f, 0x01, 0x00, 0x00, 0x68,
149 | 0xee, 0xdf, 0x5d, 0x3d, 0xaa, 0x7f, 0x01, 0x00, 0x00, 0x48, 0xef, 0x5f,
150 | 0x7f, 0xff, 0x0b, 0x00, 0x00, 0x80, 0xfe, 0xd5, 0xbf, 0x00, 0x00, 0x00,
151 | 0xe8, 0x5f, 0x00, 0x00, 0x00, 0x48, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0x48,
152 | 0x68, 0x60, 0x6f, 0xbf, 0x00, 0x00, 0x00, 0x4c, 0xee, 0xdf, 0x15, 0x6d,
153 | 0x7a, 0xc7, 0x1e, 0x00, 0x00, 0x00, 0xf0, 0x4d, 0x97, 0x7e, 0xdb, 0xa7,
154 | 0xda, 0x17, 0x00, 0x00, 0x80, 0x53, 0xda, 0xf7, 0x6a, 0xa7, 0xee, 0x6e,
155 | 0x6b, 0x00, 0x00, 0x00, 0x58, 0xd9, 0xbd, 0x9f, 0xf6, 0xea, 0x1d, 0xef,
156 | 0xca, 0x00, 0x00, 0x00, 0xb0, 0xb3, 0x7d, 0x57, 0x7e, 0x00, 0x00, 0x00,
157 | 0x90, 0xde, 0xbe, 0xfa, 0x17, 0x00, 0x00, 0x80, 0x77, 0x3b, 0x56, 0xfb,
158 | 0x02, 0x00, 0x00, 0x90, 0xda, 0xbc, 0x9f, 0x36, 0xa5, 0xf6, 0x05, 0x00,
159 | 0x00, 0x20, 0xa5, 0x7b, 0x77, 0xb5, 0xa9, 0xee, 0x05, 0x00, 0x00, 0x20,
160 | 0xad, 0x7b, 0x77, 0xbf, 0x1f, 0x03, 0x00, 0x00, 0xc0, 0xd4, 0xf6, 0x5d,
161 | 0x71, 0x2e, 0x00, 0x00, 0x00, 0x98, 0xd0, 0xbe, 0xab, 0xcf, 0x0a, 0x00,
162 | 0x00, 0x00, 0x29, 0xed, 0x0b, 0x00, 0x00, 0x00, 0xa7, 0xf4, 0x2f, 0x00,
163 | 0x00, 0x00, 0x4c, 0x6d, 0xdf, 0x15, 0xed, 0x0c, 0x00, 0x00, 0x00, 0x93,
164 | 0xfb, 0xf7, 0x8e, 0x35, 0x00, 0x00, 0x00, 0x60, 0x72, 0xfb, 0x6a, 0x60,
165 | 0x00, 0x00, 0x00, 0x4e, 0xef, 0xdf, 0x5f, 0xaf, 0x07, 0x00, 0x00, 0x00,
166 | 0x13, 0xfb, 0xf7, 0xd5, 0x9a, 0x00, 0x00, 0x00, 0x30, 0xad, 0x7f, 0x27,
167 | 0xad, 0x09, 0x00, 0x00, 0x00, 0xfa, 0x17, 0x00, 0x00, 0x00, 0xf4, 0x2f,
168 | 0x00, 0x00, 0x00, 0xe8, 0x5f, 0x00, 0x00, 0x00, 0xda, 0xfb, 0xd7, 0xff,
169 | 0x7f, 0x06, 0x00, 0x00, 0x40, 0xff, 0xea, 0x5f, 0x00, 0x00, 0x00, 0x3a,
170 | 0x1b, 0xf8, 0xd5, 0x3a, 0xfa, 0x17, 0x00, 0x00, 0x80, 0xc9, 0xfd, 0xfb,
171 | 0x4e, 0xb7, 0x6a, 0x5f, 0x00, 0x00, 0x00, 0x12, 0xfa, 0xf7, 0xbf, 0x8e,
172 | 0xbd, 0xfa, 0x73, 0x00, 0x00, 0x00, 0x70, 0x42, 0x03, 0x7f, 0xd3, 0xcc,
173 | 0x00, 0x00, 0x00, 0x90, 0xd8, 0xc0, 0x00, 0x00, 0x00, 0xa0, 0x7f, 0x01,
174 | 0x00, 0x00, 0xe0, 0xec, 0x0e, 0x06, 0x00, 0x00, 0x80, 0xf4, 0x06, 0x06,
175 | 0x00, 0x00, 0x80, 0xf4, 0x06, 0x06, 0x00, 0x00, 0x80, 0xd4, 0x16, 0x06,
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
182 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
196 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
197 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xe7, 0x0f, 0xea, 0x59, 0x23, 0xf7,
230 | 0x00, 0xe0, 0x1f, 0x00
231 | };
232 | static const unsigned int logo_len = 2740;
233 |
--------------------------------------------------------------------------------
/installer/src/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include "sha256.h"
25 | #include "pspdebug.h"
26 |
27 | #define printf psvDebugScreenPrintf
28 |
29 | #define APP_PATH "ux0:app/UPDATE365/"
30 | #define PUP_URL "https://github.com/TheOfficialFloW/update365/releases/download/v0.1/PSP2UPDAT.PUP"
31 |
32 | #define CHUNK_SIZE 64 * 1024
33 |
34 | static uint8_t psp2updat_pup_hash[0x20] = {
35 | 0x86, 0x85, 0x9B, 0x30, 0x71, 0x68, 0x12, 0x68,
36 | 0xB6, 0xD0, 0xBE, 0xB5, 0xEF, 0x69, 0x1D, 0xA8,
37 | 0x74, 0xB6, 0x72, 0x6E, 0x85, 0xB6, 0xF0, 0x6A,
38 | 0x1C, 0xDF, 0x6A, 0x0E, 0x18, 0x3E, 0x77, 0xC6
39 | };
40 |
41 | const char taihen_config_recovery_header[] =
42 | "# This file is used as an alternative if ux0:tai/config.txt is not found.\n";
43 |
44 | const char taihen_config_header[] =
45 | "# For users plugins, you must refresh taiHEN from HENkaku Settings for\n"
46 | "# changes to take place.\n"
47 | "# For kernel plugins, you must reboot for changes to take place.\n";
48 |
49 | const char taihen_config[] =
50 | "*KERNEL\n"
51 | "# henkaku.skprx is hard-coded to load and is not listed here\n"
52 | "*main\n"
53 | "# main is a special titleid for SceShell\n";
54 |
55 | const char *clean_files[] = {
56 | "ud0:PSP2UPDATE/PSP2UPDAT.PUP",
57 | "ud0:PSP2UPDATE/psp2swu.self",
58 | "ud0:PSP2UPDATE/ENSOUPDAT.PUP",
59 | "ud0:PSP2UPDATE/ensoswu.self",
60 | };
61 |
62 | void clean_ud0() {
63 | int i;
64 | for (i = 0; i < (sizeof(clean_files) / sizeof(char **)); i++) {
65 | sceIoRemove(clean_files[i]);
66 | }
67 | }
68 |
69 | int verify_cleaned() {
70 | int ret;
71 | SceIoStat stat;
72 |
73 | int i;
74 | for (i = 0; i < (sizeof(clean_files) / sizeof(char **)); i++) {
75 | if (sceIoGetstat(clean_files[i], &stat) >= 0) {
76 | return -1;
77 | }
78 | }
79 |
80 | return 0;
81 | }
82 |
83 | void ErrorExit(int milisecs, char *fmt, ...) {
84 | va_list list;
85 | char msg[256];
86 |
87 | va_start(list, fmt);
88 | vsprintf(msg, fmt, list);
89 | va_end(list);
90 |
91 | printf(msg);
92 |
93 | sceKernelPowerUnlock(0);
94 | clean_ud0();
95 | sceKernelDelayThread(milisecs * 1000);
96 | sceKernelExitProcess(0);
97 | }
98 |
99 | int write_taihen_config(const char *path, int recovery) {
100 | int fd;
101 |
102 | // write default config
103 | sceIoRemove(path);
104 | fd = sceIoOpen(path, SCE_O_TRUNC | SCE_O_CREAT | SCE_O_WRONLY, 6);
105 | if (recovery) {
106 | sceIoWrite(fd, taihen_config_recovery_header, sizeof(taihen_config_recovery_header) - 1);
107 | }
108 | sceIoWrite(fd, taihen_config_header, sizeof(taihen_config_header) - 1);
109 | sceIoWrite(fd, taihen_config, sizeof(taihen_config) - 1);
110 | sceIoClose(fd);
111 |
112 | return 0;
113 | }
114 |
115 | int extract(const char *pup, const char *psp2swu) {
116 | int inf, outf;
117 |
118 | if ((inf = sceIoOpen(pup, SCE_O_RDONLY, 0)) < 0) {
119 | return -1;
120 | }
121 |
122 | if ((outf = sceIoOpen(psp2swu, SCE_O_CREAT | SCE_O_WRONLY | SCE_O_TRUNC, 6)) < 0) {
123 | return -1;
124 | }
125 |
126 | int ret = -1;
127 | int count;
128 |
129 | if (sceIoLseek(inf, 0x18, SCE_SEEK_SET) < 0) {
130 | goto end;
131 | }
132 |
133 | if (sceIoRead(inf, &count, 4) < 4) {
134 | goto end;
135 | }
136 |
137 | if (sceIoLseek(inf, 0x80, SCE_SEEK_SET) < 0) {
138 | goto end;
139 | }
140 |
141 | struct {
142 | uint64_t id;
143 | uint64_t off;
144 | uint64_t len;
145 | uint64_t field_18;
146 | } __attribute__((packed)) file_entry;
147 |
148 | for (int i = 0; i < count; i++) {
149 | if (sceIoRead(inf, &file_entry, sizeof(file_entry)) != sizeof(file_entry)) {
150 | goto end;
151 | }
152 |
153 | if (file_entry.id == 0x200) {
154 | break;
155 | }
156 | }
157 |
158 | if (file_entry.id == 0x200) {
159 | char buffer[1024];
160 | size_t rd;
161 |
162 | if (sceIoLseek(inf, file_entry.off, SCE_SEEK_SET) < 0) {
163 | goto end;
164 | }
165 |
166 | while (file_entry.len && (rd = sceIoRead(inf, buffer, sizeof(buffer))) > 0) {
167 | if (rd > file_entry.len) {
168 | rd = file_entry.len;
169 | }
170 | sceIoWrite(outf, buffer, rd);
171 | file_entry.len -= rd;
172 | }
173 |
174 | if (file_entry.len == 0) {
175 | ret = 0;
176 | }
177 | }
178 |
179 | end:
180 | sceIoClose(inf);
181 | sceIoClose(outf);
182 | return ret;
183 | }
184 |
185 | int verify(const char *src, const uint8_t *expect_hash) {
186 | SceUID fd = sceIoOpen(src, SCE_O_RDONLY, 0);
187 | if (fd < 0)
188 | return fd;
189 |
190 | void *buf = memalign(4096, CHUNK_SIZE);
191 | if (!buf) {
192 | sceIoClose(fd);
193 | return -1;
194 | }
195 |
196 | SHA256_CTX ctx;
197 | memset(&ctx, 0, sizeof(SHA256_CTX));
198 | sha256_init(&ctx);
199 |
200 | while (1) {
201 | int read = sceIoRead(fd, buf, CHUNK_SIZE);
202 |
203 | if (read < 0) {
204 | free(buf);
205 | sceIoClose(fd);
206 | return read;
207 | }
208 |
209 | if (read == 0)
210 | break;
211 |
212 | sha256_update(&ctx, buf, read);
213 | }
214 |
215 | free(buf);
216 | sceIoClose(fd);
217 |
218 | uint8_t hash[32];
219 | sha256_final(&ctx, hash);
220 | if (memcmp(hash, expect_hash, sizeof(hash)) != 0) {
221 | return -1;
222 | }
223 |
224 | return 0;
225 | }
226 |
227 | int copy(const char *src, const char *dst) {
228 | SceUID fdsrc = sceIoOpen(src, SCE_O_RDONLY, 0);
229 | if (fdsrc < 0)
230 | return fdsrc;
231 |
232 | SceUID fddst = sceIoOpen(dst, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 6);
233 | if (fddst < 0) {
234 | sceIoClose(fdsrc);
235 | return fddst;
236 | }
237 |
238 | void *buf = memalign(4096, CHUNK_SIZE);
239 | if (!buf) {
240 | sceIoClose(fddst);
241 | sceIoClose(fdsrc);
242 | return -1;
243 | }
244 |
245 | while (1) {
246 | int read = sceIoRead(fdsrc, buf, CHUNK_SIZE);
247 |
248 | if (read < 0) {
249 | free(buf);
250 |
251 | sceIoClose(fddst);
252 | sceIoClose(fdsrc);
253 |
254 | sceIoRemove(dst);
255 |
256 | return read;
257 | }
258 |
259 | if (read == 0)
260 | break;
261 |
262 | int written = sceIoWrite(fddst, buf, read);
263 |
264 | if (written < 0) {
265 | free(buf);
266 |
267 | sceIoClose(fddst);
268 | sceIoClose(fdsrc);
269 |
270 | sceIoRemove(dst);
271 |
272 | return written;
273 | }
274 | }
275 |
276 | free(buf);
277 |
278 | sceIoClose(fddst);
279 | sceIoClose(fdsrc);
280 |
281 | return 0;
282 | }
283 |
284 | int download(const char *src, const char *dst) {
285 | int ret;
286 | int statusCode;
287 | int tmplId = -1, connId = -1, reqId = -1;
288 | SceUID fd = -1;
289 |
290 | ret = sceHttpCreateTemplate("Updater/1.00 libhttp/1.1", SCE_HTTP_VERSION_1_1, SCE_TRUE);
291 | if (ret < 0)
292 | goto ERROR_EXIT;
293 |
294 | tmplId = ret;
295 |
296 | ret = sceHttpCreateConnectionWithURL(tmplId, src, SCE_TRUE);
297 | if (ret < 0)
298 | goto ERROR_EXIT;
299 |
300 | connId = ret;
301 |
302 | ret = sceHttpCreateRequestWithURL(connId, SCE_HTTP_METHOD_GET, src, 0);
303 | if (ret < 0)
304 | goto ERROR_EXIT;
305 |
306 | reqId = ret;
307 |
308 | ret = sceHttpSendRequest(reqId, NULL, 0);
309 | if (ret < 0)
310 | goto ERROR_EXIT;
311 |
312 | ret = sceHttpGetStatusCode(reqId, &statusCode);
313 | if (ret < 0)
314 | goto ERROR_EXIT;
315 |
316 | if (statusCode == 200) {
317 | uint8_t buf[4096];
318 | uint64_t size = 0;
319 | uint32_t value = 0;
320 |
321 | ret = sceHttpGetResponseContentLength(reqId, &size);
322 | if (ret < 0)
323 | goto ERROR_EXIT;
324 |
325 | ret = sceIoOpen(dst, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 6);
326 | if (ret < 0)
327 | goto ERROR_EXIT;
328 |
329 | fd = ret;
330 |
331 | int x = psvDebugScreenGetX();
332 | int y = psvDebugScreenGetY();
333 |
334 | while (1) {
335 | int read = sceHttpReadData(reqId, buf, sizeof(buf));
336 |
337 | if (read < 0) {
338 | ret = read;
339 | break;
340 | }
341 |
342 | if (read == 0)
343 | break;
344 |
345 | int written = sceIoWrite(fd, buf, read);
346 |
347 | if (written < 0) {
348 | ret = written;
349 | break;
350 | }
351 |
352 | value += read;
353 |
354 | printf("%d%%", (value * 100) / (uint32_t)size);
355 | psvDebugScreenSetXY(x, y);
356 | }
357 | }
358 |
359 | ERROR_EXIT:
360 | if (fd >= 0)
361 | sceIoClose(fd);
362 |
363 | if (reqId >= 0)
364 | sceHttpDeleteRequest(reqId);
365 |
366 | if (connId >= 0)
367 | sceHttpDeleteConnection(connId);
368 |
369 | if (tmplId >= 0)
370 | sceHttpDeleteTemplate(tmplId);
371 |
372 | return ret;
373 | }
374 |
375 | void init_net() {
376 | static char memory[16 * 1024];
377 |
378 | sceSysmoduleLoadModule(SCE_SYSMODULE_NET);
379 | sceSysmoduleLoadModule(SCE_SYSMODULE_HTTPS);
380 |
381 | SceNetInitParam param;
382 | param.memory = memory;
383 | param.size = sizeof(memory);
384 | param.flags = 0;
385 |
386 | sceNetInit(¶m);
387 | sceNetCtlInit();
388 |
389 | sceSslInit(300 * 1024);
390 | sceHttpInit(40 * 1024);
391 |
392 | sceHttpsDisableOption(SCE_HTTPS_FLAG_SERVER_VERIFY);
393 | }
394 |
395 | void finish_net() {
396 | sceSslTerm();
397 | sceHttpTerm();
398 | sceNetCtlTerm();
399 | sceNetTerm();
400 | sceSysmoduleUnloadModule(SCE_SYSMODULE_HTTPS);
401 | sceSysmoduleUnloadModule(SCE_SYSMODULE_NET);
402 | }
403 |
404 | typedef struct {
405 | uint32_t off;
406 | uint32_t sz;
407 | uint8_t code;
408 | uint8_t type;
409 | uint8_t active;
410 | uint32_t flags;
411 | uint16_t unk;
412 | } __attribute__((packed)) partition_t;
413 |
414 | typedef struct {
415 | char magic[0x20];
416 | uint32_t version;
417 | uint32_t device_size;
418 | char unk1[0x28];
419 | partition_t partitions[0x10];
420 | char unk2[0x5e];
421 | char unk3[0x10 * 4];
422 | uint16_t sig;
423 | } __attribute__((packed)) master_block_t;
424 |
425 | const char *device = "sdstor0:int-lp-act-entire";
426 |
427 | int is_mbr(void *data) {
428 | master_block_t *master = data;
429 | if (memcmp(master->magic, "Sony Computer Entertainment Inc.", 0x20) != 0)
430 | return 0;
431 | if (master->sig != 0xAA55)
432 | return 0;
433 | return 1;
434 | }
435 |
436 | int main(int argc, char *argv[]) {
437 | int ret;
438 | SceIoStat stat;
439 | SceUID fd;
440 |
441 | psvDebugScreenInit();
442 | sceKernelPowerLock(0);
443 | sceAppMgrUmount("app0:");
444 |
445 | printf("3.65 HENkaku Enso Updater\n\n");
446 |
447 | if (sceIoDevctl("ux0:", 0x3001, NULL, 0, NULL, 0) == 0x80010030) {
448 | ErrorExit(10000, "Enable unsafe homebrew first before using this software.\n");
449 | }
450 |
451 | if (scePowerGetBatteryLifePercent() < 50) {
452 | ErrorExit(10000, "Battery has to be at least at 50%%.\n");
453 | }
454 |
455 | // detect plugins
456 | ret = taiLoadStartKernelModule(APP_PATH "kernel2.skprx", 0, NULL, 0);
457 | if (ret < 0) {
458 | ErrorExit(20000, "Disable all plugins first before using this software.\n"
459 | "If you have already disabled them, but still get this message,\n"
460 | "reboot your device and launch this software again without\n"
461 | "launching any other applications before.\n"
462 | "VitaShell or Adrenaline for example start kernel modules.\n");
463 | }
464 |
465 | ret = taiStopUnloadKernelModule(ret, 0, NULL, 0, NULL, NULL);
466 | if (ret < 0)
467 | ErrorExit(10000, "Error 0x%08X unloading kernel2.skprx.\n", ret);
468 |
469 | // detect previous enso
470 | static master_block_t master;
471 | fd = sceIoOpen(device, SCE_O_RDONLY, 0777);
472 | if (fd < 0)
473 | ErrorExit(10000, "Error 0x%08X opening device.\n", fd);
474 |
475 | if ((ret = sceIoLseek(fd, 0x200, SCE_SEEK_SET)) != 0x200) {
476 | ErrorExit(10000, "Error 0x%08X seeking device.\n", ret);
477 | }
478 | if ((ret = sceIoRead(fd, &master, sizeof(master))) != sizeof(master)) {
479 | ErrorExit(10000, "Error 0x%08X reading device.\n", ret);
480 | }
481 |
482 | sceIoClose(fd);
483 |
484 | if (is_mbr(&master)) {
485 | ErrorExit(20000, "Please uninstall enso first before updating.\n"
486 | "Tip: Unlink Memory Card in HENkaku Settings first\n"
487 | " before you uninstall enso.\n");
488 | }
489 |
490 | if (sceIoGetstat(APP_PATH "PSP2UPDAT.PUP", &stat) < 0) {
491 | ErrorExit(10000, "Could not find %s.\n", APP_PATH "PSP2UPDAT.PUP");
492 | /*
493 | printf("Do you want to download it from the internet? (X=yes, R=no)\n\n");
494 |
495 | while (1) {
496 | SceCtrlData pad;
497 | sceCtrlPeekBufferPositive(0, &pad, 1);
498 |
499 | if (pad.buttons & SCE_CTRL_CROSS)
500 | break;
501 | else if (pad.buttons & (SCE_CTRL_RTRIGGER | SCE_CTRL_R1))
502 | ErrorExit(10000, "Canceled by user.\n");
503 |
504 | sceKernelDelayThread(10000);
505 | }
506 |
507 | printf("Downloading PSP2UPDAT.PUP...");
508 | init_net();
509 | ret = download(PUP_URL, APP_PATH "PSP2UPDAT.PUP");
510 | finish_net();
511 | if (ret < 0)
512 | ErrorExit(10000, "Error 0x%08X downloading PSP2UPDAT.PUP.\n", ret);
513 | */
514 | }
515 |
516 | printf("You are about to update to Custom Firmware 3.65 HENkaku Enso.\n\n");
517 | printf("- Note that once updated there is no way to downgrade back to your\n"
518 | " current firmware.\n"
519 | "- Remember to never attempt to modify vs0: or reinstall 3.65 PUP,\n"
520 | " otherwise you will lose the ability to run homebrews forever.\n"
521 | "- Make sure that all your favorite homebrews and plugins are\n"
522 | " compatible on 3.65 before updating.\n"
523 | "- Check if you have VitaShell v1.82 or higher installed yet\n"
524 | " and if you have made a CMA backup of it already.\n"
525 | " This is very important in case you accidentally lose VitaShell.\n\n");
526 |
527 | printf("Continues in 20 seconds.\n\n");
528 | sceKernelDelayThread(20 * 1000 * 1000);
529 |
530 | printf("Press X to confirm that you have read and understood all the\n");
531 | printf("risks and suggestions above, R to exit.\n\n");
532 |
533 | while (1) {
534 | SceCtrlData pad;
535 | sceCtrlPeekBufferPositive(0, &pad, 1);
536 |
537 | if (pad.buttons & SCE_CTRL_CROSS)
538 | break;
539 | else if (pad.buttons & (SCE_CTRL_RTRIGGER | SCE_CTRL_R1))
540 | ErrorExit(10000, "Canceled by user.\n");
541 |
542 | sceKernelDelayThread(10000);
543 | }
544 |
545 | printf("This software will make PERMANENT modifications to your Vita.\n"
546 | "If anything goes wrong, there is NO RECOVERY (not even with a\n"
547 | "hardware flasher). The creators provide this tool \"as is\", without\n"
548 | "warranty of any kind, express or implied and cannot be held\n"
549 | "liable for any damage done.\n\n");
550 |
551 | printf("Continues in 20 seconds.\n\n");
552 | sceKernelDelayThread(20 * 1000 * 1000);
553 |
554 | printf("Press X to accept these terms and start the update, R to not accept and exit.\n\n");
555 |
556 | while (1) {
557 | SceCtrlData pad;
558 | sceCtrlPeekBufferPositive(0, &pad, 1);
559 |
560 | if (pad.buttons & SCE_CTRL_CROSS)
561 | break;
562 | else if (pad.buttons & (SCE_CTRL_RTRIGGER | SCE_CTRL_R1))
563 | ErrorExit(10000, "Canceled by user.\n");
564 |
565 | sceKernelDelayThread(10000);
566 | }
567 |
568 | psvDebugScreenClear();
569 | printf("3.65 HENkaku Enso Updater\n\n");
570 |
571 | printf("Cleaning ud0:...");
572 | clean_ud0();
573 | ret = verify_cleaned();
574 | if (ret < 0)
575 | ErrorExit(10000, "Error could not clean ud0:.\n");
576 | printf("OK\n");
577 | sceKernelDelayThread(500 * 1000);
578 |
579 | sceIoMkdir("ud0:PSP2UPDATE", 6);
580 |
581 | printf("Copying PSP2UPDAT.PUP to ud0:...");
582 | ret = copy(APP_PATH "PSP2UPDAT.PUP", "ud0:PSP2UPDATE/ENSOUPDAT.PUP");
583 | if (ret < 0)
584 | ErrorExit(10000, "Error 0x%08X copying PSP2UPDAT.PUP.\n", ret);
585 | printf("OK\n");
586 | sceKernelDelayThread(500 * 1000);
587 |
588 | printf("Verifying PSP2UPDAT.PUP...");
589 | ret = verify("ud0:PSP2UPDATE/ENSOUPDAT.PUP", psp2updat_pup_hash);
590 | if (ret < 0)
591 | ErrorExit(10000, "Error 0x%08X. The file is wrong.\n", ret);
592 | printf("OK\n");
593 | sceKernelDelayThread(500 * 1000);
594 |
595 | printf("Extracting psp2swu.self...");
596 | ret = extract("ud0:PSP2UPDATE/ENSOUPDAT.PUP", "ud0:PSP2UPDATE/ensoswu.self");
597 | if (ret < 0)
598 | ErrorExit(10000, "Error 0x%08X extracting psp2swu.self.\n", ret);
599 | printf("OK\n");
600 | sceKernelDelayThread(500 * 1000);
601 |
602 | printf("Removing old taiHENkaku files...");
603 |
604 | const char *files[] = {
605 | "ux0:tai/config.txt",
606 | "ur0:tai/config.txt",
607 | "ur0:tai/boot_config.txt",
608 | "ur0:tai/taihen.skprx",
609 | "ur0:tai/henkaku.skprx",
610 | "ur0:tai/henkaku.suprx",
611 | "ur0:tai/henkaku_config.bin"
612 | };
613 |
614 | int i;
615 | for (i = 0; i < (sizeof(files) / sizeof(char **)); i++) {
616 | sceIoRemove(files[i]);
617 | }
618 |
619 | printf("OK\n");
620 | sceKernelDelayThread(500 * 1000);
621 |
622 | printf("Writing new config files...");
623 | sceIoMkdir("ux0:tai", 6);
624 | sceIoMkdir("ur0:tai", 6);
625 | write_taihen_config("ux0:tai/config.txt", 0);
626 | write_taihen_config("ur0:tai/config.txt", 1);
627 | printf("OK\n");
628 | sceKernelDelayThread(500 * 1000);
629 |
630 | printf("\n");
631 | printf("Please do not press any buttons or power off the device during the\n"
632 | "update, otherwise you may cause permanent damage to your device.\n\n");
633 | sceKernelDelayThread(5 * 1000 * 1000);
634 | printf("Have a safe trip and see you on the other side.\n\n");
635 | sceKernelDelayThread(3 * 1000 * 1000);
636 | printf("Best regards,\n");
637 | sceKernelDelayThread(1 * 1000 * 1000);
638 | printf("- TheFloW\n\n");
639 | sceKernelDelayThread(3 * 1000 * 1000);
640 |
641 | printf("Starting SCE updater...\n");
642 | sceKernelDelayThread(1 * 1000 * 1000);
643 |
644 | sceKernelPowerUnlock(0);
645 |
646 | ret = taiLoadStartKernelModule("ux0:app/UPDATE365/kernel.skprx", 0, NULL, 0);
647 | if (ret < 0)
648 | ErrorExit(10000, "Error 0x%08X loading kernel.skprx.\n", ret);
649 |
650 | sceKernelDelayThread(60 * 1000 * 1000);
651 | ErrorExit(10000, "Error starting SCE updater.\n");
652 |
653 | return 0;
654 | }
655 |
--------------------------------------------------------------------------------
/henkaku/user.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "henkaku.h"
10 | #include "language.h"
11 | #include "config.h"
12 |
13 | int _vshIoMount(int id, const char *path, int permissions, void *opt);
14 |
15 | extern unsigned char _binary_system_settings_xml_start;
16 | extern unsigned char _binary_system_settings_xml_size;
17 | extern unsigned char _binary_henkaku_settings_xml_start;
18 | extern unsigned char _binary_henkaku_settings_xml_size;
19 |
20 | static henkaku_config_t config;
21 |
22 | static SceUID g_hooks[15];
23 |
24 | static uint32_t g_firmware_version = 0;
25 |
26 | static tai_hook_ref_t g_sceKernelGetSystemSwVersion_SceSettings_hook;
27 | static int sceKernelGetSystemSwVersion_SceSettings_patched(SceKernelFwInfo *info) {
28 | int ret;
29 | int ver_major;
30 | int ver_minor;
31 | char enso_string[8];
32 | ret = TAI_CONTINUE(int, g_sceKernelGetSystemSwVersion_SceSettings_hook, info);
33 | if (g_firmware_version) {
34 | ver_major = ((g_firmware_version >> 24) & 0xF) + 10 * (g_firmware_version >> 28);
35 | ver_minor = ((g_firmware_version >> 16) & 0xF) + 10 * ((g_firmware_version >> 20) & 0xF);
36 | if (ENSO_RELEASE)
37 | sceClibSnprintf(enso_string, 8, " \xE2\x97\xAF");
38 | if (BETA_RELEASE) {
39 | sceClibSnprintf(info->versionString, 16, "%d.%02d \xE5\xA4\x89\xE9\x9D\xA9-%d\xCE\xB2%d%s", ver_major, ver_minor, HENKAKU_RELEASE, BETA_RELEASE, enso_string);
40 | } else if (HENKAKU_RELEASE > 1) {
41 | sceClibSnprintf(info->versionString, 16, "%d.%02d \xE5\xA4\x89\xE9\x9D\xA9-%d%s", ver_major, ver_minor, HENKAKU_RELEASE, enso_string);
42 | } else {
43 | sceClibSnprintf(info->versionString, 16, "%d.%02d \xE5\xA4\x89\xE9\x9D\xA9%s", ver_major, ver_minor, enso_string);
44 | }
45 | }
46 | return ret;
47 | }
48 |
49 | static tai_hook_ref_t g_update_check_hook;
50 | static int update_check_patched(int a1, int a2, int *a3, int a4, int a5) {
51 | TAI_CONTINUE(int, g_update_check_hook, a1, a2, a3, a4, a5);
52 | *a3 = 0;
53 | return 0;
54 | }
55 |
56 | static tai_hook_ref_t g_game_update_check_hook;
57 | static int game_update_check_patched(int newver, int *needsupdate) {
58 | TAI_CONTINUE(int, g_game_update_check_hook, newver, needsupdate);
59 | *needsupdate = 0;
60 | return 0;
61 | }
62 |
63 | static tai_hook_ref_t g_passphrase_decrypt_hook;
64 | static void passphrase_decrypt_patched(void *dat0, void *dat1, void *dat2, char *passphrase, int *result) {
65 | TAI_CONTINUE(void, g_passphrase_decrypt_hook, dat0, dat1, dat2, passphrase, result);
66 | if (config.use_psn_spoofing && PSN_PASSPHRASE[0] != '\0' && *result == 1) {
67 | sceClibMemcpy(passphrase, PSN_PASSPHRASE, sizeof(PSN_PASSPHRASE));
68 | }
69 | }
70 |
71 | static tai_hook_ref_t g_SceVshBridge_333875AB_SceShell_hook;
72 | static int SceVshBridge_333875AB_SceShell_patched(void) {
73 | TAI_CONTINUE(int, g_SceVshBridge_333875AB_SceShell_hook);
74 | return 1;
75 | }
76 |
77 | static void save_config_user(void) {
78 | SceUID fd;
79 | int rd;
80 | sceIoMkdir("ur0:tai", 6);
81 | fd = sceIoOpen(CONFIG_PATH, SCE_O_TRUNC | SCE_O_CREAT | SCE_O_WRONLY, 6);
82 | if (fd >= 0) {
83 | rd = sceIoWrite(fd, &config, sizeof(config));
84 | sceIoClose(fd);
85 | if (rd != sizeof(config)) {
86 | LOG("config not right size: %d", rd);
87 | }
88 | } else {
89 | LOG("could not write config file");
90 | }
91 | }
92 |
93 | static int load_config_user(void) {
94 | SceUID fd;
95 | int rd;
96 | int migrate = 0;
97 | fd = sceIoOpen(CONFIG_PATH, SCE_O_RDONLY, 0);
98 | if (fd < 0) {
99 | fd = sceIoOpen(OLD_CONFIG_PATH, SCE_O_RDONLY, 0);
100 | migrate = 1;
101 | }
102 | if (fd >= 0) {
103 | rd = sceIoRead(fd, &config, sizeof(config));
104 | sceIoClose(fd);
105 | if (rd == sizeof(config)) {
106 | if (config.magic == HENKAKU_CONFIG_MAGIC) {
107 | /* if (config.version >= 8) {
108 | if (migrate) {
109 | LOG("migrating settings to new path");
110 | save_config_user();
111 | sceIoRemove(OLD_CONFIG_PATH);
112 | }
113 | return 0;
114 | } else {
115 | LOG("config version too old");
116 | }*/
117 | return 0;
118 | } else {
119 | LOG("config incorrect magic: %x", config.magic);
120 | }
121 | } else {
122 | LOG("config not right size: %d", rd);
123 | }
124 | } else {
125 | LOG("config file not found");
126 | }
127 | // default config
128 | config.magic = HENKAKU_CONFIG_MAGIC;
129 | config.version = HENKAKU_RELEASE;
130 | config.use_psn_spoofing = 1;
131 | config.allow_unsafe_hb = 0;
132 | config.use_spoofed_version = 1;
133 | config.spoofed_version = SPOOF_VERSION;
134 | return 0;
135 | }
136 |
137 | static tai_hook_ref_t g_sceRegMgrGetKeyInt_SceSystemSettingsCore_hook;
138 | static int sceRegMgrGetKeyInt_SceSystemSettingsCore_patched(const char *category, const char *name, int *value) {
139 | if (sceClibStrncmp(category, "/CONFIG/HENKAKU", 15) == 0) {
140 | if (value) {
141 | load_config_user();
142 | if (sceClibStrncmp(name, "enable_psn_spoofing", 19) == 0) {
143 | *value = config.use_psn_spoofing;
144 | } else if (sceClibStrncmp(name, "enable_unsafe_homebrew", 22) == 0) {
145 | *value = config.allow_unsafe_hb;
146 | } else if (sceClibStrncmp(name, "enable_version_spoofing", 23) == 0) {
147 | *value = config.use_spoofed_version;
148 | }
149 | }
150 | return 0;
151 | }
152 | return TAI_CONTINUE(int, g_sceRegMgrGetKeyInt_SceSystemSettingsCore_hook, category, name, value);
153 | }
154 |
155 | static tai_hook_ref_t g_sceRegMgrSetKeyInt_SceSystemSettingsCore_hook;
156 | static int sceRegMgrSetKeyInt_SceSystemSettingsCore_patched(const char *category, const char *name, int value) {
157 | if (sceClibStrncmp(category, "/CONFIG/HENKAKU", 15) == 0) {
158 | if (sceClibStrncmp(name, "enable_psn_spoofing", 19) == 0) {
159 | config.use_psn_spoofing = value;
160 | } else if (sceClibStrncmp(name, "enable_unsafe_homebrew", 22) == 0) {
161 | config.allow_unsafe_hb = value;
162 | } else if (sceClibStrncmp(name, "enable_version_spoofing", 23) == 0) {
163 | config.use_spoofed_version = value;
164 | }
165 | save_config_user();
166 | henkaku_reload_config();
167 | return 0;
168 | }
169 | return TAI_CONTINUE(int, g_sceRegMgrSetKeyInt_SceSystemSettingsCore_hook, category, name, value);
170 | }
171 |
172 | static void build_version_string(int version, char *string, int length) {
173 | if (version && string && length >= 6) {
174 | char a = (version >> 24) & 0xF;
175 | char b = (version >> 20) & 0xF;
176 | char c = (version >> 16) & 0xF;
177 | char d = (version >> 12) & 0xF;
178 | sceClibMemset(string, 0, length);
179 | string[0] = '0' + a;
180 | string[1] = '.';
181 | string[2] = '0' + b;
182 | string[3] = '0' + c;
183 | string[4] = '\0';
184 | if (d) {
185 | string[4] = '0' + d;
186 | string[5] = '\0';
187 | }
188 | }
189 | }
190 |
191 | static tai_hook_ref_t g_sceRegMgrGetKeyStr_SceSystemSettingsCore_hook;
192 | static int sceRegMgrGetKeyStr_SceSystemSettingsCore_patched(const char *category, const char *name, char *string, int length) {
193 | if (sceClibStrncmp(category, "/CONFIG/HENKAKU", 15) == 0) {
194 | if (sceClibStrncmp(name, "spoofed_version", 15) == 0) {
195 | if (string != NULL) {
196 | load_config_user();
197 | build_version_string(config.spoofed_version ? config.spoofed_version : SPOOF_VERSION, string, length);
198 | }
199 | }
200 | return 0;
201 | }
202 | return TAI_CONTINUE(int, g_sceRegMgrGetKeyStr_SceSystemSettingsCore_hook, category, name, string, length);
203 | }
204 |
205 | #define IS_DIGIT(i) (i >= '0' && i <= '9')
206 | static tai_hook_ref_t g_sceRegMgrSetKeyStr_SceSystemSettingsCore_hook;
207 | static int sceRegMgrSetKeyStr_SceSystemSettingsCore_patched(const char *category, const char *name, const char *string, int length) {
208 | if (sceClibStrncmp(category, "/CONFIG/HENKAKU", 15) == 0) {
209 | if (sceClibStrncmp(name, "spoofed_version", 15) == 0) {
210 | if (string != NULL) {
211 | if (IS_DIGIT(string[0]) && string[1] == '.' && IS_DIGIT(string[2]) && IS_DIGIT(string[3])) {
212 | char a = string[0] - '0';
213 | char b = string[2] - '0';
214 | char c = string[3] - '0';
215 | char d = IS_DIGIT(string[4]) ? string[4] - '0' : '\0';
216 | config.spoofed_version = ((a << 24) | (b << 20) | (c << 16) | (d << 12));
217 | save_config_user();
218 | henkaku_reload_config();
219 | }
220 | }
221 | }
222 | return 0;
223 | }
224 | return TAI_CONTINUE(int, g_sceRegMgrSetKeyStr_SceSystemSettingsCore_hook, category, name, string, length);
225 | }
226 |
227 | typedef struct {
228 | int size;
229 | const char *name;
230 | int type;
231 | int unk;
232 | } SceRegMgrKeysInfo;
233 |
234 | static tai_hook_ref_t g_sceRegMgrGetKeysInfo_SceSystemSettingsCore_hook;
235 | static int sceRegMgrGetKeysInfo_SceSystemSettingsCore_patched(const char *category, SceRegMgrKeysInfo *info, int unk) {
236 | if (sceClibStrncmp(category, "/CONFIG/HENKAKU", 15) == 0) {
237 | if (info) {
238 | if (sceClibStrncmp(info->name, "spoofed_version", 15) == 0) {
239 | info->type = 0x00030001; // type string
240 | } else {
241 | info->type = 0x00040000; // type integer
242 | }
243 | }
244 | return 0;
245 | }
246 | return TAI_CONTINUE(int, g_sceRegMgrGetKeysInfo_SceSystemSettingsCore_hook, category, info, unk);
247 | }
248 |
249 | static int (* g_OnButtonEventIduSettings_hook)(const char *id, int a2, void *a3);
250 | static int OnButtonEventIduSettings_patched(const char *id, int a2, void *a3) {
251 | int ret;
252 | uint32_t buf[6];
253 | if (sceClibStrncmp(id, "id_reload_taihen_config", 23) == 0) {
254 | return taiReloadConfig();
255 | } else if (sceClibStrncmp(id, "id_reboot_device", 16) == 0) {
256 | return scePowerRequestColdReset();
257 | } else if (sceClibStrncmp(id, "id_unlink_memory_card", 21) == 0) {
258 | sceClibMemset(buf, 0, sizeof(buf));
259 | if ((ret = _vshIoMount(0x800, NULL, 2, buf)) < 0) {
260 | if (ret != 0x80010011) { // SCE_ERROR_ERRNO_EEXIST (already mounted)
261 | return ret;
262 | }
263 | }
264 | if ((ret = sceIoRemove("ux0:id.dat")) < 0) {
265 | if (ret != 0x80010002) { // SCE_ERROR_ERRNO_ENOENT (no entry)
266 | return ret;
267 | }
268 | }
269 | return 0;
270 | }
271 | return g_OnButtonEventIduSettings_hook(id, a2, a3);
272 | }
273 |
274 | static tai_hook_ref_t g_scePafToplevelInitPluginFunctions_SceSettings_hook;
275 | static int scePafToplevelInitPluginFunctions_SceSettings_patched(void *a1, int a2, uint32_t *funcs) {
276 | int res = TAI_CONTINUE(int, g_scePafToplevelInitPluginFunctions_SceSettings_hook, a1, a2, funcs);
277 | char *plugin = (char *)((uint32_t *)a1)[1];
278 | if (sceClibStrncmp(plugin, "idu_settings_plugin", 19) == 0) {
279 | if (funcs[6] != (uint32_t)OnButtonEventIduSettings_patched) {
280 | g_OnButtonEventIduSettings_hook = (void *)funcs[6];
281 | funcs[6] = (uint32_t)OnButtonEventIduSettings_patched;
282 | }
283 | }
284 | return res;
285 | }
286 |
287 | static tai_hook_ref_t g_scePafMiscLoadXmlLayout_SceSettings_hook;
288 | static int scePafMiscLoadXmlLayout_SceSettings_patched(int a1, void *xml_buf, int xml_size, int a4) {
289 | if ((82+22) < xml_size && sceClibStrncmp(xml_buf+82, "system_settings_plugin", 22) == 0) {
290 | xml_buf = (void *)&_binary_system_settings_xml_start;
291 | xml_size = (int)&_binary_system_settings_xml_size;
292 | } else if ((79+19) < xml_size && sceClibStrncmp(xml_buf+79, "idu_settings_plugin", 19) == 0) {
293 | xml_buf = (void *)&_binary_henkaku_settings_xml_start;
294 | xml_size = (int)&_binary_henkaku_settings_xml_size;
295 | }
296 | return TAI_CONTINUE(int, g_scePafMiscLoadXmlLayout_SceSettings_hook, a1, xml_buf, xml_size, a4);
297 | }
298 |
299 | static tai_hook_ref_t g_scePafToplevelGetText_SceSystemSettingsCore_hook;
300 | static wchar_t *scePafToplevelGetText_SceSystemSettingsCore_patched(void *arg, char **msg) {
301 | language_container_t *language_container;
302 | int language = -1;
303 | sceRegMgrGetKeyInt("/CONFIG/SYSTEM", "language", &language);
304 | switch (language) {
305 | case SCE_SYSTEM_PARAM_LANG_JAPANESE: language_container = &language_japanese; break;
306 | case SCE_SYSTEM_PARAM_LANG_ENGLISH_US: language_container = &language_english_us; break;
307 | case SCE_SYSTEM_PARAM_LANG_FRENCH: language_container = &language_french; break;
308 | case SCE_SYSTEM_PARAM_LANG_SPANISH: language_container = &language_spanish; break;
309 | case SCE_SYSTEM_PARAM_LANG_GERMAN: language_container = &language_german; break;
310 | case SCE_SYSTEM_PARAM_LANG_ITALIAN: language_container = &language_italian; break;
311 | case SCE_SYSTEM_PARAM_LANG_DUTCH: language_container = &language_dutch; break;
312 | case SCE_SYSTEM_PARAM_LANG_PORTUGUESE_PT: language_container = &language_portuguese_pt; break;
313 | case SCE_SYSTEM_PARAM_LANG_RUSSIAN: language_container = &language_russian; break;
314 | case SCE_SYSTEM_PARAM_LANG_KOREAN: language_container = &language_korean; break;
315 | case SCE_SYSTEM_PARAM_LANG_CHINESE_T: language_container = &language_chinese_t; break;
316 | case SCE_SYSTEM_PARAM_LANG_CHINESE_S: language_container = &language_chinese_s; break;
317 | case SCE_SYSTEM_PARAM_LANG_FINNISH: language_container = &language_finnish; break;
318 | case SCE_SYSTEM_PARAM_LANG_SWEDISH: language_container = &language_swedish; break;
319 | case SCE_SYSTEM_PARAM_LANG_DANISH: language_container = &language_danish; break;
320 | case SCE_SYSTEM_PARAM_LANG_NORWEGIAN: language_container = &language_norwegian; break;
321 | case SCE_SYSTEM_PARAM_LANG_POLISH: language_container = &language_polish; break;
322 | case SCE_SYSTEM_PARAM_LANG_PORTUGUESE_BR: language_container = &language_portuguese_br; break;
323 | case SCE_SYSTEM_PARAM_LANG_ENGLISH_GB: language_container = &language_english_gb; break;
324 | case SCE_SYSTEM_PARAM_LANG_TURKISH: language_container = &language_turkish; break;
325 | default: language_container = &language_english_us; break;
326 | }
327 | if (msg && sceClibStrncmp(*msg, "msg_", 4) == 0) {
328 | #define LANGUAGE_ENTRY(name) \
329 | else if (sceClibStrncmp(*msg, #name, sizeof(#name)) == 0) { \
330 | return language_container->name; \
331 | }
332 | if (0) {}
333 | LANGUAGE_ENTRY(msg_henkaku_settings)
334 | LANGUAGE_ENTRY(msg_enable_psn_spoofing)
335 | LANGUAGE_ENTRY(msg_enable_unsafe_homebrew)
336 | LANGUAGE_ENTRY(msg_unsafe_homebrew_description)
337 | LANGUAGE_ENTRY(msg_enable_version_spoofing)
338 | LANGUAGE_ENTRY(msg_spoofed_version)
339 | LANGUAGE_ENTRY(msg_button_behavior)
340 | LANGUAGE_ENTRY(msg_button_enter)
341 | LANGUAGE_ENTRY(msg_button_cancel)
342 | LANGUAGE_ENTRY(msg_reload_taihen_config)
343 | LANGUAGE_ENTRY(msg_reload_taihen_config_success)
344 | LANGUAGE_ENTRY(msg_reboot_device)
345 | LANGUAGE_ENTRY(msg_content_downloader)
346 | LANGUAGE_ENTRY(msg_unlink_memory_card)
347 | LANGUAGE_ENTRY(msg_unlink_memory_card_success)
348 | LANGUAGE_ENTRY(msg_unlink_memory_card_error)
349 | #undef LANGUAGE_ENTRY
350 | }
351 | return TAI_CONTINUE(wchar_t *, g_scePafToplevelGetText_SceSystemSettingsCore_hook, arg, msg);
352 | }
353 |
354 | static SceUID g_system_settings_core_modid = -1;
355 | static tai_hook_ref_t g_sceKernelLoadStartModule_SceSettings_hook;
356 | static SceUID sceKernelLoadStartModule_SceSettings_patched(char *path, SceSize args, void *argp, int flags, SceKernelLMOption *option, int *status) {
357 | SceUID ret = TAI_CONTINUE(SceUID, g_sceKernelLoadStartModule_SceSettings_hook, path, args, argp, flags, option, status);
358 | if (ret >= 0 && sceClibStrncmp(path, "vs0:app/NPXS10015/system_settings_core.suprx", 44) == 0) {
359 | g_system_settings_core_modid = ret;
360 | g_hooks[7] = taiHookFunctionImport(&g_scePafToplevelInitPluginFunctions_SceSettings_hook,
361 | "SceSettings",
362 | 0x4D9A9DD0, // ScePafToplevel
363 | 0xF5354FEF,
364 | scePafToplevelInitPluginFunctions_SceSettings_patched);
365 | g_hooks[8] = taiHookFunctionImport(&g_scePafMiscLoadXmlLayout_SceSettings_hook,
366 | "SceSettings",
367 | 0x3D643CE8, // ScePafMisc
368 | 0x19FE55A8,
369 | scePafMiscLoadXmlLayout_SceSettings_patched);
370 | g_hooks[9] = taiHookFunctionImport(&g_sceRegMgrGetKeyInt_SceSystemSettingsCore_hook,
371 | "SceSystemSettingsCore",
372 | 0xC436F916, // SceRegMgr
373 | 0x16DDF3DC,
374 | sceRegMgrGetKeyInt_SceSystemSettingsCore_patched);
375 | g_hooks[10] = taiHookFunctionImport(&g_sceRegMgrSetKeyInt_SceSystemSettingsCore_hook,
376 | "SceSystemSettingsCore",
377 | 0xC436F916, // SceRegMgr
378 | 0xD72EA399,
379 | sceRegMgrSetKeyInt_SceSystemSettingsCore_patched);
380 | g_hooks[11] = taiHookFunctionImport(&g_sceRegMgrGetKeyStr_SceSystemSettingsCore_hook,
381 | "SceSystemSettingsCore",
382 | 0xC436F916, // SceRegMgr
383 | 0xE188382F,
384 | sceRegMgrGetKeyStr_SceSystemSettingsCore_patched);
385 | g_hooks[12] = taiHookFunctionImport(&g_sceRegMgrSetKeyStr_SceSystemSettingsCore_hook,
386 | "SceSystemSettingsCore",
387 | 0xC436F916, // SceRegMgr
388 | 0x41D320C5,
389 | sceRegMgrSetKeyStr_SceSystemSettingsCore_patched);
390 | g_hooks[13] = taiHookFunctionImport(&g_sceRegMgrGetKeysInfo_SceSystemSettingsCore_hook,
391 | "SceSystemSettingsCore",
392 | 0xC436F916, // SceRegMgr
393 | 0x58421DD1,
394 | sceRegMgrGetKeysInfo_SceSystemSettingsCore_patched);
395 | g_hooks[14] = taiHookFunctionImport(&g_scePafToplevelGetText_SceSystemSettingsCore_hook,
396 | "SceSystemSettingsCore",
397 | 0x4D9A9DD0, // ScePafToplevel
398 | 0x19CEFDA7,
399 | scePafToplevelGetText_SceSystemSettingsCore_patched);
400 | }
401 | return ret;
402 | }
403 |
404 | static tai_hook_ref_t g_sceKernelStopUnloadModule_SceSettings_hook;
405 | static int sceKernelStopUnloadModule_SceSettings_patched(SceUID modid, SceSize args, void *argp, int flags, SceKernelULMOption *option, int *status) {
406 | if (modid == g_system_settings_core_modid) {
407 | g_system_settings_core_modid = -1;
408 | if (g_hooks[7] >= 0) taiHookRelease(g_hooks[7], g_scePafToplevelInitPluginFunctions_SceSettings_hook);
409 | if (g_hooks[8] >= 0) taiHookRelease(g_hooks[8], g_scePafMiscLoadXmlLayout_SceSettings_hook);
410 | if (g_hooks[9] >= 0) taiHookRelease(g_hooks[9], g_sceRegMgrGetKeyInt_SceSystemSettingsCore_hook);
411 | if (g_hooks[10] >= 0) taiHookRelease(g_hooks[10], g_sceRegMgrSetKeyInt_SceSystemSettingsCore_hook);
412 | if (g_hooks[11] >= 0) taiHookRelease(g_hooks[11], g_sceRegMgrGetKeyStr_SceSystemSettingsCore_hook);
413 | if (g_hooks[12] >= 0) taiHookRelease(g_hooks[12], g_sceRegMgrSetKeyStr_SceSystemSettingsCore_hook);
414 | if (g_hooks[13] >= 0) taiHookRelease(g_hooks[13], g_sceRegMgrGetKeysInfo_SceSystemSettingsCore_hook);
415 | if (g_hooks[14] >= 0) taiHookRelease(g_hooks[14], g_scePafToplevelGetText_SceSystemSettingsCore_hook);
416 | }
417 | return TAI_CONTINUE(int, g_sceKernelStopUnloadModule_SceSettings_hook, modid, args, argp, flags, option, status);
418 | }
419 |
420 | void _start() __attribute__ ((weak, alias ("module_start")));
421 | int module_start(SceSize argc, const void *args) {
422 | tai_module_info_t info;
423 | LOG("loading HENkaku config for user");
424 | load_config_user();
425 | // find firmware version by module nid
426 | info.size = sizeof(info);
427 | if (taiGetModuleInfo("SceSettings", &info) >= 0) {
428 | switch (info.module_nid) {
429 | case 0xC2A86F54: // retail 3.60 SceSettings
430 | g_firmware_version = 0x03600000;
431 | break;
432 | case 0x13B4C016: // retail 3.65 SceSettings
433 | g_firmware_version = 0x03650000;
434 | break;
435 | case 0x313B7C2F: // retail 3.67 SceSettings
436 | g_firmware_version = 0x03670000;
437 | break;
438 | default: {
439 | g_firmware_version = 0;
440 | LOG("SceSettings NID %X not recognized", info.module_nid);
441 | }
442 | }
443 | }
444 | g_hooks[0] = taiHookFunctionImport(&g_sceKernelLoadStartModule_SceSettings_hook,
445 | "SceSettings",
446 | 0xCAE9ACE6, // SceLibKernel
447 | 0x2DCC4AFA,
448 | sceKernelLoadStartModule_SceSettings_patched);
449 | LOG("sceKernelLoadStartModule hook: %x", g_hooks[0]);
450 | g_hooks[1] = taiHookFunctionImport(&g_sceKernelStopUnloadModule_SceSettings_hook,
451 | "SceSettings",
452 | 0xCAE9ACE6, // SceLibKernel
453 | 0x2415F8A4,
454 | sceKernelStopUnloadModule_SceSettings_patched);
455 | LOG("sceKernelStopUnloadModule hook: %x", g_hooks[1]);
456 | g_hooks[2] = taiHookFunctionImport(&g_sceKernelGetSystemSwVersion_SceSettings_hook,
457 | "SceSettings",
458 | 0xEAED1616, // SceModulemgr
459 | 0x5182E212,
460 | sceKernelGetSystemSwVersion_SceSettings_patched);
461 | LOG("sceKernelGetSystemSwVersion hook: %x", g_hooks[2]);
462 | g_hooks[3] = g_hooks[4] = g_hooks[5] = -1;
463 | info.size = sizeof(info);
464 | if (taiGetModuleInfo("SceShell", &info) >= 0) {
465 | if (config.use_psn_spoofing) {
466 | // we don't have a nice clean way of doing PSN spoofing (update prompt disable) so
467 | // we are stuck with hard coding offsets. Since module NID is different for each
468 | // version and retail/dex/test unit, this should allow us to specify different
469 | // offsets.
470 | switch (info.module_nid) {
471 | case 0x0552F692: { // retail 3.60 SceShell
472 | g_hooks[3] = taiHookFunctionOffset(&g_update_check_hook,
473 | info.modid,
474 | 0, // segidx
475 | 0x363de8, // offset
476 | 1, // thumb
477 | update_check_patched);
478 | g_hooks[4] = taiHookFunctionOffset(&g_game_update_check_hook,
479 | info.modid,
480 | 0, // segidx
481 | 0x37beda, // offset
482 | 1, // thumb
483 | game_update_check_patched);
484 | g_hooks[5] = taiHookFunctionOffset(&g_passphrase_decrypt_hook,
485 | info.modid,
486 | 0, // segidx
487 | 0x325230, // offset
488 | 1, // thumb
489 | passphrase_decrypt_patched);
490 | break;
491 | }
492 | case 0xEAB89D5C: { // PTEL 3.60 SceShell thanks to CelesteBlue for offsets
493 | g_hooks[3] = taiHookFunctionOffset(&g_update_check_hook,
494 | info.modid,
495 | 0, // segidx
496 | 0x35A830, // offset
497 | 1, // thumb
498 | update_check_patched);
499 | g_hooks[4] = taiHookFunctionOffset(&g_game_update_check_hook,
500 | info.modid,
501 | 0, // segidx
502 | 0x372832, // offset
503 | 1, // thumb
504 | game_update_check_patched);
505 | g_hooks[5] = taiHookFunctionOffset(&g_passphrase_decrypt_hook,
506 | info.modid,
507 | 0, // segidx
508 | 0x31BC78, // offset
509 | 1, // thumb
510 | passphrase_decrypt_patched);
511 | break;
512 | }
513 | case 0x6CB01295: { // PDEL 3.60 SceShell thanks to anonymous for offsets
514 | g_hooks[3] = taiHookFunctionOffset(&g_update_check_hook,
515 | info.modid,
516 | 0, // segidx
517 | 0x12c882, // offset
518 | 1, // thumb
519 | update_check_patched);
520 | g_hooks[4] = taiHookFunctionOffset(&g_game_update_check_hook,
521 | info.modid,
522 | 0, // segidx
523 | 0x36df3e, // offset
524 | 1, // thumb
525 | game_update_check_patched);
526 | g_hooks[5] = taiHookFunctionOffset(&g_passphrase_decrypt_hook,
527 | info.modid,
528 | 0, // segidx
529 | 0x317384, // offset
530 | 1, // thumb
531 | passphrase_decrypt_patched);
532 | break;
533 | }
534 | case 0x5549BF1F: // retail 3.65 SceShell
535 | case 0x34B4D82E: { // retail 3.67 SceShell
536 | g_hooks[3] = taiHookFunctionOffset(&g_update_check_hook,
537 | info.modid,
538 | 0, // segidx
539 | 0x36422c, // offset
540 | 1, // thumb
541 | update_check_patched);
542 | g_hooks[4] = taiHookFunctionOffset(&g_game_update_check_hook,
543 | info.modid,
544 | 0, // segidx
545 | 0x37c31e, // offset
546 | 1, // thumb
547 | game_update_check_patched);
548 | g_hooks[5] = taiHookFunctionOffset(&g_passphrase_decrypt_hook,
549 | info.modid,
550 | 0, // segidx
551 | 0x325674, // offset
552 | 1, // thumb
553 | passphrase_decrypt_patched);
554 | break;
555 | }
556 | default: {
557 | LOG("SceShell NID %X not recognized, skipping PSN spoofing patches", info.module_nid);
558 | }
559 | }
560 | }
561 | // add patch to skip id.dat checks (only works if plugin loads before start)
562 | g_hooks[6] = taiHookFunctionImport(&g_SceVshBridge_333875AB_SceShell_hook,
563 | "SceShell",
564 | 0x35C5ACD4, // SceVshBridge
565 | 0x333875AB,
566 | SceVshBridge_333875AB_SceShell_patched);
567 | } else {
568 | LOG("skipping psn spoofing patches");
569 | }
570 | return SCE_KERNEL_START_SUCCESS;
571 | }
572 |
573 | int module_stop(SceSize argc, const void *args) {
574 | LOG("stopping module");
575 | // free hooks that didn't fail
576 | if (g_hooks[0] >= 0) taiHookRelease(g_hooks[0], g_sceKernelLoadStartModule_SceSettings_hook);
577 | if (g_hooks[1] >= 0) taiHookRelease(g_hooks[1], g_sceKernelStopUnloadModule_SceSettings_hook);
578 | if (g_hooks[2] >= 0) taiHookRelease(g_hooks[2], g_sceKernelGetSystemSwVersion_SceSettings_hook);
579 | if (g_hooks[3] >= 0) taiHookRelease(g_hooks[3], g_update_check_hook);
580 | if (g_hooks[4] >= 0) taiHookRelease(g_hooks[4], g_game_update_check_hook);
581 | if (g_hooks[5] >= 0) taiHookRelease(g_hooks[5], g_passphrase_decrypt_hook);
582 | if (g_hooks[6] >= 0) taiHookRelease(g_hooks[6], g_SceVshBridge_333875AB_SceShell_hook);
583 | return SCE_KERNEL_STOP_SUCCESS;
584 | }
585 |
--------------------------------------------------------------------------------