├── AUTHORS ├── NEWS ├── README ├── ChangeLog ├── autogen.sh ├── aes.h ├── mingw_mmap.h ├── cosunpack.c ├── configure.ac ├── unspp.c ├── cosunpkg.c ├── undat.c ├── dat.c ├── pupexplode ├── common.h ├── norunpack.c ├── eidsplitr.c ├── mingw_mmap.c ├── unself2.c ├── README_npdrm ├── Makefile.am ├── sha1.h ├── tools.h ├── unpkg.c ├── types.h ├── ungpkg.c ├── cospkg.c ├── puppack.c ├── pupunpack.c ├── bn.c ├── spp.c ├── sceverify.c ├── self.h ├── scekrit.c ├── pkg.c ├── ec.c ├── unself.c ├── sha1.c ├── makeself.c ├── INSTALL ├── readself.c ├── self.c ├── self_rebuilder.c └── COPYING /AUTHORS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | test -d m4 || mkdir m4 5 | 6 | autoreconf -fi 7 | 8 | run_configure=true 9 | for arg in $*; do 10 | case $arg in 11 | --no-configure) 12 | run_configure=false 13 | ;; 14 | *) 15 | ;; 16 | esac 17 | done 18 | 19 | if test $run_configure = true; then 20 | ./configure "$@" 21 | fi 22 | 23 | -------------------------------------------------------------------------------- /aes.h: -------------------------------------------------------------------------------- 1 | #ifndef QEMU_AES_H 2 | #define QEMU_AES_H 3 | 4 | #include "tools.h" 5 | 6 | #define AES_MAXNR 14 7 | #define AES_BLOCK_SIZE 16 8 | 9 | struct aes_key_st { 10 | uint32_t rd_key[4 *(AES_MAXNR + 1)]; 11 | int rounds; 12 | }; 13 | typedef struct aes_key_st AES_KEY; 14 | 15 | int AES_set_encrypt_key(const unsigned char *userKey, const int bits, 16 | AES_KEY *key); 17 | int AES_set_decrypt_key(const unsigned char *userKey, const int bits, 18 | AES_KEY *key); 19 | 20 | void AES_encrypt(const unsigned char *in, unsigned char *out, 21 | const AES_KEY *key); 22 | void AES_decrypt(const unsigned char *in, unsigned char *out, 23 | const AES_KEY *key); 24 | 25 | #if 0 26 | void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, 27 | const unsigned long length, const AES_KEY *key, 28 | unsigned char *ivec, const int enc); 29 | #endif 30 | #endif 31 | -------------------------------------------------------------------------------- /mingw_mmap.h: -------------------------------------------------------------------------------- 1 | /** This code is adapted from: 2 | * https://kerneltrap.org/mailarchive/git/2008/11/21/4186494 3 | * Original code by Vasyl Vavrychuk. 4 | * 5 | * This file is part of Rockstars. 6 | * Coded in Hungarian Notation so it looks stupid. :D 7 | * 8 | * If you read nothing from this file, know NOT to call the function names 9 | * below but the original mmap() and munmap() functions. 10 | */ 11 | 12 | #ifndef _MINGW_MMAP_H 13 | #define _MINGW_MMAP_H 14 | 15 | #include 16 | #include 17 | 18 | #define PROT_READ 1 19 | #define PROT_WRITE 2 20 | #define MAP_SHARED 2 21 | #define MAP_PRIVATE 3 22 | 23 | void *mingw_mmap(void *pStart, size_t sLength, int nProt, int nFlags, int nFd, off_t oOffset); 24 | #define mmap mingw_mmap 25 | 26 | int mingw_munmap(void *pStart, size_t sLength); 27 | #define munmap mingw_munmap 28 | 29 | #endif /* _MINGW_MMAP_H */ 30 | -------------------------------------------------------------------------------- /cosunpack.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Copyright 2011 glevand 3 | // Licensed under the terms of the GNU GPL, version 2 4 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "tools.h" 12 | 13 | #ifdef WIN32 14 | #define MKDIR(x,y) mkdir(x); 15 | #else 16 | #define MKDIR(x,y) mkdir(x,y) 17 | #endif 18 | 19 | static u8 *cos = NULL; 20 | 21 | static void new_dir(const char *n) 22 | { 23 | MKDIR(n, 0777); 24 | if (chdir(n) < 0) 25 | fail("chdir"); 26 | } 27 | 28 | static void do_toc(u8 *ptr) 29 | { 30 | u32 n_entries; 31 | u32 i; 32 | u8 *p; 33 | u8 *tmp; 34 | u64 size; 35 | char name[0x20]; 36 | 37 | n_entries = be32(ptr + 0x04); 38 | p = ptr + 0x10; 39 | 40 | for(i = 0; i < n_entries; i++) { 41 | memcpy(name, p + 16, 0x20); 42 | 43 | tmp = ptr + be64(p); 44 | size = be64(p + 0x08); 45 | 46 | memcpy_to_file(name, tmp, size); 47 | 48 | p += 0x30; 49 | } 50 | } 51 | 52 | int main(int argc, char *argv[]) 53 | { 54 | if (argc != 3) 55 | fail("usage: cosunpack dump.b directory"); 56 | 57 | cos = mmap_file(argv[1]); 58 | 59 | new_dir(argv[2]); 60 | 61 | do_toc(cos); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.66]) 5 | AC_INIT([ps3tools], [0.1], []) 6 | AC_CONFIG_SRCDIR([tools.c]) 7 | AC_CONFIG_HEADERS([config.h]) 8 | AM_INIT_AUTOMAKE([-Wall]) 9 | 10 | # Checks for programs. 11 | AC_PROG_CC 12 | 13 | # Checks for libraries. 14 | AC_CHECK_LIB([gmp], [__gmpz_init], [GMP_LIBS="-lgmp"], [GMP_LIBS=""]) 15 | AC_CHECK_LIB([z], [inflate]) 16 | 17 | AC_SUBST(GMP_LIBS) 18 | AM_CONDITIONAL(HAVE_LIBGMP, test "$GMP_LIBS" != "") 19 | 20 | 21 | dnl use pretty build output with automake >= 1.11 22 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], 23 | [AM_DEFAULT_VERBOSITY=1 24 | AC_SUBST(AM_DEFAULT_VERBOSITY)]) 25 | 26 | 27 | # Checks for header files. 28 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h stdint.h stdlib.h string.h unistd.h]) 29 | 30 | # Checks for typedefs, structures, and compiler characteristics. 31 | AC_C_INLINE 32 | AC_TYPE_OFF_T 33 | AC_TYPE_SIZE_T 34 | AC_TYPE_UINT16_T 35 | AC_TYPE_UINT32_T 36 | AC_TYPE_UINT64_T 37 | AC_TYPE_UINT8_T 38 | 39 | # Checks for library functions. 40 | AC_FUNC_MALLOC 41 | AC_FUNC_MMAP 42 | AC_FUNC_REALLOC 43 | AC_CHECK_FUNCS([getpagesize memset strrchr strstr strtoul strtoull]) 44 | 45 | AC_CONFIG_FILES([Makefile]) 46 | AC_OUTPUT 47 | -------------------------------------------------------------------------------- /unspp.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | u8 *pkg = NULL; 16 | static u64 header_size; 17 | static u64 dec_size; 18 | 19 | static void decrypt_spp(void) 20 | { 21 | u16 flags; 22 | u16 type; 23 | u32 hdr_len; 24 | struct keylist *k; 25 | 26 | flags = be16(pkg + 0x08); 27 | type = be16(pkg + 0x0a); 28 | hdr_len = be64(pkg + 0x10); 29 | dec_size = be64(pkg + 0x18); 30 | 31 | if (type != 4) 32 | fail("no .spp file"); 33 | 34 | k = keys_get(KEY_SPP); 35 | 36 | if (k == NULL) 37 | fail("no key found"); 38 | 39 | if (sce_decrypt_header(pkg, k) < 0) 40 | fail("header decryption failed"); 41 | 42 | if (sce_decrypt_data(pkg) < 0) 43 | fail("data decryption failed"); 44 | 45 | header_size = be64(pkg + 0x10); 46 | dec_size = be64(pkg + 0x18); 47 | } 48 | 49 | int main(int argc, char *argv[]) 50 | { 51 | if (argc == 3) { 52 | pkg = mmap_file(argv[1]); 53 | 54 | decrypt_spp(); 55 | memcpy_to_file(argv[2], pkg + header_size, dec_size); 56 | } else { 57 | fail("usage: unspp default.spp target"); 58 | } 59 | 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /cosunpkg.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef WIN32 15 | #define MKDIR(x,y) mkdir(x) 16 | #else 17 | #define MKDIR(x,y) mkdir(x,y) 18 | #endif 19 | 20 | u8 *pkg = NULL; 21 | 22 | static void unpack_file(u32 i) 23 | { 24 | u8 *ptr; 25 | u8 name[33]; 26 | u64 offset; 27 | u64 size; 28 | 29 | ptr = pkg + 0x10 + 0x30 * i; 30 | 31 | offset = be64(ptr + 0x00); 32 | size = be64(ptr + 0x08); 33 | 34 | memset(name, 0, sizeof name); 35 | strncpy((char *)name, (char *)(ptr + 0x10), 0x20); 36 | 37 | printf("unpacking %s...\n", name); 38 | memcpy_to_file((char *)name, pkg + offset, size); 39 | } 40 | 41 | static void unpack_pkg(void) 42 | { 43 | u32 n_files; 44 | u64 size; 45 | u32 i; 46 | 47 | n_files = be32(pkg + 4); 48 | size = be64(pkg + 8); 49 | 50 | for (i = 0; i < n_files; i++) 51 | unpack_file(i); 52 | } 53 | 54 | int main(int argc, char *argv[]) 55 | { 56 | if (argc != 3) 57 | fail("usage: cosunpkg filename.pkg target"); 58 | 59 | pkg = mmap_file(argv[1]); 60 | 61 | MKDIR(argv[2], 0777); 62 | 63 | if (chdir(argv[2]) != 0) 64 | fail("chdir"); 65 | 66 | unpack_pkg(); 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /undat.c: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Ninjas 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int 16 | main (int argc, char *argv[]) 17 | { 18 | FILE *in = NULL; 19 | 20 | size_t len; 21 | 22 | u8 *data; 23 | u8 dat_key[0x10], dat_iv[0x10]; 24 | u8 digest[20]; 25 | 26 | if (argc != 3) 27 | fail ("usage: undat index.dat version.txt"); 28 | 29 | in = fopen (argv[1], "rb"); 30 | if (in == NULL) 31 | fail ("Unable to open %s", argv[1]); 32 | fseek (in, 0, SEEK_END); 33 | len = ftell (in); 34 | fseek (in, 0, SEEK_SET); 35 | 36 | if (len < 0x1f) 37 | fail ("invalid index.dat size : 0x%X", len); 38 | 39 | data = malloc (len); 40 | 41 | if (fread (data, 1, len, in) != len) 42 | fail ("Unable to read index.dat file"); 43 | 44 | fclose (in); 45 | 46 | if(key_get_simple("dat-key", dat_key, 0x10) < 0) 47 | fail ("unable to load dat-key."); 48 | if(key_get_simple("dat-iv", dat_iv, 0x10) < 0) 49 | fail ("unable to load dat-iv."); 50 | 51 | aes128cbc (dat_key, dat_iv, data, len, data); 52 | sha1 (data + 32, len - 32, digest); 53 | 54 | if (memcmp (data, digest, 20) != 0) 55 | fail ("SHA1 mac mismatch"); 56 | 57 | memcpy_to_file (argv[2], data + 32, len - 32); 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /dat.c: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Ninjas 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int 16 | main (int argc, char *argv[]) 17 | { 18 | FILE *in = NULL; 19 | 20 | size_t len; 21 | 22 | size_t new_len; 23 | 24 | u8 *data; 25 | u8 dat_key[0x10], dat_iv[0x10]; 26 | u8 *out; 27 | 28 | if (argc != 3) 29 | fail ("usage: dat version.txt index.dat"); 30 | 31 | in = fopen (argv[1], "rb"); 32 | if (in == NULL) 33 | fail ("Unable to open %s", argv[1]); 34 | fseek (in, 0, SEEK_END); 35 | len = ftell (in); 36 | fseek (in, 0, SEEK_SET); 37 | 38 | data = malloc (len); 39 | 40 | if (fread (data, 1, len, in) != len) 41 | fail ("Unable to read index.dat file"); 42 | 43 | fclose (in); 44 | 45 | new_len = len + 32; 46 | if (new_len % 16 != 0) 47 | new_len += 16 - (new_len % 16); 48 | out = malloc (new_len); 49 | memset (out, '\n', new_len); 50 | memset (out, '0', 32); 51 | memcpy (out + 32, data, len); 52 | sha1 (out + 32, new_len - 32, out); 53 | 54 | if(key_get_simple("dat-key", dat_key, 0x10) < 0) 55 | fail ("unable to load dat-key."); 56 | if(key_get_simple("dat-iv", dat_iv, 0x10) < 0) 57 | fail ("unable to load dat-iv."); 58 | 59 | aes128cbc_enc (dat_key, dat_iv, out, new_len, out); 60 | 61 | memcpy_to_file (argv[2], out, new_len); 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /pupexplode: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 2 ] ; then 4 | echo "Usage: pupexplode " 5 | echo "pupexplode expands all important files in a PUP and tries to decrypt every file as a self" 6 | exit 1 7 | fi 8 | 9 | pup=$1 10 | outdir=$2 11 | 12 | pupunpack $pup $outdir || exit 13 | 14 | cd $outdir || exit 15 | 16 | mkdir update_files 17 | cd update_files 18 | tar xvf ../update_files.tar || exit 19 | 20 | for f in dev_flash*; do 21 | unpkg $f ${f}_unpkg || exit 22 | tar xvf ${f}_unpkg/content || exit 23 | done 24 | 25 | for f in *.pkg; do 26 | unpkg $f ${f%.pkg} 27 | if [ $f = "CORE_OS_PACKAGE.pkg" ]; then 28 | cosunpkg CORE_OS_PACKAGE/content CORE_OS_PACKAGE/ 29 | fi 30 | done 31 | 32 | report_result() 33 | { 34 | local r 35 | 36 | printf "$1" 37 | shift 38 | eval $@ >/dev/null 2>&1 39 | r=$? 40 | if [ $r -ne 0 ] ; then 41 | printf 'ko\n' 42 | else 43 | printf 'ok\n' 44 | fi 45 | return $r 46 | } 47 | 48 | cd .. 49 | for f in $(find . -type f); do 50 | if readself $f >/dev/null 2>&1; then 51 | report_result "unselfing $f... " unself $f ${f}.elf 52 | if [ $? -eq 0 ] ; then 53 | cpu=$(readelf -h ${f}.elf | awk '/Machine:/ {print $2}') 54 | if [ "$cpu" = "SPU" ] ; then 55 | report_result "disassembling ${f} for SPU..." "spu-objdump -d ${f}.elf > ${f}.asm 2>/dev/null" 56 | elif [ "$cpu" = "PowerPC64" ] ; then 57 | report_result "disassembling ${f} for PPC..." "ppu-objdump -d -m powerpc:common64 -EB ${f}.elf > ${f}.asm 2>/dev/null" 58 | fi 59 | fi 60 | fi 61 | done 62 | 63 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) Youness Alaoui (KaKaRoTo) 3 | * 4 | * This software is distributed under the terms of the GNU General Public 5 | * License ("GPL") version 3, as published by the Free Software Foundation. 6 | * 7 | */ 8 | 9 | #ifndef __COMMON_H__ 10 | #define __COMMON_H__ 11 | 12 | 13 | #include 14 | 15 | #ifdef WIN32 16 | #define MKDIR(x,y) mkdir(x) 17 | #else 18 | #define MKDIR(x,y) mkdir(x,y) 19 | #endif 20 | 21 | #ifdef __BIG_ENDIAN__ 22 | #define swap16(x) (x) 23 | #define swap32(x) (x) 24 | #define swap64(x) (x) 25 | #else 26 | #define swap16(x) ((((uint16_t)(x) & 0xff00) >> 8) | \ 27 | (((uint16_t)(x) & 0x00ff) << 8)) 28 | #define swap32(x) ((((uint32_t)(x) & 0xff000000) >> 24) | \ 29 | (((uint32_t)(x) & 0x00ff0000) >> 8) | \ 30 | (((uint32_t)(x) & 0x0000ff00) << 8) | \ 31 | (((uint32_t)(x) & 0x000000ff) << 24)) 32 | #define swap64(x) \ 33 | ((((uint64_t)(x) & 0xff00000000000000ull) >> 56) | \ 34 | ((uint64_t)((x) & 0x00ff000000000000ull) >> 40) | \ 35 | ((uint64_t)((x) & 0x0000ff0000000000ull) >> 24) | \ 36 | ((uint64_t)((x) & 0x000000ff00000000ull) >> 8) | \ 37 | ((uint64_t)((x) & 0x00000000ff000000ull) << 8) | \ 38 | ((uint64_t)((x) & 0x0000000000ff0000ull) << 24) | \ 39 | ((uint64_t)((x) & 0x000000000000ff00ull) << 40) | \ 40 | ((uint64_t)((x) & 0x00000000000000ffull) << 56)) 41 | #endif 42 | 43 | 44 | #define ERROR(err, msg) do { \ 45 | perror (msg); \ 46 | exit (err); \ 47 | } while(0); 48 | 49 | 50 | #endif /* __COMMON_H__ */ 51 | -------------------------------------------------------------------------------- /norunpack.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "tools.h" 11 | 12 | #ifdef WIN32 13 | #define MKDIR(x,y) mkdir(x); 14 | #else 15 | #define MKDIR(x,y) mkdir(x,y) 16 | #endif 17 | 18 | static u8 *nor = NULL; 19 | 20 | static void new_dir(const char *n) 21 | { 22 | MKDIR(n, 0777); 23 | if (chdir(n) < 0) 24 | fail("chdir"); 25 | } 26 | 27 | static void do_toc(u8 *ptr) 28 | { 29 | u32 n_entries; 30 | u32 i; 31 | u8 *p; 32 | u8 *tmp; 33 | u64 size; 34 | char name[0x20]; 35 | 36 | n_entries = be32(ptr + 0x04); 37 | p = ptr + 0x10; 38 | 39 | for(i = 0; i < n_entries; i++) { 40 | memcpy(name, p + 16, 0x20); 41 | 42 | if (strncmp(name, "asecure_loader", 0x20) == 0) { 43 | new_dir("asecure_loader"); 44 | do_toc(ptr + be64(p)); 45 | if (chdir("..") < 0) 46 | fail("chdir(..)"); 47 | } else if (strncmp(name, "ros", 3) == 0) { 48 | new_dir(name); 49 | do_toc(ptr + be64(p) + 0x10); 50 | if (chdir("..") < 0) 51 | fail("chdir(..)"); 52 | } else { 53 | tmp = ptr + be64(p); 54 | size = be64(p + 0x08); 55 | if (be32(tmp + 0x10) == 0x53434500) { 56 | tmp += 0x10; 57 | size -= 0x10; 58 | } 59 | 60 | memcpy_to_file(name, tmp, size); 61 | } 62 | p += 0x30; 63 | } 64 | } 65 | 66 | int main(int argc, char *argv[]) 67 | { 68 | if (argc != 3) 69 | fail("usage: norunpack dump.b directory"); 70 | 71 | nor = mmap_file(argv[1]); 72 | 73 | new_dir(argv[2]); 74 | 75 | do_toc(nor + 0x400); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /eidsplitr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void 6 | DumpEidData (FILE * pFile, int iInputSize, int iEidCount, 7 | char *pFilenamePrefix) 8 | { 9 | FILE *pOutput; 10 | char *szFilename; 11 | char *szBuf; 12 | int iRes, iSize; 13 | 14 | printf ("dumping EID%d from eEID at %p, size %d (%x)..\n", 15 | iEidCount, pFile, iInputSize, iInputSize); 16 | 17 | szBuf = (char *) malloc (iInputSize + 1); 18 | szFilename = (char *) malloc (strlen (pFilenamePrefix) + 2); 19 | 20 | if (szBuf == NULL) 21 | { 22 | perror ("malloc"); 23 | exit (1); 24 | }; 25 | 26 | iSize = fread (szBuf, iInputSize, 1, pFile); 27 | sprintf (szFilename, "%s%d", pFilenamePrefix, iEidCount); 28 | pOutput = fopen (szFilename, "wb"); 29 | iRes = fwrite (szBuf, iInputSize, 1, pOutput); 30 | 31 | if (iRes != iSize) 32 | { 33 | perror ("fwrite"); 34 | exit (1); 35 | }; 36 | 37 | free (szBuf); 38 | } 39 | 40 | int 41 | main (int argc, char **argv) 42 | { 43 | FILE *pFile; 44 | char *pPrefix; 45 | 46 | pFile = fopen (argv[1], "rb"); 47 | if (pFile == NULL) 48 | { 49 | usage: 50 | printf ("usage: %s \n", argv[0]); 51 | exit (1); 52 | } 53 | 54 | if (argc == 2 && argv[2] != NULL) 55 | { 56 | pPrefix = argv[2]; 57 | goto usage; 58 | } 59 | 60 | fseek (pFile, 0x70, SEEK_SET); 61 | 62 | if (pPrefix != NULL) 63 | { 64 | DumpEidData (pFile, 2144, 0, pPrefix); 65 | DumpEidData (pFile, 672, 1, pPrefix); 66 | DumpEidData (pFile, 1840, 2, pPrefix); 67 | DumpEidData (pFile, 256, 3, pPrefix); 68 | DumpEidData (pFile, 48, 4, pPrefix); 69 | DumpEidData (pFile, 2560, 5, pPrefix); 70 | } 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /mingw_mmap.c: -------------------------------------------------------------------------------- 1 | /** This code is adapted from: 2 | * https://kerneltrap.org/mailarchive/git/2008/11/21/4186494 3 | * Original code by Vasyl Vavrychuk. 4 | * 5 | * This file is part of Rockstars. 6 | * Coded in Hungarian Notation so it looks stupid. :D 7 | * 8 | * If you haven't seen the header file, call mmap() and munmap() not the 9 | * function names below! 10 | */ 11 | 12 | #ifdef __MINGW32__ 13 | 14 | #include 15 | #include "mingw_mmap.h" 16 | 17 | extern int getpagesize(void); 18 | 19 | /** 20 | * Use CreateFileMapping and MapViewOfFile to simulate POSIX mmap(). 21 | * Why Microsoft won't just implement these is beyond everyone's comprehension. 22 | * @return pointer or NULL 23 | */ 24 | void *mingw_mmap(void *pStart, size_t sLength, int nProt, int nFlags, int nFd, off_t oOffset) { 25 | (void)nProt; 26 | HANDLE hHandle; 27 | 28 | if (pStart != NULL || !(nFlags & MAP_PRIVATE)) { 29 | printf("Invalid usage of mingw_mmap"); 30 | return NULL; 31 | } 32 | 33 | if (oOffset % getpagesize() != 0) { 34 | printf("Offset does not match the memory allocation granularity"); 35 | return NULL; 36 | } 37 | 38 | hHandle = CreateFileMapping((HANDLE)_get_osfhandle(nFd), NULL, PAGE_WRITECOPY, 0, 0, NULL); 39 | if (hHandle != NULL) { 40 | pStart = MapViewOfFile(hHandle, FILE_MAP_COPY, 0, oOffset, sLength); 41 | } 42 | 43 | return pStart; 44 | } 45 | 46 | /** 47 | * Use UnmapViewOfFile to undo mmap() above. 48 | * @param pStart 49 | * @param length - Not used, kept for compatibility. 50 | * @return boolean; no checks are performed. 51 | */ 52 | int mingw_munmap(void *pStart, size_t sLength) { 53 | (void)sLength; 54 | 55 | if (UnmapViewOfFile(pStart) != 0) 56 | return FALSE; 57 | 58 | return TRUE; 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /unself2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This software is distributed under the terms of the GNU General Public 3 | * License ("GPL") version 2, as published by the Free Software Foundation. 4 | */ 5 | 6 | #include "tools.h" 7 | #include "self.h" 8 | #include "common.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | FILE *in = NULL; 18 | FILE *out = NULL; 19 | SELF self; 20 | APP_INFO app_info; 21 | ELF elf; 22 | ELF_PHDR *phdr = NULL; 23 | ELF_SHDR *shdr = NULL; 24 | SECTION_INFO *section_info = NULL; 25 | SCEVERSION_INFO sceversion_info; 26 | CONTROL_INFO *control_info = NULL; 27 | METADATA_INFO metadata_info; 28 | METADATA_HEADER metadata_header; 29 | METADATA_SECTION_HEADER *section_headers = NULL; 30 | uint8_t *keys = NULL; 31 | SIGNATURE_INFO signature_info; 32 | SIGNATURE signature; 33 | SELF_SECTION *sections = NULL; 34 | int num_sections; 35 | int i; 36 | 37 | if (argc != 3) { 38 | fprintf(stderr, "usage: %s in.self out.elf\n", argv[0]); 39 | return -1; 40 | } 41 | 42 | in = fopen (argv[1], "rb"); 43 | if (in == NULL) { 44 | ERROR (-2, "Can't open input file"); 45 | } 46 | 47 | self_read_headers(in, &self, &app_info, &elf, &phdr, &shdr, 48 | §ion_info, &sceversion_info, &control_info); 49 | 50 | self_read_metadata (in, &self, &app_info, &metadata_info, 51 | &metadata_header, §ion_headers, &keys, 52 | &signature_info, &signature, control_info); 53 | 54 | num_sections = self_load_sections (in, &self, &elf, &phdr, 55 | &metadata_header, §ion_headers, &keys, §ions); 56 | 57 | fclose (in); 58 | 59 | out = fopen (argv[2], "wb"); 60 | if (out == NULL) { 61 | ERROR (-2, "Can't open output file"); 62 | } 63 | 64 | for (i = 0; i < num_sections; i++) { 65 | if (sections[i].offset == UINT64_MAX) { 66 | continue; 67 | } 68 | fseek (out, sections[i].offset, SEEK_SET); 69 | if (fwrite (sections[i].data, 1, sections[i].size, out) != sections[i].size) { 70 | ERROR (-7, "Error writing section"); 71 | } 72 | } 73 | 74 | self_free_sections (§ions, num_sections); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /README_npdrm: -------------------------------------------------------------------------------- 1 | Based off of gitbrew's 215d8903bc86539ca1da53519e2ac10eeafc4c27 2 | ps3tools. .git folder not included to protect sensitive info about the author. 3 | Sorry about the fucked up tabs, TAB = 4 SPACES 4 LYFE!!! 4 | Add the files in the npdrm_keystuff folder to your ps3 keys folder. Create a 5 | file with your console's 16 byte IDPS in the 'idps' file in your ps3 keys 6 | folder (e.g. ~/.ps3/idps). 7 | Copy your PS3's exdata folder containing your act.dat and rif files to your 8 | ps3 keys dir (e.g. ~/.ps3/exdata/act.dat). Compile and have fun with your 9 | LEGALLY purchased NPDRM games! 10 | 11 | Also works on free games without exdata/idps. 12 | 13 | Apologies for any existing bugs in unself. Adding these changes to 14 | unself2 is left as an exercise for the reader. 15 | 16 | v2 info: 17 | Added npdrm magic to unself2 and readself2 18 | unself2 doesn't like the metadata section with type 3 in my game. 19 | This section looks to be some kind of linking information. Here is a snippet: 20 | crt0:p190002crt1:p190002libaudio_stub:p190002libaudio_stub:p190002 21 | 22 | I haven't yet looked around to see if this is type of section is documented anywhere. 23 | 24 | 25 | 26 | Thanks: 27 | fail0verflow for the orginal tools 28 | JuanNadie for figuring out NPDRM 29 | euss for his endless hours of work on the wiki 30 | 31 | 32 | Why didn't you beat me to the punch, Team PS360? I didn't need to reverse a 33 | single instruction! It isn't that hard... 34 | 35 | 36 | 37 | v3 info: 38 | unself2 now ignores metadata sections of type 3 instead of aborting. Additional 39 | help with any remaining bugs would be greatly appreciated. 40 | 41 | I'm sorry if everyone got the impression that these unself/readself 42 | modifications can, by themselves, "reactivate" your NPDRM content. These are 43 | just the first steps in the process. To those who say this is useless because 44 | you need act.dat and rif files: unless you can get unencrypted (debug) or 45 | easily decrypted (free, demos) PSN content, the only way to get the unencrypted 46 | files is by decrypting it with act.dat and the content's rif file. There are 47 | no "crypto fails" here, proper decryption with the true keys is the only way 48 | forward. Using the NPDRM algo with the right keys is the only way to decrypt 49 | unless you let GameOS do it for you and hook into GameOS to either grab 50 | intermediate keys or dump decrypted content. Using hacks to restore the NPDRM 51 | decryption info to jailbroken PS3s is only a partial fix. For instance, unless 52 | you patch vsh or set the SRTC to some time in the past, some content (even 53 | non-demos and non-trials!) expires until you log into PSN and reauthenticate. 54 | 55 | 56 | Sorry about your "technical difficulties", Team PS360. You should L2IRC. 57 | 58 | 59 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am for ps3tools 2 | # 3 | # (C) Youness Alaoui (KaKaRoTo) 4 | # 5 | # Licensed under LGPL 2.1. See file COPYING. 6 | 7 | ERROR_CFLAGS = \ 8 | $(PS3TOOLS_CFLAGS) \ 9 | -fno-strict-aliasing \ 10 | -Wextra \ 11 | -Wundef \ 12 | -Wnested-externs \ 13 | -Wwrite-strings \ 14 | -Wpointer-arith \ 15 | -Wbad-function-cast \ 16 | -Wmissing-declarations \ 17 | -Wmissing-prototypes \ 18 | -Wstrict-prototypes \ 19 | -Wredundant-decls \ 20 | -Wno-unused-parameter \ 21 | -Wno-missing-field-initializers 22 | 23 | AM_CFLAGS = \ 24 | $(ERROR_CFLAGS) \ 25 | $(ZLIB_CFLAGS) 26 | 27 | bin_PROGRAMS = sceverify \ 28 | readself \ 29 | readself2 \ 30 | unself \ 31 | unself2 \ 32 | makeself \ 33 | self_rebuilder \ 34 | ungpkg \ 35 | norunpack \ 36 | pupunpack \ 37 | puppack \ 38 | unpkg \ 39 | pkg \ 40 | cosunpkg \ 41 | cospkg \ 42 | cosunpack \ 43 | undat \ 44 | dat \ 45 | unspp \ 46 | eidsplitr \ 47 | spp 48 | 49 | bin_SCRIPTS = pupexplode 50 | 51 | if HAVE_LIBGMP 52 | bin_PROGRAMS += scekrit 53 | endif 54 | 55 | SELF_DEPS = self.c \ 56 | self.h \ 57 | common.h 58 | 59 | COMMON_DEPS = types.h \ 60 | tools.c \ 61 | tools.h \ 62 | aes.c \ 63 | aes.h \ 64 | sha1.c \ 65 | sha1.h \ 66 | ec.c \ 67 | bn.c \ 68 | mingw_mmap.c \ 69 | mingw_mmap.h 70 | 71 | sceverify_SOURCES = $(COMMON_DEPS) \ 72 | sceverify.c 73 | 74 | readself_SOURCES = $(COMMON_DEPS) \ 75 | readself.c 76 | 77 | readself2_SOURCES = $(COMMON_DEPS) \ 78 | readself2.c 79 | 80 | unself_SOURCES = $(COMMON_DEPS) \ 81 | unself.c 82 | 83 | unself2_SOURCES = $(COMMON_DEPS) \ 84 | $(SELF_DEPS) \ 85 | unself2.c 86 | 87 | makeself_SOURCES = $(COMMON_DEPS) \ 88 | makeself.c 89 | 90 | self_rebuilder_SOURCES = $(COMMON_DEPS) \ 91 | self_rebuilder.c 92 | 93 | ungpkg_SOURCES = $(COMMON_DEPS) \ 94 | ungpkg.c 95 | 96 | norunpack_SOURCES = $(COMMON_DEPS) \ 97 | norunpack.c 98 | 99 | pupunpack_SOURCES = $(COMMON_DEPS) \ 100 | pupunpack.c 101 | 102 | puppack_SOURCES = $(COMMON_DEPS) \ 103 | puppack.c 104 | 105 | unpkg_SOURCES = $(COMMON_DEPS) \ 106 | unpkg.c 107 | 108 | pkg_SOURCES = $(COMMON_DEPS) \ 109 | pkg.c 110 | 111 | cosunpkg_SOURCES = $(COMMON_DEPS) \ 112 | cosunpkg.c 113 | 114 | cospkg_SOURCES = $(COMMON_DEPS) \ 115 | cospkg.c 116 | 117 | cosunpack_SOURCES = $(COMMON_DEPS) \ 118 | cosunpack.c 119 | 120 | undat_SOURCES = $(COMMON_DEPS) \ 121 | undat.c 122 | 123 | dat_SOURCES = $(COMMON_DEPS) \ 124 | dat.c 125 | 126 | unspp_SOURCES = $(COMMON_DEPS) \ 127 | unspp.c 128 | 129 | eidsplitr_SOURCES = $(COMMON_DEPS) \ 130 | eidsplitr.c 131 | 132 | scekrit_SOURCES = $(COMMON_DEPS) \ 133 | scekrit.c 134 | scekrit_LDADD = $(GMP_LIBS) 135 | 136 | spp_SOURCES = $(COMMON_DEPS) \ 137 | spp.c 138 | unspp.c 139 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Copyright (C) 1998 5 | * Paul E. Jones 6 | * All Rights Reserved 7 | * 8 | * This software is licensed as "freeware." Permission to distribute 9 | * this software in source and binary forms is hereby granted without 10 | * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED 11 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 13 | * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING 14 | * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, 15 | * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. 16 | * 17 | * This software is licensed as "freeware." Permission to distribute 18 | * this software in source and binary forms is hereby granted without 19 | * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED 20 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 | * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING 23 | * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, 24 | * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. 25 | * 26 | ***************************************************************************** 27 | * $Id: sha1.h,v 1.2 2004/03/27 18:00:33 paulej Exp $ 28 | ***************************************************************************** 29 | * 30 | * Description: 31 | * This class implements the Secure Hashing Standard as defined 32 | * in FIPS PUB 180-1 published April 17, 1995. 33 | * 34 | * Many of the variable names in the SHA1Context, especially the 35 | * single character names, were used because those were the names 36 | * used in the publication. 37 | * 38 | * Please read the file sha1.c for more information. 39 | * 40 | */ 41 | 42 | #ifndef _SHA1_H_ 43 | #define _SHA1_H_ 44 | 45 | /* 46 | * This structure will hold context information for the hashing 47 | * operation 48 | */ 49 | typedef struct SHA1Context 50 | { 51 | unsigned Message_Digest[5]; /* Message Digest (output) */ 52 | 53 | unsigned Length_Low; /* Message length in bits */ 54 | unsigned Length_High; /* Message length in bits */ 55 | 56 | unsigned char Message_Block[64]; /* 512-bit message blocks */ 57 | int Message_Block_Index; /* Index into message block array */ 58 | 59 | int Computed; /* Is the digest computed? */ 60 | int Corrupted; /* Is the message digest corruped? */ 61 | } SHA1Context; 62 | 63 | /* 64 | * Function Prototypes 65 | */ 66 | void SHA1Reset(SHA1Context *); 67 | int SHA1Result(SHA1Context *); 68 | void SHA1Input( SHA1Context *, 69 | const unsigned char *, 70 | unsigned); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /tools.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Copyright 2007,2008,2010 Segher Boessenkool 3 | // Licensed under the terms of the GNU GPL, version 2 4 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 5 | 6 | #ifndef TOOLS_H__ 7 | #define TOOLS_H__ 1 8 | #include 9 | 10 | #include "types.h" 11 | 12 | enum sce_key { 13 | KEY_LV0 = 0, 14 | KEY_LV1, 15 | KEY_LV2, 16 | KEY_APP, 17 | KEY_ISO, 18 | KEY_LDR, 19 | KEY_PKG, 20 | KEY_SPP, 21 | KEY_NPDRM 22 | }; 23 | 24 | void print_hash(u8 *ptr, u32 len); 25 | void *mmap_file(const char *path); 26 | void memcpy_to_file(const char *fname, u8 *ptr, u64 size); 27 | const char *id2name(u32 id, struct id2name_tbl *t, const char *unk); 28 | void fail(const char *fmt, ...) __attribute__((noreturn)); 29 | void decompress(u8 *in, u64 in_len, u8 *out, u64 out_len); 30 | void get_rand(u8 *bfr, u32 size); 31 | 32 | int elf_read_hdr(u8 *hdr, struct elf_hdr *h); 33 | void elf_read_phdr(int arch64, u8 *phdr, struct elf_phdr *p); 34 | void elf_read_shdr(int arch64, u8 *shdr, struct elf_shdr *s); 35 | void elf_write_shdr(int arch64, u8 *shdr, struct elf_shdr *s); 36 | 37 | void aes256cbc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); 38 | void aes256cbc_enc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); 39 | void aes128ctr(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); 40 | void aes128cbc(u8 *key, u8 *iv_in, u8 *in, u64 len, u8 *out); 41 | void aes128cbc_enc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); 42 | void aes128(u8 *key, const u8 *in, u8 *out); 43 | void aes128_enc(u8 *key, const u8 *in, u8 *out); 44 | 45 | void sha1(u8 *data, u32 len, u8 *digest); 46 | void sha1_hmac(u8 *key, u8 *data, u32 len, u8 *digest); 47 | 48 | int key_get(enum sce_key type, const char *suffix, struct key *k); 49 | int key_get_simple(const char *name, u8 *bfr, u32 len); 50 | struct keylist *keys_get(enum sce_key type); 51 | 52 | struct rif *rif_get(const char *content_id); 53 | struct actdat *actdat_get(void); 54 | 55 | int sce_remove_npdrm(u8 *ptr, struct keylist *klist); 56 | void sce_decrypt_npdrm(u8 *ptr, struct keylist *klist, struct key *klicensee); 57 | 58 | int sce_decrypt_header(u8 *ptr, struct keylist *klist); 59 | int sce_encrypt_header(u8 *ptr, struct key *k); 60 | int sce_decrypt_data(u8 *ptr); 61 | int sce_encrypt_data(u8 *ptr); 62 | 63 | int ecdsa_get_params(u32 type, u8 *p, u8 *a, u8 *b, u8 *N, u8 *Gx, u8 *Gy); 64 | int ecdsa_set_curve(u32 type); 65 | void ecdsa_set_pub(u8 *Q); 66 | void ecdsa_set_priv(u8 *k); 67 | int ecdsa_verify(u8 *hash, u8 *R, u8 *S); 68 | void ecdsa_sign(u8 *hash, u8 *R, u8 *S); 69 | 70 | void bn_copy(u8 *d, u8 *a, u32 n); 71 | int bn_compare(u8 *a, u8 *b, u32 n); 72 | void bn_reduce(u8 *d, u8 *N, u32 n); 73 | void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); 74 | void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); 75 | void bn_to_mon(u8 *d, u8 *N, u32 n); 76 | void bn_from_mon(u8 *d, u8 *N, u32 n); 77 | void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); 78 | void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n); 79 | 80 | #define round_up(x,n) (-(-(x) & -(n))) 81 | 82 | #define array_size(x) (sizeof(x) / sizeof(*(x))) 83 | #endif 84 | -------------------------------------------------------------------------------- /unpkg.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef WIN32 16 | #define MKDIR(x,y) mkdir(x) 17 | #else 18 | #define MKDIR(x,y) mkdir(x,y) 19 | #endif 20 | 21 | u8 *pkg = NULL; 22 | static u64 dec_size; 23 | static u32 meta_offset; 24 | static u32 n_sections; 25 | 26 | static void unpack_content(const char *name) 27 | { 28 | u8 *tmp; 29 | u8 *decompressed; 30 | u64 offset; 31 | u64 size; 32 | u64 size_real; 33 | 34 | tmp = pkg + meta_offset + 0x80 + 0x30 * 2; 35 | 36 | offset = be64(tmp); 37 | size = be64(tmp + 8); 38 | size_real = dec_size - 0x80; 39 | 40 | if (be32(tmp + 0x2c) == 0x2) { 41 | decompressed = malloc(size_real); 42 | memset(decompressed, 0xaa, size_real); 43 | 44 | decompress(pkg + offset, size, decompressed, size_real); 45 | 46 | memcpy_to_file(name, decompressed, size_real); 47 | } else { 48 | memcpy_to_file(name, pkg + offset, size); 49 | } 50 | } 51 | 52 | static void unpack_info(u32 i) 53 | { 54 | u8 *tmp; 55 | u64 offset; 56 | u64 size; 57 | char path[256]; 58 | 59 | tmp = pkg + meta_offset + 0x80 + 0x30 * i; 60 | 61 | snprintf(path, sizeof path, "info%d", i); 62 | 63 | offset = be64(tmp); 64 | size = be64(tmp + 8); 65 | 66 | if (size != 0x40) 67 | fail("weird info size: %08x", size); 68 | 69 | memcpy_to_file(path, pkg + offset, size); 70 | } 71 | 72 | static void unpack_pkg(void) 73 | { 74 | unpack_info(0); 75 | unpack_info(1); 76 | unpack_content("content"); 77 | } 78 | 79 | static void decrypt_pkg(void) 80 | { 81 | u16 flags; 82 | u16 type; 83 | u32 hdr_len; 84 | struct keylist *k; 85 | 86 | flags = be16(pkg + 0x08); 87 | type = be16(pkg + 0x0a); 88 | hdr_len = be64(pkg + 0x10); 89 | dec_size = be64(pkg + 0x18); 90 | 91 | if (type != 3) 92 | fail("no .pkg file"); 93 | 94 | k = keys_get(KEY_PKG); 95 | 96 | if (k == NULL) 97 | fail("no key found"); 98 | 99 | if (sce_decrypt_header(pkg, k) < 0) 100 | fail("header decryption failed"); 101 | 102 | if (sce_decrypt_data(pkg) < 0) 103 | fail("data decryption failed"); 104 | 105 | meta_offset = be32(pkg + 0x0c); 106 | n_sections = be32(pkg + meta_offset + 0x60 + 0xc); 107 | 108 | if (n_sections != 3) 109 | fail("invalid section count: %d", n_sections); 110 | } 111 | 112 | int main(int argc, char *argv[]) 113 | { 114 | if (argc == 3) { 115 | pkg = mmap_file(argv[1]); 116 | 117 | MKDIR(argv[2], 0777); 118 | 119 | if (chdir(argv[2]) != 0) 120 | fail("chdir"); 121 | 122 | decrypt_pkg(); 123 | unpack_pkg(); 124 | } else if (argc == 4) { 125 | if (strcmp(argv[1], "-s") != 0) 126 | fail("invalid option: %s", argv[1]); 127 | 128 | pkg = mmap_file(argv[2]); 129 | 130 | decrypt_pkg(); 131 | unpack_content(argv[3]); 132 | } else { 133 | fail("usage: unpkg [-s] filename.pkg target"); 134 | } 135 | 136 | 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /types.h: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | #ifndef TYPES_H__ 5 | #define TYPES_H__ 6 | 7 | #include 8 | 9 | typedef uint64_t u64; 10 | typedef uint32_t u32; 11 | typedef uint16_t u16; 12 | typedef uint8_t u8; 13 | 14 | 15 | struct elf_phdr { 16 | u32 p_type; 17 | u64 p_off; 18 | u64 p_vaddr; 19 | u64 p_paddr; 20 | u64 p_filesz; 21 | u64 p_memsz; 22 | u32 p_flags; 23 | u64 p_align; 24 | 25 | void *ptr; 26 | }; 27 | 28 | struct elf_shdr { 29 | u32 sh_name; 30 | u32 sh_type; 31 | u32 sh_flags; 32 | u64 sh_addr; 33 | u64 sh_offset; 34 | u32 sh_size; 35 | u32 sh_link; 36 | u32 sh_info; 37 | u32 sh_addralign; 38 | u32 sh_entsize; 39 | }; 40 | 41 | #define ET_NONE 0 42 | #define ET_REL 1 43 | #define ET_EXEC 2 44 | #define ET_DYN 3 45 | #define ET_CORE 4 46 | #define ET_LOOS 0xfe00 47 | #define ET_HIOS 0xfeff 48 | #define ET_LOPROC 0xff00 49 | #define ET_HIPROC 0xffff 50 | struct elf_hdr { 51 | char e_ident[16]; 52 | u16 e_type; 53 | u16 e_machine; 54 | u32 e_version; 55 | u64 e_entry; 56 | u64 e_phoff; 57 | u64 e_shoff; 58 | u32 e_flags; 59 | u16 e_ehsize; 60 | u16 e_phentsize; 61 | u16 e_phnum; 62 | u16 e_shentsize; 63 | u16 e_shnum; 64 | u16 e_shtrndx; 65 | }; 66 | 67 | 68 | struct id2name_tbl { 69 | u32 id; 70 | const char *name; 71 | }; 72 | 73 | struct key { 74 | u8 key[32]; 75 | u8 iv[16]; 76 | 77 | int pub_avail; 78 | int priv_avail; 79 | u8 pub[40]; 80 | u8 priv[21]; 81 | u32 ctype; 82 | }; 83 | 84 | struct keylist { 85 | u32 n; 86 | struct key *keys; 87 | struct key *idps; 88 | struct key *klic; 89 | struct key *rif; 90 | struct key *npdrm_const; 91 | struct key *free_klicensee; 92 | }; 93 | 94 | struct rif { 95 | u8 unk1[0x10]; //version, license type and user number 96 | u8 titleid[0x30]; //Content ID 97 | u8 padding[0xC]; //Padding for randomness 98 | u32 actDatIndex; //Key index on act.dat between 0x00 and 0x7F 99 | u8 key[0x10]; //encrypted klicensee 100 | u64 unk2; //timestamp?? 101 | u64 unk3; //Always 0 102 | u8 rs[0x28]; 103 | } __attribute__ ((packed)); 104 | 105 | struct actdat { 106 | u8 unk1[0x10]; //Version, User number 107 | u8 keyTable[0x800]; //Key Table 108 | u8 unk2[0x800]; 109 | u8 signature[0x28]; 110 | } __attribute__ ((packed)); 111 | 112 | static inline u8 be8(u8 *p) 113 | { 114 | return *p; 115 | } 116 | 117 | static inline u16 be16(u8 *p) 118 | { 119 | u16 a; 120 | 121 | a = p[0] << 8; 122 | a |= p[1]; 123 | 124 | return a; 125 | } 126 | 127 | static inline u32 be32(u8 *p) 128 | { 129 | u32 a; 130 | 131 | a = p[0] << 24; 132 | a |= p[1] << 16; 133 | a |= p[2] << 8; 134 | a |= p[3] << 0; 135 | 136 | return a; 137 | } 138 | 139 | static inline u64 be64(u8 *p) 140 | { 141 | u32 a, b; 142 | 143 | a = be32(p); 144 | b = be32(p + 4); 145 | 146 | return ((u64)a<<32) | b; 147 | } 148 | 149 | static inline void wbe16(u8 *p, u16 v) 150 | { 151 | p[0] = v >> 8; 152 | p[1] = v; 153 | } 154 | 155 | static inline void wbe32(u8 *p, u32 v) 156 | { 157 | p[0] = v >> 24; 158 | p[1] = v >> 16; 159 | p[2] = v >> 8; 160 | p[3] = v; 161 | } 162 | 163 | static inline void wbe64(u8 *p, u64 v) 164 | { 165 | wbe32(p + 4, v); 166 | v >>= 32; 167 | wbe32(p, v); 168 | } 169 | 170 | #endif 171 | -------------------------------------------------------------------------------- /ungpkg.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010-2011 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | // Thanks to Mathieulh for his C# retail unpacker 6 | // (http://twitter.com/#!/Mathieulh/status/23070344881381376) 7 | // Thanks to Matt_P for his python debug unpacker 8 | // (https://github.com/HACKERCHANNEL/PS3Py/blob/master/pkg.py) 9 | 10 | #include "tools.h" 11 | #include "types.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef WIN32 21 | #define MKDIR(x,y) mkdir(x) 22 | #else 23 | #define MKDIR(x,y) mkdir(x,y) 24 | #endif 25 | 26 | 27 | static u8 *pkg = NULL; 28 | static u64 size; 29 | static u64 offset; 30 | 31 | 32 | static void decrypt_retail_pkg(void) 33 | { 34 | u8 key[0x10]; 35 | u8 iv[0x10]; 36 | 37 | if (be16(pkg + 0x06) != 1) 38 | fail("invalid pkg type: %x", be16(pkg + 0x06)); 39 | 40 | if (key_get_simple("gpkg-key", key, 0x10) < 0) 41 | fail("failed to load the package key."); 42 | 43 | memcpy(iv, pkg + 0x70, 0x10); 44 | aes128ctr(key, iv, pkg + offset, size, pkg + offset); 45 | } 46 | 47 | static void decrypt_debug_pkg(void) 48 | { 49 | u8 key[0x40]; 50 | u8 bfr[0x1c]; 51 | u64 i; 52 | 53 | memset(key, 0, sizeof key); 54 | memcpy(key, pkg + 0x60, 8); 55 | memcpy(key + 0x08, pkg + 0x60, 8); 56 | memcpy(key + 0x10, pkg + 0x60 + 0x08, 8); 57 | memcpy(key + 0x18, pkg + 0x60 + 0x08, 8); 58 | 59 | sha1(key, sizeof key, bfr); 60 | 61 | for (i = 0; i < size; i++) { 62 | if (i != 0 && (i % 16) == 0) { 63 | wbe64(key + 0x38, be64(key + 0x38) + 1); 64 | sha1(key, sizeof key, bfr); 65 | } 66 | pkg[offset + i] ^= bfr[i & 0xf]; 67 | } 68 | } 69 | 70 | static void unpack_pkg(void) 71 | { 72 | u64 i; 73 | u64 n_files; 74 | u32 fname_len; 75 | u32 fname_off; 76 | u64 file_offset; 77 | u32 flags; 78 | char fname[256]; 79 | u8 *tmp; 80 | 81 | n_files = be32(pkg + 0x14); 82 | 83 | for (i = 0; i < n_files; i++) { 84 | tmp = pkg + offset + i*0x20; 85 | 86 | fname_off = be32(tmp) + offset; 87 | fname_len = be32(tmp + 0x04); 88 | file_offset = be64(tmp + 0x08) + offset; 89 | size = be64(tmp + 0x10); 90 | flags = be32(tmp + 0x18); 91 | 92 | if (fname_len >= sizeof fname) 93 | fail("filename too long: %s", pkg + fname_off); 94 | 95 | memset(fname, 0, sizeof fname); 96 | strncpy(fname, (char *)(pkg + fname_off), fname_len); 97 | 98 | flags &= 0xff; 99 | if (flags == 4) 100 | MKDIR(fname, 0777); 101 | else if (flags == 1 || flags == 3) 102 | memcpy_to_file(fname, pkg + file_offset, size); 103 | else 104 | fail("unknown flags: %08x", flags); 105 | } 106 | } 107 | 108 | int main(int argc, char *argv[]) 109 | { 110 | char *dir; 111 | 112 | if (argc != 2 && argc != 3) 113 | fail("usage: ungpkg filename.pkg [target]"); 114 | 115 | pkg = mmap_file(argv[1]); 116 | 117 | if (argc == 2) { 118 | dir = malloc(0x31); 119 | memset(dir, 0, 0x31); 120 | memset(dir, 0, 0x30); 121 | memcpy(dir, pkg + 0x30, 0x30); 122 | } else { 123 | dir = argv[2]; 124 | } 125 | 126 | MKDIR(dir, 0777); 127 | 128 | if (chdir(dir) != 0) 129 | fail("chdir(%s)", dir); 130 | 131 | offset = be64(pkg + 0x20); 132 | size = be64(pkg + 0x28); 133 | 134 | if (be16(pkg + 0x04) & 0x8000) 135 | decrypt_retail_pkg(); 136 | else 137 | decrypt_debug_pkg(); 138 | 139 | unpack_pkg(); 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /cospkg.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #define MAX_FILES 255 14 | 15 | #define COS_FILE_SIZE 7340000 16 | 17 | 18 | struct pkg_file { 19 | char name[0x20]; 20 | u8 *ptr; 21 | u64 size; 22 | u64 offset; 23 | }; 24 | 25 | static u8 *hdr = NULL; 26 | static u32 hdr_size = 0; 27 | 28 | static u32 n_files = 0; 29 | static struct pkg_file files[MAX_FILES]; 30 | 31 | static void get_files(const char *d) 32 | { 33 | DIR *dir; 34 | struct dirent *de; 35 | struct stat st; 36 | char path[256]; 37 | u32 i; 38 | u64 offset; 39 | 40 | dir = opendir(d); 41 | if (dir == NULL) 42 | fail("opendir"); 43 | 44 | offset = 0; 45 | i = 0; 46 | while ((de = readdir(dir))) { 47 | if (n_files == MAX_FILES) 48 | fail("file overflow. increase MAX_FILES"); 49 | 50 | if (strcmp(de->d_name, ".") == 0) 51 | continue; 52 | 53 | if (strcmp(de->d_name, "..") == 0) 54 | continue; 55 | 56 | if (strlen(de->d_name) > 0x20) 57 | fail("name too long: %s", de->d_name); 58 | 59 | snprintf(path, sizeof path, "%s/%s", d, de->d_name); 60 | 61 | memset(&files[i], 0, sizeof(*files)); 62 | strncpy(files[i].name, de->d_name, 0x19); 63 | 64 | if (stat(path, &st) < 0) 65 | fail("cannot stat %s", path); 66 | 67 | if (!S_ISREG(st.st_mode)) 68 | fail("not a file: %s", de->d_name); 69 | 70 | files[i].size = st.st_size; 71 | 72 | files[i].ptr = mmap_file(path); 73 | if (files[i].ptr == NULL) 74 | fail("unable to mmap %s", path); 75 | 76 | files[i].offset = offset; 77 | offset = round_up(offset + files[i].size, 0x20); 78 | 79 | i++; 80 | n_files++; 81 | } 82 | } 83 | 84 | static void build_hdr(void) 85 | { 86 | u8 *p; 87 | u32 i; 88 | u64 file_size; 89 | 90 | file_size = files[n_files - 1].offset + files[n_files - 1].size; 91 | hdr_size = 0x10 + n_files * 0x30; 92 | 93 | if ((hdr_size + file_size) > COS_FILE_SIZE) 94 | fail ("Too many files, size must be under %d but it is %d", 95 | COS_FILE_SIZE, hdr_size + file_size); 96 | 97 | hdr = malloc(hdr_size); 98 | 99 | if (hdr == NULL) 100 | fail("out of memory"); 101 | 102 | memset(hdr, 0, hdr_size); 103 | p = hdr; 104 | 105 | wbe32(p + 0x00, 1); // magic 106 | wbe32(p + 0x04, n_files); 107 | wbe64(p + 0x08, COS_FILE_SIZE); 108 | p += 0x10; 109 | 110 | for (i = 0; i < n_files; i++) { 111 | wbe64(p + 0x00, files[i].offset + hdr_size); 112 | wbe64(p + 0x08, files[i].size); 113 | strncpy((char *)(p + 0x10), files[i].name, 0x20); 114 | p += 0x30; 115 | } 116 | } 117 | 118 | static void write_pkg(const char *n) 119 | { 120 | FILE *fp; 121 | u32 i; 122 | 123 | fp = fopen(n, "wb"); 124 | if (fp == NULL) 125 | fail("fopen(%s) failed", n); 126 | 127 | fwrite(hdr, hdr_size, 1, fp); 128 | 129 | for (i = 0; i < n_files; i++) { 130 | fseek(fp, files[i].offset + hdr_size, SEEK_SET); 131 | fwrite(files[i].ptr, files[i].size, 1, fp); 132 | } 133 | 134 | fseek (fp, COS_FILE_SIZE-1, SEEK_SET); 135 | fwrite("", 1, 1, fp); 136 | 137 | fclose(fp); 138 | } 139 | 140 | int main(int argc, char *argv[]) 141 | { 142 | if (argc != 3) 143 | fail("usage: cospkg cos.pkg dir"); 144 | 145 | get_files(argv[2]); 146 | build_hdr(); 147 | write_pkg(argv[1]); 148 | 149 | return 0; 150 | } 151 | -------------------------------------------------------------------------------- /puppack.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "tools.h" 12 | 13 | #define MAX_FILES 10 14 | 15 | static FILE *fp; 16 | static u8 pup_hmac[0x40]; 17 | static u8 hdr[0x30 + 0x40 * MAX_FILES + 0x20]; 18 | static u64 n_files; 19 | static u64 data_size; 20 | static u64 build = 0xfa11; 21 | 22 | static struct { 23 | u8 *ptr; 24 | u64 id; 25 | u64 len; 26 | u64 offset; 27 | } files[MAX_FILES]; 28 | 29 | static struct id2name_tbl t_names[] = { 30 | {0x100, "version.txt"}, 31 | {0x101, "license.xml"}, 32 | {0x102, "promo_flags.txt"}, 33 | {0x103, "update_flags.txt"}, 34 | {0x104, "patch_build.txt"}, 35 | {0x200, "ps3swu.self"}, 36 | {0x201, "vsh.tar"}, 37 | {0x202, "dots.txt"}, 38 | {0x203, "patch_data.pkg"}, 39 | {0x300, "update_files.tar"}, 40 | {0x501, "spkg_hdr.tar"}, 41 | {0x601, "ps3swu2.self"}, 42 | {0, NULL} 43 | }; 44 | 45 | 46 | static void find_files(void) 47 | { 48 | struct id2name_tbl *t; 49 | struct stat st; 50 | u64 offset; 51 | u32 i; 52 | 53 | n_files = 0; 54 | data_size = 0; 55 | 56 | t = t_names; 57 | while(t->name != NULL) { 58 | if (stat(t->name, &st) >= 0) { 59 | files[n_files].id = t->id; 60 | files[n_files].ptr = mmap_file(t->name); 61 | files[n_files].len = st.st_size; 62 | data_size += files[n_files].len; 63 | n_files++; 64 | } 65 | t++; 66 | } 67 | 68 | offset = 0x50 + 0x40 * n_files; 69 | for (i = 0; i < n_files; i++) { 70 | files[i].offset = offset; 71 | offset += files[i].len; 72 | } 73 | } 74 | 75 | static void calc_hmac(u8 *ptr, u64 len, u8 *hmac) 76 | { 77 | memset(hmac, 0, 0x20); 78 | sha1_hmac(pup_hmac, ptr, len, hmac); 79 | } 80 | 81 | static void build_header(void) 82 | { 83 | u32 i; 84 | 85 | memset(hdr, 0, sizeof hdr); 86 | memcpy(hdr, "SCEUF\0\0\0", 8); 87 | 88 | wbe64(hdr + 0x08, 1); 89 | wbe64(hdr + 0x10, build); 90 | wbe64(hdr + 0x18, n_files); 91 | wbe64(hdr + 0x20, 0x50 + n_files * 0x40); 92 | wbe64(hdr + 0x28, data_size); 93 | 94 | for (i = 0; i < n_files; i++) { 95 | wbe64(hdr + 0x30 + 0x20 * i + 0x00, files[i].id); 96 | wbe64(hdr + 0x30 + 0x20 * i + 0x08, files[i].offset); 97 | wbe64(hdr + 0x30 + 0x20 * i + 0x10, files[i].len); 98 | wbe64(hdr + 0x30 + 0x20 * i + 0x18, 0); 99 | 100 | wbe64(hdr + 0x30 + 0x20 * n_files + 0x20 * i, i); 101 | calc_hmac(files[i].ptr, files[i].len, 102 | hdr + 0x30 + 0x20 * n_files + 0x20 * i + 0x08); 103 | } 104 | 105 | calc_hmac(hdr, 0x30 + 0x40 * n_files, 106 | hdr + 0x30 + 0x40 * n_files); 107 | } 108 | 109 | static void write_pup(void) 110 | { 111 | u32 i; 112 | 113 | fseek(fp, 0, SEEK_SET); 114 | fwrite(hdr, 0x50 + 0x40 * n_files, 1, fp); 115 | 116 | for (i = 0; i < n_files; i++) { 117 | fseek(fp, files[i].offset, SEEK_SET); 118 | fwrite(files[i].ptr, files[i].len, 1, fp); 119 | } 120 | } 121 | 122 | int main(int argc, char *argv[]) 123 | { 124 | if (argc < 3) 125 | fail("usage: puppack filename.pup directory [build number]"); 126 | 127 | if (argc == 4) 128 | build = atoi(argv[3]); 129 | 130 | if (key_get_simple("pup-hmac", pup_hmac, sizeof pup_hmac) < 0) 131 | fail("pup hmac key not available"); 132 | 133 | fp = fopen(argv[1], "wb"); 134 | if (fp == NULL) 135 | fail("fopen(%s)", argv[1]); 136 | 137 | if (chdir(argv[2]) < 0) 138 | fail("chdir(%s)", argv[1]); 139 | 140 | find_files(); 141 | build_header(); 142 | write_pup(); 143 | 144 | fclose(fp); 145 | 146 | return 0; 147 | } 148 | 149 | -------------------------------------------------------------------------------- /pupunpack.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "tools.h" 11 | 12 | #ifdef WIN32 13 | #define MKDIR(x,y) mkdir(x) 14 | #else 15 | #define MKDIR(x,y) mkdir(x,y) 16 | #endif 17 | 18 | static u8 *pup = NULL; 19 | static u8 pup_hmac[0x40]; 20 | static int got_hmac = -1; 21 | static u64 n_sections; 22 | static u64 hdr_size; 23 | 24 | static struct id2name_tbl t_names[] = { 25 | {0x100, "version.txt"}, 26 | {0x101, "license.xml"}, 27 | {0x102, "promo_flags.txt"}, 28 | {0x103, "update_flags.txt"}, 29 | {0x104, "patch_build.txt"}, 30 | {0x200, "ps3swu.self"}, 31 | {0x201, "vsh.tar"}, 32 | {0x202, "dots.txt"}, 33 | {0x203, "patch_data.pkg"}, 34 | {0x300, "update_files.tar"}, 35 | {0x501, "spkg_hdr.tar"}, 36 | {0x601, "ps3swu2.self"}, 37 | {0, NULL} 38 | }; 39 | 40 | static int check_hmac(u8 *hmac, u8 *bfr, u64 len) 41 | { 42 | u8 calc[0x14]; 43 | 44 | if (hmac == NULL) 45 | return 1; 46 | 47 | if (got_hmac < 0) 48 | return 1; 49 | 50 | sha1_hmac(pup_hmac, bfr, len, calc); 51 | 52 | if (memcmp(calc, hmac, sizeof calc) == 0) 53 | return 0; 54 | else 55 | return -1; 56 | } 57 | 58 | static u8 *find_hmac(u32 entry) 59 | { 60 | u8 *ptr; 61 | u32 i; 62 | 63 | ptr = pup + 0x30 + 0x20 * n_sections; 64 | 65 | for(i = 0; i < n_sections; i++) { 66 | if (be64(ptr) == entry) 67 | return ptr + 8; 68 | ptr += 0x20; 69 | } 70 | 71 | fail("not found: %d", entry); 72 | return NULL; 73 | } 74 | 75 | static void do_section(u64 i) 76 | { 77 | u8 *ptr; 78 | u64 entry; 79 | u64 offset; 80 | u64 size; 81 | int hmac_res; 82 | const char *fname; 83 | const char *hmac_status; 84 | 85 | ptr = pup + 0x30 + 0x20 * i; 86 | entry = be64(ptr); 87 | offset = be64(ptr + 0x08); 88 | size = be64(ptr + 0x10); 89 | 90 | fname = id2name(entry, t_names, NULL); 91 | if (fname == NULL) 92 | fail("unknown entry id: %08x_%08x", (u32)(entry >> 32), (u32)entry); 93 | 94 | hmac_res = check_hmac(find_hmac(i), pup + offset, size); 95 | if (hmac_res < 0) 96 | hmac_status = "FAIL"; 97 | else if (hmac_res == 0) 98 | hmac_status = "OK"; 99 | else 100 | hmac_status = "???"; 101 | 102 | printf("unpacking %s (%08x_%08x bytes; hmac: %s)...\n", fname, (u32)(size >> 32), (u32)size, hmac_status); 103 | memcpy_to_file(fname, pup + offset, size); 104 | } 105 | 106 | static void do_pup(void) 107 | { 108 | u64 data_size; 109 | u64 i; 110 | int res; 111 | 112 | n_sections = be64(pup + 0x18); 113 | hdr_size = be64(pup + 0x20); 114 | data_size = be64(pup + 0x28); 115 | 116 | printf("sections: %" PRIu64 "\n", n_sections); 117 | printf("hdr size: %08x_%08x\n", (u32)(hdr_size >> 32), (u32)hdr_size); 118 | printf("data size: %08x_%08x\n", (u32)(data_size >> 32), (u32)data_size); 119 | printf("header hmac: "); 120 | 121 | res = check_hmac(pup + 0x30 + 0x40 * n_sections, pup, 0x30 + 0x40 * n_sections); 122 | 123 | if (res < 0) 124 | printf("FAIL\n"); 125 | else if (res == 0) 126 | printf("OK\n"); 127 | else 128 | printf("???\n"); 129 | 130 | for (i = 0; i < n_sections; i++) 131 | do_section(i); 132 | } 133 | 134 | int main(int argc, char *argv[]) 135 | { 136 | (void)argc; 137 | 138 | if (argc < 3) 139 | fail("usage: pupunpack filename.pup directory"); 140 | 141 | got_hmac = key_get_simple("pup-hmac", pup_hmac, sizeof pup_hmac); 142 | pup = mmap_file(argv[1]); 143 | 144 | if(pup != NULL) 145 | { 146 | if (MKDIR(argv[2], 0777) < 0) 147 | fail("mkdir(%s)", argv[2]); 148 | if (chdir(argv[2]) < 0) 149 | fail("chdir(%s)", argv[2]); 150 | do_pup(); 151 | } 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /bn.c: -------------------------------------------------------------------------------- 1 | // Copyright 2007,2008,2010 Segher Boessenkool 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include 6 | #include 7 | 8 | #include "tools.h" 9 | 10 | static void bn_print(char *name, u8 *a, u32 n) 11 | { 12 | u32 i; 13 | 14 | printf("%s = ", name); 15 | 16 | for (i = 0; i < n; i++) 17 | printf("%02x", a[i]); 18 | 19 | printf("\n"); 20 | } 21 | 22 | static void bn_zero(u8 *d, u32 n) 23 | { 24 | memset(d, 0, n); 25 | } 26 | 27 | void bn_copy(u8 *d, u8 *a, u32 n) 28 | { 29 | memcpy(d, a, n); 30 | } 31 | 32 | int bn_compare(u8 *a, u8 *b, u32 n) 33 | { 34 | u32 i; 35 | 36 | for (i = 0; i < n; i++) { 37 | if (a[i] < b[i]) 38 | return -1; 39 | if (a[i] > b[i]) 40 | return 1; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | static u8 bn_add_1(u8 *d, u8 *a, u8 *b, u32 n) 47 | { 48 | u32 i; 49 | u32 dig; 50 | u8 c; 51 | 52 | c = 0; 53 | for (i = n - 1; i < n; i--) { 54 | dig = a[i] + b[i] + c; 55 | c = dig >> 8; 56 | d[i] = dig; 57 | } 58 | 59 | return c; 60 | } 61 | 62 | static u8 bn_sub_1(u8 *d, u8 *a, u8 *b, u32 n) 63 | { 64 | u32 i; 65 | u32 dig; 66 | u8 c; 67 | 68 | c = 1; 69 | for (i = n - 1; i < n; i--) { 70 | dig = a[i] + 255 - b[i] + c; 71 | c = dig >> 8; 72 | d[i] = dig; 73 | } 74 | 75 | return 1 - c; 76 | } 77 | 78 | void bn_reduce(u8 *d, u8 *N, u32 n) 79 | { 80 | if (bn_compare(d, N, n) >= 0) 81 | bn_sub_1(d, d, N, n); 82 | } 83 | 84 | void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) 85 | { 86 | if (bn_add_1(d, a, b, n)) 87 | bn_sub_1(d, d, N, n); 88 | 89 | bn_reduce(d, N, n); 90 | } 91 | 92 | void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) 93 | { 94 | if (bn_sub_1(d, a, b, n)) 95 | bn_add_1(d, d, N, n); 96 | } 97 | 98 | static const u8 inv256[0x80] = { 99 | 0x01, 0xab, 0xcd, 0xb7, 0x39, 0xa3, 0xc5, 0xef, 100 | 0xf1, 0x1b, 0x3d, 0xa7, 0x29, 0x13, 0x35, 0xdf, 101 | 0xe1, 0x8b, 0xad, 0x97, 0x19, 0x83, 0xa5, 0xcf, 102 | 0xd1, 0xfb, 0x1d, 0x87, 0x09, 0xf3, 0x15, 0xbf, 103 | 0xc1, 0x6b, 0x8d, 0x77, 0xf9, 0x63, 0x85, 0xaf, 104 | 0xb1, 0xdb, 0xfd, 0x67, 0xe9, 0xd3, 0xf5, 0x9f, 105 | 0xa1, 0x4b, 0x6d, 0x57, 0xd9, 0x43, 0x65, 0x8f, 106 | 0x91, 0xbb, 0xdd, 0x47, 0xc9, 0xb3, 0xd5, 0x7f, 107 | 0x81, 0x2b, 0x4d, 0x37, 0xb9, 0x23, 0x45, 0x6f, 108 | 0x71, 0x9b, 0xbd, 0x27, 0xa9, 0x93, 0xb5, 0x5f, 109 | 0x61, 0x0b, 0x2d, 0x17, 0x99, 0x03, 0x25, 0x4f, 110 | 0x51, 0x7b, 0x9d, 0x07, 0x89, 0x73, 0x95, 0x3f, 111 | 0x41, 0xeb, 0x0d, 0xf7, 0x79, 0xe3, 0x05, 0x2f, 112 | 0x31, 0x5b, 0x7d, 0xe7, 0x69, 0x53, 0x75, 0x1f, 113 | 0x21, 0xcb, 0xed, 0xd7, 0x59, 0xc3, 0xe5, 0x0f, 114 | 0x11, 0x3b, 0x5d, 0xc7, 0x49, 0x33, 0x55, 0xff, 115 | }; 116 | 117 | static void bn_mon_muladd_dig(u8 *d, u8 *a, u8 b, u8 *N, u32 n) 118 | { 119 | u32 dig; 120 | u32 i; 121 | 122 | u8 z = -(d[n-1] + a[n-1]*b) * inv256[N[n-1]/2]; 123 | 124 | dig = d[n-1] + a[n-1]*b + N[n-1]*z; 125 | dig >>= 8; 126 | 127 | for (i = n - 2; i < n; i--) { 128 | dig += d[i] + a[i]*b + N[i]*z; 129 | d[i+1] = dig; 130 | dig >>= 8; 131 | } 132 | 133 | d[0] = dig; 134 | dig >>= 8; 135 | 136 | if (dig) 137 | bn_sub_1(d, d, N, n); 138 | 139 | bn_reduce(d, N, n); 140 | } 141 | 142 | void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) 143 | { 144 | u8 t[512]; 145 | u32 i; 146 | 147 | bn_zero(t, n); 148 | 149 | for (i = n - 1; i < n; i--) 150 | bn_mon_muladd_dig(t, a, b[i], N, n); 151 | 152 | bn_copy(d, t, n); 153 | } 154 | 155 | void bn_to_mon(u8 *d, u8 *N, u32 n) 156 | { 157 | u32 i; 158 | 159 | for (i = 0; i < 8*n; i++) 160 | bn_add(d, d, d, N, n); 161 | } 162 | 163 | void bn_from_mon(u8 *d, u8 *N, u32 n) 164 | { 165 | u8 t[512]; 166 | 167 | bn_zero(t, n); 168 | t[n-1] = 1; 169 | bn_mon_mul(d, d, t, N, n); 170 | } 171 | 172 | static void bn_mon_exp(u8 *d, u8 *a, u8 *N, u32 n, u8 *e, u32 en) 173 | { 174 | u8 t[512]; 175 | u32 i; 176 | u8 mask; 177 | 178 | bn_zero(d, n); 179 | d[n-1] = 1; 180 | bn_to_mon(d, N, n); 181 | 182 | for (i = 0; i < en; i++) 183 | for (mask = 0x80; mask != 0; mask >>= 1) { 184 | bn_mon_mul(t, d, d, N, n); 185 | if ((e[i] & mask) != 0) 186 | bn_mon_mul(d, t, a, N, n); 187 | else 188 | bn_copy(d, t, n); 189 | } 190 | } 191 | 192 | void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n) 193 | { 194 | u8 t[512], s[512]; 195 | 196 | bn_zero(s, n); 197 | s[n-1] = 2; 198 | bn_sub_1(t, N, s, n); 199 | bn_mon_exp(d, a, N, n, t, n); 200 | } 201 | -------------------------------------------------------------------------------- /spp.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Copyright 2011 glevand 3 | // Licensed under the terms of the GNU GPL, version 2 4 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 5 | 6 | #include "tools.h" 7 | #include "types.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static struct key k; 17 | static FILE *fp; 18 | 19 | static u8 *content; 20 | static u64 content_size; 21 | 22 | static u8 sce_hdr[0x20]; 23 | static u8 meta_hdr[0x1e0]; 24 | 25 | static u8 *spp; 26 | static u64 spp_size; 27 | 28 | static void get_profile(const char *filename) 29 | { 30 | struct stat st; 31 | 32 | content = mmap_file(filename); 33 | 34 | if (stat(filename, &st) < 0) 35 | fail("stat(%s) failed", filename); 36 | 37 | content_size = st.st_size; 38 | } 39 | 40 | static void get_key(const char *suffix) 41 | { 42 | if (key_get(KEY_SPP, suffix, &k) < 0) 43 | fail("key_get() failed"); 44 | 45 | if (k.pub_avail < 0) 46 | fail("no public key available"); 47 | 48 | if (k.priv_avail < 0) 49 | fail("no private key available"); 50 | 51 | if (ecdsa_set_curve(k.ctype) < 0) 52 | fail("ecdsa_set_curve failed"); 53 | 54 | ecdsa_set_pub(k.pub); 55 | ecdsa_set_priv(k.priv); 56 | } 57 | 58 | static void build_sce_hdr(void) 59 | { 60 | memset(sce_hdr, 0, sizeof sce_hdr); 61 | 62 | wbe32(sce_hdr + 0x00, 0x53434500); // magic 63 | wbe32(sce_hdr + 0x04, 2); // version 64 | wbe16(sce_hdr + 0x08, 0); // dunno, sdk type? 65 | wbe16(sce_hdr + 0x0a, 4); // SCE header type; profile 66 | wbe32(sce_hdr + 0x0c, 0); // meta offset 67 | wbe64(sce_hdr + 0x10, sizeof sce_hdr + sizeof meta_hdr); 68 | wbe64(sce_hdr + 0x18, content_size); 69 | } 70 | 71 | static void build_meta_hdr(void) 72 | { 73 | u8 *ptr; 74 | 75 | memset(meta_hdr, 0, sizeof meta_hdr); 76 | ptr = meta_hdr; 77 | 78 | // keys for metadata encryption 79 | get_rand(ptr, 0x10); 80 | get_rand(ptr + 0x20, 0x10); 81 | ptr += 0x40; 82 | 83 | // area covered by the signature 84 | wbe64(ptr + 0x00, sizeof sce_hdr + sizeof meta_hdr - 0x30); 85 | wbe32(ptr + 0x08, 1); 86 | wbe32(ptr + 0x0c, 2); // number of encrypted headers 87 | wbe32(ptr + 0x10, 2 * 8); // number of keys/hashes required 88 | ptr += 0x20; 89 | 90 | // header 91 | wbe64(ptr + 0x00, 0x200); // offset 92 | wbe64(ptr + 0x08, 0x20); // size 93 | wbe32(ptr + 0x10, 1); // unknown 94 | wbe32(ptr + 0x14, 1); // index 95 | wbe32(ptr + 0x18, 2); // unknown again 96 | wbe32(ptr + 0x1c, 0); // sha index 97 | wbe32(ptr + 0x20, 1); // no encryption 98 | wbe32(ptr + 0x24, 0xffffffff); // key index 99 | wbe32(ptr + 0x28, 0xffffffff); // iv index 100 | wbe32(ptr + 0x2c, 0x1); // no compression 101 | ptr += 0x30; 102 | 103 | // profile 104 | wbe64(ptr + 0x00, 0x220); // offset 105 | wbe64(ptr + 0x08, content_size - 0x20); 106 | wbe32(ptr + 0x10, 2); // unknown 107 | wbe32(ptr + 0x14, 2); // index 108 | wbe32(ptr + 0x18, 2); // unknown again 109 | wbe32(ptr + 0x1c, 8); // sha index 110 | wbe32(ptr + 0x20, 3); // encrypted 111 | wbe32(ptr + 0x24, 0); // key index 112 | wbe32(ptr + 0x28, 1); // iv index 113 | wbe32(ptr + 0x2c, 0x1); // no compression 114 | ptr += 0x30; 115 | 116 | // add keys/ivs and hmac keys 117 | get_rand(ptr, 2 * 8 * 0x10); 118 | } 119 | 120 | static void build_spp(void) 121 | { 122 | spp_size = sizeof sce_hdr + sizeof meta_hdr; 123 | spp_size += content_size; 124 | 125 | spp = malloc(spp_size); 126 | if (!spp) 127 | fail("out of memory"); 128 | 129 | memset(spp, 0xaa, spp_size); 130 | memcpy(spp, sce_hdr, 0x20); 131 | memcpy(spp + 0x20, meta_hdr, 0x1e0); 132 | memcpy(spp + 0x200, content, content_size); 133 | } 134 | 135 | static void calculate_hash(u8 *data, u64 len, u8 *digest) 136 | { 137 | memset(digest, 0, 0x20); 138 | sha1_hmac(digest + 0x20, data, len, digest); 139 | } 140 | 141 | static void hash_spp(void) 142 | { 143 | calculate_hash(spp + 0x200, 0x20, spp + 0x80 + 2*0x30); 144 | calculate_hash(spp + 0x220, content_size - 0x20, 145 | spp + 0x80 + 2*0x30 + 8*0x10); 146 | } 147 | 148 | static void sign_spp(void) 149 | { 150 | u8 *r, *s; 151 | u8 hash[20]; 152 | u64 sig_len; 153 | 154 | sig_len = be64(spp + 0x60); 155 | r = spp + sig_len; 156 | s = r + 21; 157 | 158 | sha1(spp, sig_len, hash); 159 | 160 | ecdsa_sign(hash, r, s); 161 | } 162 | 163 | int main(int argc, char *argv[]) 164 | { 165 | if (argc != 4) 166 | fail("usage: spp [key suffix] [filename.pp] [filename.spp]"); 167 | 168 | fp = fopen(argv[3], "wb"); 169 | if (fp == NULL) 170 | fail("fopen(%s) failed", argv[3]); 171 | 172 | get_key(argv[1]); 173 | get_profile(argv[2]); 174 | 175 | build_sce_hdr(); 176 | build_meta_hdr(); 177 | 178 | build_spp(); 179 | hash_spp(); 180 | sign_spp(); 181 | 182 | sce_encrypt_data(spp); 183 | sce_encrypt_header(spp, &k); 184 | 185 | fwrite(spp, spp_size, 1, fp); 186 | fclose(fp); 187 | 188 | return 0; 189 | } 190 | -------------------------------------------------------------------------------- /sceverify.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static u8 *ptr = NULL; 14 | 15 | static u16 type; 16 | static u16 flags; 17 | static u32 meta_offset; 18 | static u64 info_offset; 19 | static u32 app_type; 20 | static u64 filesize; 21 | static u64 header_len; 22 | static int did_fail = 0; 23 | 24 | static struct keylist *klist = NULL; 25 | 26 | static struct keylist *self_load_keys(void) 27 | { 28 | enum sce_key id; 29 | 30 | switch (app_type) { 31 | case 1: 32 | id = KEY_LV0; 33 | break; 34 | case 2: 35 | id = KEY_LV1; 36 | break; 37 | case 3: 38 | id = KEY_LV2; 39 | break; 40 | case 4: 41 | id = KEY_APP; 42 | break; 43 | case 5: 44 | id = KEY_ISO; 45 | break; 46 | case 6: 47 | id = KEY_LDR; 48 | break; 49 | default: 50 | fail("invalid type: %08x", app_type); 51 | } 52 | 53 | return keys_get(id); 54 | } 55 | 56 | static void read_self_header(void) 57 | { 58 | flags = be16(ptr + 0x08); 59 | meta_offset = be32(ptr + 0x0c); 60 | header_len = be64(ptr + 0x10); 61 | filesize = be64(ptr + 0x18); 62 | info_offset = be64(ptr + 0x28); 63 | 64 | app_type = be32(ptr + info_offset + 0x0c); 65 | 66 | klist = self_load_keys(); 67 | } 68 | 69 | static void read_pkg_header(void) 70 | { 71 | flags = be16(ptr + 0x08); 72 | meta_offset = be32(ptr + 0x0c); 73 | header_len = be64(ptr + 0x10); 74 | filesize = be64(ptr + 0x18); 75 | 76 | klist = keys_get(KEY_PKG); 77 | } 78 | 79 | static void read_spp_header(void) 80 | { 81 | flags = be16(ptr + 0x08); 82 | meta_offset = be32(ptr + 0x0c); 83 | header_len = be64(ptr + 0x10); 84 | filesize = be64(ptr + 0x18); 85 | 86 | klist = keys_get(KEY_SPP); 87 | } 88 | 89 | static void decrypt(void) 90 | { 91 | int keyid; 92 | 93 | keyid = sce_decrypt_header(ptr, klist); 94 | 95 | if (keyid < 0) 96 | fail("sce_decrypt_header failed"); 97 | 98 | if (sce_decrypt_data(ptr) < 0) 99 | fail("sce_decrypt_data failed"); 100 | 101 | if (klist->keys[keyid].pub_avail < 0) 102 | fail("no public key available"); 103 | 104 | if (ecdsa_set_curve(klist->keys[keyid].ctype) < 0) 105 | fail("ecdsa_set_curve failed"); 106 | 107 | ecdsa_set_pub(klist->keys[keyid].pub); 108 | } 109 | 110 | static void verify_signature(void) 111 | { 112 | u8 *r, *s; 113 | u8 hash[20]; 114 | u64 sig_len; 115 | 116 | sig_len = be64(ptr + meta_offset + 0x60); 117 | r = ptr + sig_len; 118 | s = r + 21; 119 | 120 | sha1(ptr, sig_len, hash); 121 | 122 | printf("Signature\n"); 123 | if (ecdsa_verify(hash, r, s)) 124 | printf(" Status: OK\n"); 125 | else 126 | printf(" Status: FAIL\n"); 127 | 128 | printf("\n"); 129 | } 130 | 131 | static int verify_hash(u8 *p, u8 *hashes) 132 | { 133 | u64 offset; 134 | u64 size; 135 | u64 id; 136 | u8 *hash, *key; 137 | u8 result[20]; 138 | 139 | offset = be64(p + 0x00); 140 | size = be64(p + 0x08); 141 | id = be32(p + 0x1c); 142 | 143 | if (id == 0xffffffff) 144 | return 0; 145 | 146 | hash = hashes + id * 0x10; 147 | key = hash + 0x20; 148 | 149 | // XXX: possible integer overflow here 150 | if (offset > (filesize + header_len)) 151 | return 1; 152 | 153 | // XXX: possible integer overflow here 154 | if ((offset + size) > (filesize + header_len)) 155 | return 1; 156 | 157 | sha1_hmac(key, ptr + offset, size, result); 158 | 159 | if (memcmp(result, hash, 20) == 0) 160 | return 0; 161 | else 162 | return -1; 163 | } 164 | 165 | static void verify_hashes(void) 166 | { 167 | u32 meta_n_hdr; 168 | u32 i; 169 | u8 *hashes; 170 | int res; 171 | 172 | meta_n_hdr = be32(ptr + meta_offset + 0x60 + 0xc); 173 | hashes = ptr + meta_offset + 0x80 + 0x30 * meta_n_hdr; 174 | 175 | printf("Hashes\n"); 176 | 177 | for (i = 0; i < meta_n_hdr; i++) { 178 | printf(" Section #%02d: ", i); 179 | res = verify_hash(ptr + meta_offset + 0x80 + 0x30 * i, hashes); 180 | if (res < 0) { 181 | did_fail = 1; 182 | printf("FAIL*\n"); 183 | } else if (res > 0) { 184 | printf("???\n"); 185 | } else { 186 | printf("OK\n"); 187 | } 188 | } 189 | 190 | printf("\n"); 191 | } 192 | 193 | int main(int argc, char *argv[]) 194 | { 195 | if (argc != 2) 196 | fail("usage: sceverify filename"); 197 | 198 | ptr = mmap_file(argv[1]); 199 | 200 | type = be16(ptr + 0x0a); 201 | 202 | if (type == 1) 203 | read_self_header(); 204 | else if(type == 3) 205 | read_pkg_header(); 206 | else if(type == 4) 207 | read_spp_header(); 208 | else 209 | fail("Unknown type: %d", type); 210 | 211 | if (flags & 0x8000) 212 | fail("devkit file; nothing to verify"); 213 | 214 | if (klist == NULL) 215 | fail("no key found"); 216 | 217 | decrypt(); 218 | verify_signature(); 219 | verify_hashes(); 220 | 221 | if (did_fail) 222 | printf(" * please not that the hash will always fail for " 223 | "unaligned non-LOAD phdrs\n"); 224 | return 0; 225 | } 226 | -------------------------------------------------------------------------------- /self.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This software is distributed under the terms of the GNU General Public 3 | * License ("GPL") version 2, as published by the Free Software Foundation. 4 | */ 5 | 6 | #ifndef SELF_H__ 7 | #define SELF_H__ 8 | 9 | #include 10 | #include 11 | 12 | #define SCE_MAGIC 0x53434500 13 | 14 | typedef struct { 15 | uint32_t magic; 16 | uint32_t version; 17 | uint16_t flags; 18 | uint16_t type; 19 | uint32_t metadata_offset; 20 | uint64_t header_len; 21 | uint64_t elf_filesize; 22 | uint64_t unknown; 23 | uint64_t appinfo_offset; 24 | uint64_t elf_offset; 25 | uint64_t phdr_offset; 26 | uint64_t shdr_offset; 27 | uint64_t section_info_offset; 28 | uint64_t sceversion_offset; 29 | uint64_t controlinfo_offset; 30 | uint64_t controlinfo_size; 31 | uint64_t padding; 32 | } __attribute__((packed)) SELF; 33 | 34 | typedef struct { 35 | uint64_t authid; 36 | uint32_t vendor_id; 37 | uint32_t self_type; 38 | uint32_t version; 39 | uint8_t padding[12]; 40 | } __attribute__((packed)) APP_INFO; 41 | 42 | typedef struct { 43 | uint8_t ident[16]; 44 | uint16_t type; 45 | uint16_t machine; 46 | uint32_t version; 47 | uint64_t entry_point; 48 | uint64_t phdr_offset; 49 | uint64_t shdr_offset; 50 | uint16_t flags; 51 | uint32_t header_size; 52 | uint16_t phent_size; 53 | uint16_t phnum; 54 | uint16_t shent_size; 55 | uint16_t shnum; 56 | uint16_t shstrndx; 57 | } __attribute__((packed)) ELF; 58 | 59 | typedef struct { 60 | uint32_t type; 61 | uint32_t flags; 62 | uint64_t offset_in_file; 63 | uint64_t vitual_addr; 64 | uint64_t phys_addr; 65 | uint64_t segment_size; 66 | uint64_t segment_mem_size; 67 | uint64_t alignment; 68 | } __attribute__((packed)) ELF_PHDR; 69 | 70 | typedef struct { 71 | uint32_t name_idx; 72 | uint32_t type; 73 | uint64_t flags; 74 | uint64_t virtual_addr; 75 | uint64_t offset_in_file; 76 | uint64_t segment_size; 77 | uint32_t link; 78 | uint32_t info; 79 | uint64_t addr_align; 80 | uint64_t entry_size; 81 | } __attribute__((packed)) ELF_SHDR; 82 | 83 | typedef struct { 84 | uint64_t offset; 85 | uint64_t size; 86 | uint32_t compressed; // 2=compressed 87 | uint32_t unknown1; 88 | uint32_t unknown2; 89 | uint32_t encrypted; // 1=encrypted 90 | } __attribute__((packed)) SECTION_INFO; 91 | 92 | typedef struct { 93 | uint32_t unknown1; 94 | uint32_t unknown2; 95 | uint32_t unknown3; 96 | uint32_t unknown4; 97 | } __attribute__((packed)) SCEVERSION_INFO; 98 | 99 | typedef struct { 100 | uint32_t type; // 1==control flags; 2==file digest 101 | uint32_t size; 102 | union { 103 | // type 1 104 | struct { 105 | uint64_t control_flags; 106 | uint8_t padding[32]; 107 | } control_flags; 108 | 109 | // type 2 110 | struct { 111 | uint64_t unknown; 112 | uint8_t digest1[20]; 113 | uint8_t digest2[20]; 114 | uint8_t padding[8]; 115 | } file_digest; 116 | 117 | struct { 118 | uint32_t unknown1; 119 | uint32_t unknown2; 120 | uint32_t magic; 121 | uint32_t unknown3; 122 | uint32_t license_type; 123 | uint32_t type; 124 | uint8_t content_id[0x30]; 125 | uint8_t hash[0x10]; 126 | uint8_t hash_iv[0x10]; 127 | uint8_t hash_xor[0x10]; 128 | uint8_t padding[0x10]; 129 | } npdrm; 130 | }; 131 | } __attribute__((packed)) CONTROL_INFO; 132 | 133 | 134 | typedef struct { 135 | //uint8_t ignore[32]; 136 | uint8_t key[16]; 137 | uint8_t key_pad[16]; 138 | uint8_t iv[16]; 139 | uint8_t iv_pad[16]; 140 | } __attribute__((packed)) METADATA_INFO; 141 | 142 | typedef struct { 143 | uint64_t signature_input_length; 144 | uint32_t unknown1; 145 | uint32_t section_count; 146 | uint32_t key_count; 147 | uint32_t signature_info_size; 148 | uint64_t unknown2; 149 | } __attribute__((packed)) METADATA_HEADER; 150 | 151 | typedef struct { 152 | uint64_t data_offset; 153 | uint64_t data_size; 154 | uint32_t type; // 1 = shdr, 2 == phdr 155 | uint32_t program_idx; 156 | uint32_t unknown; 157 | uint32_t sha1_idx; 158 | uint32_t encrypted; // 3=yes; 1=no 159 | uint32_t key_idx; 160 | uint32_t iv_idx; 161 | uint32_t compressed; // 2=yes; 1=no 162 | } __attribute__((packed)) METADATA_SECTION_HEADER; 163 | 164 | typedef struct { 165 | uint8_t sha1[20]; 166 | uint8_t padding[12]; 167 | uint8_t hmac_key[64]; 168 | } __attribute__((packed)) SECTION_HASH; 169 | 170 | typedef struct { 171 | uint32_t unknown1; 172 | uint32_t signature_size; 173 | uint64_t unknown2; 174 | uint64_t unknown3; 175 | uint64_t unknown4; 176 | uint64_t unknown5; 177 | uint32_t unknown6; 178 | uint32_t unknown7; 179 | } __attribute__((packed)) SIGNATURE_INFO; 180 | 181 | typedef struct { 182 | uint8_t r[21]; 183 | uint8_t s[21]; 184 | uint8_t padding[6]; 185 | } __attribute__((packed)) SIGNATURE; 186 | 187 | 188 | typedef struct { 189 | uint8_t *data; 190 | uint64_t size; 191 | uint64_t offset; 192 | } SELF_SECTION; 193 | 194 | 195 | 196 | void self_read_headers(FILE *in, SELF *self, APP_INFO *app_info, ELF *elf, 197 | ELF_PHDR **phdr, ELF_SHDR **shdr, SECTION_INFO **section_info, 198 | SCEVERSION_INFO *sceversion_info, CONTROL_INFO **control_info); 199 | 200 | void self_read_metadata (FILE *in, SELF *self, APP_INFO *app_info, 201 | METADATA_INFO *metadata_info, METADATA_HEADER *metadata_header, 202 | METADATA_SECTION_HEADER **section_headers, uint8_t **keys, 203 | SIGNATURE_INFO *signature_info, SIGNATURE *signature, CONTROL_INFO *control_info); 204 | 205 | int self_load_sections (FILE *in, SELF *self, ELF *elf, ELF_PHDR **phdr, 206 | METADATA_HEADER *metadata_header, METADATA_SECTION_HEADER **section_headers, 207 | uint8_t **keys, SELF_SECTION **sections); 208 | 209 | void self_free_sections (SELF_SECTION **sections, uint32_t num_sections); 210 | 211 | #endif /* SELF_H__ */ 212 | -------------------------------------------------------------------------------- /scekrit.c: -------------------------------------------------------------------------------- 1 | // SCEkrit.c (v1.01): Compute Sony's Private Keys 2 | // Based on Sven's sceverify.c 3 | // ------------------------------------------------------------- 4 | // Compile by copying to fail0verflow's ps3tools and add 5 | // SCEkrit.c to TOOLS in the Makefile. 6 | // Run with two files (selfs, pkgs) signed by the same key. 7 | // Depends on libgmp; add -lgmp to LDFLAGS 8 | // - Aaron Lindsay / @AerialX 9 | // And thanks gbcft! 10 | 11 | // Copyright 2010 Sven Peter 12 | // Licensed under the terms of the GNU GPL, version 2 13 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 14 | 15 | #include "tools.h" 16 | #include "types.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static int keyid = -1; 25 | 26 | static u8 *ptr1 = NULL; 27 | static u8 *ptr2 = NULL; 28 | 29 | static u16 type; 30 | typedef struct { 31 | u16 flags; 32 | u32 meta_offset; 33 | u64 info_offset; 34 | u32 app_type; 35 | u64 filesize; 36 | u64 header_len; 37 | } fileinfo; 38 | 39 | static fileinfo info1; 40 | static fileinfo info2; 41 | 42 | static struct keylist *klist = NULL; 43 | 44 | static struct keylist *self_load_keys(fileinfo* info) 45 | { 46 | enum sce_key id; 47 | 48 | switch (info->app_type) { 49 | case 1: 50 | id = KEY_LV0; 51 | break; 52 | case 2: 53 | id = KEY_LV1; 54 | break; 55 | case 3: 56 | id = KEY_LV2; 57 | break; 58 | case 4: 59 | id = KEY_APP; 60 | break; 61 | case 5: 62 | id = KEY_ISO; 63 | break; 64 | case 6: 65 | id = KEY_LDR; 66 | break; 67 | default: 68 | fail("invalid type: %08x", info->app_type); 69 | } 70 | 71 | return keys_get(id); 72 | } 73 | 74 | static void read_self_header(u8* ptr, fileinfo* info) 75 | { 76 | info->flags = be16(ptr + 0x08); 77 | info->meta_offset = be32(ptr + 0x0c); 78 | info->header_len = be64(ptr + 0x10); 79 | info->filesize = be64(ptr + 0x18); 80 | info->info_offset = be64(ptr + 0x28); 81 | 82 | info->app_type = be32(ptr + info->info_offset + 0x0c); 83 | 84 | klist = self_load_keys(info); 85 | } 86 | 87 | static void read_pkg_header(u8* ptr, fileinfo* info) 88 | { 89 | info->flags = be16(ptr + 0x08); 90 | info->meta_offset = be32(ptr + 0x0c); 91 | info->header_len = be64(ptr + 0x10); 92 | info->filesize = be64(ptr + 0x18); 93 | 94 | klist = keys_get(KEY_PKG); 95 | } 96 | 97 | static void decrypt(u8* ptr) 98 | { 99 | if (keyid < 0) 100 | keyid = sce_decrypt_header(ptr, klist); 101 | else if (keyid != sce_decrypt_header(ptr, klist)) 102 | fail("Both files must have the same key id"); 103 | 104 | if (keyid < 0) 105 | fail("sce_decrypt_header failed"); 106 | 107 | if (sce_decrypt_data(ptr) < 0) 108 | fail("sce_decrypt_data failed"); 109 | 110 | if (klist->keys[keyid].pub_avail < 0) 111 | fail("no public key available"); 112 | 113 | if (ecdsa_set_curve(klist->keys[keyid].ctype) < 0) 114 | fail("ecdsa_set_curve failed"); 115 | 116 | ecdsa_set_pub(klist->keys[keyid].pub); 117 | } 118 | 119 | static void verify_signature(u8* ptr, fileinfo* info, u8* hash, u8** s, u8** r) 120 | { 121 | u64 sig_len; 122 | 123 | sig_len = be64(ptr + info->meta_offset + 0x60); 124 | *r = ptr + sig_len; 125 | *s = *r + 21; 126 | 127 | sha1(ptr, sig_len, hash); 128 | 129 | printf("Signature\n"); 130 | if (ecdsa_verify(hash, *r, *s)) 131 | printf(" Status: OK\n"); 132 | else 133 | printf(" Status: FAIL\n"); 134 | } 135 | 136 | static void load_num(mpz_t n, u8* un) 137 | { 138 | char buffer[0x100]; 139 | char* ptr = buffer; 140 | int i; 141 | for (i = 0; i < 21; i++) { 142 | sprintf(ptr, "%02x", un[i]); 143 | ptr += 2; 144 | } 145 | mpz_set_str(n, buffer, 16); 146 | } 147 | 148 | static char* calculate_private_key(u8* us1, u8* us2, u8* uz1, u8* uz2, u8* un, u8* ur) 149 | { 150 | mpz_t s1, s2, z1, z2, n, r, k, dA; 151 | mpz_init(s1); mpz_init(s2); mpz_init(z1); mpz_init(z2); mpz_init(n); mpz_init(r); mpz_init(k); mpz_init(dA); 152 | load_num(s1, us1); load_num(s2, us2); load_num(z1, uz1); load_num(z2, uz2); load_num(n, un); load_num(r, ur); 153 | 154 | mpz_sub(z2, z1, z2); 155 | mpz_sub(s2, s1, s2); 156 | mpz_invert(s2, s2, n); 157 | mpz_mul(k, z2, s2); 158 | mpz_mod(k, k, n); 159 | 160 | mpz_mul(s2, s1, k); 161 | mpz_sub(s2, s2, z1); 162 | mpz_invert(r, r, n); 163 | mpz_mul(dA, s2, r); 164 | mpz_mod(dA, dA, n); 165 | 166 | // printf("k: %s\n", mpz_get_str(NULL, 16, k)); 167 | return mpz_get_str(NULL, 16, dA); 168 | } 169 | 170 | int main(int argc, char *argv[]) 171 | { 172 | if (argc != 3) 173 | fail("usage: scesekrit signedfile1 signedfile2"); 174 | 175 | ptr1 = mmap_file(argv[1]); 176 | ptr2 = mmap_file(argv[2]); 177 | 178 | type = be16(ptr1 + 0x0a); 179 | if (type != be16(ptr2 + 0x0a)) 180 | fail("Files must be the same type"); 181 | 182 | if (type == 1) { 183 | read_self_header(ptr1, &info1); 184 | } else if(type == 3) { 185 | read_pkg_header(ptr1, &info1); 186 | } else 187 | fail("Unknown type: %d", type); 188 | 189 | if ((info1.flags) & 0x8000) 190 | fail("devkit file; nothing to verify"); 191 | 192 | if (klist == NULL) 193 | fail("no key found"); 194 | 195 | decrypt(ptr1); 196 | 197 | if (type == 1) { 198 | read_self_header(ptr2, &info2); 199 | } else if(type == 3) { 200 | read_pkg_header(ptr2, &info2); 201 | } else 202 | fail("Unknown type: %d", type); 203 | 204 | if ((info2.flags) & 0x8000) 205 | fail("devkit file; nothing to verify"); 206 | 207 | if (klist == NULL) 208 | fail("no key found"); 209 | 210 | decrypt(ptr2); 211 | 212 | u8* s1; 213 | u8* s2; 214 | u8 z1[21]; 215 | u8 z2[21]; 216 | u8* r1; 217 | u8* r2; 218 | u8 ec[21]; 219 | u8 n[21]; 220 | z1[0] = 0; 221 | z2[0] = 0; 222 | 223 | ecdsa_get_params(klist->keys[keyid].ctype, ec, ec, ec, n, ec, ec); 224 | 225 | printf("%s ", argv[1]); 226 | verify_signature(ptr1, &info1, z1 + 1, &s1, &r1); 227 | printf("%s ", argv[2]); 228 | verify_signature(ptr2, &info2, z2 + 1, &s2, &r2); 229 | 230 | if (memcmp(r1, r2, 21)) 231 | fail("Both files must share the same r signature value."); 232 | 233 | const char* dA = calculate_private_key(s1, s2, z1, z2, n, r1); 234 | 235 | int len = strlen(dA); 236 | int i; 237 | printf("Private Key: "); 238 | for (i = len / 2; i < 21; i++) 239 | printf("00"); 240 | printf("%s\n", dA); 241 | 242 | return 0; 243 | } 244 | -------------------------------------------------------------------------------- /pkg.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | static struct key k; 17 | static FILE *fp; 18 | 19 | static u8 info0[0x40]; 20 | static u8 info1[0x40]; 21 | 22 | static u8 *content; 23 | static u64 content_size_real; 24 | static u64 content_size_compressed; 25 | 26 | static u8 sce_hdr[0x20]; 27 | static u8 meta_hdr[0x2a0]; 28 | 29 | static u8 *pkg; 30 | static u64 pkg_size; 31 | 32 | static void get_file(u8 *bfr, const char *name, u64 size) 33 | { 34 | FILE *fp; 35 | 36 | fp = fopen(name, "rb"); 37 | if (fp == NULL) 38 | fail("fopen(%s) failed", name); 39 | 40 | fread(bfr, size, 1, fp); 41 | fclose(fp); 42 | } 43 | 44 | static void get_content(void) 45 | { 46 | u8 *base; 47 | uLongf size_zlib; 48 | int res; 49 | struct stat st; 50 | 51 | base = mmap_file("content"); 52 | 53 | if (stat("content", &st) < 0) 54 | fail("stat(content) failed"); 55 | 56 | content_size_real = st.st_size; 57 | content_size_compressed = compressBound(content_size_real); 58 | size_zlib = content_size_compressed; 59 | 60 | content = malloc(content_size_compressed); 61 | if (!content) 62 | fail("out of memory"); 63 | 64 | res = compress(content, &size_zlib, base, content_size_real); 65 | if (res != Z_OK) 66 | fail("compress returned %d", res); 67 | 68 | content_size_compressed = size_zlib; 69 | content = realloc(content, content_size_compressed); 70 | if (!content) 71 | fail("out of memory"); 72 | } 73 | 74 | static void get_key(const char *suffix) 75 | { 76 | if (key_get(KEY_PKG, suffix, &k) < 0) 77 | fail("key_get() failed"); 78 | 79 | if (k.pub_avail < 0) 80 | fail("no public key available"); 81 | 82 | if (k.priv_avail < 0) 83 | fail("no private key available"); 84 | 85 | if (ecdsa_set_curve(k.ctype) < 0) 86 | fail("ecdsa_set_curve failed"); 87 | 88 | ecdsa_set_pub(k.pub); 89 | ecdsa_set_priv(k.priv); 90 | } 91 | 92 | static void build_sce_hdr(void) 93 | { 94 | memset(sce_hdr, 0, sizeof sce_hdr); 95 | 96 | wbe32(sce_hdr + 0x00, 0x53434500); // magic 97 | wbe32(sce_hdr + 0x04, 2); // version 98 | wbe16(sce_hdr + 0x08, 0); // dunno, sdk type? 99 | wbe16(sce_hdr + 0x0a, 3); // SCE header type; pkg 100 | wbe32(sce_hdr + 0x0c, 0); // meta offset 101 | wbe64(sce_hdr + 0x10, sizeof sce_hdr + sizeof meta_hdr); 102 | wbe64(sce_hdr + 0x18, 0x80 + content_size_real); 103 | } 104 | 105 | static void build_meta_hdr(void) 106 | { 107 | u8 *ptr; 108 | 109 | memset(meta_hdr, 0, sizeof meta_hdr); 110 | ptr = meta_hdr; 111 | 112 | // keys for metadata encryptiomn 113 | get_rand(ptr, 0x10); 114 | get_rand(ptr + 0x20, 0x10); 115 | ptr += 0x40; 116 | 117 | // area covered by the signature 118 | wbe64(ptr + 0x00, sizeof sce_hdr + sizeof meta_hdr - 0x30); 119 | wbe32(ptr + 0x0c, 3); // number of encrypted headers 120 | wbe32(ptr + 0x10, 3 * 8); // number of keys/hashes required 121 | ptr += 0x20; 122 | 123 | // first info header 124 | wbe64(ptr + 0x00, 0x2c0); // offset 125 | wbe64(ptr + 0x08, 0x40); // size 126 | wbe32(ptr + 0x10, 1); // unknown 127 | wbe32(ptr + 0x14, 1); // index 128 | wbe32(ptr + 0x18, 2); // unknown again 129 | wbe32(ptr + 0x1c, 0); // sha index 130 | wbe32(ptr + 0x20, 1); // no encryption 131 | wbe32(ptr + 0x24, 0xffffffff); // key index 132 | wbe32(ptr + 0x28, 0xffffffff); // iv index 133 | wbe32(ptr + 0x2c, 0x1); // no compression 134 | ptr += 0x30; 135 | 136 | // second info header 137 | wbe64(ptr + 0x00, 0x300); // offset 138 | wbe64(ptr + 0x08, 0x40); // size 139 | wbe32(ptr + 0x10, 2); // unknown 140 | wbe32(ptr + 0x14, 2); // index 141 | wbe32(ptr + 0x18, 2); // unknown again 142 | wbe32(ptr + 0x1c, 8); // sha index 143 | wbe32(ptr + 0x20, 1); // no encryption 144 | wbe32(ptr + 0x24, 0xffffffff); // key index 145 | wbe32(ptr + 0x28, 0xffffffff); // iv index 146 | wbe32(ptr + 0x2c, 0x1); // no compression 147 | ptr += 0x30; 148 | 149 | // package files 150 | wbe64(ptr + 0x00, 0x340); // offset 151 | wbe64(ptr + 0x08, content_size_compressed); 152 | wbe32(ptr + 0x10, 3); // unknown 153 | wbe32(ptr + 0x14, 3); // index 154 | wbe32(ptr + 0x18, 2); // unknown again 155 | wbe32(ptr + 0x1c, 16); // sha index 156 | wbe32(ptr + 0x20, 3); // encrypted 157 | wbe32(ptr + 0x24, 22); // key index 158 | wbe32(ptr + 0x28, 23); // iv index 159 | wbe32(ptr + 0x2c, 2); // compressed 160 | ptr += 0x30; 161 | 162 | // add keys/ivs and hmac keys 163 | get_rand(ptr, 3 * 8 * 0x10); 164 | } 165 | 166 | static void fix_info_hdr(void) 167 | { 168 | wbe64(info0 + 0x18, content_size_real); 169 | wbe64(info0 + 0x20, content_size_compressed); 170 | wbe64(info1 + 0x18, content_size_real); 171 | wbe64(info1 + 0x20, content_size_compressed); 172 | } 173 | 174 | static void build_pkg(void) 175 | { 176 | pkg_size = sizeof sce_hdr + sizeof meta_hdr + 0x80; 177 | pkg_size += content_size_compressed; 178 | pkg_size = round_up(pkg_size, 0x100); 179 | 180 | pkg = malloc(pkg_size); 181 | if (!pkg) 182 | fail("out of memory"); 183 | 184 | memset(pkg, 0xaa, pkg_size); 185 | memcpy(pkg, sce_hdr, 0x20); 186 | memcpy(pkg + 0x20, meta_hdr, 0x2a0); 187 | memcpy(pkg + 0x2c0, info0, 0x40); 188 | memcpy(pkg + 0x300, info1, 0x40); 189 | memcpy(pkg + 0x340, content, content_size_compressed); 190 | } 191 | 192 | static void calculate_hash(u8 *data, u64 len, u8 *digest) 193 | { 194 | memset(digest, 0, 0x20); 195 | sha1_hmac(digest + 0x20, data, len, digest); 196 | } 197 | 198 | static void hash_pkg(void) 199 | { 200 | calculate_hash(pkg + 0x2c0, 0x40, pkg + 0x80 + 3*0x30); 201 | calculate_hash(pkg + 0x300, 0x40, pkg + 0x80 + 3*0x30 + 8*0x10); 202 | calculate_hash(pkg + 0x340, content_size_compressed, 203 | pkg + 0x80 + 3*0x30 + 16*0x10); 204 | } 205 | 206 | static void sign_pkg(void) 207 | { 208 | u8 *r, *s; 209 | u8 hash[20]; 210 | u64 sig_len; 211 | 212 | sig_len = be64(pkg + 0x60); 213 | r = pkg + sig_len; 214 | s = r + 21; 215 | 216 | sha1(pkg, sig_len, hash); 217 | 218 | ecdsa_sign(hash, r, s); 219 | } 220 | 221 | int main(int argc, char *argv[]) 222 | { 223 | if (argc != 4) 224 | fail("usage: pkg [key suffix] [contents] [filename.pkg]"); 225 | 226 | fp = fopen(argv[3], "wb"); 227 | if (fp == NULL) 228 | fail("fopen(%s) failed", argv[3]); 229 | 230 | if (chdir(argv[2]) < 0) 231 | fail("chdir"); 232 | 233 | get_key(argv[1]); 234 | get_file(info0, "info0", 0x40); 235 | get_file(info1, "info1", 0x40); 236 | get_content(); 237 | 238 | build_sce_hdr(); 239 | build_meta_hdr(); 240 | fix_info_hdr(); 241 | 242 | build_pkg(); 243 | hash_pkg(); 244 | sign_pkg(); 245 | 246 | sce_encrypt_data(pkg); 247 | sce_encrypt_header(pkg, &k); 248 | 249 | fwrite(pkg, pkg_size, 1, fp); 250 | fclose(fp); 251 | 252 | return 0; 253 | } 254 | -------------------------------------------------------------------------------- /ec.c: -------------------------------------------------------------------------------- 1 | // Copyright 2007,2008,2010 Segher Boessenkool 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include 6 | #include 7 | 8 | #include "tools.h" 9 | 10 | struct point { 11 | u8 x[20]; 12 | u8 y[20]; 13 | }; 14 | 15 | static u8 ec_p[20]; 16 | static u8 ec_a[20]; // mon 17 | static u8 ec_b[20]; // mon 18 | static u8 ec_N[21]; 19 | static struct point ec_G; // mon 20 | static struct point ec_Q; // mon 21 | static u8 ec_k[21]; 22 | 23 | static void elt_copy(u8 *d, u8 *a) 24 | { 25 | memcpy(d, a, 20); 26 | } 27 | 28 | static void elt_zero(u8 *d) 29 | { 30 | memset(d, 0, 20); 31 | } 32 | 33 | static int elt_is_zero(u8 *d) 34 | { 35 | u32 i; 36 | 37 | for (i = 0; i < 20; i++) 38 | if (d[i] != 0) 39 | return 0; 40 | 41 | return 1; 42 | } 43 | 44 | static void elt_add(u8 *d, u8 *a, u8 *b) 45 | { 46 | bn_add(d, a, b, ec_p, 20); 47 | } 48 | 49 | static void elt_sub(u8 *d, u8 *a, u8 *b) 50 | { 51 | bn_sub(d, a, b, ec_p, 20); 52 | } 53 | 54 | static void elt_mul(u8 *d, u8 *a, u8 *b) 55 | { 56 | bn_mon_mul(d, a, b, ec_p, 20); 57 | } 58 | 59 | static void elt_square(u8 *d, u8 *a) 60 | { 61 | elt_mul(d, a, a); 62 | } 63 | 64 | static void elt_inv(u8 *d, u8 *a) 65 | { 66 | u8 s[20]; 67 | elt_copy(s, a); 68 | bn_mon_inv(d, s, ec_p, 20); 69 | } 70 | 71 | static void point_to_mon(struct point *p) 72 | { 73 | bn_to_mon(p->x, ec_p, 20); 74 | bn_to_mon(p->y, ec_p, 20); 75 | } 76 | 77 | static void point_from_mon(struct point *p) 78 | { 79 | bn_from_mon(p->x, ec_p, 20); 80 | bn_from_mon(p->y, ec_p, 20); 81 | } 82 | 83 | #if 0 84 | static int point_is_on_curve(u8 *p) 85 | { 86 | u8 s[20], t[20]; 87 | u8 *x, *y; 88 | 89 | x = p; 90 | y = p + 20; 91 | 92 | elt_square(t, x); 93 | elt_mul(s, t, x); 94 | 95 | elt_mul(t, x, ec_a); 96 | elt_add(s, s, t); 97 | 98 | elt_add(s, s, ec_b); 99 | 100 | elt_square(t, y); 101 | elt_sub(s, s, t); 102 | 103 | return elt_is_zero(s); 104 | } 105 | #endif 106 | 107 | static void point_zero(struct point *p) 108 | { 109 | elt_zero(p->x); 110 | elt_zero(p->y); 111 | } 112 | 113 | static int point_is_zero(struct point *p) 114 | { 115 | return elt_is_zero(p->x) && elt_is_zero(p->y); 116 | } 117 | 118 | static void point_double(struct point *r, struct point *p) 119 | { 120 | u8 s[20], t[20]; 121 | struct point pp; 122 | u8 *px, *py, *rx, *ry; 123 | 124 | pp = *p; 125 | 126 | px = pp.x; 127 | py = pp.y; 128 | rx = r->x; 129 | ry = r->y; 130 | 131 | if (elt_is_zero(py)) { 132 | point_zero(r); 133 | return; 134 | } 135 | 136 | elt_square(t, px); // t = px*px 137 | elt_add(s, t, t); // s = 2*px*px 138 | elt_add(s, s, t); // s = 3*px*px 139 | elt_add(s, s, ec_a); // s = 3*px*px + a 140 | elt_add(t, py, py); // t = 2*py 141 | elt_inv(t, t); // t = 1/(2*py) 142 | elt_mul(s, s, t); // s = (3*px*px+a)/(2*py) 143 | 144 | elt_square(rx, s); // rx = s*s 145 | elt_add(t, px, px); // t = 2*px 146 | elt_sub(rx, rx, t); // rx = s*s - 2*px 147 | 148 | elt_sub(t, px, rx); // t = -(rx-px) 149 | elt_mul(ry, s, t); // ry = -s*(rx-px) 150 | elt_sub(ry, ry, py); // ry = -s*(rx-px) - py 151 | } 152 | 153 | static void point_add(struct point *r, struct point *p, struct point *q) 154 | { 155 | u8 s[20], t[20], u[20]; 156 | u8 *px, *py, *qx, *qy, *rx, *ry; 157 | struct point pp, qq; 158 | 159 | pp = *p; 160 | qq = *q; 161 | 162 | px = pp.x; 163 | py = pp.y; 164 | qx = qq.x; 165 | qy = qq.y; 166 | rx = r->x; 167 | ry = r->y; 168 | 169 | if (point_is_zero(&pp)) { 170 | elt_copy(rx, qx); 171 | elt_copy(ry, qy); 172 | return; 173 | } 174 | 175 | if (point_is_zero(&qq)) { 176 | elt_copy(rx, px); 177 | elt_copy(ry, py); 178 | return; 179 | } 180 | 181 | elt_sub(u, qx, px); 182 | 183 | if (elt_is_zero(u)) { 184 | elt_sub(u, qy, py); 185 | if (elt_is_zero(u)) 186 | point_double(r, &pp); 187 | else 188 | point_zero(r); 189 | 190 | return; 191 | } 192 | 193 | elt_inv(t, u); // t = 1/(qx-px) 194 | elt_sub(u, qy, py); // u = qy-py 195 | elt_mul(s, t, u); // s = (qy-py)/(qx-px) 196 | 197 | elt_square(rx, s); // rx = s*s 198 | elt_add(t, px, qx); // t = px+qx 199 | elt_sub(rx, rx, t); // rx = s*s - (px+qx) 200 | 201 | elt_sub(t, px, rx); // t = -(rx-px) 202 | elt_mul(ry, s, t); // ry = -s*(rx-px) 203 | elt_sub(ry, ry, py); // ry = -s*(rx-px) - py 204 | } 205 | 206 | static void point_mul(struct point *d, u8 *a, struct point *b) // a is bignum 207 | { 208 | u32 i; 209 | u8 mask; 210 | 211 | point_zero(d); 212 | 213 | for (i = 0; i < 21; i++) 214 | for (mask = 0x80; mask != 0; mask >>= 1) { 215 | point_double(d, d); 216 | if ((a[i] & mask) != 0) 217 | point_add(d, d, b); 218 | } 219 | } 220 | 221 | static void generate_ecdsa(u8 *R, u8 *S, u8 *k, u8 *hash) 222 | { 223 | u8 e[21]; 224 | u8 kk[21]; 225 | u8 m[21]; 226 | u8 minv[21]; 227 | struct point mG; 228 | 229 | e[0] = 0; 230 | memcpy(e + 1, hash, 20); 231 | bn_reduce(e, ec_N, 21); 232 | 233 | try_again: 234 | 235 | get_rand(m, sizeof m); 236 | m[0] = 0; 237 | if (bn_compare(m, ec_N, 21) >= 0) 238 | goto try_again; 239 | 240 | // R = (mG).x 241 | 242 | point_mul(&mG, m, &ec_G); 243 | point_from_mon(&mG); 244 | R[0] = 0; 245 | elt_copy(R+1, mG.x); 246 | 247 | // S = m**-1*(e + Rk) (mod N) 248 | 249 | bn_copy(kk, k, 21); 250 | bn_reduce(kk, ec_N, 21); 251 | bn_to_mon(m, ec_N, 21); 252 | bn_to_mon(e, ec_N, 21); 253 | bn_to_mon(R, ec_N, 21); 254 | bn_to_mon(kk, ec_N, 21); 255 | 256 | bn_mon_mul(S, R, kk, ec_N, 21); 257 | bn_add(kk, S, e, ec_N, 21); 258 | bn_mon_inv(minv, m, ec_N, 21); 259 | bn_mon_mul(S, minv, kk, ec_N, 21); 260 | 261 | bn_from_mon(R, ec_N, 21); 262 | bn_from_mon(S, ec_N, 21); 263 | } 264 | 265 | static int check_ecdsa(struct point *Q, u8 *R, u8 *S, u8 *hash) 266 | { 267 | u8 Sinv[21]; 268 | u8 e[21]; 269 | u8 w1[21], w2[21]; 270 | struct point r1, r2; 271 | u8 rr[21]; 272 | 273 | e[0] = 0; 274 | memcpy(e + 1, hash, 20); 275 | bn_reduce(e, ec_N, 21); 276 | 277 | bn_to_mon(R, ec_N, 21); 278 | bn_to_mon(S, ec_N, 21); 279 | bn_to_mon(e, ec_N, 21); 280 | 281 | bn_mon_inv(Sinv, S, ec_N, 21); 282 | 283 | bn_mon_mul(w1, e, Sinv, ec_N, 21); 284 | bn_mon_mul(w2, R, Sinv, ec_N, 21); 285 | 286 | bn_from_mon(w1, ec_N, 21); 287 | bn_from_mon(w2, ec_N, 21); 288 | 289 | point_mul(&r1, w1, &ec_G); 290 | point_mul(&r2, w2, Q); 291 | 292 | point_add(&r1, &r1, &r2); 293 | 294 | point_from_mon(&r1); 295 | 296 | rr[0] = 0; 297 | memcpy(rr + 1, r1.x, 20); 298 | bn_reduce(rr, ec_N, 21); 299 | 300 | bn_from_mon(R, ec_N, 21); 301 | bn_from_mon(S, ec_N, 21); 302 | 303 | return (bn_compare(rr, R, 21) == 0); 304 | } 305 | 306 | #if 0 307 | static void ec_priv_to_pub(u8 *k, u8 *Q) 308 | { 309 | point_mul(Q, k, ec_G); 310 | } 311 | #endif 312 | 313 | int ecdsa_set_curve(u32 type) 314 | { 315 | if (ecdsa_get_params(type, ec_p, ec_a, ec_b, ec_N, ec_G.x, ec_G.y) < 0) 316 | return -1; 317 | 318 | bn_to_mon(ec_a, ec_p, 20); 319 | bn_to_mon(ec_b, ec_p, 20); 320 | 321 | point_to_mon(&ec_G); 322 | 323 | return 0; 324 | } 325 | 326 | void ecdsa_set_pub(u8 *Q) 327 | { 328 | memcpy(ec_Q.x, Q, 20); 329 | memcpy(ec_Q.y, Q+20, 20); 330 | point_to_mon(&ec_Q); 331 | } 332 | 333 | void ecdsa_set_priv(u8 *k) 334 | { 335 | memcpy(ec_k, k, sizeof ec_k); 336 | } 337 | 338 | int ecdsa_verify(u8 *hash, u8 *R, u8 *S) 339 | { 340 | return check_ecdsa(&ec_Q, R, S, hash); 341 | } 342 | 343 | void ecdsa_sign(u8 *hash, u8 *R, u8 *S) 344 | { 345 | generate_ecdsa(R, S, ec_k, hash); 346 | } 347 | -------------------------------------------------------------------------------- /unself.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define MAX_SECTIONS 255 14 | 15 | static u8 *self = NULL; 16 | static u8 *elf = NULL; 17 | static FILE *out = NULL; 18 | 19 | static u64 info_offset; 20 | static u32 key_ver; 21 | static u64 phdr_offset; 22 | static u64 shdr_offset; 23 | static u64 sec_offset; 24 | static u64 ver_offset; 25 | static u64 version; 26 | static u64 elf_offset; 27 | static u64 meta_offset; 28 | static u64 header_len; 29 | static u64 filesize; 30 | static u32 arch64; 31 | static u32 n_sections; 32 | 33 | static struct elf_hdr ehdr; 34 | 35 | static u32 app_type; 36 | 37 | static struct { 38 | u32 offset; 39 | u32 size; 40 | u32 compressed; 41 | u32 size_uncompressed; 42 | u32 elf_offset; 43 | } self_sections[MAX_SECTIONS]; 44 | 45 | static void read_header(void) 46 | { 47 | key_ver = be16(self + 0x08); 48 | meta_offset = be32(self + 0x0c); 49 | header_len = be64(self + 0x10); 50 | filesize = be64(self + 0x18); 51 | info_offset = be64(self + 0x28); 52 | elf_offset = be64(self + 0x30); 53 | phdr_offset = be64(self + 0x38) - elf_offset; 54 | shdr_offset = be64(self + 0x40) - elf_offset; 55 | sec_offset = be64(self + 0x48); 56 | ver_offset = be64(self + 0x50); 57 | 58 | version = be64(self + info_offset + 0x10); 59 | app_type = be32(self + info_offset + 0x0c); 60 | 61 | elf = self + elf_offset; 62 | arch64 = elf_read_hdr(elf, &ehdr); 63 | } 64 | 65 | struct self_sec { 66 | u32 idx; 67 | u64 offset; 68 | u64 size; 69 | u32 compressed; 70 | u32 encrypted; 71 | u64 next; 72 | }; 73 | 74 | static void read_section(u32 i, struct self_sec *sec) 75 | { 76 | u8 *ptr; 77 | 78 | ptr = self + sec_offset + i*0x20; 79 | 80 | sec->idx = i; 81 | sec->offset = be64(ptr + 0x00); 82 | sec->size = be64(ptr + 0x08); 83 | sec->compressed = be32(ptr + 0x10) == 2 ? 1 : 0; 84 | sec->encrypted = be32(ptr + 0x1c); 85 | sec->next = be64(ptr + 0x20); 86 | } 87 | 88 | static int qsort_compare(const void *a, const void *b) 89 | { 90 | const struct self_sec *sa, *sb; 91 | sa = a; 92 | sb = b; 93 | 94 | if (sa->offset > sb->offset) 95 | return 1; 96 | else if(sa->offset < sb->offset) 97 | return -1; 98 | else 99 | return 0; 100 | } 101 | 102 | static void read_sections(void) 103 | { 104 | struct self_sec s[MAX_SECTIONS]; 105 | struct elf_phdr p; 106 | u32 i; 107 | u32 j; 108 | u32 n_secs; 109 | u32 self_offset, elf_offset; 110 | 111 | memset(s, 0, sizeof s); 112 | for (i = 0, j = 0; i < ehdr.e_phnum; i++) { 113 | read_section(i, &s[j]); 114 | if (s[j].compressed) 115 | j++; 116 | } 117 | 118 | n_secs = j; 119 | qsort(s, n_secs, sizeof(*s), qsort_compare); 120 | 121 | elf_offset = 0; 122 | self_offset = header_len; 123 | j = 0; 124 | i = 0; 125 | while (elf_offset < filesize) { 126 | if (i == n_secs) { 127 | self_sections[j].offset = self_offset; 128 | self_sections[j].size = filesize - elf_offset; 129 | self_sections[j].compressed = 0; 130 | self_sections[j].size_uncompressed = filesize - elf_offset; 131 | self_sections[j].elf_offset = elf_offset; 132 | elf_offset = filesize; 133 | } else if (self_offset == s[i].offset) { 134 | self_sections[j].offset = self_offset; 135 | self_sections[j].size = s[i].size; 136 | self_sections[j].compressed = 1; 137 | elf_read_phdr(arch64, elf + phdr_offset + 138 | (ehdr.e_phentsize * s[i].idx), &p); 139 | self_sections[j].size_uncompressed = p.p_filesz; 140 | self_sections[j].elf_offset = p.p_off; 141 | 142 | elf_offset = p.p_off + p.p_filesz; 143 | self_offset = s[i].next; 144 | i++; 145 | } else { 146 | elf_read_phdr(arch64, elf + phdr_offset + 147 | (ehdr.e_phentsize * s[i].idx), &p); 148 | self_sections[j].offset = self_offset; 149 | self_sections[j].size = p.p_off - elf_offset; 150 | self_sections[j].compressed = 0; 151 | self_sections[j].size_uncompressed = self_sections[j].size; 152 | self_sections[j].elf_offset = elf_offset; 153 | 154 | elf_offset += self_sections[j].size; 155 | self_offset += s[i].offset - self_offset; 156 | } 157 | j++; 158 | } 159 | 160 | n_sections = j; 161 | } 162 | 163 | static void write_elf(void) 164 | { 165 | u32 i; 166 | u8 *bfr; 167 | u32 size; 168 | u32 offset = 0; 169 | 170 | for (i = 0; i < n_sections; i++) { 171 | fseek(out, self_sections[i].elf_offset, SEEK_SET); 172 | offset = self_sections[i].elf_offset; 173 | if (self_sections[i].compressed) { 174 | size = self_sections[i].size_uncompressed; 175 | 176 | bfr = malloc(size); 177 | if (bfr == NULL) 178 | fail("failed to allocate %d bytes", size); 179 | 180 | offset += size; 181 | 182 | printf("compressed self_sections[i].offset 0x%x self_sections[i].size 0x%x\n", 183 | self_sections[i].offset,self_sections[i].size); 184 | 185 | 186 | decompress(self + self_sections[i].offset, 187 | self_sections[i].size, 188 | bfr, size); 189 | fwrite(bfr, size, 1, out); 190 | free(bfr); 191 | } else { 192 | bfr = self + self_sections[i].offset; 193 | size = self_sections[i].size; 194 | offset += size; 195 | 196 | fwrite(bfr, size, 1, out); 197 | } 198 | } 199 | } 200 | 201 | static void remove_shnames(u64 shdr_offset, u16 n_shdr, u64 shstrtab_offset, u32 strtab_size) 202 | { 203 | u16 i; 204 | u32 size; 205 | struct elf_shdr s; 206 | 207 | if (arch64) 208 | size = 0x40; 209 | else 210 | size = 0x28; 211 | 212 | for (i = 0; i < n_shdr; i++) { 213 | elf_read_shdr(arch64, elf + shdr_offset + i * size, &s); 214 | 215 | s.sh_name = 0; 216 | if (s.sh_type == 3) { 217 | s.sh_offset = shstrtab_offset; 218 | s.sh_size = strtab_size; 219 | } 220 | 221 | elf_write_shdr(arch64, elf + shdr_offset + i * size, &s); 222 | } 223 | } 224 | 225 | static void check_elf(void) 226 | { 227 | u8 bfr[0x48]; 228 | u64 elf_offset; 229 | u64 phdr_offset; 230 | u64 shdr_offset; 231 | u64 phdr_offset_new; 232 | u64 shdr_offset_new; 233 | u64 shstrtab_offset; 234 | u16 n_phdr; 235 | u16 n_shdr; 236 | const char shstrtab[] = ".unknown\0\0"; 237 | const char elf_magic[4] = {0x7f, 'E', 'L', 'F'}; 238 | 239 | fseek(out, 0, SEEK_SET); 240 | fread(bfr, 4, 1, out); 241 | 242 | if (memcmp(bfr, elf_magic, sizeof elf_magic) == 0) 243 | return; 244 | 245 | elf_offset = be64(self + 0x30); 246 | phdr_offset = be64(self + 0x38) - elf_offset; 247 | shdr_offset = be64(self + 0x40) - elf_offset; 248 | 249 | if (arch64) { 250 | fseek(out, 0x48, SEEK_SET); 251 | phdr_offset_new = 0x48; 252 | 253 | fseek(out, 0, SEEK_END); 254 | shdr_offset_new = ftell(out); 255 | 256 | n_phdr = be16(elf + 0x38); 257 | n_shdr = be16(elf + 0x3c); 258 | shstrtab_offset = shdr_offset_new + n_shdr * 0x40; 259 | 260 | remove_shnames(shdr_offset, n_shdr, shstrtab_offset, sizeof shstrtab); 261 | 262 | fseek(out, phdr_offset_new, SEEK_SET); 263 | fwrite(elf + phdr_offset, 0x38, n_phdr, out); 264 | 265 | fseek(out, shdr_offset_new, SEEK_SET); 266 | fwrite(elf + shdr_offset, 0x40, n_shdr, out); 267 | 268 | wbe64(elf + 0x20, phdr_offset_new); 269 | wbe64(elf + 0x28, shdr_offset_new); 270 | 271 | fseek(out, SEEK_SET, 0); 272 | fwrite(elf, 0x48, 1, out); 273 | 274 | fseek(out, shstrtab_offset, SEEK_SET); 275 | fwrite(shstrtab, sizeof shstrtab, 1, out); 276 | } else { 277 | fseek(out, 0x34, SEEK_SET); 278 | phdr_offset_new = 0x34; 279 | fseek(out, 0, SEEK_END); 280 | shdr_offset_new = ftell(out); 281 | 282 | n_phdr = be16(elf + 0x2c); 283 | n_shdr = be16(elf + 0x30); 284 | shstrtab_offset = shdr_offset_new + n_shdr * 0x40; 285 | 286 | remove_shnames(shdr_offset, n_shdr, shstrtab_offset, sizeof shstrtab); 287 | 288 | fseek(out, phdr_offset_new, SEEK_SET); 289 | fwrite(elf + phdr_offset, 0x20, n_phdr, out); 290 | 291 | fseek(out, shdr_offset_new, SEEK_SET); 292 | fwrite(elf + shdr_offset, 0x28, n_shdr, out); 293 | 294 | wbe32(elf + 0x1c, phdr_offset_new); 295 | wbe32(elf + 0x20, shdr_offset_new); 296 | 297 | fseek(out, SEEK_SET, 0); 298 | fwrite(elf, 0x34, 1, out); 299 | 300 | fseek(out, shstrtab_offset, SEEK_SET); 301 | fwrite(shstrtab, sizeof shstrtab, 1, out); 302 | } 303 | } 304 | 305 | static struct keylist *self_load_keys(void) 306 | { 307 | enum sce_key id; 308 | 309 | switch (app_type) { 310 | case 1: 311 | id = KEY_LV0; 312 | break; 313 | case 2: 314 | id = KEY_LV1; 315 | break; 316 | case 3: 317 | id = KEY_LV2; 318 | break; 319 | case 4: 320 | id = KEY_APP; 321 | break; 322 | case 5: 323 | id = KEY_ISO; 324 | break; 325 | case 6: 326 | id = KEY_LDR; 327 | break; 328 | case 8: 329 | id = KEY_NPDRM; 330 | break; 331 | default: 332 | fail("invalid type: %08x", app_type); 333 | } 334 | 335 | return keys_get(id); 336 | } 337 | 338 | static void self_decrypt(void) 339 | { 340 | struct keylist *klist; 341 | 342 | klist = self_load_keys(); 343 | if (klist == NULL) 344 | fail("no key found"); 345 | 346 | if (sce_remove_npdrm(self, klist) < 0) 347 | fail("self_remove_npdrm failed"); 348 | 349 | if (sce_decrypt_header(self, klist) < 0) 350 | fail("self_decrypt_header failed"); 351 | 352 | if (sce_decrypt_data(self) < 0) 353 | fail("self_decrypt_data failed"); 354 | } 355 | 356 | int main(int argc, char *argv[]) 357 | { 358 | if (argc != 3) 359 | fail("usage: unself in.self out.elf"); 360 | 361 | self = mmap_file(argv[1]); 362 | 363 | if (be32(self) != 0x53434500) 364 | fail("not a SELF"); 365 | 366 | read_header(); 367 | read_sections(); 368 | 369 | if (key_ver != 0x8000) 370 | self_decrypt(); 371 | 372 | out = fopen(argv[2], "wb+"); 373 | 374 | write_elf(); 375 | check_elf(); 376 | 377 | fclose(out); 378 | 379 | return 0; 380 | } 381 | -------------------------------------------------------------------------------- /sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.c 3 | * 4 | * Copyright (C) 1998 5 | * Paul E. Jones 6 | * All Rights Reserved 7 | * 8 | * This software is licensed as "freeware." Permission to distribute 9 | * this software in source and binary forms is hereby granted without 10 | * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED 11 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 12 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 13 | * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING 14 | * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, 15 | * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. 16 | * 17 | ***************************************************************************** 18 | * $Id: sha1.c,v 1.2 2004/03/27 18:00:33 paulej Exp $ 19 | ***************************************************************************** 20 | * 21 | * Description: 22 | * This file implements the Secure Hashing Standard as defined 23 | * in FIPS PUB 180-1 published April 17, 1995. 24 | * 25 | * The Secure Hashing Standard, which uses the Secure Hashing 26 | * Algorithm (SHA), produces a 160-bit message digest for a 27 | * given data stream. In theory, it is highly improbable that 28 | * two messages will produce the same message digest. Therefore, 29 | * this algorithm can serve as a means of providing a "fingerprint" 30 | * for a message. 31 | * 32 | * Portability Issues: 33 | * SHA-1 is defined in terms of 32-bit "words". This code was 34 | * written with the expectation that the processor has at least 35 | * a 32-bit machine word size. If the machine word size is larger, 36 | * the code should still function properly. One caveat to that 37 | * is that the input functions taking characters and character 38 | * arrays assume that only 8 bits of information are stored in each 39 | * character. 40 | * 41 | * Caveats: 42 | * SHA-1 is designed to work with messages less than 2^64 bits 43 | * long. Although SHA-1 allows a message digest to be generated for 44 | * messages of any number of bits less than 2^64, this 45 | * implementation only works with messages with a length that is a 46 | * multiple of the size of an 8-bit character. 47 | * 48 | */ 49 | 50 | #include "sha1.h" 51 | 52 | /* 53 | * Define the circular shift macro 54 | */ 55 | #define SHA1CircularShift(bits,word) \ 56 | ((((word) << (bits)) & 0xFFFFFFFF) | \ 57 | ((word) >> (32-(bits)))) 58 | 59 | /* Function prototypes */ 60 | void SHA1ProcessMessageBlock(SHA1Context *); 61 | void SHA1PadMessage(SHA1Context *); 62 | 63 | /* 64 | * SHA1Reset 65 | * 66 | * Description: 67 | * This function will initialize the SHA1Context in preparation 68 | * for computing a new message digest. 69 | * 70 | * Parameters: 71 | * context: [in/out] 72 | * The context to reset. 73 | * 74 | * Returns: 75 | * Nothing. 76 | * 77 | * Comments: 78 | * 79 | */ 80 | void SHA1Reset(SHA1Context *context) 81 | { 82 | context->Length_Low = 0; 83 | context->Length_High = 0; 84 | context->Message_Block_Index = 0; 85 | 86 | context->Message_Digest[0] = 0x67452301; 87 | context->Message_Digest[1] = 0xEFCDAB89; 88 | context->Message_Digest[2] = 0x98BADCFE; 89 | context->Message_Digest[3] = 0x10325476; 90 | context->Message_Digest[4] = 0xC3D2E1F0; 91 | 92 | context->Computed = 0; 93 | context->Corrupted = 0; 94 | } 95 | 96 | /* 97 | * SHA1Result 98 | * 99 | * Description: 100 | * This function will return the 160-bit message digest into the 101 | * Message_Digest array within the SHA1Context provided 102 | * 103 | * Parameters: 104 | * context: [in/out] 105 | * The context to use to calculate the SHA-1 hash. 106 | * 107 | * Returns: 108 | * 1 if successful, 0 if it failed. 109 | * 110 | * Comments: 111 | * 112 | */ 113 | int SHA1Result(SHA1Context *context) 114 | { 115 | 116 | if (context->Corrupted) 117 | { 118 | return 0; 119 | } 120 | 121 | if (!context->Computed) 122 | { 123 | SHA1PadMessage(context); 124 | context->Computed = 1; 125 | } 126 | 127 | return 1; 128 | } 129 | 130 | /* 131 | * SHA1Input 132 | * 133 | * Description: 134 | * This function accepts an array of octets as the next portion of 135 | * the message. 136 | * 137 | * Parameters: 138 | * context: [in/out] 139 | * The SHA-1 context to update 140 | * message_array: [in] 141 | * An array of characters representing the next portion of the 142 | * message. 143 | * length: [in] 144 | * The length of the message in message_array 145 | * 146 | * Returns: 147 | * Nothing. 148 | * 149 | * Comments: 150 | * 151 | */ 152 | void SHA1Input( SHA1Context *context, 153 | const unsigned char *message_array, 154 | unsigned length) 155 | { 156 | if (!length) 157 | { 158 | return; 159 | } 160 | 161 | if (context->Computed || context->Corrupted) 162 | { 163 | context->Corrupted = 1; 164 | return; 165 | } 166 | 167 | while(length-- && !context->Corrupted) 168 | { 169 | context->Message_Block[context->Message_Block_Index++] = 170 | (*message_array & 0xFF); 171 | 172 | context->Length_Low += 8; 173 | /* Force it to 32 bits */ 174 | context->Length_Low &= 0xFFFFFFFF; 175 | if (context->Length_Low == 0) 176 | { 177 | context->Length_High++; 178 | /* Force it to 32 bits */ 179 | context->Length_High &= 0xFFFFFFFF; 180 | if (context->Length_High == 0) 181 | { 182 | /* Message is too long */ 183 | context->Corrupted = 1; 184 | } 185 | } 186 | 187 | if (context->Message_Block_Index == 64) 188 | { 189 | SHA1ProcessMessageBlock(context); 190 | } 191 | 192 | message_array++; 193 | } 194 | } 195 | 196 | /* 197 | * SHA1ProcessMessageBlock 198 | * 199 | * Description: 200 | * This function will process the next 512 bits of the message 201 | * stored in the Message_Block array. 202 | * 203 | * Parameters: 204 | * None. 205 | * 206 | * Returns: 207 | * Nothing. 208 | * 209 | * Comments: 210 | * Many of the variable names in the SHAContext, especially the 211 | * single character names, were used because those were the names 212 | * used in the publication. 213 | * 214 | * 215 | */ 216 | void SHA1ProcessMessageBlock(SHA1Context *context) 217 | { 218 | const unsigned K[] = /* Constants defined in SHA-1 */ 219 | { 220 | 0x5A827999, 221 | 0x6ED9EBA1, 222 | 0x8F1BBCDC, 223 | 0xCA62C1D6 224 | }; 225 | int t; /* Loop counter */ 226 | unsigned temp; /* Temporary word value */ 227 | unsigned W[80]; /* Word sequence */ 228 | unsigned A, B, C, D, E; /* Word buffers */ 229 | 230 | /* 231 | * Initialize the first 16 words in the array W 232 | */ 233 | for(t = 0; t < 16; t++) 234 | { 235 | W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; 236 | W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; 237 | W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; 238 | W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); 239 | } 240 | 241 | for(t = 16; t < 80; t++) 242 | { 243 | W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 244 | } 245 | 246 | A = context->Message_Digest[0]; 247 | B = context->Message_Digest[1]; 248 | C = context->Message_Digest[2]; 249 | D = context->Message_Digest[3]; 250 | E = context->Message_Digest[4]; 251 | 252 | for(t = 0; t < 20; t++) 253 | { 254 | temp = SHA1CircularShift(5,A) + 255 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 256 | temp &= 0xFFFFFFFF; 257 | E = D; 258 | D = C; 259 | C = SHA1CircularShift(30,B); 260 | B = A; 261 | A = temp; 262 | } 263 | 264 | for(t = 20; t < 40; t++) 265 | { 266 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; 267 | temp &= 0xFFFFFFFF; 268 | E = D; 269 | D = C; 270 | C = SHA1CircularShift(30,B); 271 | B = A; 272 | A = temp; 273 | } 274 | 275 | for(t = 40; t < 60; t++) 276 | { 277 | temp = SHA1CircularShift(5,A) + 278 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 279 | temp &= 0xFFFFFFFF; 280 | E = D; 281 | D = C; 282 | C = SHA1CircularShift(30,B); 283 | B = A; 284 | A = temp; 285 | } 286 | 287 | for(t = 60; t < 80; t++) 288 | { 289 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; 290 | temp &= 0xFFFFFFFF; 291 | E = D; 292 | D = C; 293 | C = SHA1CircularShift(30,B); 294 | B = A; 295 | A = temp; 296 | } 297 | 298 | context->Message_Digest[0] = 299 | (context->Message_Digest[0] + A) & 0xFFFFFFFF; 300 | context->Message_Digest[1] = 301 | (context->Message_Digest[1] + B) & 0xFFFFFFFF; 302 | context->Message_Digest[2] = 303 | (context->Message_Digest[2] + C) & 0xFFFFFFFF; 304 | context->Message_Digest[3] = 305 | (context->Message_Digest[3] + D) & 0xFFFFFFFF; 306 | context->Message_Digest[4] = 307 | (context->Message_Digest[4] + E) & 0xFFFFFFFF; 308 | 309 | context->Message_Block_Index = 0; 310 | } 311 | 312 | /* 313 | * SHA1PadMessage 314 | * 315 | * Description: 316 | * According to the standard, the message must be padded to an even 317 | * 512 bits. The first padding bit must be a '1'. The last 64 318 | * bits represent the length of the original message. All bits in 319 | * between should be 0. This function will pad the message 320 | * according to those rules by filling the Message_Block array 321 | * accordingly. It will also call SHA1ProcessMessageBlock() 322 | * appropriately. When it returns, it can be assumed that the 323 | * message digest has been computed. 324 | * 325 | * Parameters: 326 | * context: [in/out] 327 | * The context to pad 328 | * 329 | * Returns: 330 | * Nothing. 331 | * 332 | * Comments: 333 | * 334 | */ 335 | void SHA1PadMessage(SHA1Context *context) 336 | { 337 | /* 338 | * Check to see if the current message block is too small to hold 339 | * the initial padding bits and length. If so, we will pad the 340 | * block, process it, and then continue padding into a second 341 | * block. 342 | */ 343 | if (context->Message_Block_Index > 55) 344 | { 345 | context->Message_Block[context->Message_Block_Index++] = 0x80; 346 | while(context->Message_Block_Index < 64) 347 | { 348 | context->Message_Block[context->Message_Block_Index++] = 0; 349 | } 350 | 351 | SHA1ProcessMessageBlock(context); 352 | 353 | while(context->Message_Block_Index < 56) 354 | { 355 | context->Message_Block[context->Message_Block_Index++] = 0; 356 | } 357 | } 358 | else 359 | { 360 | context->Message_Block[context->Message_Block_Index++] = 0x80; 361 | while(context->Message_Block_Index < 56) 362 | { 363 | context->Message_Block[context->Message_Block_Index++] = 0; 364 | } 365 | } 366 | 367 | /* 368 | * Store the message length as the last 8 octets 369 | */ 370 | context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; 371 | context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; 372 | context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; 373 | context->Message_Block[59] = (context->Length_High) & 0xFF; 374 | context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; 375 | context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; 376 | context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; 377 | context->Message_Block[63] = (context->Length_Low) & 0xFF; 378 | 379 | SHA1ProcessMessageBlock(context); 380 | } 381 | -------------------------------------------------------------------------------- /makeself.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | #include "tools.h" 6 | #include "types.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define ALIGNMENT 0x20 16 | #define MAX_PHDR 255 17 | 18 | static u8 *elf = NULL; 19 | static u8 *self = NULL; 20 | 21 | static enum sce_key type; 22 | 23 | struct elf_hdr ehdr; 24 | struct elf_phdr phdr[MAX_PHDR]; 25 | static int arch64; 26 | 27 | static u8 sce_header[0x70]; 28 | static u8 info_header[0x20]; 29 | static u8 ctrl_header[0x70]; 30 | static u8 version_header[0x10]; 31 | 32 | static u8 *sec_header; 33 | static u32 sec_header_size; 34 | 35 | static u8 *meta_header; 36 | static u32 meta_header_size; 37 | 38 | static u64 header_size; 39 | static u32 meta_offset; 40 | static u64 elf_size; 41 | static u64 compressed_size; 42 | static u64 info_offset; 43 | static u64 version_offset; 44 | static u64 elf_offset; 45 | static u64 phdr_offset; 46 | static u64 shdr_offset; 47 | static u64 sec_offset; 48 | static u64 ctrl_offset; 49 | static u64 version; 50 | static u64 auth_id; 51 | static u64 vendor_id; 52 | static u16 sdk_type; 53 | 54 | struct key ks; 55 | 56 | static const char *elf_name = NULL; 57 | static const char *self_name = NULL; 58 | static int compression = 0; 59 | 60 | static struct { 61 | u64 offset; 62 | u64 size; 63 | u8 *ptr; 64 | int compressed; 65 | } phdr_map[MAX_PHDR]; 66 | 67 | static void get_type(const char *p) 68 | { 69 | if (strncmp(p, "lv0", 4) == 0) 70 | type = KEY_LV0; 71 | else if (strncmp(p, "lv1", 4) == 0) 72 | type = KEY_LV1; 73 | else if (strncmp(p, "lv2", 4) == 0) 74 | type = KEY_LV2; 75 | else if (strncmp(p, "iso", 4) == 0) 76 | type = KEY_ISO; 77 | else if (strncmp(p, "app", 4) == 0) 78 | type = KEY_APP; 79 | else if (strncmp(p, "ldr", 4) == 0) 80 | type = KEY_LDR; 81 | else 82 | fail("invalid type: %s", p); 83 | } 84 | 85 | static void get_keys(const char *suffix) 86 | { 87 | if (key_get(type, suffix, &ks) < 0) 88 | fail("key_get failed"); 89 | 90 | if (ks.pub_avail < 0) 91 | fail("no public key available"); 92 | 93 | if (ks.priv_avail < 0) 94 | fail("no private key available"); 95 | 96 | if (ecdsa_set_curve(ks.ctype) < 0) 97 | fail("ecdsa_set_curve failed"); 98 | 99 | ecdsa_set_pub(ks.pub); 100 | ecdsa_set_priv(ks.priv); 101 | } 102 | 103 | static void parse_elf(void) 104 | { 105 | u32 i; 106 | 107 | arch64 = elf_read_hdr(elf, &ehdr); 108 | 109 | for (i = 0; i < ehdr.e_phnum; i++) 110 | elf_read_phdr(arch64, elf + ehdr.e_phoff + i * ehdr.e_phentsize, &phdr[i]); 111 | } 112 | 113 | static void build_sce_hdr(void) 114 | { 115 | memset(sce_header, 0, sizeof sce_header); 116 | 117 | wbe32(sce_header + 0x00, 0x53434500); // magic 118 | wbe32(sce_header + 0x04, 2); // version 119 | wbe16(sce_header + 0x08, sdk_type); // dunno, sdk type? 120 | wbe16(sce_header + 0x0a, 1); // SCE header type; self 121 | wbe32(sce_header + 0x0c, meta_offset); 122 | wbe64(sce_header + 0x10, header_size); 123 | wbe64(sce_header + 0x18, round_up(elf_size, ALIGNMENT)); 124 | wbe64(sce_header + 0x20, 3); // dunno, has to be 3 125 | wbe64(sce_header + 0x28, info_offset); 126 | wbe64(sce_header + 0x30, elf_offset); 127 | wbe64(sce_header + 0x38, phdr_offset); 128 | wbe64(sce_header + 0x40, shdr_offset); 129 | wbe64(sce_header + 0x48, sec_offset); 130 | wbe64(sce_header + 0x50, version_offset); 131 | wbe64(sce_header + 0x58, ctrl_offset); 132 | wbe64(sce_header + 0x60, 0x70); // ctrl size 133 | } 134 | 135 | static void build_version_hdr(void) 136 | { 137 | memset(version_header, 0, sizeof version_header); 138 | wbe32(version_header, 1); 139 | wbe32(version_header + 0x08, 0x10); 140 | } 141 | 142 | static void build_info_hdr(void) 143 | { 144 | u32 app_type; 145 | 146 | memset(info_header, 0, sizeof info_header); 147 | 148 | switch (type) { 149 | case KEY_LV0: 150 | app_type = 1; 151 | break; 152 | case KEY_LV1: 153 | app_type = 2; 154 | break; 155 | case KEY_LV2: 156 | app_type = 3; 157 | break; 158 | case KEY_APP: 159 | app_type = 4; 160 | break; 161 | case KEY_ISO: 162 | app_type = 5; 163 | break; 164 | case KEY_LDR: 165 | app_type = 6; 166 | break; 167 | default: 168 | fail("something that should never fail failed."); 169 | } 170 | 171 | wbe64(info_header + 0x00, auth_id); 172 | wbe32(info_header + 0x08, vendor_id); 173 | wbe32(info_header + 0x0c, app_type); 174 | wbe64(info_header + 0x10, version); // version 1.0.0 175 | } 176 | 177 | static void build_ctrl_hdr(void) 178 | { 179 | memset(ctrl_header, 0, sizeof ctrl_header); 180 | 181 | wbe32(ctrl_header + 0x00, 1); // type: control flags 182 | wbe32(ctrl_header + 0x04, 0x30); // length 183 | // flags are all zero here 184 | 185 | wbe32(ctrl_header + 0x30, 2); // type: digest 186 | wbe32(ctrl_header + 0x34, 0x40); // length 187 | } 188 | 189 | static void build_sec_hdr(void) 190 | { 191 | u32 i; 192 | u8 *ptr; 193 | 194 | sec_header_size = ehdr.e_phnum * 0x20; 195 | sec_header = malloc(sec_header_size); 196 | 197 | memset(sec_header, 0, sec_header_size); 198 | 199 | for (i = 0; i < ehdr.e_phnum; i++) { 200 | ptr = sec_header + i * 0x20; 201 | 202 | wbe64(ptr + 0x00, phdr_map[i].offset); 203 | wbe64(ptr + 0x08, phdr_map[i].size); 204 | 205 | if (phdr_map[i].compressed == 1) 206 | wbe32(ptr + 0x10, 2); 207 | else 208 | wbe32(ptr + 0x10, 1); 209 | 210 | wbe32(ptr + 0x14, 0); // unknown 211 | wbe32(ptr + 0x18, 0); // unknown 212 | 213 | if (phdr[i].p_type == 1) 214 | wbe32(ptr + 0x1c, 1); // encrypted LOAD phdr 215 | else 216 | wbe32(ptr + 0x1c, 0); // no loadable phdr 217 | } 218 | } 219 | 220 | static void meta_add_phdr(u8 *ptr, u32 i) 221 | { 222 | wbe64(ptr + 0x00, phdr_map[i].offset); 223 | wbe64(ptr + 0x08, phdr_map[i].size); 224 | 225 | // unknown 226 | wbe32(ptr + 0x10, 2); 227 | wbe32(ptr + 0x14, i); // phdr index maybe? 228 | wbe32(ptr + 0x18, 2); 229 | 230 | wbe32(ptr + 0x1c, i*8); // sha index 231 | wbe32(ptr + 0x20, 1); // not encpryted 232 | wbe32(ptr + 0x24, 0xffffffff); // no key 233 | wbe32(ptr + 0x28, 0xffffffff); // no iv 234 | wbe32(ptr + 0x2c, 1); // not compressed 235 | } 236 | 237 | static void meta_add_load(u8 *ptr, u32 i) 238 | { 239 | wbe64(ptr + 0x00, phdr_map[i].offset); 240 | wbe64(ptr + 0x08, phdr_map[i].size); 241 | 242 | // unknown 243 | wbe32(ptr + 0x10, 2); 244 | wbe32(ptr + 0x14, i); // phdr index maybe? 245 | wbe32(ptr + 0x18, 2); 246 | 247 | wbe32(ptr + 0x1c, i*8); // sha index 248 | wbe32(ptr + 0x20, 3); // phdr is encrypted 249 | wbe32(ptr + 0x24, (i*8) + 6); // key index 250 | wbe32(ptr + 0x28, (i*8) + 7); // iv index 251 | 252 | if (phdr_map[i].compressed == 1) 253 | wbe32(ptr + 0x2c, 2); 254 | else 255 | wbe32(ptr + 0x2c, 1); 256 | } 257 | 258 | static void build_meta_hdr(void) 259 | { 260 | u32 i; 261 | u8 *ptr; 262 | 263 | meta_header_size = 0x80 + ehdr.e_phnum * (0x30 + 0x20 + 0x60) + 0x30; 264 | meta_header = malloc(meta_header_size); 265 | memset(meta_header, 0, meta_header_size); 266 | 267 | ptr = meta_header + 0x20; 268 | 269 | // aes keys for meta encryption 270 | get_rand(ptr, 0x10); 271 | get_rand(ptr + 0x20, 0x10); 272 | ptr += 0x40; 273 | 274 | // area covered by the signature 275 | wbe64(ptr + 0x00, meta_offset + meta_header_size - 0x30); 276 | 277 | wbe32(ptr + 0x08, 1); 278 | wbe32(ptr + 0x0c, ehdr.e_phnum); // number of encrypted headers 279 | wbe32(ptr + 0x10, ehdr.e_phnum * 8); // number of keys/hashes required 280 | wbe32(ptr + 0x14, meta_header_size / 0x10); 281 | ptr += 0x20; 282 | 283 | // add encrypted phdr information 284 | for (i = 0; i < ehdr.e_phnum; i++) { 285 | if (phdr[i].p_type == 1) 286 | meta_add_load(ptr, i); 287 | else 288 | meta_add_phdr(ptr, i); 289 | 290 | ptr += 0x30; 291 | } 292 | 293 | // add keys/ivs and hmac keys 294 | get_rand(ptr, ehdr.e_phnum * 8 * 0x10); 295 | } 296 | 297 | static void calculate_hashes(void) 298 | { 299 | u32 i; 300 | u8 *keys; 301 | 302 | keys = self + meta_offset + 0x80 + (0x30 * ehdr.e_phnum); 303 | 304 | for (i = 0; i < ehdr.e_phnum; i++) { 305 | memset(keys + (i * 8 * 0x10), 0, 0x20); 306 | sha1_hmac(keys + ((i * 8) + 2) * 0x10, 307 | self + phdr_map[i].offset, 308 | phdr_map[i].size, 309 | keys + (i * 8) * 0x10 310 | ); 311 | } 312 | } 313 | 314 | static void build_hdr(void) 315 | { 316 | memcpy(self, sce_header, sizeof sce_header); 317 | memcpy(self + info_offset, info_header, sizeof info_header); 318 | memcpy(self + version_offset, version_header, sizeof version_header); 319 | memcpy(self + ctrl_offset, ctrl_header, sizeof ctrl_header); 320 | memcpy(self + sec_offset, sec_header, sec_header_size); 321 | memcpy(self + phdr_offset, elf + ehdr.e_phoff, ehdr.e_phnum * ehdr.e_phentsize); 322 | // memcpy(self + shdr_offset, elf + ehdr.e_shoff, ehdr.e_shnum * ehdr.e_shentsize); 323 | memcpy(self + meta_offset, meta_header, meta_header_size); 324 | memcpy(self + elf_offset, elf, ehdr.e_ehsize); 325 | } 326 | 327 | static void write_elf(void) 328 | { 329 | u32 i; 330 | 331 | if (compression) { 332 | for (i = 0; i < ehdr.e_phnum; i++) { 333 | memcpy(self + phdr_map[i].offset, 334 | phdr_map[i].ptr, 335 | phdr_map[i].size); 336 | } 337 | memcpy(self + shdr_offset, elf + ehdr.e_shoff, ehdr.e_shnum * ehdr.e_shentsize); 338 | } else { 339 | memcpy(self + header_size, elf, elf_size); 340 | } 341 | } 342 | 343 | static void compress_elf(void) 344 | { 345 | u32 i; 346 | u64 offset; 347 | uLongf size_zlib; 348 | int res; 349 | u64 size_compressed; 350 | 351 | offset = header_size; 352 | 353 | for (i = 0; i < ehdr.e_phnum; i++) { 354 | phdr_map[i].offset = offset; 355 | 356 | if (phdr[i].p_type != 1) { 357 | phdr_map[i].ptr = elf + phdr[i].p_off; 358 | phdr_map[i].size = phdr[i].p_filesz; 359 | phdr_map[i].compressed = 0; 360 | offset = round_up(offset + phdr[i].p_filesz, 0x20); 361 | continue; 362 | } 363 | 364 | size_compressed = compressBound(phdr[i].p_filesz); 365 | size_zlib = size_compressed; 366 | 367 | phdr_map[i].ptr = malloc(size_compressed); 368 | if (!phdr_map[i].ptr) 369 | fail("out of memory"); 370 | 371 | res = compress(phdr_map[i].ptr, &size_zlib, 372 | elf + phdr[i].p_off, phdr[i].p_filesz); 373 | 374 | if (size_zlib >= phdr[i].p_filesz) { 375 | free(phdr_map[i].ptr); 376 | phdr_map[i].ptr = elf + phdr[i].p_off; 377 | phdr_map[i].size = phdr[i].p_filesz; 378 | phdr_map[i].compressed = 0; 379 | offset = round_up(offset + phdr[i].p_filesz, ALIGNMENT); 380 | } else { 381 | phdr_map[i].ptr = realloc(phdr_map[i].ptr, size_zlib); 382 | if (phdr_map[i].ptr == NULL) 383 | fail("out of memory"); 384 | 385 | phdr_map[i].size = size_zlib; 386 | phdr_map[i].compressed = 1; 387 | offset = round_up(offset + phdr_map[i].size, ALIGNMENT); 388 | } 389 | } 390 | 391 | compressed_size = phdr_map[i - 1].offset + phdr_map[i - 1].size; 392 | shdr_offset = compressed_size; 393 | compressed_size += ehdr.e_shentsize * ehdr.e_shnum; 394 | } 395 | 396 | static void fill_phdr_map(void) 397 | { 398 | u32 i; 399 | 400 | memset(phdr_map, 0, sizeof phdr_map); 401 | 402 | for (i = 0; i < ehdr.e_phnum; i++) { 403 | phdr_map[i].offset = phdr[i].p_off + header_size; 404 | phdr_map[i].size = phdr[i].p_filesz; 405 | phdr_map[i].compressed = 0; 406 | phdr[i].ptr = NULL; 407 | } 408 | 409 | compressed_size = elf_size; 410 | shdr_offset = ehdr.e_shoff + header_size; 411 | } 412 | 413 | static void sign_hdr(void) 414 | { 415 | u8 *r, *s; 416 | u8 hash[20]; 417 | u64 sig_len; 418 | 419 | sig_len = be64(self + meta_offset + 0x60); 420 | r = self + sig_len; 421 | s = r + 21; 422 | 423 | sha1(self, sig_len, hash); 424 | 425 | ecdsa_sign(hash, r, s); 426 | } 427 | 428 | static u64 get_filesize(const char *path) 429 | { 430 | struct stat st; 431 | 432 | stat(path, &st); 433 | 434 | return st.st_size; 435 | } 436 | 437 | static void get_version(const char *v) 438 | { 439 | u8 *ptr; 440 | u32 i; 441 | u32 maj, min, rev; 442 | u32 tmp; 443 | 444 | i = 0; 445 | maj = min = rev = tmp = 0; 446 | ptr = (u8 *)v; 447 | while (*ptr) { 448 | if (i > 2) { 449 | fprintf(stderr, "WARNING: invalid sdk_version, using 1.0.0\n"); 450 | version = 1ULL << 48; 451 | return; 452 | } 453 | 454 | if (*ptr == '.') { 455 | if (i == 0) 456 | maj = tmp; 457 | else if (i == 1) 458 | min = tmp; 459 | else if (i == 2) 460 | rev = tmp; 461 | i++; 462 | ptr++; 463 | tmp = 0; 464 | continue; 465 | } 466 | 467 | if (*ptr >= '0' && *ptr <= '9') { 468 | tmp <<= 4; 469 | tmp += *ptr - '0'; 470 | ptr++; 471 | continue; 472 | } 473 | 474 | fprintf(stderr, "WARNING: invalid sdk_version, using 1.0.0\n"); 475 | version = 1ULL << 48; 476 | return; 477 | } 478 | 479 | if (i == 2) 480 | rev = tmp; 481 | 482 | version = ((u64)maj & 0xffff) << 48; 483 | version |= ((u64)min & 0xffff) << 32; 484 | version |= rev; 485 | } 486 | 487 | static void get_vendor(char *v) 488 | { 489 | vendor_id = strtoull(v, NULL, 16); 490 | } 491 | 492 | static void get_auth(char *a) 493 | { 494 | auth_id = strtoull(a, NULL, 16); 495 | } 496 | 497 | static void get_sdktype(char * t) 498 | { 499 | sdk_type = strtoul(t, NULL, 10); 500 | } 501 | 502 | static void get_args(int argc, char *argv[]) 503 | { 504 | u32 i; 505 | 506 | if (argc != 9 && argc != 10) 507 | fail("usage: makeself [-c] [type] [version suffix] [version] [vendor id] [auth id] [sdk type] [elf] [self]"); 508 | 509 | i = 1; 510 | 511 | if (argc == 10) { 512 | if (strcmp(argv[1], "-c") != 0) 513 | fail("invalid option: %s", argv[1]); 514 | compression = 1; 515 | i++; 516 | } 517 | 518 | get_type(argv[i++]); 519 | get_keys(argv[i++]); 520 | get_version(argv[i++]); 521 | get_vendor(argv[i++]); 522 | get_auth(argv[i++]); 523 | get_sdktype(argv[i++]); 524 | 525 | elf_name = argv[i++]; 526 | self_name = argv[i++]; 527 | 528 | if (compression) { 529 | if (type == KEY_ISO) 530 | fail("no compression support for isolated modules"); 531 | if (type == KEY_LDR) 532 | fail("no compression support for secure loaders"); 533 | } 534 | } 535 | 536 | 537 | int main(int argc, char *argv[]) 538 | { 539 | FILE *fp; 540 | u8 bfr[ALIGNMENT]; 541 | 542 | get_args(argc, argv); 543 | 544 | elf_size = get_filesize(elf_name); 545 | elf = mmap_file(elf_name); 546 | 547 | parse_elf(); 548 | 549 | meta_header_size = 0x80 + ehdr.e_phnum * (0x30 + 0x20 + 0x60) + 0x30; 550 | info_offset = 0x70; 551 | elf_offset = 0x90; 552 | phdr_offset = elf_offset + ehdr.e_ehsize; 553 | sec_offset = round_up(phdr_offset + ehdr.e_phentsize * ehdr.e_phnum, ALIGNMENT); 554 | version_offset = round_up(sec_offset + ehdr.e_phnum * 0x20, ALIGNMENT); 555 | ctrl_offset = round_up(version_offset + 0x10, ALIGNMENT); 556 | meta_offset = round_up(ctrl_offset + 0x70, ALIGNMENT); 557 | header_size = round_up(meta_offset + meta_header_size, 0x80); 558 | 559 | if (compression) 560 | compress_elf(); 561 | else 562 | fill_phdr_map(); 563 | 564 | build_sce_hdr(); 565 | build_info_hdr(); 566 | build_ctrl_hdr(); 567 | build_sec_hdr(); 568 | build_version_hdr(); 569 | build_meta_hdr(); 570 | 571 | self = malloc(header_size + elf_size); 572 | memset(self, 0, header_size + elf_size); 573 | 574 | build_hdr(); 575 | write_elf(); 576 | calculate_hashes(); 577 | sign_hdr(); 578 | 579 | sce_encrypt_data(self); 580 | sce_encrypt_header(self, &ks); 581 | 582 | fp = fopen(self_name, "wb"); 583 | if (fp == NULL) 584 | fail("fopen(%s) failed", self_name); 585 | 586 | if (fwrite(self, header_size + compressed_size, 1, fp) != 1) 587 | fail("unable to write self"); 588 | 589 | memset(bfr, 0, sizeof bfr); 590 | fwrite(bfr, round_up(compressed_size, ALIGNMENT) - compressed_size, 1, fp); 591 | 592 | fclose(fp); 593 | 594 | return 0; 595 | } 596 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007, 2008, 2009 Free Software Foundation, Inc. 6 | 7 | Copying and distribution of this file, with or without modification, 8 | are permitted in any medium without royalty provided the copyright 9 | notice and this notice are preserved. This file is offered as-is, 10 | without warranty of any kind. 11 | 12 | Basic Installation 13 | ================== 14 | 15 | Briefly, the shell commands `./configure; make; make install' should 16 | configure, build, and install this package. The following 17 | more-detailed instructions are generic; see the `README' file for 18 | instructions specific to this package. Some packages provide this 19 | `INSTALL' file but do not implement all of the features documented 20 | below. The lack of an optional feature in a given package is not 21 | necessarily a bug. More recommendations for GNU packages can be found 22 | in *note Makefile Conventions: (standards)Makefile Conventions. 23 | 24 | The `configure' shell script attempts to guess correct values for 25 | various system-dependent variables used during compilation. It uses 26 | those values to create a `Makefile' in each directory of the package. 27 | It may also create one or more `.h' files containing system-dependent 28 | definitions. Finally, it creates a shell script `config.status' that 29 | you can run in the future to recreate the current configuration, and a 30 | file `config.log' containing compiler output (useful mainly for 31 | debugging `configure'). 32 | 33 | It can also use an optional file (typically called `config.cache' 34 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 35 | the results of its tests to speed up reconfiguring. Caching is 36 | disabled by default to prevent problems with accidental use of stale 37 | cache files. 38 | 39 | If you need to do unusual things to compile the package, please try 40 | to figure out how `configure' could check whether to do them, and mail 41 | diffs or instructions to the address given in the `README' so they can 42 | be considered for the next release. If you are using the cache, and at 43 | some point `config.cache' contains results you don't want to keep, you 44 | may remove or edit it. 45 | 46 | The file `configure.ac' (or `configure.in') is used to create 47 | `configure' by a program called `autoconf'. You need `configure.ac' if 48 | you want to change it or regenerate `configure' using a newer version 49 | of `autoconf'. 50 | 51 | The simplest way to compile this package is: 52 | 53 | 1. `cd' to the directory containing the package's source code and type 54 | `./configure' to configure the package for your system. 55 | 56 | Running `configure' might take a while. While running, it prints 57 | some messages telling which features it is checking for. 58 | 59 | 2. Type `make' to compile the package. 60 | 61 | 3. Optionally, type `make check' to run any self-tests that come with 62 | the package, generally using the just-built uninstalled binaries. 63 | 64 | 4. Type `make install' to install the programs and any data files and 65 | documentation. When installing into a prefix owned by root, it is 66 | recommended that the package be configured and built as a regular 67 | user, and only the `make install' phase executed with root 68 | privileges. 69 | 70 | 5. Optionally, type `make installcheck' to repeat any self-tests, but 71 | this time using the binaries in their final installed location. 72 | This target does not install anything. Running this target as a 73 | regular user, particularly if the prior `make install' required 74 | root privileges, verifies that the installation completed 75 | correctly. 76 | 77 | 6. You can remove the program binaries and object files from the 78 | source code directory by typing `make clean'. To also remove the 79 | files that `configure' created (so you can compile the package for 80 | a different kind of computer), type `make distclean'. There is 81 | also a `make maintainer-clean' target, but that is intended mainly 82 | for the package's developers. If you use it, you may have to get 83 | all sorts of other programs in order to regenerate files that came 84 | with the distribution. 85 | 86 | 7. Often, you can also type `make uninstall' to remove the installed 87 | files again. In practice, not all packages have tested that 88 | uninstallation works correctly, even though it is required by the 89 | GNU Coding Standards. 90 | 91 | 8. Some packages, particularly those that use Automake, provide `make 92 | distcheck', which can by used by developers to test that all other 93 | targets like `make install' and `make uninstall' work correctly. 94 | This target is generally not run by end users. 95 | 96 | Compilers and Options 97 | ===================== 98 | 99 | Some systems require unusual options for compilation or linking that 100 | the `configure' script does not know about. Run `./configure --help' 101 | for details on some of the pertinent environment variables. 102 | 103 | You can give `configure' initial values for configuration parameters 104 | by setting variables in the command line or in the environment. Here 105 | is an example: 106 | 107 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 108 | 109 | *Note Defining Variables::, for more details. 110 | 111 | Compiling For Multiple Architectures 112 | ==================================== 113 | 114 | You can compile the package for more than one kind of computer at the 115 | same time, by placing the object files for each architecture in their 116 | own directory. To do this, you can use GNU `make'. `cd' to the 117 | directory where you want the object files and executables to go and run 118 | the `configure' script. `configure' automatically checks for the 119 | source code in the directory that `configure' is in and in `..'. This 120 | is known as a "VPATH" build. 121 | 122 | With a non-GNU `make', it is safer to compile the package for one 123 | architecture at a time in the source code directory. After you have 124 | installed the package for one architecture, use `make distclean' before 125 | reconfiguring for another architecture. 126 | 127 | On MacOS X 10.5 and later systems, you can create libraries and 128 | executables that work on multiple system types--known as "fat" or 129 | "universal" binaries--by specifying multiple `-arch' options to the 130 | compiler but only a single `-arch' option to the preprocessor. Like 131 | this: 132 | 133 | ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 134 | CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ 135 | CPP="gcc -E" CXXCPP="g++ -E" 136 | 137 | This is not guaranteed to produce working output in all cases, you 138 | may have to build one architecture at a time and combine the results 139 | using the `lipo' tool if you have problems. 140 | 141 | Installation Names 142 | ================== 143 | 144 | By default, `make install' installs the package's commands under 145 | `/usr/local/bin', include files under `/usr/local/include', etc. You 146 | can specify an installation prefix other than `/usr/local' by giving 147 | `configure' the option `--prefix=PREFIX', where PREFIX must be an 148 | absolute file name. 149 | 150 | You can specify separate installation prefixes for 151 | architecture-specific files and architecture-independent files. If you 152 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 153 | PREFIX as the prefix for installing programs and libraries. 154 | Documentation and other data files still use the regular prefix. 155 | 156 | In addition, if you use an unusual directory layout you can give 157 | options like `--bindir=DIR' to specify different values for particular 158 | kinds of files. Run `configure --help' for a list of the directories 159 | you can set and what kinds of files go in them. In general, the 160 | default for these options is expressed in terms of `${prefix}', so that 161 | specifying just `--prefix' will affect all of the other directory 162 | specifications that were not explicitly provided. 163 | 164 | The most portable way to affect installation locations is to pass the 165 | correct locations to `configure'; however, many packages provide one or 166 | both of the following shortcuts of passing variable assignments to the 167 | `make install' command line to change installation locations without 168 | having to reconfigure or recompile. 169 | 170 | The first method involves providing an override variable for each 171 | affected directory. For example, `make install 172 | prefix=/alternate/directory' will choose an alternate location for all 173 | directory configuration variables that were expressed in terms of 174 | `${prefix}'. Any directories that were specified during `configure', 175 | but not in terms of `${prefix}', must each be overridden at install 176 | time for the entire installation to be relocated. The approach of 177 | makefile variable overrides for each directory variable is required by 178 | the GNU Coding Standards, and ideally causes no recompilation. 179 | However, some platforms have known limitations with the semantics of 180 | shared libraries that end up requiring recompilation when using this 181 | method, particularly noticeable in packages that use GNU Libtool. 182 | 183 | The second method involves providing the `DESTDIR' variable. For 184 | example, `make install DESTDIR=/alternate/directory' will prepend 185 | `/alternate/directory' before all installation names. The approach of 186 | `DESTDIR' overrides is not required by the GNU Coding Standards, and 187 | does not work on platforms that have drive letters. On the other hand, 188 | it does better at avoiding recompilation issues, and works well even 189 | when some directory options were not specified in terms of `${prefix}' 190 | at `configure' time. 191 | 192 | Optional Features 193 | ================= 194 | 195 | If the package supports it, you can cause programs to be installed 196 | with an extra prefix or suffix on their names by giving `configure' the 197 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 198 | 199 | Some packages pay attention to `--enable-FEATURE' options to 200 | `configure', where FEATURE indicates an optional part of the package. 201 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 202 | is something like `gnu-as' or `x' (for the X Window System). The 203 | `README' should mention any `--enable-' and `--with-' options that the 204 | package recognizes. 205 | 206 | For packages that use the X Window System, `configure' can usually 207 | find the X include and library files automatically, but if it doesn't, 208 | you can use the `configure' options `--x-includes=DIR' and 209 | `--x-libraries=DIR' to specify their locations. 210 | 211 | Some packages offer the ability to configure how verbose the 212 | execution of `make' will be. For these packages, running `./configure 213 | --enable-silent-rules' sets the default to minimal output, which can be 214 | overridden with `make V=1'; while running `./configure 215 | --disable-silent-rules' sets the default to verbose, which can be 216 | overridden with `make V=0'. 217 | 218 | Particular systems 219 | ================== 220 | 221 | On HP-UX, the default C compiler is not ANSI C compatible. If GNU 222 | CC is not installed, it is recommended to use the following options in 223 | order to use an ANSI C compiler: 224 | 225 | ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" 226 | 227 | and if that doesn't work, install pre-built binaries of GCC for HP-UX. 228 | 229 | On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot 230 | parse its `' header file. The option `-nodtk' can be used as 231 | a workaround. If GNU CC is not installed, it is therefore recommended 232 | to try 233 | 234 | ./configure CC="cc" 235 | 236 | and if that doesn't work, try 237 | 238 | ./configure CC="cc -nodtk" 239 | 240 | On Solaris, don't put `/usr/ucb' early in your `PATH'. This 241 | directory contains several dysfunctional programs; working variants of 242 | these programs are available in `/usr/bin'. So, if you need `/usr/ucb' 243 | in your `PATH', put it _after_ `/usr/bin'. 244 | 245 | On Haiku, software installed for all users goes in `/boot/common', 246 | not `/usr/local'. It is recommended to use the following options: 247 | 248 | ./configure --prefix=/boot/common 249 | 250 | Specifying the System Type 251 | ========================== 252 | 253 | There may be some features `configure' cannot figure out 254 | automatically, but needs to determine by the type of machine the package 255 | will run on. Usually, assuming the package is built to be run on the 256 | _same_ architectures, `configure' can figure that out, but if it prints 257 | a message saying it cannot guess the machine type, give it the 258 | `--build=TYPE' option. TYPE can either be a short name for the system 259 | type, such as `sun4', or a canonical name which has the form: 260 | 261 | CPU-COMPANY-SYSTEM 262 | 263 | where SYSTEM can have one of these forms: 264 | 265 | OS 266 | KERNEL-OS 267 | 268 | See the file `config.sub' for the possible values of each field. If 269 | `config.sub' isn't included in this package, then this package doesn't 270 | need to know the machine type. 271 | 272 | If you are _building_ compiler tools for cross-compiling, you should 273 | use the option `--target=TYPE' to select the type of system they will 274 | produce code for. 275 | 276 | If you want to _use_ a cross compiler, that generates code for a 277 | platform different from the build platform, you should specify the 278 | "host" platform (i.e., that on which the generated programs will 279 | eventually be run) with `--host=TYPE'. 280 | 281 | Sharing Defaults 282 | ================ 283 | 284 | If you want to set default values for `configure' scripts to share, 285 | you can create a site shell script called `config.site' that gives 286 | default values for variables like `CC', `cache_file', and `prefix'. 287 | `configure' looks for `PREFIX/share/config.site' if it exists, then 288 | `PREFIX/etc/config.site' if it exists. Or, you can set the 289 | `CONFIG_SITE' environment variable to the location of the site script. 290 | A warning: not all `configure' scripts look for a site script. 291 | 292 | Defining Variables 293 | ================== 294 | 295 | Variables not defined in a site shell script can be set in the 296 | environment passed to `configure'. However, some packages may run 297 | configure again during the build, and the customized values of these 298 | variables may be lost. In order to avoid this problem, you should set 299 | them in the `configure' command line, using `VAR=value'. For example: 300 | 301 | ./configure CC=/usr/local2/bin/gcc 302 | 303 | causes the specified `gcc' to be used as the C compiler (unless it is 304 | overridden in the site shell script). 305 | 306 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 307 | an Autoconf bug. Until the bug is fixed you can use this workaround: 308 | 309 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 310 | 311 | `configure' Invocation 312 | ====================== 313 | 314 | `configure' recognizes the following options to control how it 315 | operates. 316 | 317 | `--help' 318 | `-h' 319 | Print a summary of all of the options to `configure', and exit. 320 | 321 | `--help=short' 322 | `--help=recursive' 323 | Print a summary of the options unique to this package's 324 | `configure', and exit. The `short' variant lists options used 325 | only in the top level, while the `recursive' variant lists options 326 | also present in any nested packages. 327 | 328 | `--version' 329 | `-V' 330 | Print the version of Autoconf used to generate the `configure' 331 | script, and exit. 332 | 333 | `--cache-file=FILE' 334 | Enable the cache: use and save the results of the tests in FILE, 335 | traditionally `config.cache'. FILE defaults to `/dev/null' to 336 | disable caching. 337 | 338 | `--config-cache' 339 | `-C' 340 | Alias for `--cache-file=config.cache'. 341 | 342 | `--quiet' 343 | `--silent' 344 | `-q' 345 | Do not print messages saying which checks are being made. To 346 | suppress all normal output, redirect it to `/dev/null' (any error 347 | messages will still be shown). 348 | 349 | `--srcdir=DIR' 350 | Look for the package's source code in directory DIR. Usually 351 | `configure' can determine that directory automatically. 352 | 353 | `--prefix=DIR' 354 | Use DIR as the installation prefix. *note Installation Names:: 355 | for more details, including other options available for fine-tuning 356 | the installation locations. 357 | 358 | `--no-create' 359 | `-n' 360 | Run the configure checks, but stop before creating any output 361 | files. 362 | 363 | `configure' also accepts some other, not widely useful, options. Run 364 | `configure --help' for more details. 365 | 366 | -------------------------------------------------------------------------------- /readself.c: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Sven Peter 2 | // Licensed under the terms of the GNU GPL, version 2 3 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 4 | 5 | // 6 | // Thanks to xorloser for his selftool! 7 | // (see xorloser.com) 8 | // 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | #include "tools.h" 15 | 16 | static u8 *self; 17 | static u8 *elf; 18 | 19 | static struct elf_hdr ehdr; 20 | 21 | static int arch64; 22 | static u32 meta_offset; 23 | static u64 elf_offset; 24 | static u64 header_len; 25 | static u64 phdr_offset; 26 | static u64 shdr_offset; 27 | static u64 filesize; 28 | static u32 vendorid; 29 | static u64 authid; 30 | static u64 app_version; 31 | static u32 app_type; 32 | static u16 sdk_type; 33 | static u64 info_offset; 34 | static u64 sec_offset; 35 | static u64 ver_info; 36 | static u64 ctrl_offset; 37 | static u64 ctrl_size; 38 | 39 | static int decrypted = -1; 40 | 41 | struct id2name_tbl t_sdk_type[] = { 42 | {0, "Retail (Type 0)"}, 43 | {1, "Retail"}, 44 | {2, "Retail (Type 1)"}, 45 | {3, "Unknown SDK3"}, 46 | {4, "Retail >=3.40"}, 47 | {5, "Unknown SDK5"}, 48 | {6, "Unknown SDK6"}, 49 | {7, "Retail >=3.50"}, 50 | {8, "Unknown SDK8"}, 51 | {9, "Unknown SDK9"}, 52 | {10, "Retail >=3.55"}, 53 | {11, "Unknown SDK11"}, 54 | {12, "Unknown SDK12"}, 55 | {13, "Retail >=3.56"}, 56 | {14, "Unknown SDK14"}, 57 | {15, "Unknown SDK15"}, 58 | {16, "Retail >=3.60"}, 59 | {17, "Unknown SDK17"}, 60 | {18, "Unknown SDK18"}, 61 | {19, "Retail >=3.65"}, 62 | {20, "Unknown SDK20"}, 63 | {21, "Unknown SDK21"}, 64 | {22, "Retail >=3.70"}, 65 | {23, "Unknown SDK23"}, 66 | {24, "Unknown SDK24"}, 67 | {0x8000, "Devkit"}, 68 | {0, NULL} 69 | }; 70 | 71 | struct id2name_tbl t_app_type[] = { 72 | {1, "level 0"}, 73 | {2, "level 1"}, 74 | {3, "level 2"}, 75 | {4, "application"}, 76 | {5, "isolated SPU module"}, 77 | {6, "secure loader"}, 78 | {8, "NP-DRM application"}, 79 | {0, NULL} 80 | }; 81 | 82 | static struct id2name_tbl t_shdr_type[] = { 83 | {0, "NULL"}, 84 | {1, "PROGBITS"}, 85 | {2, "SYMTAB"}, 86 | {3, "STRTAB"}, 87 | {4, "RELA"}, 88 | {5, "HASH"}, 89 | {6, "DYNAMIC"}, 90 | {7, "NOTE"}, 91 | {8, "NOBITS"}, 92 | {9, "REL"}, 93 | {10, "SHLIB"}, 94 | {11, "DYNSYM"}, 95 | {12, NULL}, 96 | }; 97 | 98 | static struct id2name_tbl t_elf_type[] = { 99 | {ET_NONE, "None"}, 100 | {ET_REL, "Relocatable file"}, 101 | {ET_EXEC, "Executable file"}, 102 | {ET_DYN, "Shared object file"}, 103 | {ET_CORE, "Core file"}, 104 | {0, NULL} 105 | }; 106 | 107 | static struct id2name_tbl t_elf_machine[] = { 108 | {20, "PowerPC"}, 109 | {21, "PowerPC64"}, 110 | {23, "SPE"}, 111 | {0, NULL} 112 | }; 113 | 114 | 115 | static struct id2name_tbl t_phdr_type[] = { 116 | {0, "NULL"}, 117 | {1, "LOAD"}, 118 | {2, "DYN"}, 119 | {3, "INTPR"}, 120 | {4, "NOTE"}, 121 | {5, "SHLIB"}, 122 | {6, "PHDR"}, 123 | {0, NULL} 124 | }; 125 | 126 | static struct id2name_tbl t_compressed[] = { 127 | {1, "[NO ]"}, 128 | {2, "[YES]"}, 129 | {0, NULL} 130 | }; 131 | 132 | static struct id2name_tbl t_encrypted[] = { 133 | {0, "[N/A]"}, 134 | {1, "[YES]"}, 135 | {2, "[NO ]"}, 136 | {0, NULL} 137 | }; 138 | 139 | static void parse_self(void) 140 | { 141 | sdk_type = be16(self + 0x08); 142 | meta_offset = be32(self + 0x0c); 143 | header_len = be64(self + 0x10); 144 | filesize = be64(self + 0x18); 145 | info_offset = be64(self + 0x28); 146 | elf_offset = be64(self + 0x30); 147 | phdr_offset = be64(self + 0x38) - elf_offset; 148 | shdr_offset = be64(self + 0x40) - elf_offset; 149 | sec_offset = be64(self + 0x48); 150 | ver_info = be64(self + 0x50); 151 | ctrl_offset = be64(self + 0x58); 152 | ctrl_size = be64(self + 0x60); 153 | 154 | vendorid = be32(self + info_offset + 0x08); 155 | authid = be64(self + info_offset + 0x00); 156 | app_type = be32(self + info_offset + 0x0c); 157 | app_version = be64(self + info_offset + 0x10); 158 | 159 | elf = self + elf_offset; 160 | arch64 = elf_read_hdr(elf, &ehdr); 161 | } 162 | 163 | 164 | static struct keylist *self_load_keys(void) 165 | { 166 | enum sce_key id; 167 | 168 | switch (app_type) { 169 | case 1: 170 | id = KEY_LV0; 171 | break; 172 | case 2: 173 | id = KEY_LV1; 174 | break; 175 | case 3: 176 | id = KEY_LV2; 177 | break; 178 | case 4: 179 | id = KEY_APP; 180 | break; 181 | case 5: 182 | id = KEY_ISO; 183 | break; 184 | case 6: 185 | id = KEY_LDR; 186 | break; 187 | case 8: 188 | id = KEY_NPDRM; 189 | break; 190 | default: 191 | fail("invalid type: %08x", app_type); 192 | } 193 | 194 | return keys_get(id); 195 | } 196 | 197 | static void decrypt_header(void) 198 | { 199 | struct keylist *klist; 200 | 201 | klist = self_load_keys(); 202 | if (klist == NULL) 203 | return; 204 | 205 | sce_remove_npdrm(self, klist); 206 | decrypted = sce_decrypt_header(self, klist); 207 | free(klist->keys); 208 | free(klist); 209 | } 210 | 211 | 212 | static const char *get_auth_type(void) 213 | { 214 | return "Unknown"; 215 | } 216 | 217 | static void show_self_header(void) 218 | { 219 | printf("SELF header\n"); 220 | printf(" elf #1 offset: %08x_%08x\n", (u32)(elf_offset>>32), (u32)elf_offset); 221 | printf(" header len: %08x_%08x\n", (u32)(header_len>>32), (u32)header_len); 222 | printf(" meta offset: %08x_%08x\n", 0, meta_offset); 223 | printf(" phdr offset: %08x_%08x\n", (u32)(phdr_offset>>32), (u32)phdr_offset); 224 | printf(" shdr offset: %08x_%08x\n", (u32)(shdr_offset>>32), (u32)shdr_offset); 225 | printf(" file size: %08x_%08x\n", (u32)(filesize>>32), (u32)filesize); 226 | printf(" auth id: %08x_%08x (%s)\n", (u32)(authid>>32), (u32)authid, get_auth_type()); 227 | printf(" vendor id: %08x\n", vendorid); 228 | printf(" info offset: %08x_%08x\n", (u32)(info_offset >> 32), (u32)info_offset); 229 | printf(" sinfo offset: %08x_%08x\n", (u32)(sec_offset >> 32), (u32)sec_offset); 230 | printf(" version offset: %08x_%08x\n", (u32)(ver_info >> 32), (u32)ver_info); 231 | printf(" control info: %08x_%08x (%08x_%08x bytes)\n", 232 | (u32)(ctrl_offset >> 32), (u32)ctrl_offset, 233 | (u32)(ctrl_size >> 32), (u32)ctrl_size); 234 | 235 | printf(" app version: %x.%x.%x\n", (u16)(app_version >> 48), (u16)(app_version >> 32), (u32)app_version); 236 | printf(" SDK type: %s\n", id2name(sdk_type, t_sdk_type, "unknown")); 237 | printf(" app type: %s\n", id2name(app_type, t_app_type, "unknown")); 238 | 239 | 240 | printf("\n"); 241 | } 242 | 243 | static void show_ctrl(void) 244 | { 245 | u32 i, j; 246 | u32 type, length; 247 | 248 | printf("Control info\n"); 249 | 250 | for (i = 0; i < ctrl_size; ) { 251 | type = be32(self + ctrl_offset + i); 252 | length = be32(self + ctrl_offset + i + 0x04); 253 | switch (type) { 254 | case 1: 255 | if (length == 0x30) { 256 | printf(" control flags:\n "); 257 | print_hash(self + ctrl_offset + i + 0x10, 0x10); 258 | printf("\n"); 259 | break; 260 | } 261 | case 2: 262 | if (length == 0x40) { 263 | printf(" file digest:\n "); 264 | print_hash(self + ctrl_offset + i + 0x10, 0x14); 265 | printf("\n "); 266 | print_hash(self + ctrl_offset + i + 0x24, 0x14); 267 | printf("\n"); 268 | break; 269 | } 270 | if (length == 0x30) { 271 | printf(" file digest:\n "); 272 | print_hash(self + ctrl_offset + i + 0x10, 0x14); 273 | printf("\n"); 274 | break; 275 | } 276 | case 3: 277 | if (length == 0x90) { 278 | 279 | char id[0x31]; 280 | memset(id, 0, 0x31); 281 | memcpy(id, self + ctrl_offset + i + 0x20, 0x30); 282 | 283 | printf(" NPDRM info:\n"); 284 | printf(" magic: %08x\n", be32(self + ctrl_offset + i + 0x10)); 285 | printf(" unk0 : %08x\n", be32(self + ctrl_offset + i + 0x14)); 286 | printf(" unk1 : %08x\n", be32(self + ctrl_offset + i + 0x18)); 287 | printf(" unk2 : %08x\n", be32(self + ctrl_offset + i + 0x1c)); 288 | printf(" content_id: %s\n", id); 289 | printf(" digest: "); 290 | print_hash(self + ctrl_offset + i + 0x50, 0x10); 291 | printf("\n invdigest: "); 292 | print_hash(self + ctrl_offset + i + 0x60, 0x10); 293 | printf("\n xordigest: "); 294 | print_hash(self + ctrl_offset + i + 0x70, 0x10); 295 | printf("\n"); 296 | break; 297 | } 298 | default: 299 | printf(" unknown:\n"); 300 | for(j = 0; j < length; j++) { 301 | if ((j % 16) == 0) 302 | printf(" "); 303 | printf(" %02x", be8(self + ctrl_offset + i + j)); 304 | if ((j % 16) == 15 || (j == length - 1)) 305 | printf("\n"); 306 | } 307 | break; 308 | } 309 | i += length; 310 | } 311 | printf("\n"); 312 | } 313 | 314 | static void show_sinfo(void) 315 | { 316 | u32 i; 317 | u64 offset, size; 318 | u32 compressed, encrypted; 319 | u32 unk1, unk2; 320 | 321 | printf("Section header\n"); 322 | 323 | printf(" offset size compressed unk1" 324 | " unk2 encrypted\n"); 325 | 326 | for (i = 0; i < ehdr.e_phnum; i++) { 327 | offset = be64(self + sec_offset + i*0x20 + 0x00); 328 | size = be64(self + sec_offset + i*0x20 + 0x08); 329 | compressed = be32(self + sec_offset + i*0x20 + 0x10); 330 | unk1 = be32(self + sec_offset + i*0x20 + 0x14); 331 | unk2 = be32(self + sec_offset + i*0x20 + 0x18); 332 | encrypted = be32(self + sec_offset + i*0x20 + 0x1c); 333 | printf(" %08x_%08x %08x_%08x %s %08x %08x %s\n", 334 | (u32)(offset >> 32), (u32)offset, 335 | (u32)(size >> 32), (u32)size, 336 | id2name(compressed, t_compressed, "[???]"), 337 | unk1, unk2, 338 | id2name(encrypted, t_encrypted, "[???]") 339 | ); 340 | } 341 | 342 | printf("\n"); 343 | } 344 | 345 | static void show_meta(void) 346 | { 347 | u32 meta_len; 348 | u32 meta_n_hdr; 349 | u32 meta_n_keys; 350 | u32 i; 351 | u64 offset, size; 352 | u8 *tmp; 353 | 354 | printf("Encrypted Metadata\n"); 355 | 356 | if (sdk_type == 0x8000) { 357 | printf(" no encrypted metadata in fselfs.\n\n"); 358 | return; 359 | } 360 | 361 | if (decrypted < 0) { 362 | printf(" unable to decrypt metadata\n\n"); 363 | return; 364 | } 365 | 366 | meta_len = be32(self + meta_offset + 0x60 + 0x4); 367 | meta_n_hdr = be32(self + meta_offset + 0x60 + 0xc); 368 | meta_n_keys = be32(self + meta_offset + 0x60 + 0x10); 369 | 370 | printf(" Key: "); 371 | print_hash(self + meta_offset + 0x20, 0x10); 372 | printf("\n"); 373 | 374 | printf(" IV : "); 375 | print_hash(self + meta_offset + 0x40, 0x10); 376 | printf("\n"); 377 | 378 | printf(" Signature end %08x\n", meta_len); 379 | printf(" Sections %d\n", meta_n_hdr); 380 | printf(" Keys %d\n", meta_n_keys); 381 | printf("\n"); 382 | 383 | printf(" Sections\n"); 384 | printf(" Offset Length Key IV SHA1 Type\n"); 385 | for (i = 0; i < meta_n_hdr; i++) { 386 | tmp = self + meta_offset + 0x80 + 0x30*i; 387 | offset = be64(tmp); 388 | size = be64(tmp + 8); 389 | printf(" %08x_%08x %08x_%08x %03d %03d %03d %4d\n", 390 | (u32)(offset >> 32), (u32)offset, (u32)(size >> 32), (u32)size, 391 | be32(tmp + 0x24), be32(tmp + 0x28), be32(tmp + 0x1c), be32(tmp + 0x10)); 392 | } 393 | printf("\n"); 394 | 395 | printf(" Keys\n"); 396 | printf(" Idx Data\n"); 397 | tmp = self + meta_offset + 0x80 + 0x30*meta_n_hdr; 398 | for (i = 0; i < meta_n_keys; i++) { 399 | printf(" %03d ", i); 400 | print_hash(tmp + i*0x10, 0x10); 401 | printf("\n"); 402 | } 403 | printf("\n"); 404 | 405 | printf("\n"); 406 | 407 | } 408 | 409 | static void show_elf_header(void) 410 | { 411 | printf("ELF header\n"); 412 | 413 | printf(" type: %s\n", id2name(ehdr.e_type, t_elf_type, "unknown")); 414 | printf(" machine: %s\n", id2name(ehdr.e_machine, t_elf_machine, "unknown")); 415 | printf(" version: %d\n", ehdr.e_version); 416 | 417 | if (arch64) { 418 | printf(" phdr offset: %08x_%08x\n", 419 | (u32)(ehdr.e_phoff>>32), (u32)ehdr.e_phoff); 420 | printf(" shdr offset: %08x_%08x\n", 421 | (u32)(ehdr.e_phoff>>32), (u32)ehdr.e_shoff); 422 | printf(" entry: %08x_%08x\n", 423 | (u32)(ehdr.e_entry>>32), (u32)ehdr.e_entry); 424 | } else { 425 | printf(" phdr offset: %08x\n", 426 | (u32)ehdr.e_phoff); 427 | printf(" shdr offset: %08x\n", 428 | (u32)ehdr.e_shoff); 429 | printf(" entry: %08x\n", 430 | (u32)ehdr.e_entry); 431 | } 432 | 433 | printf(" flags: %08x\n", ehdr.e_flags); 434 | printf(" header size: %08x\n", ehdr.e_ehsize); 435 | printf(" program header size: %08x\n", 436 | ehdr.e_phentsize); 437 | printf(" program headers: %d\n", ehdr.e_phnum); 438 | printf(" section header size: %08x\n", 439 | ehdr.e_shentsize); 440 | printf(" section headers: %d\n", ehdr.e_shnum); 441 | printf(" section header string table index: %d\n", ehdr.e_shtrndx); 442 | 443 | printf("\n"); 444 | } 445 | 446 | static void get_flags(u32 flags, char *ptr) 447 | { 448 | memset(ptr, '-', 3); 449 | ptr[3] = 0; 450 | 451 | if (flags & 4) 452 | ptr[0] = 'r'; 453 | if (flags & 2) 454 | ptr[1] = 'w'; 455 | if (flags & 1) 456 | ptr[2] = 'x'; 457 | } 458 | 459 | static void show_phdr(unsigned int idx) 460 | { 461 | struct elf_phdr p; 462 | char ppc[4], spe[4], rsx[4]; 463 | 464 | elf_read_phdr(arch64, elf + phdr_offset + (ehdr.e_phentsize * idx), &p); 465 | 466 | get_flags(p.p_flags, ppc); 467 | get_flags(p.p_flags >> 20, spe); 468 | get_flags(p.p_flags >> 24, rsx); 469 | 470 | if (arch64) { 471 | printf(" %5s %08x_%08x %08x_%08x %08x_%08x\n" 472 | " %08x_%08x %08x_%08x" 473 | " %s %s %s %08x_%08x\n", 474 | id2name(p.p_type, t_phdr_type, "?????"), 475 | (u32)(p.p_off >> 32) , (u32)p.p_off, 476 | (u32)(p.p_vaddr >> 32) , (u32)p.p_vaddr, 477 | (u32)(p.p_paddr >> 32) , (u32)p.p_paddr, 478 | (u32)(p.p_memsz >> 32) , (u32)p.p_memsz, 479 | (u32)(p.p_filesz >> 32) , (u32)p.p_filesz, 480 | ppc, spe, rsx, 481 | (u32)(p.p_align >> 32) , (u32)p.p_align 482 | ); 483 | } else { 484 | printf(" %5s %08x %08x %08x " 485 | "%08x %08x %s %s %s %08x\n", 486 | id2name(p.p_type, t_phdr_type, "?????"), 487 | (u32)p.p_off, (u32)p.p_vaddr, 488 | (u32)p.p_paddr, (u32)p.p_memsz, (u32)p.p_filesz, 489 | ppc, spe, rsx, (u32)p.p_align); 490 | } 491 | } 492 | 493 | static void get_shdr_flags(u32 flags, char *ptr) 494 | { 495 | memset(ptr, ' ', 3); 496 | ptr[3] = 0; 497 | 498 | if (flags & 4) 499 | ptr[0] = 'w'; 500 | if (flags & 2) 501 | ptr[1] = 'a'; 502 | if (flags & 1) 503 | ptr[2] = 'e'; 504 | } 505 | 506 | static void show_shdr(unsigned int idx) 507 | { 508 | struct elf_shdr s; 509 | char flags[4]; 510 | 511 | elf_read_shdr(arch64, elf + shdr_offset + (ehdr.e_shentsize * idx), &s); 512 | get_shdr_flags(s.sh_flags, flags); 513 | 514 | if (arch64) { 515 | printf(" [%02d] %-15s %-9s %08x_%08x" 516 | " %02d %-3s %02d %03d %02d\n" 517 | " %08x_%08x %08x_%08x\n", 518 | idx, "", 519 | id2name(s.sh_type, t_shdr_type, "????"), 520 | (u32)(s.sh_addr >> 32), (u32)s.sh_addr, 521 | s.sh_entsize, flags, s.sh_link, s.sh_info, 522 | s.sh_addralign, 523 | (u32)(s.sh_offset >> 32), (u32)s.sh_offset, 524 | 0, (u32)s.sh_size 525 | ); 526 | } else { 527 | printf(" [%02d] %-15s %-9s %08x" 528 | " %08x %08x %02d %-3s %02d %02d %02d\n", 529 | idx, "", 530 | id2name(s.sh_type, t_shdr_type, "????"), 531 | (u32)s.sh_addr, (u32)s.sh_offset, 532 | s.sh_size, s.sh_entsize, 533 | flags, s.sh_link, s.sh_info, s.sh_addralign); 534 | 535 | } 536 | } 537 | 538 | static void show_phdrs(void) 539 | { 540 | unsigned int i; 541 | 542 | printf("Program headers\n"); 543 | 544 | if (ehdr.e_phnum == 0) { 545 | printf("No program headers in this file.\n"); 546 | } else { 547 | if (arch64) 548 | printf(" type offset vaddr " 549 | "paddr\n memsize filesize" 550 | " PPU SPE RSX align\n"); 551 | else 552 | printf(" type offset vaddr paddr " 553 | "memsize filesize PPU SPE RSX align\n"); 554 | for (i = 0; i < ehdr.e_phnum; i++) 555 | show_phdr(i); 556 | } 557 | 558 | printf("\n"); 559 | } 560 | 561 | static void show_shdrs(void) 562 | { 563 | unsigned int i; 564 | 565 | printf("Section headers\n"); 566 | 567 | if (ehdr.e_shnum == 0) { 568 | printf("No section headers in this file.\n"); 569 | } else { 570 | if (arch64) 571 | printf(" [Nr] Name Type Addr" 572 | " ES Flg Lk Inf Al\n" 573 | " Off Size\n"); 574 | else 575 | printf(" [Nr] Name Type Addr" 576 | " Off Size ES Flg Lk Inf Al\n"); 577 | for (i = 0; i < ehdr.e_shnum; i++) 578 | show_shdr(i); 579 | } 580 | 581 | printf("\n"); 582 | } 583 | 584 | int main(int argc, char *argv[]) 585 | { 586 | if (argc != 2) 587 | fail("usage: readself file.self"); 588 | 589 | self = mmap_file(argv[1]); 590 | 591 | parse_self(); 592 | decrypt_header(); 593 | 594 | show_self_header(); 595 | show_ctrl(); 596 | show_sinfo(); 597 | show_meta(); 598 | show_elf_header(); 599 | show_phdrs(); 600 | show_shdrs(); 601 | 602 | return 0; 603 | } 604 | -------------------------------------------------------------------------------- /self.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This software is distributed under the terms of the GNU General Public 3 | * License ("GPL") version 2, as published by the Free Software Foundation. 4 | */ 5 | 6 | #include "tools.h" 7 | #include "self.h" 8 | #include "common.h" 9 | 10 | #include 11 | #include 12 | 13 | static struct keylist *load_keys(APP_INFO *app_info); 14 | static int decrypt_metadata(uint8_t *metadata, uint32_t metadata_size, 15 | struct keylist *klist); 16 | static int remove_npdrm(SELF *self, CONTROL_INFO *control_info, uint8_t *metadata, 17 | struct keylist *klist); 18 | static void decrypt_npdrm(uint8_t *metadata, struct keylist *klist, 19 | struct key *klicensee); 20 | 21 | 22 | 23 | 24 | void 25 | self_read_headers(FILE *in, SELF *self, APP_INFO *app_info, ELF *elf, 26 | ELF_PHDR **phdr, ELF_SHDR **shdr, SECTION_INFO **section_info, 27 | SCEVERSION_INFO *sceversion_info, CONTROL_INFO **control_info) 28 | { 29 | 30 | // SELF 31 | if (fread (self, sizeof(SELF), 1, in) != 1) { 32 | ERROR (-3, "Couldn't read SELF header"); 33 | } 34 | 35 | self->magic = swap32 (self->magic); 36 | self->version = swap32 (self->version); 37 | self->flags = swap16 (self->flags); 38 | self->type = swap16 (self->type); 39 | self->metadata_offset = swap32 (self->metadata_offset); 40 | self->header_len = swap64 (self->header_len); 41 | self->elf_filesize = swap64 (self->elf_filesize); 42 | self->appinfo_offset = swap64 (self->appinfo_offset); 43 | self->elf_offset = swap64 (self->elf_offset); 44 | self->phdr_offset = swap64 (self->phdr_offset); 45 | self->shdr_offset = swap64 (self->shdr_offset); 46 | self->section_info_offset = swap64 (self->section_info_offset); 47 | self->sceversion_offset = swap64 (self->sceversion_offset); 48 | self->controlinfo_offset = swap64 (self->controlinfo_offset); 49 | self->controlinfo_size = swap64 (self->controlinfo_size); 50 | 51 | if (self->magic != SCE_MAGIC) { 52 | ERROR (-3, "not a SELF\n"); 53 | } 54 | 55 | // APP INFO 56 | if (app_info) { 57 | fseek (in, self->appinfo_offset, SEEK_SET); 58 | if (fread (app_info, sizeof(APP_INFO), 1, in) != 1) { 59 | ERROR (-3, "Couldn't read APP INFO header"); 60 | } 61 | app_info->authid = swap64 (app_info->authid); 62 | app_info->vendor_id = swap32 (app_info->vendor_id); 63 | app_info->self_type = swap32 (app_info->self_type); 64 | app_info->version = swap32 (app_info->version); 65 | } 66 | 67 | // ELF 68 | if (elf) { 69 | fseek (in, self->elf_offset, SEEK_SET); 70 | if (fread (elf, sizeof(ELF), 1, in) != 1) { 71 | ERROR (-3, "Couldn't read APP INFO header"); 72 | } 73 | elf->type = swap16 (elf->type); 74 | elf->machine = swap16 (elf->machine); 75 | elf->version = swap32 (elf->version); 76 | elf->entry_point = swap64 (elf->entry_point); 77 | elf->phdr_offset = swap64 (elf->phdr_offset); 78 | elf->shdr_offset = swap64 (elf->shdr_offset); 79 | elf->flags = swap16 (elf->flags); 80 | elf->header_size = swap32 (elf->header_size); 81 | elf->phent_size = swap16 (elf->phent_size); 82 | elf->phnum = swap16 (elf->phnum); 83 | elf->shent_size = swap16 (elf->shent_size); 84 | elf->shnum = swap16 (elf->shnum); 85 | elf->shstrndx = swap16 (elf->shstrndx); 86 | } 87 | 88 | // PHDR and SECTION INFO 89 | if (phdr || section_info) { 90 | uint16_t phnum = 0; 91 | uint16_t i; 92 | 93 | if (elf) { 94 | phnum = elf->phnum; 95 | } else { 96 | fseek (in, self->elf_offset + 52, SEEK_SET); 97 | fread (&phnum, sizeof(uint16_t), 1, in); 98 | } 99 | 100 | if (phdr) { 101 | ELF_PHDR *elf_phdr = NULL; 102 | 103 | elf_phdr = malloc (sizeof(ELF_PHDR) * phnum); 104 | 105 | fseek (in, self->phdr_offset, SEEK_SET); 106 | if (fread (elf_phdr, sizeof(ELF_PHDR), phnum, in) != phnum) { 107 | ERROR (-3, "Couldn't read ELF PHDR header"); 108 | } 109 | 110 | for (i = 0; i < phnum; i++) { 111 | elf_phdr[i].type = swap32 (elf_phdr[i].type); 112 | elf_phdr[i].flags = swap32 (elf_phdr[i].flags); 113 | elf_phdr[i].offset_in_file = swap64 (elf_phdr[i].offset_in_file); 114 | elf_phdr[i].vitual_addr = swap64 (elf_phdr[i].vitual_addr); 115 | elf_phdr[i].phys_addr = swap64 (elf_phdr[i].phys_addr); 116 | elf_phdr[i].segment_size = swap64 (elf_phdr[i].segment_size); 117 | elf_phdr[i].segment_mem_size = swap64 (elf_phdr[i].segment_mem_size); 118 | elf_phdr[i].alignment = swap64 (elf_phdr[i].alignment); 119 | } 120 | 121 | *phdr = elf_phdr; 122 | } 123 | 124 | // SECTION INFO 125 | if (section_info) { 126 | SECTION_INFO *sections = NULL; 127 | 128 | sections = malloc (sizeof(SECTION_INFO) * phnum); 129 | 130 | fseek (in, self->section_info_offset, SEEK_SET); 131 | if (fread (sections, sizeof(SECTION_INFO), phnum, in) != phnum) { 132 | ERROR (-3, "Couldn't read SECTION INFO header"); 133 | } 134 | 135 | for (i = 0; i < phnum; i++) { 136 | sections[i].offset = swap64 (sections[i].offset); 137 | sections[i].size = swap64 (sections[i].size); 138 | sections[i].compressed = swap32 (sections[i].compressed); 139 | sections[i].encrypted = swap32 (sections[i].encrypted); 140 | } 141 | 142 | *section_info = sections; 143 | } 144 | } 145 | 146 | // SCE VERSION INFO 147 | if (sceversion_info) { 148 | fseek (in, self->sceversion_offset, SEEK_SET); 149 | if (fread (sceversion_info, sizeof(SCEVERSION_INFO), 1, in) != 1) { 150 | ERROR (-3, "Couldn't read SCE VERSION INFO header"); 151 | } 152 | } 153 | 154 | // CONTROL INFO 155 | if (control_info) { 156 | uint32_t offset = 0; 157 | uint32_t index = 0; 158 | CONTROL_INFO *info = NULL; 159 | 160 | while (offset < self->controlinfo_size) { 161 | 162 | info = realloc (info, sizeof(CONTROL_INFO) * (index + 1)); 163 | 164 | fseek (in, self->controlinfo_offset + offset, SEEK_SET); 165 | 166 | if (fread (info + index, sizeof(CONTROL_INFO), 1, in) != 1) { 167 | ERROR (-3, "Couldn't read CONTROL INFO header"); 168 | } 169 | 170 | info[index].type = swap32 (info[index].type); 171 | info[index].size = swap32 (info[index].size); 172 | if (info[index].type == 1) 173 | info[index].control_flags.control_flags = 174 | swap64 (info[index].control_flags.control_flags); 175 | if (info[index].type == 3) 176 | info[index].npdrm.license_type = 177 | swap32 (info[index].npdrm.license_type); 178 | 179 | offset += info[index].size; 180 | index++; 181 | } 182 | *control_info = info; 183 | } 184 | 185 | 186 | // SHDR 187 | if (shdr) { 188 | uint16_t shnum = 0; 189 | uint16_t i; 190 | ELF_SHDR *elf_shdr = NULL; 191 | 192 | if (elf) { 193 | shnum = elf->shnum; 194 | } else { 195 | fseek (in, self->elf_offset + 56, SEEK_SET); 196 | fread (&shnum, sizeof(uint16_t), 1, in); 197 | } 198 | 199 | if (shnum > 0 && self->shdr_offset != 0) { 200 | elf_shdr = malloc (sizeof(ELF_SHDR) * shnum); 201 | 202 | fseek (in, self->shdr_offset, SEEK_SET); 203 | if (fread (elf_shdr, sizeof(ELF_SHDR), shnum, in) != shnum) { 204 | ERROR (-3, "Couldn't read ELF SHDR header"); 205 | } 206 | 207 | for (i = 0; i < shnum; i++) { 208 | elf_shdr[i].name_idx = swap32 (elf_shdr[i].name_idx); 209 | elf_shdr[i].type = swap32 (elf_shdr[i].type); 210 | elf_shdr[i].flags = swap64 (elf_shdr[i].flags); 211 | elf_shdr[i].virtual_addr = swap64 (elf_shdr[i].virtual_addr); 212 | elf_shdr[i].offset_in_file = swap64 (elf_shdr[i].offset_in_file); 213 | elf_shdr[i].segment_size = swap64 (elf_shdr[i].segment_size); 214 | elf_shdr[i].link = swap32 (elf_shdr[i].link); 215 | elf_shdr[i].info = swap32 (elf_shdr[i].info); 216 | elf_shdr[i].addr_align = swap64 (elf_shdr[i].addr_align); 217 | elf_shdr[i].entry_size = swap64 (elf_shdr[i].entry_size); 218 | } 219 | 220 | *shdr = elf_shdr; 221 | } 222 | } 223 | 224 | } 225 | 226 | 227 | void 228 | self_read_metadata (FILE *in, SELF *self, APP_INFO *app_info, 229 | METADATA_INFO *metadata_info, METADATA_HEADER *metadata_header, 230 | METADATA_SECTION_HEADER **section_headers, uint8_t **keys, 231 | SIGNATURE_INFO *signature_info, SIGNATURE *signature, CONTROL_INFO *control_info) 232 | { 233 | uint8_t *metadata = NULL; 234 | uint32_t metadata_size = self->header_len - self->metadata_offset - 0x20; 235 | uint8_t *ptr = NULL; 236 | uint32_t i; 237 | 238 | metadata = malloc (metadata_size); 239 | fseek (in, self->metadata_offset + 0x20, SEEK_SET); 240 | 241 | if (fread (metadata, 1, metadata_size, in) != metadata_size) { 242 | ERROR (-3, "Couldn't read METADATA"); 243 | } 244 | 245 | if (self->flags != 0x800) { 246 | struct keylist *klist; 247 | 248 | klist = load_keys(app_info); 249 | if (klist == NULL) 250 | ERROR(-5, "no key found"); 251 | 252 | if (remove_npdrm (self, control_info, metadata, klist) < 0) 253 | ERROR (-5, "Error removing NPDRM"); 254 | 255 | if (decrypt_metadata (metadata, metadata_size, klist) < 0) 256 | ERROR (-5, "Error decrypting metadata"); 257 | } 258 | 259 | ptr = metadata; 260 | *metadata_info = *((METADATA_INFO *)ptr); 261 | ptr += sizeof(METADATA_INFO); 262 | if (metadata_header) { 263 | *metadata_header = *((METADATA_HEADER *)ptr); 264 | metadata_header->signature_input_length = 265 | swap64 (metadata_header->signature_input_length); 266 | metadata_header->section_count = swap32 (metadata_header->section_count); 267 | metadata_header->key_count = swap32 (metadata_header->key_count); 268 | metadata_header->signature_info_size = 269 | swap32 (metadata_header->signature_info_size); 270 | } 271 | ptr += sizeof(METADATA_HEADER); 272 | if (section_headers) { 273 | *section_headers = malloc (sizeof(METADATA_SECTION_HEADER) * 274 | metadata_header->section_count); 275 | for (i = 0; i < metadata_header->section_count; i++) { 276 | (*section_headers)[i] = *((METADATA_SECTION_HEADER *)ptr); 277 | ptr += sizeof(METADATA_SECTION_HEADER); 278 | (*section_headers)[i].data_offset = swap64 ((*section_headers)[i].data_offset); 279 | (*section_headers)[i].data_size = swap64 ((*section_headers)[i].data_size); 280 | (*section_headers)[i].type = swap32 ((*section_headers)[i].type); 281 | (*section_headers)[i].program_idx = swap32 ((*section_headers)[i].program_idx); 282 | (*section_headers)[i].sha1_idx = swap32 ((*section_headers)[i].sha1_idx); 283 | (*section_headers)[i].encrypted = swap32 ((*section_headers)[i].encrypted); 284 | (*section_headers)[i].key_idx = swap32 ((*section_headers)[i].key_idx); 285 | (*section_headers)[i].iv_idx = swap32 ((*section_headers)[i].iv_idx); 286 | (*section_headers)[i].compressed = swap32 ((*section_headers)[i].compressed); 287 | }; 288 | } else { 289 | ptr += sizeof(METADATA_SECTION_HEADER) * metadata_header->section_count; 290 | } 291 | *keys = malloc (metadata_header->key_count * 0x10); 292 | memcpy (*keys, ptr, metadata_header->key_count * 0x10); 293 | ptr += metadata_header->key_count * 0x10; 294 | if (signature_info) { 295 | *signature_info = *((SIGNATURE_INFO *)ptr); 296 | signature_info->signature_size = swap32 (signature_info->signature_size); 297 | } 298 | ptr += sizeof(SIGNATURE_INFO); 299 | if (signature) { 300 | *signature = *((SIGNATURE *)ptr); 301 | } 302 | ptr += sizeof(SIGNATURE); 303 | free (metadata); 304 | } 305 | 306 | int 307 | self_load_sections (FILE *in, SELF *self, ELF *elf, ELF_PHDR **phdr, 308 | METADATA_HEADER *metadata_header, METADATA_SECTION_HEADER **section_headers, 309 | uint8_t **keys, SELF_SECTION **sections) 310 | { 311 | uint32_t num_sections = 0; 312 | uint32_t i; 313 | 314 | num_sections = metadata_header->section_count + 1; 315 | 316 | *sections = malloc (sizeof(SELF_SECTION) * num_sections); 317 | // ELF header 318 | for (i = 0; i < num_sections; i++) { 319 | uint32_t size; 320 | METADATA_SECTION_HEADER *hdr; 321 | 322 | if (i == 0) { 323 | uint32_t elf_size; 324 | 325 | hdr = (*section_headers); 326 | elf_size = elf->header_size + (elf->phent_size * elf->phnum); 327 | size = hdr->data_offset - self->header_len; 328 | if (size < elf_size) 329 | size = elf_size; 330 | (*sections)[i].offset = 0; 331 | (*sections)[i].size = size; 332 | (*sections)[i].data = malloc (size); 333 | 334 | fseek (in, self->header_len, SEEK_SET); 335 | if (fread ((*sections)[0].data, 1, size, in) != size) { 336 | ERROR (-6, "Couldn't read section"); 337 | } 338 | 339 | fseek (in, self->elf_offset, SEEK_SET); 340 | if (fread ((*sections)[0].data, 1, size, in) != size) { 341 | ERROR (-6, "Couldn't read section"); 342 | } 343 | } else { 344 | uint8_t *temp_data = NULL; 345 | 346 | hdr = (*section_headers) + i - 1; 347 | if (hdr->type == 2) { 348 | // phdr 349 | size = (*phdr)[hdr->program_idx].segment_size; 350 | (*sections)[i].offset = (*phdr)[hdr->program_idx].offset_in_file; 351 | } else if (hdr->type == 1) { 352 | // shdr 353 | size = (*section_headers)[i-1].data_size; 354 | (*sections)[i].offset = elf->shdr_offset; 355 | } else { 356 | (*sections)[i].offset = UINT64_MAX; 357 | printf("Section %d unkown type: %d. Skipping!\n", i, hdr->type); 358 | } 359 | 360 | (*sections)[i].size = size; 361 | (*sections)[i].data = malloc (size); 362 | 363 | temp_data = malloc (hdr->data_size); 364 | fseek (in, hdr->data_offset, SEEK_SET); 365 | if (fread (temp_data, 1, hdr->data_size, in) != hdr->data_size) { 366 | ERROR (-6, "Couldn't read section"); 367 | } 368 | 369 | if (hdr->encrypted == 3) 370 | aes128ctr(*keys + 0x10 * hdr->key_idx, *keys + 0x10 * hdr->iv_idx, 371 | temp_data, hdr->data_size, temp_data); 372 | 373 | if (hdr->compressed == 2) 374 | decompress(temp_data, hdr->data_size, (*sections)[i].data, size); 375 | else 376 | memcpy ((*sections)[i].data, temp_data, size); 377 | 378 | free (temp_data); 379 | } 380 | } 381 | 382 | return num_sections; 383 | } 384 | 385 | void 386 | self_free_sections (SELF_SECTION **sections, uint32_t num_sections) 387 | { 388 | uint32_t i; 389 | 390 | for (i = 0; i < num_sections; i++) { 391 | free ((*sections)[i].data); 392 | } 393 | free (*sections); 394 | *sections = NULL; 395 | } 396 | 397 | static struct keylist * 398 | load_keys(APP_INFO *app_info) 399 | { 400 | enum sce_key id; 401 | 402 | switch (app_info->self_type) { 403 | case 1: 404 | id = KEY_LV0; 405 | break; 406 | case 2: 407 | id = KEY_LV1; 408 | break; 409 | case 3: 410 | id = KEY_LV2; 411 | break; 412 | case 4: 413 | id = KEY_APP; 414 | break; 415 | case 5: 416 | id = KEY_ISO; 417 | break; 418 | case 6: 419 | id = KEY_LDR; 420 | break; 421 | case 8: 422 | id = KEY_NPDRM; 423 | break; 424 | default: 425 | fprintf (stderr, "SELF type is invalid : 0x%08X\n", app_info->self_type); 426 | exit (-4); 427 | } 428 | 429 | return keys_get(id); 430 | } 431 | 432 | static int 433 | remove_npdrm(SELF *self, CONTROL_INFO *control_info, uint8_t *metadata, struct keylist *klist) 434 | { 435 | CONTROL_INFO *info; 436 | u32 license_type; 437 | char content_id[0x31] = {'\0'}; 438 | struct rif *rif; 439 | struct actdat *actdat; 440 | u8 enc_const[0x10]; 441 | u8 dec_actdat[0x10]; 442 | struct key klicensee; 443 | int i; 444 | u64 off; 445 | 446 | for (i = off = 0; off < self->controlinfo_size; i++) { 447 | info = &control_info[i]; 448 | if (info->type == 3) { 449 | license_type = info->npdrm.license_type; 450 | switch (license_type) { 451 | case 1: 452 | // cant decrypt network stuff 453 | return -1; 454 | case 2: 455 | memcpy(content_id, info->npdrm.content_id, 0x30); 456 | rif = rif_get(content_id); 457 | if (rif == NULL) { 458 | return -1; 459 | } 460 | aes128(klist->rif->key, rif->padding, rif->padding); 461 | aes128_enc(klist->idps->key, klist->npdrm_const->key, enc_const); 462 | actdat = actdat_get(); 463 | if (actdat == NULL) { 464 | return -1; 465 | } 466 | aes128(enc_const, &actdat->keyTable[swap32(rif->actDatIndex)*0x10], dec_actdat); 467 | aes128(dec_actdat, rif->key, klicensee.key); 468 | decrypt_npdrm(metadata, klist, &klicensee); 469 | return 1; 470 | case 3: 471 | decrypt_npdrm(metadata, klist, klist->free_klicensee); 472 | return 1; 473 | } 474 | } 475 | 476 | off += info->size; 477 | } 478 | return 0; 479 | } 480 | 481 | static void 482 | decrypt_npdrm(uint8_t *metadata, struct keylist *klist, struct key *klicensee) 483 | { 484 | struct key d_klic; 485 | 486 | // iv is 0 487 | memset(&d_klic, 0, sizeof(struct key)); 488 | aes128(klist->klic->key, klicensee->key, d_klic.key); 489 | 490 | aes128cbc(d_klic.key, d_klic.iv, metadata, 0x40, metadata); 491 | } 492 | 493 | static int 494 | decrypt_metadata(uint8_t *metadata, uint32_t metadata_size, 495 | struct keylist *klist) 496 | { 497 | uint32_t i; 498 | METADATA_INFO metadata_info; 499 | uint8_t zero[16] = {0}; 500 | 501 | for (i = 0; i < klist->n; i++) { 502 | aes256cbc(klist->keys[i].key, klist->keys[i].iv, 503 | metadata, sizeof(METADATA_INFO), (uint8_t *) &metadata_info); 504 | 505 | if (memcmp (metadata_info.key_pad, zero, 16) == 0 && 506 | memcmp (metadata_info.iv_pad, zero, 16) == 0) { 507 | memcpy(metadata, &metadata_info, sizeof(METADATA_INFO)); 508 | break; 509 | } 510 | } 511 | 512 | if (i >= klist->n) 513 | return -1; 514 | 515 | aes128ctr(metadata_info.key, metadata_info.iv, 516 | metadata + sizeof(METADATA_INFO), 517 | metadata_size - sizeof(METADATA_INFO), 518 | metadata + sizeof(METADATA_INFO)); 519 | 520 | return i; 521 | } 522 | -------------------------------------------------------------------------------- /self_rebuilder.c: -------------------------------------------------------------------------------- 1 | // based on fail0verflow reverse engineering of self executables 2 | // Copyright 2010 Sven Peter 3 | // 2011 Modified By Anonymous developers on EFNET 4 | // Licensed under the terms of the GNU GPL, version 2 5 | // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt 6 | 7 | #include "tools.h" 8 | #include "types.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define ALIGNMENT 0x20 18 | #define MAX_PHDR 255 19 | //#define DEBUG 1 20 | 21 | // pseudo header for self_rebuilder 22 | // All structure start here 23 | static struct { 24 | u32 offset ; 25 | u32 size ; 26 | u32 compressed ; 27 | u32 size_uncompressed ; 28 | u32 elf_offset ; 29 | } self_sections[MAX_PHDR] ; 30 | 31 | struct self_sec { 32 | u32 idx ; 33 | u64 offset ; 34 | u64 size ; 35 | u32 compressed ; 36 | u32 encrypted ; 37 | u64 next ; 38 | } ; 39 | 40 | static struct { 41 | u32 count ; 42 | u32 address ; 43 | int size ; 44 | u32 number ; 45 | u32 compressed ; 46 | } compressed_sections[MAX_PHDR] ; 47 | 48 | enum { 49 | VERIFY_HASH = 0, 50 | SIGN_HASH, 51 | } ; 52 | 53 | // end 54 | 55 | static u8 *elf = NULL ; 56 | static u8 *self = NULL ; 57 | 58 | static u32 type ; 59 | static int packed_type ; 60 | 61 | struct elf_hdr ehdr ; 62 | struct elf_shdr eshdr ; 63 | struct elf_phdr phdr[MAX_PHDR] ; 64 | 65 | static int arch64 ; 66 | 67 | static u32 meta_offset ; 68 | static u64 elf_size ; 69 | static u64 info_offset ; 70 | static u64 elf_offset ; 71 | static u64 phdr_offset ; 72 | static u64 shdr_offset ; 73 | static u64 sec_offset ; 74 | static u64 ctrl_offset ; 75 | static u64 version ; 76 | static u64 auth_id ; 77 | static u64 vendor_id ; 78 | static u16 sdk_type ; 79 | static char versionsuffix[4] ; 80 | 81 | static u32 n_sections ; 82 | 83 | // readself 84 | static u64 filesize ; 85 | static int self_size ; 86 | static u64 header_len ; 87 | static u64 ver_info ; 88 | static u64 ctrl_size ; 89 | static int decrypted = -1 ; 90 | 91 | // 92 | struct key ks ; 93 | 94 | static const char *elf_name = NULL ; 95 | static const char *self_name = NULL ; 96 | 97 | struct id2name_tbl t_sdk_type[] = { 98 | {0, "Retail (Type 0)"}, 99 | {1, "Retail"}, 100 | {2, "Retail (Type 1)"}, 101 | {3, "Unknown SDK3"}, 102 | {4, "Unknown > = 3.42"}, 103 | {5, "Unknown SDK5"}, 104 | {6, "Unknown SDK6"}, 105 | {7, "Unknown > = 3.50"}, 106 | {8, "Unknown SDK8"}, 107 | {9, "Unknown SDK9"}, 108 | {0x8000, "Devkit"}, 109 | {0, NULL} 110 | } ; 111 | 112 | struct id2name_tbl t_app_type[] = { 113 | {1, "level 0"}, 114 | {2, "level 1"}, 115 | {3, "level 2"}, 116 | {4, "application"}, 117 | {5, "isolated SPU module"}, 118 | {6, "secure loader"}, 119 | {7, "unknown app type"}, 120 | {8, "NP-DRM application"}, 121 | {0, NULL} 122 | } ; 123 | 124 | static void 125 | get_keys (const char *suffix) 126 | { 127 | if (key_get (packed_type, suffix, &ks) < 0) { 128 | fail ("key_get failed") ; 129 | } 130 | 131 | if (ks.pub_avail < 0) { 132 | fail ("no public key available") ; 133 | } 134 | 135 | if (ks.priv_avail < 0) { 136 | fail ("no private key available") ; 137 | } 138 | 139 | if (ecdsa_set_curve (ks.ctype) < 0) { 140 | fail ("ecdsa_set_curve failed") ; 141 | } 142 | 143 | ecdsa_set_pub (ks.pub) ; 144 | ecdsa_set_priv (ks.priv) ; 145 | } 146 | 147 | static void 148 | parse_elf (void) 149 | { 150 | u32 i ; 151 | 152 | arch64 = elf_read_hdr (elf, &ehdr) ; 153 | 154 | for (i = 0; i < ehdr.e_phnum; i++) { 155 | elf_read_phdr (arch64, elf + ehdr.e_phoff + i * ehdr.e_phentsize, &phdr[i]) ; 156 | } 157 | } 158 | 159 | static void 160 | parse_self (void) 161 | { 162 | //here we are taking every self information needed and more 163 | sdk_type = be16 (self + 0x08) ; 164 | meta_offset = be32 (self + 0x0c) ; 165 | header_len = be64 (self + 0x10) ; 166 | filesize = be64 (self + 0x18) ; 167 | info_offset = be64 (self + 0x28) ; 168 | elf_offset = be64 (self + 0x30) ; 169 | phdr_offset = be64 (self + 0x38) - elf_offset ; 170 | shdr_offset = be64 (self + 0x40) - elf_offset ; 171 | sec_offset = be64 (self + 0x48) ; 172 | ver_info = be64 (self + 0x50) ; 173 | ctrl_offset = be64 (self + 0x58) ; 174 | ctrl_size = be64 (self + 0x60) ; 175 | 176 | vendor_id = be32 (self + info_offset + 0x08) ; 177 | auth_id = be64 (self + info_offset + 0x00) ; 178 | type = be32 (self + info_offset + 0x0c) ; 179 | packed_type = (type - 1) ; 180 | version = be64 (self + info_offset + 0x10) ; 181 | 182 | elf = self + elf_offset ; 183 | arch64 = elf_read_hdr (elf, &ehdr) ; 184 | } 185 | 186 | static int 187 | qsort_compare (const void *a, const void *b) 188 | { 189 | const struct self_sec *sa, *sb ; 190 | 191 | sa = a ; 192 | sb = b ; 193 | 194 | if (sa->offset > sb->offset) { 195 | return 1 ; 196 | } else if (sa->offset < sb->offset) { 197 | return -1 ; 198 | } else { 199 | return 0 ; 200 | } 201 | } 202 | 203 | static void 204 | read_section (u32 i, struct self_sec *sec) 205 | { 206 | u8 *ptr ; 207 | 208 | ptr = self + sec_offset + i * 0x20 ; 209 | 210 | sec->idx = i ; 211 | sec->offset = be64 (ptr + 0x00) ; 212 | sec->size = be64 (ptr + 0x08) ; 213 | sec->compressed = be32 (ptr + 0x10) == 2 ? 1 : 0 ; 214 | sec->encrypted = be32 (ptr + 0x1c) ; 215 | sec->next = be64 (ptr + 0x20) ; 216 | } 217 | 218 | 219 | // Change compressed section size 220 | static void 221 | change_section_size (u32 i, u64 size) 222 | { 223 | u8 *ptr ; 224 | 225 | ptr = self + sec_offset + i * 0x20 ; 226 | 227 | self_sections[i + 1].size = size ; 228 | wbe64 (ptr + 0x08, size) ; 229 | wbe64 (self + meta_offset + 0x60 + 0x20 + i * 0x30 + 0x08, size) ; 230 | } 231 | 232 | // Change compressed section offset 233 | /* 234 | static void 235 | change_section_offset (u32 i, int delta) 236 | { 237 | u8 *ptr ; 238 | u64 val ; 239 | 240 | ptr = self + sec_offset + i * 0x20 ; 241 | val = be64 (ptr) ; 242 | val += delta ; 243 | wbe64 (ptr, val) ; 244 | 245 | self_sections[i + 1].offset = val ; 246 | wbe64 (self + meta_offset + 0x60 + 0x20 + i * 0x30 + 0x00, val) ; 247 | compressed_sections[i].address += delta ; 248 | 249 | } 250 | */ 251 | 252 | // read every original section to know the number and the position 253 | static void 254 | read_sections (void) 255 | { 256 | struct self_sec s[MAX_PHDR] ; 257 | struct elf_phdr p ; 258 | u32 i ; 259 | u32 j ; 260 | u32 n_secs ; 261 | u32 self_offset, elf_offset ; 262 | 263 | memset (s, 0, sizeof s) ; 264 | for (i = 0, j = 0; i < ehdr.e_phnum; i++) { 265 | read_section (i, &s[j]) ; 266 | if (s[j].compressed) { 267 | j++ ; 268 | } 269 | } 270 | 271 | n_secs = j ; 272 | qsort (s, n_secs, sizeof (*s), qsort_compare) ; 273 | 274 | elf_offset = 0 ; 275 | self_offset = header_len ; 276 | j = 0 ; 277 | i = 0 ; 278 | while (elf_offset < filesize) { 279 | if (i == n_secs) { 280 | self_sections[j].offset = self_offset ; 281 | self_sections[j].size = filesize - elf_offset ; 282 | self_sections[j].compressed = 0 ; 283 | self_sections[j].size_uncompressed = filesize - elf_offset ; 284 | self_sections[j].elf_offset = elf_offset ; 285 | elf_offset = filesize ; 286 | } else if (self_offset == s[i].offset) { 287 | self_sections[j].offset = self_offset ; 288 | self_sections[j].size = s[i].size ; 289 | compressed_sections[i].size = self_sections[j].size ; 290 | compressed_sections[i].address = self_sections[j].offset ; 291 | self_sections[j].compressed = 1 ; 292 | elf_read_phdr (arch64, elf + phdr_offset + (ehdr.e_phentsize * s[i].idx), &p) ; 293 | self_sections[j].size_uncompressed = p.p_filesz ; 294 | self_sections[j].elf_offset = p.p_off ; 295 | elf_offset = p.p_off + p.p_filesz ; 296 | self_offset = s[i].next ; 297 | compressed_sections[i].number = j ; 298 | compressed_sections[i].compressed = 1 ; 299 | #ifdef DEBUG 300 | printf ("section number compressed %d size 0x%x\n", 301 | compressed_sections[0].count, compressed_sections[i].size) ; 302 | #endif 303 | i++ ; 304 | compressed_sections[0].count = i ; 305 | } else { 306 | elf_read_phdr (arch64, elf + phdr_offset + (ehdr.e_phentsize * s[i].idx), &p) ; 307 | self_sections[j].offset = self_offset ; 308 | self_sections[j].size = p.p_off - elf_offset ; 309 | self_sections[j].compressed = 0 ; 310 | self_sections[j].size_uncompressed = self_sections[j].size ; 311 | self_sections[j].elf_offset = elf_offset ; 312 | 313 | elf_offset += self_sections[j].size ; 314 | self_offset += s[i].offset - self_offset ; 315 | } 316 | j++ ; 317 | } 318 | n_sections = j ; 319 | } 320 | 321 | 322 | static void 323 | write_sections (void) 324 | { 325 | unsigned int i = 0 ; 326 | unsigned int level ; 327 | unsigned long size_compressed = 16 * 1024 * 1024 ; 328 | u8 *compressed_buffer = NULL ; 329 | 330 | for (i = 0; i < compressed_sections[0].count; i++) { 331 | level = 7 ; 332 | if (compressed_sections[i].compressed) { 333 | size_compressed = 16 * 1024 * 1024 ; 334 | compressed_buffer = malloc (size_compressed) ; 335 | if (compress2 (compressed_buffer, &size_compressed, 336 | elf + phdr[i].p_off, phdr[i].p_filesz, 6) != Z_OK) { 337 | perror ("couldn't compress data") ; 338 | exit (-1) ; 339 | } 340 | 341 | #if 1 342 | while ( (int) size_compressed > compressed_sections[i].size ) { 343 | if (compress2 (compressed_buffer, &size_compressed, 344 | elf + phdr[i].p_off, phdr[i].p_filesz, level) != Z_OK) { 345 | perror ("couldn't compress data") ; 346 | exit (-1) ; 347 | } 348 | if ( (int) size_compressed > compressed_sections[i].size) { 349 | if ( level > 9 ) { 350 | perror ("Compressed data is too big") ; 351 | exit (-1) ; 352 | } 353 | } 354 | level++; 355 | } 356 | #else 357 | { 358 | int delta, j ; 359 | delta = size_compressed - compressed_sections[i].size ; 360 | 361 | if (delta % 0x10 != 0) { 362 | delta += (0x10 - delta % 0x10) ; 363 | } 364 | self_size += delta ; 365 | for (j = i + 1; j < compressed_sections[0].count; j++) { 366 | change_section_offset (j, delta) ; 367 | } 368 | } 369 | #endif 370 | 371 | printf (" ELF section %02x\n level: %d\n size: 0x%x\n new size: 0x%x\n", 372 | compressed_sections[i].number, 373 | (int) level, 374 | compressed_sections[i].size, 375 | (unsigned int) size_compressed) ; 376 | change_section_size (i, size_compressed) ; 377 | 378 | memcpy (self + compressed_sections[i].address, compressed_buffer, 379 | size_compressed) ; 380 | compressed_sections[i].size = size_compressed ; 381 | free (compressed_buffer) ; 382 | } 383 | } 384 | printf ("\n") ; 385 | } 386 | 387 | static void 388 | sign_header (void) 389 | { 390 | u8 *r, *s ; 391 | u8 hash[20] ; 392 | u64 sig_len ; 393 | 394 | sig_len = be64 (self + meta_offset + 0x60) ; 395 | r = self + sig_len ; 396 | s = r + 21 ; 397 | 398 | sha1 (self, sig_len, hash) ; 399 | 400 | ecdsa_sign (hash, r, s) ; 401 | } 402 | 403 | static u64 404 | get_filesize (const char *path) 405 | { 406 | struct stat st ; 407 | 408 | stat (path, &st) ; 409 | 410 | return st.st_size ; 411 | } 412 | 413 | static struct keylist * 414 | self_load_keys (void) 415 | { 416 | enum sce_key id ; 417 | 418 | switch (type) { 419 | case 1: 420 | id = KEY_LV0 ; 421 | break ; 422 | case 2: 423 | id = KEY_LV1 ; 424 | break ; 425 | case 3: 426 | id = KEY_LV2 ; 427 | break ; 428 | case 4: 429 | id = KEY_APP ; 430 | break ; 431 | case 5: 432 | id = KEY_ISO ; 433 | break ; 434 | case 6: 435 | id = KEY_LDR ; 436 | break ; 437 | default: 438 | fail ("invalid type: %08x", type) ; 439 | return NULL ; 440 | break ; 441 | } 442 | return keys_get (id) ; 443 | } 444 | 445 | static void 446 | decrypt_header (void) 447 | { 448 | struct keylist *klist ; 449 | 450 | klist = self_load_keys () ; 451 | if (klist == NULL) 452 | return ; 453 | 454 | decrypted = sce_decrypt_header (self, klist) ; 455 | 456 | free (klist->keys) ; 457 | free (klist) ; 458 | } 459 | 460 | static void 461 | show_self_header (void) 462 | { 463 | printf ("SELF header information\n") ; 464 | printf (" auth id: %08x%08x \n", (u32) (auth_id >> 32), 465 | (u32) auth_id) ; 466 | printf (" vendor id: %08x%08x\n", (u32) (vendor_id >> 32), 467 | (u32) vendor_id) ; 468 | printf (" app version: %x.%x.%x\n", (u16) (version >> 48), 469 | (u16) (version >> 32), (u32) version) ; 470 | 471 | /* take version suffix */ 472 | sprintf (versionsuffix, "%x%02x", (u16) (version >> 48), (u16) (version >> 32)) ; 473 | printf (" version suffix: %s ", versionsuffix) ; 474 | printf ("\n") ; 475 | 476 | printf (" SDK type: %s\n", id2name (sdk_type, t_sdk_type, "unknown")) ; 477 | #ifdef DEBUG 478 | printf (" type: %d\n sdk_type: %d\n", type, sdk_type) ; 479 | #endif 480 | printf (" app type: %s\n", id2name (type, t_app_type, "unknown")) ; 481 | } 482 | 483 | static void 484 | verify_signature (void) 485 | { 486 | u8 *r, *s ; 487 | u8 hash[20] ; 488 | u64 sig_len ; 489 | 490 | sig_len = be64 (self + meta_offset + 0x60) ; 491 | r = self + sig_len ; 492 | s = r + 21 ; 493 | 494 | sha1 (self, sig_len, hash) ; 495 | 496 | printf ("Signature of the SELF header\n") ; 497 | if (ecdsa_verify (hash, r, s)) { 498 | printf (" Status: OK\n") ; 499 | } else { 500 | printf (" Status: FAIL\n") ; 501 | } 502 | printf ("\n") ; 503 | } 504 | 505 | static int 506 | verify_sign_hash (u8 * p, u8 * hashes, u8 * result, int sign) 507 | { 508 | u64 offset ; 509 | u64 size ; 510 | u64 id ; 511 | u8 *hash, *key ; 512 | 513 | offset = be64 (p + 0x00) ; 514 | size = be64 (p + 0x08) ; 515 | id = be32 (p + 0x1c) ; 516 | 517 | if (id == 0xffffffff) { 518 | return 0 ; 519 | } 520 | 521 | hash = hashes + id * 0x10 ; 522 | key = hash + 0x20 ; 523 | 524 | // XXX: possible integer overflow here 525 | if (offset > (filesize + header_len)) { 526 | return 1 ; 527 | } 528 | 529 | // XXX: possible integer overflow here 530 | if ( (offset + size) > (filesize + header_len)) { 531 | return 1 ; 532 | } 533 | 534 | //Fix all section sign 535 | if (sign) { 536 | sha1_hmac (key, self + offset, size, hash) ; 537 | } else { 538 | sha1_hmac (key, self + offset, size, result) ; 539 | } 540 | 541 | if (memcmp (result, hash, 20) == 0) { 542 | return 0 ; 543 | } else { 544 | return -1 ; 545 | } 546 | } 547 | 548 | static void 549 | calculate_hashes (void) 550 | { 551 | u32 i ; 552 | u32 meta_n_hdr ; 553 | u8 result[20] ; 554 | u8 *hashes ; 555 | 556 | meta_n_hdr = be32 (self + meta_offset + 0x60 + 0xc) ; 557 | hashes = self + meta_offset + 0x80 + (0x30 * meta_n_hdr) ; 558 | 559 | for (i = 0; i < meta_n_hdr; i++) { 560 | verify_sign_hash (self + meta_offset + 0x80 + 0x30 * i, 561 | hashes, result, SIGN_HASH) ; 562 | } 563 | } 564 | 565 | static void 566 | verify_hashes (void) 567 | { 568 | u32 meta_n_hdr ; 569 | u32 i ; 570 | u8 *hashes ; 571 | u8 result[20] ; 572 | int res ; 573 | 574 | meta_n_hdr = be32 (self + meta_offset + 0x60 + 0xc) ; 575 | hashes = self + meta_offset + 0x80 + 0x30 * meta_n_hdr ; 576 | 577 | printf ("Verifying hashes\n") ; 578 | 579 | for (i = 0; i < meta_n_hdr; i++) { 580 | printf (" Section %02d\n", i) ; 581 | res = verify_sign_hash (self + meta_offset + 0x80 + 0x30 * i, 582 | hashes, result, VERIFY_HASH) ; 583 | if (res < 0) { 584 | printf (" hash: FAIL\n") ; 585 | } else if (res > 0) { 586 | printf (" hash: wtf phony???\n") ; 587 | } else { 588 | printf (" hash: OK\n") ; 589 | } 590 | } 591 | 592 | printf ("\n") ; 593 | } 594 | 595 | static void 596 | decrypt (void) 597 | { 598 | int keyid ; 599 | struct keylist *klist ; 600 | 601 | klist = self_load_keys () ; 602 | if (klist == NULL) 603 | return ; 604 | 605 | keyid = sce_decrypt_header (self, klist) ; 606 | 607 | if (keyid < 0) { 608 | fail ("sce_decrypt_header failed") ; 609 | } 610 | 611 | if (sce_decrypt_data (self) < 0) { 612 | fail ("sce_decrypt_data failed") ; 613 | } 614 | 615 | if (klist->keys[keyid].pub_avail < 0) { 616 | fail ("no public key available") ; 617 | } 618 | 619 | if (ecdsa_set_curve (klist->keys[keyid].ctype) < 0) { 620 | fail ("ecdsa_set_curve failed") ; 621 | } 622 | 623 | ecdsa_set_pub (klist->keys[keyid].pub) ; 624 | } 625 | 626 | int 627 | main (int argc, char *argv[]) 628 | { 629 | FILE *fp ; 630 | 631 | printf ("SELF Rebuilder by Anonymous developers on EFNET\n") ; 632 | printf (" SELF and SPRX packer and signer \n") ; 633 | printf (" Based on the fail0verflow Tools \n") ; 634 | printf (" ! use with caution ! \n") ; 635 | 636 | printf ("\n") ; 637 | if (argc != 4) { 638 | printf ("Usage: %s \n", argv[0]) ; 639 | printf ("\tinput.elf: The input ELF to sign \n" 640 | "\toutput.self: The output SELF/SPRX to generate\n" 641 | "\toriginal.self: The reference original SELF/SPRX\n") ; 642 | return -1 ; 643 | } 644 | self_size = get_filesize (argv[3]) ; 645 | self = mmap_file (argv[3]) ; 646 | 647 | parse_self () ; 648 | decrypt_header () ; 649 | 650 | show_self_header () ; 651 | 652 | read_sections () ; 653 | 654 | get_keys (versionsuffix) ; 655 | 656 | elf_name = argv[1] ; 657 | self_name = argv[2] ; 658 | 659 | printf ("\nStarting to build self or sprx now...\n") ; 660 | 661 | elf_size = get_filesize (elf_name) ; 662 | elf = mmap_file (elf_name) ; 663 | 664 | parse_elf () ; 665 | 666 | write_sections () ; 667 | 668 | calculate_hashes () ; 669 | sign_header () ; 670 | sce_decrypt_data (self) ; 671 | sce_encrypt_header (self, &ks) ; 672 | fp = fopen (self_name, "wb") ; 673 | if (fp == NULL) { 674 | fail ("fopen (%s) failed", self_name) ; 675 | } 676 | 677 | if (fwrite (self, self_size, 1, fp) != 1) { 678 | fail ("unable to write self") ; 679 | } 680 | 681 | fclose (fp) ; 682 | 683 | self = mmap_file (self_name) ; 684 | 685 | parse_self () ; 686 | decrypt () ; 687 | verify_signature () ; 688 | verify_hashes () ; 689 | 690 | printf (" Finished\n") ; 691 | 692 | return 0 ; 693 | } 694 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------