├── README.md ├── loader ├── exefs_src │ └── main.npdm ├── source │ ├── trampoline.s │ ├── nro.h │ └── main.c └── Makefile ├── installer ├── exefs_src │ └── main.npdm ├── Makefile ├── source │ └── main.c └── Makefile.normal ├── installer_obf ├── exefs_src │ └── main.npdm ├── Makefile ├── obfuscator │ ├── CodeSegment.py │ ├── Variable.py │ ├── Random.py │ ├── ScrambledString.py │ ├── ScrambledConstant.py │ ├── Services.py │ ├── Operators.py │ ├── Crypto.py │ ├── ScrambledIpcCommand.py │ ├── Main.py │ └── SecretGenerators.py └── Makefile.normal └── runner_obf ├── Makefile ├── Service.py ├── docs ├── memory.txt └── gadgets.txt ├── StringEncoder.py ├── RopChain.py ├── Gadgets.py ├── Main.py ├── ImmEncoder.py ├── IpcCommand.py ├── test └── run_rop.py └── Sequences.py /README.md: -------------------------------------------------------------------------------- 1 | # nx-hbl -------------------------------------------------------------------------------- /loader/exefs_src/main.npdm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/switchbrew/nx-hbexploit300-obf/HEAD/loader/exefs_src/main.npdm -------------------------------------------------------------------------------- /installer/exefs_src/main.npdm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/switchbrew/nx-hbexploit300-obf/HEAD/installer/exefs_src/main.npdm -------------------------------------------------------------------------------- /installer_obf/exefs_src/main.npdm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/switchbrew/nx-hbexploit300-obf/HEAD/installer_obf/exefs_src/main.npdm -------------------------------------------------------------------------------- /runner_obf/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | mkdir -p build/ 3 | python2 Main.py 4 | 5 | test: all 6 | python2 test/run_rop.py build/rop.bin build/rop_relocs.bin 7 | 8 | clean: 9 | rm -rf build/ 10 | -------------------------------------------------------------------------------- /installer_obf/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C ../loader 3 | mkdir -p source/ 4 | mkdir -p build/ 5 | cp ../loader/loader.pfs0 build/hbl.pfs0 6 | python2 obfuscator/Main.py > source/main.c 7 | make -f Makefile.normal 8 | 9 | clean: 10 | make -C ../loader clean 11 | make -f Makefile.normal clean 12 | -------------------------------------------------------------------------------- /installer/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C ../loader 3 | mkdir -p build/ 4 | cp ../loader/loader.pfs0 build/loader.pfs0 5 | bin2c -d source/loader_bin.h -o source/loader_bin.c -n hbl_bin build/loader.pfs0 6 | make -f Makefile.normal 7 | 8 | clean: 9 | make -C ../loader clean 10 | make -f Makefile.normal clean 11 | -------------------------------------------------------------------------------- /installer_obf/obfuscator/CodeSegment.py: -------------------------------------------------------------------------------- 1 | class Raw: 2 | def __init__(self, code): 3 | self.code = code 4 | 5 | def generate(self): 6 | return self.code 7 | 8 | class Combined: 9 | def __init__(self, seg1, seg2): 10 | self.segs = [seg1, seg2] 11 | def generate(self): 12 | return self.segs[0].generate() + self.segs[1].generate() 13 | -------------------------------------------------------------------------------- /installer_obf/obfuscator/Variable.py: -------------------------------------------------------------------------------- 1 | g_names = {} 2 | 3 | def alloc_name(hint='v'): 4 | global g_names 5 | if hint not in g_names: 6 | g_names[hint] = 0 7 | 8 | if hint != 'v': 9 | ret = '%s_%d' % (hint, g_names[hint]) 10 | else: 11 | ret = '%s%d' % (hint, g_names[hint]) 12 | g_names[hint] += 1 13 | return ret 14 | 15 | g_errctr = 0 16 | 17 | def alloc_err(): 18 | global g_errctr 19 | g_errctr += 1 20 | return g_errctr 21 | 22 | -------------------------------------------------------------------------------- /runner_obf/Service.py: -------------------------------------------------------------------------------- 1 | import Sequences 2 | 3 | class Service: 4 | def __init__(self, handle_ptr, service_str, fatal): 5 | self.handle_ptr = handle_ptr 6 | self.service_str = service_str 7 | self.fatal = fatal 8 | 9 | def generate(self): 10 | ret = [ 11 | Sequences.Load_X0X1X2X3(self.handle_ptr, self.service_str), 12 | Sequences.SmGetService(), 13 | ] 14 | if self.fatal: 15 | ret += [ 16 | Sequences.CrashIfResultFailed() 17 | ] 18 | return ret 19 | -------------------------------------------------------------------------------- /installer_obf/obfuscator/Random.py: -------------------------------------------------------------------------------- 1 | g_seed = 0xdeadbeef 2 | 3 | def get_u32(): 4 | global g_seed 5 | g_seed *= 7 6 | g_seed ^= (g_seed >> 3) 7 | g_seed = g_seed & 0xffffffff 8 | g_seed += (g_seed << 8) & (g_seed >> 1) 9 | g_seed = g_seed & 0xffffffff 10 | g_seed ^= (g_seed << 11) & (g_seed >> 3) 11 | g_seed = g_seed & 0xffffffff 12 | g_seed += 387147981 13 | g_seed = g_seed & 0xffffffff 14 | g_seed ^= (g_seed << 11) | (g_seed >> 3) 15 | g_seed = g_seed & 0xffffffff 16 | return g_seed 17 | 18 | def from_list(li): 19 | return li[get_u32() % len(li)] 20 | 21 | def from_dict(di): 22 | return from_list(di.keys()) 23 | -------------------------------------------------------------------------------- /runner_obf/docs/memory.txt: -------------------------------------------------------------------------------- 1 | Addr: 0x5840000000 Size: 0x2000 State: 3 R-X rtld 2 | Addr: 0x5840002000 Size: 0x1000 State: 3 R-- 3 | Addr: 0x5840003000 Size: 0x1000 State: 4 RW- 4 | 5 | Addr: 0x5840004000 Size: 0x5e3000 State: 3 R-X main 6 | Addr: 0x58405e7000 Size: 0x2c5000 State: 3 R-- 7 | Addr: 0x58408ac000 Size: 0x11f000 State: 4 RW- 8 | 9 | Addr: 0x58409cb000 Size: 0x1000 State: 3 R-X sdk 10 | Addr: 0x58409cc000 Size: 0x1000 State: 3 R-- 11 | Addr: 0x58409cd000 Size: 0x1000 State: 4 RW- 12 | 13 | 14 | * mersenne twister inner function 15 | pretty complicated 16 | 17 | * heapchunk mac 18 | nice and eazy 19 | 20 | * parsing kernel descriptors 21 | DONE 22 | 23 | * kip1 decompression 24 | -------------------------------------------------------------------------------- /loader/source/trampoline.s: -------------------------------------------------------------------------------- 1 | .section .text.nroEntrypointTrampoline, "ax", %progbits 2 | 3 | .global nroEntrypointTrampoline 4 | .type nroEntrypointTrampoline, %function 5 | .align 2 6 | 7 | .cfi_startproc 8 | 9 | nroEntrypointTrampoline: 10 | 11 | // Reset stack pointer. 12 | adrp x8, __stack_top //Defined in libnx. 13 | ldr x8, [x8, #:lo12:__stack_top] 14 | mov sp, x8 15 | 16 | // Call NRO. 17 | blr x2 18 | 19 | // Save retval 20 | adrp x1, g_lastRet 21 | add x1, x1, #:lo12:g_lastRet 22 | str x0, [x1] 23 | 24 | // Reset stack pointer and load next NRO. 25 | adrp x8, __stack_top 26 | ldr x8, [x8, #:lo12:__stack_top] 27 | mov sp, x8 28 | 29 | b loadNro 30 | 31 | .cfi_endproc 32 | -------------------------------------------------------------------------------- /loader/source/nro.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NROHEADER_MAGICNUM 0x304f524e 4 | 5 | #define ASSETHEADER_MAGICNUM 0x54455341 6 | #define ASSETHEADER_VERSION 0 7 | 8 | typedef struct { 9 | u32 FileOff; 10 | u32 Size; 11 | } NsoSegment; 12 | 13 | typedef struct { 14 | u32 unused; 15 | u32 modOffset; 16 | u8 Padding[8]; 17 | } NroStart; 18 | 19 | typedef struct { 20 | u32 Magic; 21 | u32 Unk1; 22 | u32 size; 23 | u32 Unk2; 24 | NsoSegment Segments[3]; 25 | u32 bssSize; 26 | u32 Unk3; 27 | u8 BuildId[0x20]; 28 | u8 Padding[0x20]; 29 | } NroHeader; 30 | 31 | typedef struct { 32 | u64 offset; 33 | u64 size; 34 | } AssetSection; 35 | 36 | typedef struct { 37 | u32 magic; 38 | u32 version; 39 | AssetSection icon; 40 | AssetSection nacp; 41 | AssetSection romfs; 42 | } AssetHeader; 43 | -------------------------------------------------------------------------------- /runner_obf/StringEncoder.py: -------------------------------------------------------------------------------- 1 | import ImmEncoder 2 | import Gadgets 3 | import Sequences 4 | import random 5 | 6 | class Str: 7 | def __init__(self, dst, s): 8 | self.dst = dst 9 | self.pre = '' 10 | self.post = '' 11 | alpha = 'abcdefghijklmnopqrstuvwxyz@\0' 12 | for i in range(57): 13 | self.pre += random.choice(alpha) 14 | self.s = s 15 | while len(self.pre+self.s) < 256: 16 | self.s += random.choice(alpha) 17 | self.s = self.pre + self.s 18 | def generate(self, r): 19 | ret = [] 20 | 21 | idx = list(range(len(self.s))) 22 | random.shuffle(idx) 23 | 24 | for i in idx: 25 | ch = ord(self.s[i]) 26 | imm = ImmEncoder.get_imm_encoder(ch) 27 | ret += imm.generate(r) 28 | 29 | ret += [ 30 | Sequences.Load_X0X1X2X3(imm.get_imm_placeholder()), 31 | Sequences.Load_X0X1X2X3(self.dst+(i-len(self.pre)), Gadgets.RelativeReference(-7*8), Gadgets.Imm(1)), 32 | Sequences.Memcpy() 33 | ] 34 | 35 | return ret 36 | -------------------------------------------------------------------------------- /installer_obf/obfuscator/ScrambledString.py: -------------------------------------------------------------------------------- 1 | import ScrambledConstant 2 | import Variable 3 | import struct 4 | 5 | class ScrambledString: 6 | def __init__(self, value, max_len=None, binary=False): 7 | self.value = value 8 | self.max_len = max_len 9 | if binary: 10 | self.var_name = Variable.alloc_name('bin') 11 | else: 12 | self.var_name = Variable.alloc_name('str') 13 | self.binary = binary 14 | 15 | def generate(self): 16 | value = self.value 17 | 18 | value += '\0' 19 | value += '\0' * ((4-len(value)) % 4) 20 | 21 | buf_size = self.max_len 22 | if buf_size is None: 23 | buf_size = len(value) 24 | 25 | if self.binary: 26 | ret = '// Encoding binary\n' 27 | else: 28 | ret = '// Encoding string "%s"\n' % self.value 29 | 30 | ret += 'char %s[%d];\n' % (self.var_name, buf_size) 31 | 32 | for i in range(len(value)/4): 33 | part = value[4*i : 4*i+4] 34 | part = struct.unpack('> 1) ^ (0xedb88320 & -(crc & 1)) 10 | return crc 11 | 12 | def crc32c(crc, p, len): 13 | for i in range(len): 14 | crc = crc ^ ord(p[i]) 15 | for j in range(8): 16 | crc = (crc >> 1) ^ (0x82F63B78 & -(crc & 1)) 17 | return crc 18 | 19 | class RawValue: 20 | def __init__(self, x): 21 | self.x = x 22 | def get_result(self): 23 | if type(self.x) == str: 24 | raise 0 25 | return self.x 26 | def get_var_name(self): 27 | if type(self.x) == int: 28 | raise 0 29 | return self.x 30 | 31 | class Operator: 32 | def __init__(self, a, b): 33 | if type(a) in [int, str]: 34 | a = RawValue(a) 35 | if type(b) in [int, str]: 36 | b = RawValue(b) 37 | self.a = a 38 | self.b = b 39 | self.var_name = Variable.alloc_name() 40 | def get_var_name(self): 41 | return self.var_name 42 | 43 | class AddOp(Operator): 44 | def generate_code(self): 45 | return 'u32 {0} = {1} + {2};\n'.format(self.var_name, self.a.get_var_name(), self.b.get_var_name()) 46 | def get_result(self): 47 | return (self.a.get_result() + self.b.get_result()) & 0xFFFFFFFF 48 | 49 | class SubOp(Operator): 50 | def generate_code(self): 51 | return 'u32 {0} = {1} - {2};\n'.format(self.var_name, self.a.get_var_name(), self.b.get_var_name()) 52 | def get_result(self): 53 | return (self.a.get_result() - self.b.get_result() + (1 << 32)) & 0xFFFFFFFF 54 | 55 | class XorOp(Operator): 56 | def generate_code(self): 57 | return 'u32 {0} = {1} ^ {2};\n'.format(self.var_name, self.a.get_var_name(), self.b.get_var_name()) 58 | def get_result(self): 59 | return (self.a.get_result() ^ self.b.get_result()) & 0xFFFFFFFF 60 | 61 | class Crc32Op(Operator): 62 | def generate_code(self): 63 | return 'u32 {0} = __crc32w({1}, {2});\n'.format(self.var_name, self.a.get_var_name(), self.b.get_var_name()) 64 | def get_result(self): 65 | return crc32(self.a.get_result(), struct.pack(' 0: 85 | masks += [ 86 | low 87 | ] 88 | 89 | high = self.imm >> 24 90 | if high > 0: 91 | masks += [ 92 | high 93 | ] 94 | 95 | masks_idxs = list(range(len(masks))) 96 | random.shuffle(masks_idxs) 97 | 98 | ret = [] 99 | for i, m in enumerate(masks_idxs): 100 | ret += [ 101 | Sequences.LoadX8(Gadgets.KernelGadget(0x541C)), 102 | Sequences.Load_X0X1X2X3( 103 | Gadgets.PlaceholderReference(self.placeholder, 0), 104 | scratch_zero, scratch_zero2, 105 | Gadgets.Imm(0xF | (masks[m] << 5) | (m << 29)) 106 | ), 107 | Sequences.CallX8() 108 | ] 109 | return ret 110 | 111 | def get_imm_placeholder(self): 112 | return self.placeholder 113 | -------------------------------------------------------------------------------- /runner_obf/IpcCommand.py: -------------------------------------------------------------------------------- 1 | import Sequences 2 | import Gadgets 3 | import ImmEncoder 4 | import struct 5 | 6 | class WriteImm4: 7 | def __init__(self, dst, imm): 8 | self.dst = dst 9 | self.imm = imm 10 | 11 | def generate(self, r): 12 | imm = ImmEncoder.get_imm_encoder(self.imm) 13 | 14 | ret = [] 15 | ret += imm.generate(r) 16 | ret += [ 17 | Sequences.LoadX8(Sequences.Write_W2_X0().get_addr()), 18 | Sequences.Load_X0X1X2X3(self.dst, Gadgets.DontCare(), imm.get_imm_placeholder()), 19 | Sequences.CallX8() 20 | ] 21 | 22 | return ret 23 | 24 | IPC_PTR = Gadgets.RtldGadget(0x3000) 25 | 26 | class Cmd: 27 | def __init__(self, handle_ptr, cmd_id, raw=[], cmd_type=4, x=None): 28 | self.cmd_id = cmd_id 29 | self.raw = raw 30 | self.cmd_type = cmd_type 31 | self.x = x 32 | self.handle_ptr = handle_ptr 33 | 34 | def generate(self, r): 35 | ret = [] 36 | 37 | x_flag = 0 38 | if self.x is None: 39 | x_possibilities = [None] 40 | x_flag = 0 41 | else: 42 | x_possibilities = [] 43 | x_flag = 1 44 | 45 | size = self.x[1] 46 | 47 | for bit32_35 in range(1 << (35-32+1)): 48 | for bit36_38 in range(1 << (39-36+1)): 49 | x_possibilities += [(size << 16) | (bit32_35 << 12) | (bit36_38 << 6)] 50 | 51 | for x_desc in x_possibilities: 52 | off = 0 53 | 54 | # Write cmd hdr0 55 | ret += WriteImm4(IPC_PTR+off, self.cmd_type | (x_flag << 16)).generate(r) 56 | off += 4 57 | 58 | # Write cmd hdr1 59 | ret += WriteImm4(IPC_PTR+off, ((2*len(self.raw)) + 4 + 4)).generate(r) 60 | off += 4 61 | 62 | # Write X descriptor 63 | if not (x_desc is None): 64 | ret += WriteImm4(IPC_PTR+off, x_desc).generate(r) 65 | off += 4 66 | 67 | ret += [ 68 | Sequences.Load_X0X1X2X3(IPC_PTR+off, self.x[0], Gadgets.Imm(4)), 69 | Sequences.Memcpy() 70 | ] 71 | off += 4 72 | 73 | off = (off + 15) &~ 15 74 | 75 | # Write SFCI magic 76 | ret += WriteImm4(IPC_PTR+off, 0x49434653).generate(r) 77 | off += 4 78 | ret += WriteImm4(IPC_PTR+off, 0).generate(r) 79 | off += 4 80 | 81 | # Write cmd id 82 | ret += WriteImm4(IPC_PTR+off, self.cmd_id).generate(r) 83 | off += 4 84 | ret += WriteImm4(IPC_PTR+off, 0).generate(r) 85 | off += 4 86 | 87 | # Write raw section 88 | for ra in self.raw: 89 | ret += WriteImm4(IPC_PTR+off, ra).generate(r) 90 | off += 4 91 | ret += WriteImm4(IPC_PTR+off, ra>>32).generate(r) 92 | off += 4 93 | 94 | # Setup handle for call 95 | handle = Gadgets.DontCare() 96 | handle_ref = Gadgets.PlaceholderReference(handle) 97 | 98 | ret += [ 99 | Sequences.Load_X0X1X2X3(handle_ref, self.handle_ptr, Gadgets.Imm(4)), 100 | Sequences.Memcpy() 101 | ] 102 | 103 | # Call svcSendSyncRequestWithUserBuffer 104 | ret += [ 105 | Sequences.LoadX8(Sequences.SendSyncRequestWithUserBuffer().get_addr()), 106 | Sequences.Load_X0X1X2X3(IPC_PTR, Gadgets.Imm(0x1000), handle), 107 | Sequences.CallX8(), 108 | #Sequences.CrashIfResultFailed() 109 | ] 110 | 111 | return ret 112 | -------------------------------------------------------------------------------- /installer_obf/obfuscator/ScrambledIpcCommand.py: -------------------------------------------------------------------------------- 1 | import Variable 2 | import ScrambledConstant 3 | 4 | TEST=0 5 | 6 | SFCI_MAGIC=0x49434653 7 | 8 | class IpcCommand: 9 | def __init__(self, service_handle_varname, cmd_id, cmd_type=4, x=[], a=[], b=[], raw=[], handles=[], pid=False, ignore_error=False): 10 | self.service_handle_varname = service_handle_varname 11 | 12 | self.cmd_id = ScrambledConstant.ScrambledConstant(cmd_id) 13 | self.cmd_hdr0 = ScrambledConstant.ScrambledConstant(cmd_type | (len(x)<<16) | (len(a)<<20) | (len(b)<<24)) 14 | 15 | if (len(handles) > 0) or pid: 16 | has_handle = 0x80000000 17 | else: 18 | has_handle = 0 19 | self.cmd_hdr1 = ScrambledConstant.ScrambledConstant((len(raw) + 4 + 4) | has_handle) 20 | 21 | cmd_hdr2 = 0 22 | if pid: 23 | cmd_hdr2 |= 1 24 | cmd_hdr2 |= (len(handles) << 1) 25 | self.cmd_hdr2 = ScrambledConstant.ScrambledConstant(cmd_hdr2) 26 | 27 | self.handles = handles 28 | self.pid = pid 29 | self.x = x 30 | self.a = a 31 | self.b = b 32 | self.ignore_error = ignore_error 33 | 34 | if len(self.b) > 0: 35 | raise NotImplementedError() 36 | 37 | raw = [SFCI_MAGIC, 0, cmd_id, 0] + raw 38 | self.raw = [] 39 | 40 | for r in raw: 41 | if type(r) is int or type(r) is long: 42 | self.raw.append(ScrambledConstant.ScrambledConstant(r)) 43 | else: 44 | self.raw.append(r) 45 | 46 | def generate(self): 47 | ret = '' 48 | ret += self.cmd_hdr0.generate_scramble() 49 | ret += self.cmd_hdr1.generate_scramble() 50 | ret += self.cmd_hdr2.generate_scramble() 51 | 52 | for r in self.raw: 53 | if isinstance(r, ScrambledConstant.ScrambledConstant): 54 | ret += r.generate_scramble() 55 | 56 | variables = { 57 | 'tls_ptr': Variable.alloc_name('tls_ptr'), 58 | 'cmd_hdr0': self.cmd_hdr0.get_var_name(), 59 | 'cmd_hdr1': self.cmd_hdr1.get_var_name(), 60 | 'cmd_hdr2': self.cmd_hdr2.get_var_name(), 61 | 'service_handle': self.service_handle_varname 62 | } 63 | 64 | ### Emit ipc headers 65 | ret += \ 66 | ''' 67 | u32* {tls_ptr} = (u32*)armGetTls(); 68 | {tls_ptr}[0] = {cmd_hdr0}; 69 | {tls_ptr}[1] = {cmd_hdr1}; 70 | {tls_ptr}[2] = {cmd_hdr2}; 71 | 72 | '''.format(**variables) 73 | 74 | handle_offset = 2 75 | if self.pid or len(self.handles): 76 | handle_offset += 1 77 | if self.pid: 78 | handle_offset += 2 79 | 80 | ### Emit handles 81 | for h in self.handles: 82 | ret += '''{tls_ptr}[%d] = %s;''' % (handle_offset, h) 83 | handle_offset += 1 84 | 85 | ### Emit X descriptors 86 | for xx in self.x: 87 | ret += '''{tls_ptr}[%d] = (((((u64)%s) >> 32) & 0xF) << 12) | (((((u64)%s) >> 36) & 0xF) << 6);'''.format(**variables) % (handle_offset, xx[0], xx[0]) 88 | 89 | size = ScrambledConstant.ScrambledConstant(xx[1]) 90 | ret += size.generate_scramble() 91 | ret += '''*(((u16*)(&{tls_ptr}[%d]))+1) = %s;\n'''.format(**variables) % (handle_offset, size.get_var_name()) 92 | 93 | ret += '''{tls_ptr}[%d+1] = ((u64)%s) & 0xFFFFFFFF;\n'''.format(**variables) % (handle_offset, xx[0]) 94 | handle_offset += 2 95 | 96 | ### Emit A descriptors 97 | for aa in self.a: 98 | size = ScrambledConstant.ScrambledConstant(aa[1]) 99 | ret += size.generate_scramble() 100 | ret += '''{tls_ptr}[%d] = %s;\n'''.format(**variables) % (handle_offset, size.get_var_name()) 101 | ret += '''{tls_ptr}[%d+1] = ((u64)%s) & 0xFFFFFFFF;\n'''.format(**variables) % (handle_offset, aa[0]) 102 | ret += '''{tls_ptr}[%d+2] = (((((u64)%s) >> 32) & 0xF) << 28) | (((((u64)%s) >> 36) & 0xF) << 2);\n'''.format(**variables) % (handle_offset, aa[0], aa[0]) 103 | 104 | if len(aa) > 2: 105 | flags = aa[2] 106 | else: 107 | flags = 0 108 | ret += '''{tls_ptr}[%d+2] |= %d;\n'''.format(**variables) % (handle_offset, flags) 109 | 110 | handle_offset += 3 111 | 112 | ### Emit raws 113 | offset = ((handle_offset + 3) / 4) * 4 114 | for r in self.raw: 115 | if isinstance(r, ScrambledConstant.ScrambledConstant): 116 | ret += ('{tls_ptr}[%d] = %s;\n'.format(**variables)) % (offset, r.get_var_name()) 117 | else: 118 | ret += ('{tls_ptr}[%d] = %s;\n'.format(**variables)) % (offset, r) 119 | offset += 1 120 | 121 | ret += 'rc = svcSendSyncRequest({service_handle});\n'.format(**variables) 122 | 123 | if TEST and not self.ignore_error: 124 | ret += 'if (rc) fatalSimple(MAKERESULT(222, %d));\n' % Variable.alloc_err() 125 | 126 | return ret 127 | 128 | def __repr__(self): 129 | return self.generate() 130 | -------------------------------------------------------------------------------- /installer_obf/obfuscator/Main.py: -------------------------------------------------------------------------------- 1 | import ScrambledIpcCommand 2 | import ScrambledString 3 | import CodeSegment 4 | import Services 5 | import Crypto 6 | 7 | ### Initial vars 8 | TEST = 0 9 | code = [] 10 | 11 | ### Encrypt hbl.nsp 12 | hbl = open('build/hbl.pfs0', 'rb').read() 13 | hbl += 'X' * ((0x1000 - (len(hbl) % 0x1000)) % 0x1000) 14 | 15 | hbl_bin_size = len(hbl) 16 | assert (hbl_bin_size % 0x1000) == 0 17 | 18 | ### Boilerplate 19 | code.append(CodeSegment.Raw(''' 20 | #include 21 | #include 22 | #include // for crc intrinsics 23 | #include // for neon+crypto intrinsics 24 | 25 | u32 __nx_applet_type = AppletType_None; 26 | 27 | static char g_heap[0x20000]; 28 | 29 | void __libnx_initheap(void) 30 | { 31 | extern char* fake_heap_start; 32 | extern char* fake_heap_end; 33 | 34 | fake_heap_start = &g_heap[0]; 35 | fake_heap_end = &g_heap[sizeof g_heap]; 36 | } 37 | 38 | void __appInit(void) 39 | { 40 | if (R_FAILED(smInitialize())) 41 | fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); 42 | } 43 | 44 | void threadfunc(void); 45 | 46 | int main(int argc, char* argv[]) 47 | { 48 | static Thread t; 49 | Result rc; 50 | 51 | rc = threadCreate(&t, (ThreadFunc) &threadfunc, NULL, 0x4000, 0x28, 1); 52 | if (rc) fatalSimple(rc); 53 | 54 | rc = threadStart(&t); 55 | if (rc) fatalSimple(rc); 56 | 57 | svcExitThread(); 58 | } 59 | 60 | void threadfunc(void) { 61 | Handle tmp_handle; 62 | Result rc; 63 | 64 | ''')) 65 | 66 | srv = Services.Services() 67 | code.append(srv) 68 | 69 | ### ipcDuplicateSession 70 | for i in range(64): 71 | idx, idx_obf =srv.get_index('pm:shell') 72 | code.append(idx_obf) 73 | code.append(ScrambledIpcCommand.IpcCommand(srv.get_handle(idx), 2, cmd_type=5, raw=[0], ignore_error=True)) 74 | 75 | srv = Services.Services() 76 | code.append(srv) 77 | 78 | ### fsGetPid 79 | idx, idx_obf = srv.get_index('fsp-srv') 80 | code.append(idx_obf) 81 | 82 | code.append( 83 | CodeSegment.Combined( 84 | ScrambledIpcCommand.IpcCommand(srv.get_handle(idx), 1, raw=[0, 0], pid=True), 85 | CodeSegment.Raw('''u64 pid = ((u32*)armGetTls())[3];''')) 86 | ) 87 | 88 | ### fsprClearPerm 89 | idx, idx_obf = srv.get_index('fsp-pr') 90 | code.append(idx_obf) 91 | 92 | code.append(ScrambledIpcCommand.IpcCommand(srv.get_handle(idx), 1, raw=['pid', 0])) 93 | 94 | ### fsprSetFullPerm 95 | code.append(CodeSegment.Raw(''' 96 | char b0[0x1c]; 97 | memset(b0, 0, sizeof b0); 98 | *(u32*)(&b0[0]) = 1; 99 | *(u64*)(&b0[4]) = -1ull; 100 | *(u32*)(&b0[0x0C]) = sizeof b0; 101 | *(u32*)(&b0[0x14]) = sizeof b0; 102 | 103 | char b1[0x2c]; 104 | memset(b1, 0, sizeof b1); 105 | *(u32*)(&b1[0]) = 1; 106 | *(u64*)(&b1[4]) = -1ull; 107 | *(u64*)(&b1[0x14]) = -1ull; 108 | *(u64*)(&b1[0x24]) = -1ull; 109 | ''')) 110 | 111 | idx, idx_obf = srv.get_index('fsp-pr') 112 | code.append(idx_obf) 113 | 114 | code.append(ScrambledIpcCommand.IpcCommand( 115 | srv.get_handle(idx), 0, raw = [3, 0, 'pid', 0, 0x0000100A, 0x01000000, 0x1c, 0, 0x2c, 0], a = [['&b0[0]', 0x1c], ['&b1[0]', 0x2c]] 116 | )) 117 | 118 | ### fsInitialize 119 | idx, idx_obf = srv.get_index('fsp-srv') 120 | code.append(idx_obf) 121 | 122 | code.append(ScrambledIpcCommand.IpcCommand( 123 | srv.get_handle(idx), 124 | 1, raw = [0, 0], pid=True 125 | )) 126 | 127 | ### fsMountBis 128 | code.append(CodeSegment.Raw(''' 129 | char buf[300]; 130 | buf[0] = 0; 131 | ''')) 132 | 133 | idx, idx_obf = srv.get_index('fsp-srv') 134 | code.append(idx_obf) 135 | 136 | code.append(CodeSegment.Combined( 137 | ScrambledIpcCommand.IpcCommand( 138 | srv.get_handle(idx), 11, raw = [30, 0], x = [['&buf[0]', 300]] 139 | ), 140 | CodeSegment.Raw('''Handle nand_handle = ((u32*)armGetTls())[3];''')) 141 | ) 142 | 143 | ### fsFsDeleteFile 144 | file_path = ScrambledString.ScrambledString('/.nsp', 300) 145 | code.append(file_path) 146 | 147 | code.append(ScrambledIpcCommand.IpcCommand( 148 | 'nand_handle', 1, raw=[], x = [[file_path.get_var_name(), 300]], 149 | ignore_error=True 150 | )) 151 | 152 | 153 | ### fsFsCreateFile 154 | code.append(ScrambledIpcCommand.IpcCommand( 155 | 'nand_handle', 0, raw=[0, 0, hbl_bin_size, 0, 0], x = [[file_path.get_var_name(), 300]], 156 | )) 157 | 158 | ### fsFsOpenFile 159 | code.append(CodeSegment.Combined( 160 | ScrambledIpcCommand.IpcCommand( 161 | 'nand_handle', 8, raw=[2, 0], x = [[file_path.get_var_name(), 300]]), 162 | CodeSegment.Raw('''Handle file_handle = ((u32*)armGetTls())[3];''')) 163 | ) 164 | 165 | ### fsFileWrite 166 | chunks = [] 167 | 168 | for offset in range(0, hbl_bin_size, 0x400): 169 | chunk = hbl[offset:offset+0x400] 170 | chunks.append({'enc': Crypto.Decryptor(chunk), 'offset': offset}) 171 | 172 | import random 173 | random.shuffle(chunks) 174 | 175 | for c in chunks: 176 | enc = c['enc'] 177 | offset = c['offset'] 178 | 179 | code.append(enc) 180 | code.append(ScrambledIpcCommand.IpcCommand( 181 | 'file_handle', 1, raw=[0, 0, offset, 0, len(chunk), 0], a = [[enc.get_var_name(), len(chunk), 1]] 182 | )) 183 | 184 | code.append(CodeSegment.Raw(''' 185 | fatalSimple(MAKERESULT(0, 1337)); 186 | } 187 | ''')) 188 | 189 | ### Generate code 190 | for c in code: 191 | print c.generate() 192 | -------------------------------------------------------------------------------- /installer/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "loader_bin.h" 5 | 6 | u32 __nx_applet_type = AppletType_None; 7 | 8 | static char g_heap[0x20000]; 9 | 10 | void __libnx_initheap(void) 11 | { 12 | extern char* fake_heap_start; 13 | extern char* fake_heap_end; 14 | 15 | fake_heap_start = &g_heap[0]; 16 | fake_heap_end = &g_heap[sizeof g_heap]; 17 | } 18 | 19 | void ipcDuplicateSession(Service* s) 20 | { 21 | u32* buf = (u32*)armGetTls(); 22 | 23 | buf[0] = 5; 24 | buf[1] = 8; 25 | buf[4] = SFCI_MAGIC; 26 | buf[5] = 0; 27 | buf[6] = 2; 28 | buf[7] = 0; 29 | 30 | ipcDispatch(s->handle); 31 | } 32 | 33 | Result fsGetPid(Service* s, u64* pid_out) 34 | { 35 | Result rc; 36 | 37 | IpcCommand c; 38 | ipcInitialize(&c); 39 | ipcSendPid(&c); 40 | 41 | struct { 42 | u64 magic; 43 | u64 cmd_id; 44 | u64 unk; 45 | } *raw; 46 | 47 | raw = ipcPrepareHeader(&c, sizeof(*raw)); 48 | 49 | raw->magic = SFCI_MAGIC; 50 | raw->cmd_id = 1; 51 | raw->unk = 0; 52 | 53 | rc = serviceIpcDispatch(s); 54 | 55 | if (R_SUCCEEDED(rc)) { 56 | *pid_out = ((u32*)armGetTls())[3]; 57 | } 58 | 59 | return rc; 60 | } 61 | 62 | Result fsprClearPerm(Service* s, u64 pid) 63 | { 64 | IpcCommand c; 65 | ipcInitialize(&c); 66 | 67 | struct { 68 | u64 magic; 69 | u64 cmd_id; 70 | u64 pid; 71 | } *raw; 72 | 73 | raw = ipcPrepareHeader(&c, sizeof(*raw)); 74 | 75 | raw->magic = SFCI_MAGIC; 76 | raw->cmd_id = 1; 77 | raw->pid = pid; 78 | 79 | return serviceIpcDispatch(s); 80 | } 81 | 82 | Result fsprSetFullPerm(Service* s, u64 pid) 83 | { 84 | char b0[0x1c]; 85 | memset(b0, 0, sizeof b0); 86 | *(u32*)(&b0[0]) = 1; 87 | *(u64*)(&b0[4]) = -1ull; 88 | *(u32*)(&b0[0x0C]) = sizeof b0; 89 | *(u32*)(&b0[0x14]) = sizeof b0; 90 | 91 | char b1[0x2c]; 92 | memset(b1, 0, sizeof b1); 93 | *(u32*)(&b1[0]) = 1; 94 | *(u64*)(&b1[4]) = -1ull; 95 | *(u64*)(&b1[0x14]) = -1ull; 96 | *(u64*)(&b1[0x24]) = -1ull; 97 | 98 | IpcCommand c; 99 | ipcInitialize(&c); 100 | ipcAddSendBuffer(&c, b0, sizeof b0, 0); 101 | ipcAddSendBuffer(&c, b1, sizeof b1, 0); 102 | 103 | struct { 104 | u64 magic; 105 | u64 cmd_id; 106 | u64 storage_id; 107 | u64 pid; 108 | u64 title_id; 109 | u64 b0_size; 110 | u64 b1_size; 111 | } *raw; 112 | 113 | raw = ipcPrepareHeader(&c, sizeof(*raw)); 114 | 115 | raw->magic = SFCI_MAGIC; 116 | raw->cmd_id = 0; 117 | raw->storage_id = 3; 118 | raw->pid = pid; 119 | raw->title_id = 0x010000000000100A; 120 | raw->b0_size = sizeof b0; 121 | raw->b1_size = sizeof b1; 122 | 123 | return serviceIpcDispatch(s); 124 | } 125 | 126 | Result fsMountBis(Service* s, u32 partition_id, FsFileSystem* fs_out) 127 | { 128 | Result rc; 129 | 130 | char buf[300]; 131 | buf[0] = '\0'; 132 | 133 | IpcCommand c; 134 | ipcInitialize(&c); 135 | ipcAddSendStatic(&c, buf, sizeof buf, 0); 136 | 137 | struct { 138 | u64 magic; 139 | u64 cmd_id; 140 | u64 partition_id; 141 | } *raw; 142 | 143 | raw = ipcPrepareHeader(&c, sizeof(*raw)); 144 | 145 | raw->magic = SFCI_MAGIC; 146 | raw->cmd_id = 11; 147 | raw->partition_id = partition_id; 148 | 149 | rc = serviceIpcDispatch(s); 150 | 151 | if (R_SUCCEEDED(rc)) { 152 | IpcParsedCommand r; 153 | ipcParse(&r); 154 | 155 | struct { 156 | u64 magic; 157 | u64 result; 158 | } *resp = r.Raw; 159 | 160 | rc = resp->result; 161 | 162 | if (R_SUCCEEDED(rc)) { 163 | fs_out->h = r.Handles[0]; 164 | } 165 | } 166 | 167 | return rc; 168 | } 169 | 170 | void __appInit(void) 171 | { 172 | if (R_FAILED(smInitialize())) 173 | fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); 174 | } 175 | 176 | int main(int argc, char **argv) 177 | { 178 | Result rc; 179 | Service pm_shell; 180 | rc = smGetService(&pm_shell, "pm:shell"); 181 | if (rc) fatalSimple(MAKERESULT(349, 1)); 182 | 183 | int i; 184 | for(i=0; i<256; i++) 185 | ipcDuplicateSession(&pm_shell); 186 | 187 | Service fsp_srv; 188 | rc = smGetService(&fsp_srv, "fsp-srv"); 189 | if (rc) fatalSimple(MAKERESULT(349, 2)); 190 | 191 | u64 pid; 192 | rc = fsGetPid(&fsp_srv, &pid); 193 | if (rc) fatalSimple(MAKERESULT(349, 3)); 194 | 195 | serviceClose(&fsp_srv); 196 | 197 | Service fsp_pr; 198 | rc = smGetService(&fsp_pr, "fsp-pr"); 199 | if (rc) fatalSimple(MAKERESULT(349, 4)); 200 | 201 | rc = fsprClearPerm(&fsp_pr, pid); 202 | if (rc) fatalSimple(MAKERESULT(349, 5)); 203 | 204 | rc = fsprSetFullPerm(&fsp_pr, pid); 205 | if (rc) fatalSimple(rc); 206 | 207 | rc = fsInitialize(); 208 | if (rc) fatalSimple(MAKERESULT(349, 7)); 209 | 210 | FsFileSystem fs_nand; 211 | rc = fsMountBis(fsGetServiceSession(), 30, &fs_nand); 212 | if (rc) fatalSimple(rc); 213 | 214 | rc = fsFsDeleteFile(&fs_nand, "/hbl.nsp"); 215 | 216 | rc = fsFsCreateFile(&fs_nand, "/hbl.nsp", hbl_bin_size, 0 /* flags */); 217 | if (rc) fatalSimple(MAKERESULT(349, 9)); 218 | 219 | FsFile f; 220 | rc = fsFsOpenFile(&fs_nand, "/hbl.nsp", FS_OPEN_WRITE /* flags */, &f); 221 | if (rc) fatalSimple(MAKERESULT(349, 10)); 222 | 223 | rc = fsFileWrite(&f, 0, hbl_bin, hbl_bin_size); 224 | if (rc) fatalSimple(MAKERESULT(349, 11)); 225 | 226 | fatalSimple(MAKERESULT(0, 1337)); 227 | return 0; 228 | } 229 | -------------------------------------------------------------------------------- /runner_obf/test/run_rop.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | #from __future__ import print_function 3 | from unicorn import * 4 | from unicorn.arm64_const import * 5 | import sys 6 | import struct 7 | 8 | CODE_BASE = 0xA0000000 9 | MAIN_BASE = 0xA0000000+0x4000 10 | 11 | def hexdump(src, length=16): 12 | FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) 13 | lines = [] 14 | for c in xrange(0, len(src), length): 15 | chars = src[c:c+length] 16 | hex = ' '.join(["%02x" % ord(x) for x in chars]) 17 | printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars]) 18 | lines.append("%04x %-*s %s\n" % (c, length*3, hex, printable)) 19 | return ''.join(lines) 20 | 21 | def dump(mu, addr, sz): 22 | mem = mu.mem_read(addr, sz) 23 | mem = ''.join(chr(m) for m in mem) 24 | print hexdump(mem) 25 | 26 | def regs(mu): 27 | print '____' 28 | print '' 29 | print '' 30 | print "X0 = 0x%x" % mu.reg_read(UC_ARM64_REG_X0) 31 | print "X1 = 0x%x" % mu.reg_read(UC_ARM64_REG_X1) 32 | print "X2 = 0x%x" % mu.reg_read(UC_ARM64_REG_X2) 33 | print "X3 = 0x%x" % mu.reg_read(UC_ARM64_REG_X3) 34 | print "X4 = 0x%x" % mu.reg_read(UC_ARM64_REG_X4) 35 | print "X5 = 0x%x" % mu.reg_read(UC_ARM64_REG_X5) 36 | print "X6 = 0x%x" % mu.reg_read(UC_ARM64_REG_X6) 37 | print "X7 = 0x%x" % mu.reg_read(UC_ARM64_REG_X7) 38 | print "X8 = 0x%x" % mu.reg_read(UC_ARM64_REG_X8) 39 | print "X9 = 0x%x" % mu.reg_read(UC_ARM64_REG_X9) 40 | print "X10 = 0x%x" % mu.reg_read(UC_ARM64_REG_X10) 41 | print "X11 = 0x%x" % mu.reg_read(UC_ARM64_REG_X11) 42 | print "X12 = 0x%x" % mu.reg_read(UC_ARM64_REG_X12) 43 | print "X13 = 0x%x" % mu.reg_read(UC_ARM64_REG_X13) 44 | print "X14 = 0x%x" % mu.reg_read(UC_ARM64_REG_X14) 45 | print "X15 = 0x%x" % mu.reg_read(UC_ARM64_REG_X15) 46 | print "X16 = 0x%x" % mu.reg_read(UC_ARM64_REG_X16) 47 | print "X17 = 0x%x" % mu.reg_read(UC_ARM64_REG_X17) 48 | print "X18 = 0x%x" % mu.reg_read(UC_ARM64_REG_X18) 49 | print "X19 = 0x%x" % mu.reg_read(UC_ARM64_REG_X19) 50 | print "X20 = 0x%x" % mu.reg_read(UC_ARM64_REG_X20) 51 | print "X21 = 0x%x" % mu.reg_read(UC_ARM64_REG_X21) 52 | print "X22 = 0x%x" % mu.reg_read(UC_ARM64_REG_X22) 53 | print "X23 = 0x%x" % mu.reg_read(UC_ARM64_REG_X23) 54 | print "X24 = 0x%x" % mu.reg_read(UC_ARM64_REG_X24) 55 | print "X25 = 0x%x" % mu.reg_read(UC_ARM64_REG_X25) 56 | print "X26 = 0x%x" % mu.reg_read(UC_ARM64_REG_X26) 57 | print "X27 = 0x%x" % mu.reg_read(UC_ARM64_REG_X27) 58 | print "X28 = 0x%x" % mu.reg_read(UC_ARM64_REG_X28) 59 | print "X29 = 0x%x" % mu.reg_read(UC_ARM64_REG_X29) 60 | print "X30 = 0x%x" % mu.reg_read(UC_ARM64_REG_X30) 61 | print "PC = 0x%x" % mu.reg_read(UC_ARM64_REG_PC) 62 | print "SP = 0x%x" % mu.reg_read(UC_ARM64_REG_SP) 63 | 64 | def hook(uc): 65 | pc = mu.reg_read(UC_ARM64_REG_PC) 66 | x0 = mu.reg_read(UC_ARM64_REG_X0) 67 | x1 = mu.reg_read(UC_ARM64_REG_X1) 68 | 69 | # smGetService 70 | if pc == (MAIN_BASE + 0x3DC674+4+8): 71 | print 'smGetService' 72 | mu.mem_write(x0, '\x13\x37\x00\x00') 73 | mu.reg_write(UC_ARM64_REG_PC, MAIN_BASE + 0x3DC6A0) 74 | mu.reg_write(UC_ARM64_REG_X0, 0) 75 | #sys.stdin.read(1) 76 | # svcSendSyncRequestWithUserBuffer 77 | elif pc == (MAIN_BASE + 0x3ED3DC): 78 | print 'svcSendSyncRequestWithUserBuffer' 79 | dump(mu, CODE_BASE+0x3000, 0x80) 80 | dump(mu, MAIN_BASE+0x8AC000, 0x80) 81 | mu.reg_write(UC_ARM64_REG_PC, MAIN_BASE + 0x3ED3DC+4) 82 | #sys.stdin.read(1) 83 | # infloop 84 | elif pc == (CODE_BASE + 0xAC): 85 | print 'INFLOOP' 86 | sys.exit(0) 87 | elif pc == 0xfffffff7ffc39880: 88 | print 'WRITEEEEEEEEEEEEEE %x' % x0 89 | if x0 == 0xa1000000: 90 | mu.reg_write(UC_ARM64_REG_PC, 0xfffffff7ffc39884) 91 | 92 | def hook_code(uc, address, size, user_data): 93 | hook(uc) 94 | 95 | mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM | UC_MODE_LITTLE_ENDIAN) 96 | 97 | kernel_base = 0xFFFFFFF7FFC00000 98 | kernel = open('test/v3.0_.text_0xFFFFFFF7FFC00000.bin', 'rb').read() 99 | 100 | mu.mem_map(kernel_base, len(kernel)) 101 | mu.mem_write(kernel_base, kernel) 102 | 103 | code_base = CODE_BASE 104 | code_size = 0x9cb000 105 | mu.mem_map(code_base, code_size) 106 | 107 | rtld = open('test/rtld_text.bin', 'rb').read() 108 | mu.mem_write(code_base, rtld) 109 | rtld = open('test/rtld_rodata.bin', 'rb').read() 110 | mu.mem_write(code_base+0x2000, rtld) 111 | rtld = open('test/rtld_data.bin', 'rb').read() 112 | mu.mem_write(code_base+0x3000, rtld) 113 | 114 | main = open('test/main_text.bin', 'rb').read() 115 | mu.mem_write(code_base+0x4000, main) 116 | main = open('test/main_rodata.bin', 'rb').read() 117 | mu.mem_write(code_base+0x4000+0x5e3000, main) 118 | main = open('test/main_data.bin', 'rb').read() 119 | mu.mem_write(code_base+0x4000+0x5e3000+0x2c5000, main) 120 | 121 | rop_base = 0x30000000 122 | rop = open(sys.argv[1], 'rb').read() 123 | rop_relocs = open(sys.argv[2], 'rb').read() 124 | 125 | for i in range(len(rop_relocs)/8): 126 | t, r = struct.unpack('DEVKITA64") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITA64)/switch_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". 19 | # 20 | # NO_ICON: if set to anything, do not use icon. 21 | # NO_NACP: if set to anything, no .nacp file is generated. 22 | # APP_TITLE is the name of the app stored in the .nacp file (Optional) 23 | # APP_AUTHOR is the author of the app stored in the .nacp file (Optional) 24 | # APP_VERSION is the version of the app stored in the .nacp file (Optional) 25 | # APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) 26 | # ICON is the filename of the icon (.jpg), relative to the project folder. 27 | # If not set, it attempts to use one of the following (in this order): 28 | # - .jpg 29 | # - icon.jpg 30 | # - /default_icon.jpg 31 | #--------------------------------------------------------------------------------- 32 | TARGET := $(notdir $(CURDIR)) 33 | BUILD := build 34 | SOURCES := source 35 | DATA := data 36 | INCLUDES := include 37 | EXEFS_SRC := exefs_src 38 | 39 | #--------------------------------------------------------------------------------- 40 | # options for code generation 41 | #--------------------------------------------------------------------------------- 42 | ARCH := -march=armv8-a -mtp=soft -fPIE 43 | 44 | CFLAGS := -g -Wall -O2 \ 45 | -ffast-math \ 46 | $(ARCH) $(DEFINES) 47 | 48 | CFLAGS += $(INCLUDE) -DSWITCH 49 | 50 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 51 | 52 | ASFLAGS := -g $(ARCH) 53 | LDFLAGS = -specs=switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 54 | 55 | LIBS := -lnx 56 | 57 | #--------------------------------------------------------------------------------- 58 | # list of directories containing libraries, this must be the top level containing 59 | # include and lib 60 | #--------------------------------------------------------------------------------- 61 | LIBDIRS := $(PORTLIBS) $(LIBNX) 62 | 63 | 64 | #--------------------------------------------------------------------------------- 65 | # no real need to edit anything past this point unless you need to add additional 66 | # rules for different file extensions 67 | #--------------------------------------------------------------------------------- 68 | ifneq ($(BUILD),$(notdir $(CURDIR))) 69 | #--------------------------------------------------------------------------------- 70 | 71 | export OUTPUT := $(CURDIR)/$(TARGET) 72 | export TOPDIR := $(CURDIR) 73 | 74 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 75 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 76 | 77 | export DEPSDIR := $(CURDIR)/$(BUILD) 78 | 79 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 80 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 81 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 82 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 83 | 84 | #--------------------------------------------------------------------------------- 85 | # use CXX for linking C++ projects, CC for standard C 86 | #--------------------------------------------------------------------------------- 87 | ifeq ($(strip $(CPPFILES)),) 88 | #--------------------------------------------------------------------------------- 89 | export LD := $(CC) 90 | #--------------------------------------------------------------------------------- 91 | else 92 | #--------------------------------------------------------------------------------- 93 | export LD := $(CXX) 94 | #--------------------------------------------------------------------------------- 95 | endif 96 | #--------------------------------------------------------------------------------- 97 | 98 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 99 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 100 | 101 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 102 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 103 | -I$(CURDIR)/$(BUILD) 104 | 105 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 106 | 107 | export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) 108 | 109 | ifeq ($(strip $(ICON)),) 110 | icons := $(wildcard *.jpg) 111 | ifneq (,$(findstring $(TARGET).jpg,$(icons))) 112 | export APP_ICON := $(TOPDIR)/$(TARGET).jpg 113 | else 114 | ifneq (,$(findstring icon.jpg,$(icons))) 115 | export APP_ICON := $(TOPDIR)/icon.jpg 116 | endif 117 | endif 118 | else 119 | export APP_ICON := $(TOPDIR)/$(ICON) 120 | endif 121 | 122 | ifeq ($(strip $(NO_ICON)),) 123 | export NROFLAGS += --icon=$(APP_ICON) 124 | endif 125 | 126 | ifeq ($(strip $(NO_NACP)),) 127 | export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp 128 | endif 129 | 130 | ifneq ($(APP_TITLEID),) 131 | export NACPFLAGS += --titleid=$(APP_TITLEID) 132 | endif 133 | 134 | .PHONY: $(BUILD) clean all 135 | 136 | #--------------------------------------------------------------------------------- 137 | all: $(BUILD) 138 | 139 | $(BUILD): 140 | @[ -d $@ ] || mkdir -p $@ 141 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 142 | 143 | #--------------------------------------------------------------------------------- 144 | clean: 145 | @echo clean ... 146 | @rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf 147 | 148 | 149 | #--------------------------------------------------------------------------------- 150 | else 151 | .PHONY: all 152 | 153 | DEPENDS := $(OFILES:.o=.d) 154 | 155 | #--------------------------------------------------------------------------------- 156 | # main targets 157 | #--------------------------------------------------------------------------------- 158 | all : $(OUTPUT).pfs0 $(OUTPUT).nro 159 | 160 | $(OUTPUT).pfs0 : $(OUTPUT).nso 161 | 162 | $(OUTPUT).nso : $(OUTPUT).elf 163 | 164 | ifeq ($(strip $(NO_NACP)),) 165 | $(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp 166 | else 167 | $(OUTPUT).nro : $(OUTPUT).elf 168 | endif 169 | 170 | $(OUTPUT).elf : $(OFILES) 171 | 172 | #--------------------------------------------------------------------------------- 173 | # you need a rule like this for each extension you use as binary data 174 | #--------------------------------------------------------------------------------- 175 | %.bin.o : %.bin 176 | #--------------------------------------------------------------------------------- 177 | @echo $(notdir $<) 178 | @$(bin2o) 179 | 180 | -include $(DEPENDS) 181 | 182 | #--------------------------------------------------------------------------------------- 183 | endif 184 | #--------------------------------------------------------------------------------------- 185 | -------------------------------------------------------------------------------- /installer/Makefile.normal: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITA64)),) 6 | $(error "Please set DEVKITA64 in your environment. export DEVKITA64=DEVKITA64") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITA64)/switch_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". 19 | # 20 | # NO_ICON: if set to anything, do not use icon. 21 | # NO_NACP: if set to anything, no .nacp file is generated. 22 | # APP_TITLE is the name of the app stored in the .nacp file (Optional) 23 | # APP_AUTHOR is the author of the app stored in the .nacp file (Optional) 24 | # APP_VERSION is the version of the app stored in the .nacp file (Optional) 25 | # APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) 26 | # ICON is the filename of the icon (.jpg), relative to the project folder. 27 | # If not set, it attempts to use one of the following (in this order): 28 | # - .jpg 29 | # - icon.jpg 30 | # - /default_icon.jpg 31 | #--------------------------------------------------------------------------------- 32 | TARGET := $(notdir $(CURDIR)) 33 | BUILD := build 34 | SOURCES := source 35 | DATA := data 36 | INCLUDES := include 37 | EXEFS_SRC := exefs_src 38 | 39 | #--------------------------------------------------------------------------------- 40 | # options for code generation 41 | #--------------------------------------------------------------------------------- 42 | ARCH := -march=armv8-a+crypto -mtp=soft -fPIE -mtune=cortex-a57 43 | 44 | CFLAGS := -g -Wall -O2 \ 45 | -ffast-math \ 46 | $(ARCH) $(DEFINES) 47 | 48 | CFLAGS += $(INCLUDE) -DSWITCH 49 | 50 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 51 | 52 | ASFLAGS := -g $(ARCH) 53 | LDFLAGS = -specs=switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 54 | 55 | LIBS := -lnx 56 | 57 | #--------------------------------------------------------------------------------- 58 | # list of directories containing libraries, this must be the top level containing 59 | # include and lib 60 | #--------------------------------------------------------------------------------- 61 | LIBDIRS := $(PORTLIBS) $(LIBNX) 62 | 63 | 64 | #--------------------------------------------------------------------------------- 65 | # no real need to edit anything past this point unless you need to add additional 66 | # rules for different file extensions 67 | #--------------------------------------------------------------------------------- 68 | ifneq ($(BUILD),$(notdir $(CURDIR))) 69 | #--------------------------------------------------------------------------------- 70 | 71 | export OUTPUT := $(CURDIR)/$(TARGET) 72 | export TOPDIR := $(CURDIR) 73 | 74 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 75 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 76 | 77 | export DEPSDIR := $(CURDIR)/$(BUILD) 78 | 79 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 80 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 81 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 82 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 83 | 84 | #--------------------------------------------------------------------------------- 85 | # use CXX for linking C++ projects, CC for standard C 86 | #--------------------------------------------------------------------------------- 87 | ifeq ($(strip $(CPPFILES)),) 88 | #--------------------------------------------------------------------------------- 89 | export LD := $(CC) 90 | #--------------------------------------------------------------------------------- 91 | else 92 | #--------------------------------------------------------------------------------- 93 | export LD := $(CXX) 94 | #--------------------------------------------------------------------------------- 95 | endif 96 | #--------------------------------------------------------------------------------- 97 | 98 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 99 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 100 | 101 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 102 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 103 | -I$(CURDIR)/$(BUILD) 104 | 105 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 106 | 107 | export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) 108 | 109 | ifeq ($(strip $(ICON)),) 110 | icons := $(wildcard *.jpg) 111 | ifneq (,$(findstring $(TARGET).jpg,$(icons))) 112 | export APP_ICON := $(TOPDIR)/$(TARGET).jpg 113 | else 114 | ifneq (,$(findstring icon.jpg,$(icons))) 115 | export APP_ICON := $(TOPDIR)/icon.jpg 116 | endif 117 | endif 118 | else 119 | export APP_ICON := $(TOPDIR)/$(ICON) 120 | endif 121 | 122 | #ifeq ($(strip $(NO_ICON)),) 123 | # export NROFLAGS += --icon=$(APP_ICON) 124 | #endif 125 | 126 | #ifeq ($(strip $(NO_NACP)),) 127 | # export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp 128 | #endif 129 | 130 | #ifneq ($(APP_TITLEID),) 131 | # export NACPFLAGS += --titleid=$(APP_TITLEID) 132 | #endif 133 | 134 | .PHONY: $(BUILD) clean all 135 | 136 | #--------------------------------------------------------------------------------- 137 | all: $(BUILD) 138 | 139 | $(BUILD): 140 | @[ -d $@ ] || mkdir -p $@ 141 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.normal 142 | 143 | #--------------------------------------------------------------------------------- 144 | clean: 145 | @echo clean ... 146 | @rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf 147 | 148 | 149 | #--------------------------------------------------------------------------------- 150 | else 151 | .PHONY: all 152 | 153 | DEPENDS := $(OFILES:.o=.d) 154 | 155 | #--------------------------------------------------------------------------------- 156 | # main targets 157 | #--------------------------------------------------------------------------------- 158 | all : $(OUTPUT).pfs0 $(OUTPUT).nro 159 | 160 | $(OUTPUT).pfs0 : $(OUTPUT).nso 161 | 162 | $(OUTPUT).nso : $(OUTPUT).elf 163 | 164 | ifeq ($(strip $(NO_NACP)),) 165 | $(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp 166 | else 167 | $(OUTPUT).nro : $(OUTPUT).elf 168 | endif 169 | 170 | $(OUTPUT).elf : $(OFILES) 171 | 172 | #--------------------------------------------------------------------------------- 173 | # you need a rule like this for each extension you use as binary data 174 | #--------------------------------------------------------------------------------- 175 | %.bin.o : %.bin 176 | #--------------------------------------------------------------------------------- 177 | @echo $(notdir $<) 178 | @$(bin2o) 179 | 180 | -include $(DEPENDS) 181 | 182 | #--------------------------------------------------------------------------------------- 183 | endif 184 | #--------------------------------------------------------------------------------------- 185 | -------------------------------------------------------------------------------- /installer_obf/Makefile.normal: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITA64)),) 6 | $(error "Please set DEVKITA64 in your environment. export DEVKITA64=DEVKITA64") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITA64)/switch_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". 19 | # 20 | # NO_ICON: if set to anything, do not use icon. 21 | # NO_NACP: if set to anything, no .nacp file is generated. 22 | # APP_TITLE is the name of the app stored in the .nacp file (Optional) 23 | # APP_AUTHOR is the author of the app stored in the .nacp file (Optional) 24 | # APP_VERSION is the version of the app stored in the .nacp file (Optional) 25 | # APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) 26 | # ICON is the filename of the icon (.jpg), relative to the project folder. 27 | # If not set, it attempts to use one of the following (in this order): 28 | # - .jpg 29 | # - icon.jpg 30 | # - /default_icon.jpg 31 | #--------------------------------------------------------------------------------- 32 | TARGET := $(notdir $(CURDIR)) 33 | BUILD := build 34 | SOURCES := source 35 | DATA := data 36 | INCLUDES := include 37 | EXEFS_SRC := exefs_src 38 | 39 | #--------------------------------------------------------------------------------- 40 | # options for code generation 41 | #--------------------------------------------------------------------------------- 42 | ARCH := -march=armv8-a+crc+crypto -mtp=soft -fPIE -mtune=cortex-a57 43 | 44 | CFLAGS := -g -Wall -O2 \ 45 | -ffast-math \ 46 | $(ARCH) $(DEFINES) 47 | 48 | CFLAGS += $(INCLUDE) -DSWITCH 49 | 50 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 51 | 52 | ASFLAGS := -g $(ARCH) 53 | LDFLAGS = -specs=switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 54 | 55 | LIBS := -lnx 56 | 57 | #--------------------------------------------------------------------------------- 58 | # list of directories containing libraries, this must be the top level containing 59 | # include and lib 60 | #--------------------------------------------------------------------------------- 61 | LIBDIRS := $(PORTLIBS) $(LIBNX) 62 | 63 | 64 | #--------------------------------------------------------------------------------- 65 | # no real need to edit anything past this point unless you need to add additional 66 | # rules for different file extensions 67 | #--------------------------------------------------------------------------------- 68 | ifneq ($(BUILD),$(notdir $(CURDIR))) 69 | #--------------------------------------------------------------------------------- 70 | 71 | export OUTPUT := $(CURDIR)/$(TARGET) 72 | export TOPDIR := $(CURDIR) 73 | 74 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 75 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 76 | 77 | export DEPSDIR := $(CURDIR)/$(BUILD) 78 | 79 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 80 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 81 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 82 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 83 | 84 | #--------------------------------------------------------------------------------- 85 | # use CXX for linking C++ projects, CC for standard C 86 | #--------------------------------------------------------------------------------- 87 | ifeq ($(strip $(CPPFILES)),) 88 | #--------------------------------------------------------------------------------- 89 | export LD := $(CC) 90 | #--------------------------------------------------------------------------------- 91 | else 92 | #--------------------------------------------------------------------------------- 93 | export LD := $(CXX) 94 | #--------------------------------------------------------------------------------- 95 | endif 96 | #--------------------------------------------------------------------------------- 97 | 98 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 99 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 100 | 101 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 102 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 103 | -I$(CURDIR)/$(BUILD) 104 | 105 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 106 | 107 | export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) 108 | 109 | ifeq ($(strip $(ICON)),) 110 | icons := $(wildcard *.jpg) 111 | ifneq (,$(findstring $(TARGET).jpg,$(icons))) 112 | export APP_ICON := $(TOPDIR)/$(TARGET).jpg 113 | else 114 | ifneq (,$(findstring icon.jpg,$(icons))) 115 | export APP_ICON := $(TOPDIR)/icon.jpg 116 | endif 117 | endif 118 | else 119 | export APP_ICON := $(TOPDIR)/$(ICON) 120 | endif 121 | 122 | #ifeq ($(strip $(NO_ICON)),) 123 | # export NROFLAGS += --icon=$(APP_ICON) 124 | #endif 125 | 126 | #ifeq ($(strip $(NO_NACP)),) 127 | # export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp 128 | #endif 129 | 130 | #ifneq ($(APP_TITLEID),) 131 | # export NACPFLAGS += --titleid=$(APP_TITLEID) 132 | #endif 133 | 134 | .PHONY: $(BUILD) clean all 135 | 136 | #--------------------------------------------------------------------------------- 137 | all: $(BUILD) 138 | 139 | $(BUILD): 140 | @[ -d $@ ] || mkdir -p $@ 141 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.normal 142 | 143 | #--------------------------------------------------------------------------------- 144 | clean: 145 | @echo clean ... 146 | @rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf 147 | 148 | 149 | #--------------------------------------------------------------------------------- 150 | else 151 | .PHONY: all 152 | 153 | DEPENDS := $(OFILES:.o=.d) 154 | 155 | #--------------------------------------------------------------------------------- 156 | # main targets 157 | #--------------------------------------------------------------------------------- 158 | all : $(OUTPUT).pfs0 $(OUTPUT).nro 159 | 160 | $(OUTPUT).pfs0 : $(OUTPUT).nso 161 | 162 | $(OUTPUT).nso : $(OUTPUT).elf 163 | 164 | ifeq ($(strip $(NO_NACP)),) 165 | $(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp 166 | else 167 | $(OUTPUT).nro : $(OUTPUT).elf 168 | endif 169 | 170 | $(OUTPUT).elf : $(OFILES) 171 | 172 | #--------------------------------------------------------------------------------- 173 | # you need a rule like this for each extension you use as binary data 174 | #--------------------------------------------------------------------------------- 175 | %.bin.o : %.bin 176 | #--------------------------------------------------------------------------------- 177 | @echo $(notdir $<) 178 | @$(bin2o) 179 | 180 | -include $(DEPENDS) 181 | 182 | #--------------------------------------------------------------------------------------- 183 | endif 184 | #--------------------------------------------------------------------------------------- 185 | -------------------------------------------------------------------------------- /installer_obf/obfuscator/SecretGenerators.py: -------------------------------------------------------------------------------- 1 | import Random 2 | import Variable 3 | 4 | class SecretGenerator: 5 | def __init__(self): 6 | self.var_name = Variable.alloc_name() 7 | self.secret = None 8 | def get_var_name(self): 9 | return self.var_name 10 | def get_result(self): 11 | return self.secret 12 | 13 | class RandomNumberSecretGenerator(SecretGenerator): 14 | def __init__(self): 15 | SecretGenerator.__init__(self) 16 | self.secret = Random.get_u32() 17 | def generate_code(self): 18 | return 'u32 {0} = 0x{1:08x};\n'.format(self.var_name, self.secret) 19 | 20 | CORE_ID = 1 21 | 22 | KERNEL_RETVALS_300 = { 23 | 0xFFFFFFF7FFC01840: lambda x0: 0, 24 | 0xFFFFFFF7FFC05018: lambda x0: (x0&0xFFFF0000) | 0xB340, # movk x0, 0xb340; ret. Instruction only modified lower 16-bits 25 | 0xFFFFFFF7FFC05018: lambda x0: (x0&0xFFFF0000) | 0xB340, 26 | 0xFFFFFFF7FFC05D1C: lambda x0: (x0&0xFFFF0000) | 0xB3A0, 27 | 0xFFFFFFF7FFC05D1C: lambda x0: (x0&0xFFFF0000) | 0xB3A0, 28 | 0xFFFFFFF7FFC05FDC: lambda x0: (x0&0xFFFF0000) | 0xB428, 29 | 0xFFFFFFF7FFC05FDC: lambda x0: (x0&0xFFFF0000) | 0xB428, 30 | 0xFFFFFFF7FFC05FF4: lambda x0: 1, 31 | 0xFFFFFFF7FFC06000: lambda x0: x0, # ret 32 | 0xFFFFFFF7FFC06814: lambda x0: (x0&0xFFFF0000) | 0xB4E8, 33 | 0xFFFFFFF7FFC06814: lambda x0: (x0&0xFFFF0000) | 0xB4E8, 34 | 0xFFFFFFF7FFC08574: lambda x0: 0, 35 | 0xFFFFFFF7FFC09698: lambda x0: (x0&0xFFFF0000) | 0xB720, 36 | 0xFFFFFFF7FFC09698: lambda x0: (x0&0xFFFF0000) | 0xB720, 37 | 0xFFFFFFF7FFC097F0: lambda x0: (x0&0xFFFF0000) | 0xB788, 38 | 0xFFFFFFF7FFC097F0: lambda x0: (x0&0xFFFF0000) | 0xB788, 39 | 0xFFFFFFF7FFC098C4: lambda x0: (x0&0xFFFF0000) | 0xB828, 40 | 0xFFFFFFF7FFC098C4: lambda x0: (x0&0xFFFF0000) | 0xB828, 41 | 0xFFFFFFF7FFC098DC: lambda x0: 1, 42 | 0xFFFFFFF7FFC0A69C: lambda x0: (x0&0xFFFF0000) | 0xB898, 43 | 0xFFFFFFF7FFC0A69C: lambda x0: (x0&0xFFFF0000) | 0xB898, 44 | 0xFFFFFFF7FFC0B724: lambda x0: 1, 45 | 0xFFFFFFF7FFC0BF78: lambda x0: 1, 46 | 0xFFFFFFF7FFC0C1C8: lambda x0: 0, 47 | 0xFFFFFFF7FFC0C390: lambda x0: 1, 48 | 0xFFFFFFF7FFC0C418: lambda x0: 1, 49 | 0xFFFFFFF7FFC1B814: lambda x0: (x0&0xFFFF0000) | 0xB9D8, 50 | 0xFFFFFFF7FFC1B814: lambda x0: (x0&0xFFFF0000) | 0xB9D8, 51 | 0xFFFFFFF7FFC1E52C: lambda x0: (x0&0xFFFF0000) | 0xBA78, 52 | 0xFFFFFFF7FFC1E52C: lambda x0: (x0&0xFFFF0000) | 0xBA78, 53 | 0xFFFFFFF7FFC1EC90: lambda x0: (x0&0xFFFF0000) | 0xBB30, 54 | 0xFFFFFFF7FFC1EC90: lambda x0: (x0&0xFFFF0000) | 0xBB30, 55 | 0xFFFFFFF7FFC20A2C: lambda x0: 1, 56 | 0xFFFFFFF7FFC20A34: lambda x0: 1, 57 | 0xFFFFFFF7FFC20EC4: lambda x0: (x0&0xFFFF0000) | 0xBBD0, 58 | 0xFFFFFFF7FFC20EC4: lambda x0: (x0&0xFFFF0000) | 0xBBD0, 59 | 0xFFFFFFF7FFC20F14: lambda x0: 0, 60 | 0xFFFFFFF7FFC2176C: lambda x0: x0, 61 | 0xFFFFFFF7FFC24CCC: lambda x0: (x0&0xFFFF0000) | 0xBC58, 62 | 0xFFFFFFF7FFC24CCC: lambda x0: (x0&0xFFFF0000) | 0xBC58, 63 | 0xFFFFFFF7FFC24ECC: lambda x0: (x0&0xFFFF0000) | 0xBD20, 64 | 0xFFFFFFF7FFC24ECC: lambda x0: (x0&0xFFFF0000) | 0xBD20, 65 | 0xFFFFFFF7FFC24F44: lambda x0: x0, 66 | 0xFFFFFFF7FFC25264: lambda x0: (x0&0xFFFF0000) | 0xBD90, 67 | 0xFFFFFFF7FFC25264: lambda x0: (x0&0xFFFF0000) | 0xBD90, 68 | 0xFFFFFFF7FFC25764: lambda x0: (x0&0xFFFF0000) | 0xBE00, 69 | 0xFFFFFFF7FFC25764: lambda x0: (x0&0xFFFF0000) | 0xBE00, 70 | 0xFFFFFFF7FFC25838: lambda x0: x0, 71 | 0xFFFFFFF7FFC25908: lambda x0: x0, 72 | 0xFFFFFFF7FFC26EA0: lambda x0: 0, 73 | 0xFFFFFFF7FFC26EA8: lambda x0: 0, 74 | 0xFFFFFFF7FFC27F08: lambda x0: (x0 + 0x70) & 0xFFFFFFFF, 75 | 0xFFFFFFF7FFC27F40: lambda x0: (x0&0xFFFF0000) | 0xBF08, 76 | 0xFFFFFFF7FFC27F40: lambda x0: (x0&0xFFFF0000) | 0xBF08, 77 | 0xFFFFFFF7FFC29028: lambda x0: (x0&0xFFFF0000) | 0xC020, 78 | 0xFFFFFFF7FFC29028: lambda x0: (x0&0xFFFF0000) | 0xC020, 79 | 0xFFFFFFF7FFC29040: lambda x0: 1, 80 | 0xFFFFFFF7FFC29280: lambda x0: (x0&0xFFFF0000) | 0xC098, 81 | 0xFFFFFFF7FFC29280: lambda x0: (x0&0xFFFF0000) | 0xC098, 82 | 0xFFFFFFF7FFC29368: lambda x0: (x0&0xFFFF0000) | 0xC108, 83 | 0xFFFFFFF7FFC29368: lambda x0: (x0&0xFFFF0000) | 0xC108, 84 | 0xFFFFFFF7FFC29380: lambda x0: 1, 85 | 0xFFFFFFF7FFC29384: lambda x0: x0, 86 | #0xFFFFFFF7FFC2B3D4: lambda x0: 0, # should be fine 87 | 0xFFFFFFF7FFC2F01C: lambda x0: x0, 88 | 0xFFFFFFF7FFC2F834: lambda x0: x0, 89 | 0xFFFFFFF7FFC2F998: lambda x0: x0, 90 | 0xFFFFFFF7FFC2F9CC: lambda x0: x0, 91 | #0xFFFFFFF7FFC2F8DC: lambda x0: x0, # BAD 92 | 0xFFFFFFF7FFC2FC10: lambda x0: x0, 93 | 0xFFFFFFF7FFC3044C: lambda x0: x0, 94 | 0xFFFFFFF7FFC30484: lambda x0: x0, 95 | 0xFFFFFFF7FFC304EC: lambda x0: x0, 96 | 0xFFFFFFF7FFC306FC: lambda x0: x0, 97 | 0xFFFFFFF7FFC30C10: lambda x0: x0, 98 | 0xFFFFFFF7FFC30C48: lambda x0: x0, 99 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 100 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 101 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 102 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 103 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 104 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 105 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 106 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 107 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 108 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 109 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 110 | #0xFFFFFFF7FFC33178: lambda x0: CORE_ID, # !!!CORE ID!!! 111 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 112 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 113 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 114 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 115 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 116 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 117 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 118 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 119 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 120 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 121 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 122 | #0xFFFFFFF7FFC33BB4: lambda x0: CORE_ID, # !!!CORE ID!!! 123 | 0xFFFFFFF7FFC345D8: lambda x0: 0x1B, 124 | 0xFFFFFFF7FFC345EC: lambda x0: 9, 125 | 0xFFFFFFF7FFC34600: lambda x0: 9, 126 | 0xFFFFFFF7FFC3934C: lambda x0: (x0+0x80) & 0xFFFFFFFF, # add x0, 0x80; ret. 127 | 0xFFFFFFF7FFC397D0: lambda x0: 1, 128 | 0xFFFFFFF7FFC3984C: lambda x0: 1, 129 | 0xFFFFFFF7FFC39884: lambda x0: 1, 130 | 0xFFFFFFF7FFC398C0: lambda x0: 0, 131 | 0xFFFFFFF7FFC398E8: lambda x0: 1, 132 | 0xFFFFFFF7FFC39964: lambda x0: 1, 133 | 0xFFFFFFF7FFC399D8: lambda x0: 0, 134 | 0xFFFFFFF7FFC39A00: lambda x0: 1, 135 | 0xFFFFFFF7FFC39A38: lambda x0: 1, 136 | 0xFFFFFFF7FFC39A3C: lambda x0: x0, 137 | 0xFFFFFFF7FFC39C4C: lambda x0: 1, 138 | 0xFFFFFFF7FFC3B4F0: lambda x0: x0, 139 | 0xFFFFFFF7FFC3CACC: lambda x0: (x0&0xFFFF0000) | 0xCCE8, 140 | 0xFFFFFFF7FFC4157C: lambda x0: 5, 141 | 0xFFFFFFF7FFC46B7C: lambda x0: 1, 142 | 143 | } 144 | 145 | class KernelFunctionRetvalSecretGenerator(SecretGenerator): 146 | def __init__(self): 147 | SecretGenerator.__init__(self) 148 | def generate_code(self): 149 | func = Random.from_dict(KERNEL_RETVALS_300) 150 | x0 = Random.get_u32() 151 | self.secret = KERNEL_RETVALS_300[func](x0) 152 | 153 | return 'u32 {0} = {1}; // Returns 0x{2:08x}\n'.format(self.var_name, '((u32(*)(u32))0x%xull)(0x%x)' % (func, x0), self.secret) 154 | 155 | 156 | LIBNX_RETVALS = { 157 | 'svcSetMemoryPermission(1, 0, 0)': 0xCC01, 158 | 'svcSetMemoryPermission(0, 0, 0)': 0xCA01, 159 | 'svcSetMemoryPermission(0, 0x1000, 8)': 0xD801, 160 | 'svcSetMemoryPermission(0x1000, 0x1000, 3)': 0xD401, 161 | 'svcUnmapTransferMemory(-1, 0x1000, 0x1000)': 0xE401, 162 | #'svcSetThreadCoreMask(0xFFFF8000, 0, 0)': 0xE801, 163 | #'svcSetThreadCoreMask(0xFFFF8000, 0, -1)': 0xE201, 164 | 'svcConnectToNamedPort(&tmp_handle, NULL)': 0xE601, 165 | 'svcConnectToNamedPort(&tmp_handle, "xxxxxxxxxxxxxx")': 0xEE01, 166 | 'svcConnectToNamedPort(&tmp_handle, "banana")': 0xF201, 167 | 'svcSetMemoryAttribute(1, 0, 0, 0)': 0xCC01, 168 | 'svcSetMemoryAttribute(0, 0, 0, 0)': 0xCA01, 169 | 'svcMapMemory(1, 0, 0)': 0xCC01, 170 | 'svcMapMemory(0, 0, 0)': 0xCA01, 171 | 'svcUnmapMemory(1, 0, 0)': 0xCC01, 172 | 'svcUnmapMemory(0, 0, 0)': 0xCA01, 173 | 'svcOutputDebugString("", 0)': 0, 174 | } 175 | 176 | class LibnxFunctionRetvalSecretGenerator(SecretGenerator): 177 | def __init__(self): 178 | SecretGenerator.__init__(self) 179 | def generate_code(self): 180 | func = Random.from_dict(LIBNX_RETVALS) 181 | self.secret = LIBNX_RETVALS[func] 182 | 183 | return 'u32 {0} = {1}; // Returns 0x{2:x}\n'.format(self.var_name, func, self.secret) 184 | 185 | 186 | g_list = [ 187 | RandomNumberSecretGenerator, 188 | RandomNumberSecretGenerator, 189 | RandomNumberSecretGenerator, 190 | RandomNumberSecretGenerator, 191 | RandomNumberSecretGenerator, 192 | RandomNumberSecretGenerator, 193 | RandomNumberSecretGenerator, 194 | LibnxFunctionRetvalSecretGenerator, 195 | LibnxFunctionRetvalSecretGenerator, 196 | KernelFunctionRetvalSecretGenerator, 197 | KernelFunctionRetvalSecretGenerator, 198 | KernelFunctionRetvalSecretGenerator, 199 | KernelFunctionRetvalSecretGenerator, 200 | ] 201 | 202 | def get_N_random_secrets(num): 203 | secrets = [] 204 | for i in range(num): 205 | SecretGeneratorType = g_list[Random.get_u32() % len(g_list)] 206 | secrets.append(SecretGeneratorType()) 207 | return secrets 208 | -------------------------------------------------------------------------------- /loader/source/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "nro.h" 5 | 6 | #define MODULE_HBL 347 7 | 8 | const char* g_easterEgg = "Do you mean to tell me that you're thinking seriously of building that way, when and if you are an architect?"; 9 | 10 | static char g_argv[2048]; 11 | static char g_nextArgv[2048]; 12 | static char g_nextNroPath[512]; 13 | static u64 g_nroAddr = 0; 14 | static u64 g_nroSize = 0; 15 | static NroHeader g_nroHeader; 16 | 17 | static u8 g_savedTls[0x100]; 18 | 19 | // Used by trampoline.s 20 | Result g_lastRet = 0; 21 | 22 | extern void* __stack_top;//Defined in libnx. 23 | #define STACK_SIZE 0x100000 //Change this if main-thread stack size ever changes. 24 | 25 | void __libnx_initheap(void) 26 | { 27 | static char g_innerheap[0x20000]; 28 | 29 | extern char* fake_heap_start; 30 | extern char* fake_heap_end; 31 | 32 | fake_heap_start = &g_innerheap[0]; 33 | fake_heap_end = &g_innerheap[sizeof g_innerheap]; 34 | } 35 | 36 | void __appInit(void) 37 | { 38 | (void) g_easterEgg[0]; 39 | 40 | Result rc; 41 | 42 | rc = smInitialize(); 43 | if (R_FAILED(rc)) 44 | fatalSimple(MAKERESULT(MODULE_HBL, 1)); 45 | 46 | rc = fsInitialize(); 47 | if (R_FAILED(rc)) 48 | fatalSimple(MAKERESULT(MODULE_HBL, 2)); 49 | 50 | fsdevInit(); 51 | } 52 | 53 | static void* g_heapAddr; 54 | static size_t g_heapSize; 55 | 56 | void setupHbHeap(void) 57 | { 58 | u64 size = 0; 59 | void* addr = NULL; 60 | u64 mem_available = 0, mem_used = 0; 61 | Result rc=0; 62 | 63 | svcGetInfo(&mem_available, 6, CUR_PROCESS_HANDLE, 0); 64 | svcGetInfo(&mem_used, 7, CUR_PROCESS_HANDLE, 0); 65 | if (mem_available > mem_used+0x200000) 66 | size = (mem_available - mem_used - 0x200000) & ~0x1FFFFF; 67 | if (size==0) 68 | size = 0x2000000*16; 69 | 70 | rc = svcSetHeapSize(&addr, size); 71 | 72 | if (R_FAILED(rc) || addr==NULL) 73 | fatalSimple(MAKERESULT(MODULE_HBL, 9)); 74 | 75 | g_heapAddr = addr; 76 | g_heapSize = size; 77 | } 78 | 79 | static Handle g_port; 80 | static Handle g_procHandle; 81 | 82 | void threadFunc(void* ctx) 83 | { 84 | Handle session; 85 | Result rc; 86 | 87 | rc = svcWaitSynchronizationSingle(g_port, -1); 88 | if (R_FAILED(rc)) 89 | fatalSimple(MAKERESULT(MODULE_HBL, 22)); 90 | 91 | rc = svcAcceptSession(&session, g_port); 92 | if (R_FAILED(rc)) 93 | fatalSimple(MAKERESULT(MODULE_HBL, 14)); 94 | 95 | s32 idx = 0; 96 | rc = svcReplyAndReceive(&idx, &session, 1, 0, -1); 97 | if (R_FAILED(rc)) 98 | fatalSimple(MAKERESULT(MODULE_HBL, 15)); 99 | 100 | IpcParsedCommand ipc; 101 | rc = ipcParse(&ipc); 102 | if (R_FAILED(rc)) 103 | fatalSimple(MAKERESULT(MODULE_HBL, 16)); 104 | 105 | if (ipc.NumHandles != 1) 106 | fatalSimple(MAKERESULT(MODULE_HBL, 17)); 107 | 108 | g_procHandle = ipc.Handles[0]; 109 | svcCloseHandle(session); 110 | } 111 | 112 | void getOwnProcessHandle(void) 113 | { 114 | static Thread t; 115 | Result rc; 116 | 117 | rc = threadCreate(&t, &threadFunc, NULL, 0x1000, 0x20, 0); 118 | if (R_FAILED(rc)) 119 | fatalSimple(MAKERESULT(MODULE_HBL, 10)); 120 | 121 | rc = smUnregisterService("appletOE"); 122 | if (R_FAILED(rc)) 123 | fatalSimple(MAKERESULT(MODULE_HBL, 11)); 124 | 125 | rc = smRegisterService(&g_port, "appletOE", false, 1); 126 | if (R_FAILED(rc)) 127 | fatalSimple(MAKERESULT(MODULE_HBL, 12)); 128 | 129 | rc = threadStart(&t); 130 | if (R_FAILED(rc)) 131 | fatalSimple(MAKERESULT(MODULE_HBL, 13)); 132 | 133 | Service srv; 134 | rc = smGetService(&srv, "appletOE"); 135 | if (R_FAILED(rc)) 136 | fatalSimple(MAKERESULT(MODULE_HBL, 23)); 137 | 138 | IpcCommand ipc; 139 | ipcSendHandleCopy(&ipc, 0xffff8001); 140 | 141 | struct { 142 | int x, y; 143 | }* raw; 144 | 145 | raw = ipcPrepareHeader(&ipc, sizeof(*raw)); 146 | raw->x = raw->y = 0; 147 | 148 | rc = serviceIpcDispatch(&srv); 149 | 150 | threadWaitForExit(&t); 151 | threadClose(&t); 152 | 153 | serviceClose(&srv); 154 | svcCloseHandle(g_port); 155 | 156 | smExit(); 157 | } 158 | 159 | void loadNro(void) 160 | { 161 | NroHeader* header = NULL; 162 | size_t rw_size=0; 163 | Result rc=0; 164 | 165 | svcSleepThread(1000000000);//Wait for sm-sysmodule to handle closing the sm session from this process. Without this delay smInitialize will fail once eventually used later. 166 | //TODO: Lower the above delay-value? 167 | 168 | memcpy((u8*)armGetTls() + 0x100, g_savedTls, 0x100); 169 | 170 | if (g_nroSize > 0) 171 | { 172 | // Unmap previous NRO. 173 | header = &g_nroHeader; 174 | rw_size = header->Segments[2].Size + header->bssSize; 175 | rw_size = (rw_size+0xFFF) & ~0xFFF; 176 | 177 | // .text 178 | rc = svcUnmapProcessCodeMemory( 179 | g_procHandle, g_nroAddr + header->Segments[0].FileOff, ((u64) g_heapAddr) + header->Segments[0].FileOff, header->Segments[0].Size); 180 | 181 | if (R_FAILED(rc)) 182 | fatalSimple(MAKERESULT(MODULE_HBL, 24)); 183 | 184 | // .rodata 185 | rc = svcUnmapProcessCodeMemory( 186 | g_procHandle, g_nroAddr + header->Segments[1].FileOff, ((u64) g_heapAddr) + header->Segments[1].FileOff, header->Segments[1].Size); 187 | 188 | if (R_FAILED(rc)) 189 | fatalSimple(MAKERESULT(MODULE_HBL, 25)); 190 | 191 | // .data + .bss 192 | rc = svcUnmapProcessCodeMemory( 193 | g_procHandle, g_nroAddr + header->Segments[2].FileOff, ((u64) g_heapAddr) + header->Segments[2].FileOff, rw_size); 194 | 195 | if (R_FAILED(rc)) 196 | fatalSimple(MAKERESULT(MODULE_HBL, 26)); 197 | 198 | g_nroAddr = g_nroSize = 0; 199 | } 200 | 201 | if (strlen(g_nextNroPath) == 0) 202 | { 203 | strcpy(g_nextNroPath, "sdmc:/hbmenu.nro"); 204 | strcpy(g_nextArgv, "sdmc:/hbmenu.nro"); 205 | } 206 | 207 | memcpy(g_argv, g_nextArgv, sizeof g_argv); 208 | 209 | uint8_t *nrobuf = (uint8_t*) g_heapAddr; 210 | 211 | NroStart* start = (NroStart*) (nrobuf + 0); 212 | header = (NroHeader*) (nrobuf + sizeof(NroStart)); 213 | uint8_t* rest = (uint8_t*) (nrobuf + sizeof(NroStart) + sizeof(NroHeader)); 214 | 215 | FILE* f = fopen(g_nextNroPath, "rb"); 216 | if (f == NULL) 217 | fatalSimple(MAKERESULT(MODULE_HBL, 3)); 218 | 219 | // Reset NRO path to load hbmenu by default next time. 220 | g_nextNroPath[0] = '\0'; 221 | 222 | if (fread(start, sizeof(*start), 1, f) != 1) 223 | fatalSimple(MAKERESULT(MODULE_HBL, 4)); 224 | 225 | if (fread(header, sizeof(*header), 1, f) != 1) 226 | fatalSimple(MAKERESULT(MODULE_HBL, 4)); 227 | 228 | if(header->Magic != NROHEADER_MAGICNUM) 229 | fatalSimple(MAKERESULT(MODULE_HBL, 5)); 230 | 231 | size_t rest_size = header->size - (sizeof(NroStart) + sizeof(NroHeader)); 232 | if (fread(rest, rest_size, 1, f) != 1) 233 | fatalSimple(MAKERESULT(MODULE_HBL, 7)); 234 | 235 | fclose(f); 236 | 237 | size_t total_size = header->size + header->bssSize; 238 | total_size = (total_size+0xFFF) & ~0xFFF; 239 | 240 | rw_size = header->Segments[2].Size + header->bssSize; 241 | rw_size = (rw_size+0xFFF) & ~0xFFF; 242 | 243 | int i; 244 | for (i=0; i<3; i++) 245 | { 246 | if (header->Segments[i].FileOff >= header->size || header->Segments[i].Size > header->size || 247 | (header->Segments[i].FileOff + header->Segments[i].Size) > header->size) 248 | { 249 | fatalSimple(MAKERESULT(MODULE_HBL, 6)); 250 | } 251 | } 252 | 253 | // todo: Detect whether NRO fits into heap or not. 254 | 255 | // Copy header to elsewhere because we're going to unmap it next. 256 | memcpy(&g_nroHeader, header, sizeof(g_nroHeader)); 257 | header = &g_nroHeader; 258 | 259 | u64 map_addr; 260 | 261 | do { 262 | map_addr = randomGet64() & 0xFFFFFF000ull; 263 | rc = svcMapProcessCodeMemory(g_procHandle, map_addr, (u64)nrobuf, total_size); 264 | 265 | } while (rc == 0xDC01 || rc == 0xD401); 266 | 267 | if (R_FAILED(rc)) 268 | fatalSimple(MAKERESULT(MODULE_HBL, 18)); 269 | 270 | // .text 271 | rc = svcSetProcessMemoryPermission( 272 | g_procHandle, map_addr + header->Segments[0].FileOff, header->Segments[0].Size, PERM_R | PERM_X); 273 | 274 | if (R_FAILED(rc)) 275 | fatalSimple(MAKERESULT(MODULE_HBL, 19)); 276 | 277 | // .rodata 278 | rc = svcSetProcessMemoryPermission( 279 | g_procHandle, map_addr + header->Segments[1].FileOff, header->Segments[1].Size, PERM_R); 280 | 281 | if (R_FAILED(rc)) 282 | fatalSimple(MAKERESULT(MODULE_HBL, 20)); 283 | 284 | // .data + .bss 285 | rc = svcSetProcessMemoryPermission( 286 | g_procHandle, map_addr + header->Segments[2].FileOff, rw_size, PERM_RW); 287 | 288 | if (R_FAILED(rc)) 289 | fatalSimple(MAKERESULT(MODULE_HBL, 21)); 290 | 291 | u64 nro_size = header->Segments[2].FileOff + rw_size; 292 | u64 nro_heap_start = ((u64) g_heapAddr) + nro_size; 293 | u64 nro_heap_size = g_heapSize + (u64) g_heapAddr - (u64) nro_heap_start; 294 | 295 | #define M EntryFlag_IsMandatory 296 | 297 | static ConfigEntry entries[] = { 298 | { EntryType_MainThreadHandle, 0, {0, 0} }, 299 | { EntryType_ProcessHandle, 0, {0, 0} }, 300 | { EntryType_AppletType, 0, {AppletType_LibraryApplet, 0} }, 301 | { EntryType_OverrideHeap, M, {0, 0} }, 302 | { EntryType_Argv, 0, {0, 0} }, 303 | { EntryType_NextLoadPath, 0, {0, 0} }, 304 | { EntryType_LastLoadResult, 0, {0, 0} }, 305 | { EntryType_SyscallAvailableHint, 0, {0xffffffffffffffff, 0x1fc00000007ffff} }, 306 | { EntryType_EndOfList, 0, {0, 0} } 307 | }; 308 | 309 | // MainThreadHandle 310 | entries[0].Value[0] = envGetMainThreadHandle(); 311 | // ProcessHandle 312 | entries[1].Value[0] = g_procHandle; 313 | // OverrideHeap 314 | entries[3].Value[0] = nro_heap_start; 315 | entries[3].Value[1] = nro_heap_size; 316 | // Argv 317 | entries[4].Value[1] = (u64) &g_argv[0]; 318 | // NextLoadPath 319 | entries[5].Value[0] = (u64) &g_nextNroPath[0]; 320 | entries[5].Value[1] = (u64) &g_nextArgv[0]; 321 | // LastLoadResult 322 | entries[6].Value[0] = g_lastRet; 323 | 324 | u64 entrypoint = map_addr; 325 | 326 | g_nroAddr = map_addr; 327 | g_nroSize = nro_size; 328 | 329 | memset(__stack_top - STACK_SIZE, 0, STACK_SIZE); 330 | 331 | extern NORETURN void nroEntrypointTrampoline(u64 entries_ptr, u64 handle, u64 entrypoint); 332 | nroEntrypointTrampoline((u64) entries, -1, entrypoint); 333 | } 334 | 335 | int main(int argc, char **argv) 336 | { 337 | memcpy(g_savedTls, (u8*)armGetTls() + 0x100, 0x100); 338 | 339 | setupHbHeap(); 340 | getOwnProcessHandle(); 341 | loadNro(); 342 | 343 | fatalSimple(MAKERESULT(MODULE_HBL, 8)); 344 | return 0; 345 | } 346 | --------------------------------------------------------------------------------