forked from len0rd/rockbox
Introduce upgtools for sony nwz players
This tool can unpack UPG archives for firmware updates. Change-Id: I32f5f1a84759198c7af4a4ecfd7aa65eaeda567a
This commit is contained in:
parent
8c1a9f5082
commit
cb09e369fb
10 changed files with 1078 additions and 0 deletions
26
utils/nwztools/upgtools/Makefile
Normal file
26
utils/nwztools/upgtools/Makefile
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
DEFINES=
|
||||||
|
CC=gcc
|
||||||
|
CXX=g++
|
||||||
|
LD=g++
|
||||||
|
PROFILE=
|
||||||
|
CFLAGS=-g $(PROFILE) -std=c99 -W -Wall $(DEFINES) `pkg-config --cflags openssl` `pkg-config --cflags libcrypto++`
|
||||||
|
CXXFLAGS=-g $(PROFILE) -W -Wall $(DEFINES) `pkg-config --cflags openssl` `pkg-config --cflags libcrypto++`
|
||||||
|
LDFLAGS=$(PROFILE) `pkg-config --libs openssl` `pkg-config --libs libcrypto++` -lcrypt
|
||||||
|
BINS=upgtool
|
||||||
|
|
||||||
|
all: $(BINS)
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
upgtool: upgtool.o misc.o fwp.o mg.o keysig_search.o
|
||||||
|
$(LD) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -fr *.o
|
||||||
|
|
||||||
|
veryclean:
|
||||||
|
rm -rf $(BINS)
|
56
utils/nwztools/upgtools/fwp.c
Normal file
56
utils/nwztools/upgtools/fwp.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "fwp.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "mg.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int fwp_read(void *in, int size, void *out, uint8_t *key)
|
||||||
|
{
|
||||||
|
return mg_decrypt_fw(in, size, out, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t g_key[NWZ_KEY_SIZE];
|
||||||
|
|
||||||
|
void fwp_setkey(char key[NWZ_KEY_SIZE])
|
||||||
|
{
|
||||||
|
memcpy(g_key, key, NWZ_KEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fwp_crypt(void *buf, int size, int mode)
|
||||||
|
{
|
||||||
|
while(size >= NWZ_KEY_SIZE)
|
||||||
|
{
|
||||||
|
if(mode)
|
||||||
|
mg_decrypt_pass(buf, NWZ_KEY_SIZE, buf, g_key);
|
||||||
|
else
|
||||||
|
mg_encrypt_pass(buf, NWZ_KEY_SIZE, buf, g_key);
|
||||||
|
buf += NWZ_KEY_SIZE;
|
||||||
|
size -= NWZ_KEY_SIZE;
|
||||||
|
}
|
||||||
|
if(size != 0)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "Cannot fwp_crypt non-multiple of 8!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
44
utils/nwztools/upgtools/fwp.h
Normal file
44
utils/nwztools/upgtools/fwp.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef __fwp_h__
|
||||||
|
#define __fwp_h__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NWZ_KAS_SIZE 32
|
||||||
|
#define NWZ_KEYSIG_SIZE 51
|
||||||
|
#define NWZ_KEY_SIZE 8
|
||||||
|
#define NWZ_EXPKEY_SIZE (NWZ_KEY_SIZE * NWZ_KEY_SIZE)
|
||||||
|
#define NWZ_DES_BLOCK 8
|
||||||
|
|
||||||
|
int fwp_read(void *in, int size, void *out, uint8_t *key);
|
||||||
|
void fwp_setkey(char key[8]);
|
||||||
|
int fwp_crypt(void *buf, int size, int mode);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __fwp_h__ */
|
157
utils/nwztools/upgtools/keysig_search.c
Normal file
157
utils/nwztools/upgtools/keysig_search.c
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "keysig_search.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "mg.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define HEX_MAJ
|
||||||
|
|
||||||
|
static uint8_t g_cipher[8];
|
||||||
|
static keysig_notify_fn_t g_notify;
|
||||||
|
static uint8_t g_key[8];
|
||||||
|
static void *g_user;
|
||||||
|
static bool is_hex[256];
|
||||||
|
static bool is_init = false;
|
||||||
|
#ifdef HEX_MAJ
|
||||||
|
static char hex_digits[] = "02468ABEF";
|
||||||
|
#else
|
||||||
|
static char hex_digits[] = "02468abef";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void keysig_search_init()
|
||||||
|
{
|
||||||
|
if(is_init) return;
|
||||||
|
is_init = true;
|
||||||
|
memset(is_hex, 0, sizeof(is_hex));
|
||||||
|
for(int i = '0'; i <= '9'; i++)
|
||||||
|
is_hex[i] = true;
|
||||||
|
#ifdef HEX_MAJ
|
||||||
|
for(int i = 'A'; i <= 'F'; i++)
|
||||||
|
#else
|
||||||
|
for(int i = 'a'; i <= 'f'; i++)
|
||||||
|
#endif
|
||||||
|
is_hex[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_full_ascii(uint8_t *arr)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 8; i++)
|
||||||
|
if(!is_hex[arr[i]])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool check_stupid()
|
||||||
|
{
|
||||||
|
uint8_t res[8];
|
||||||
|
mg_decrypt_fw(g_cipher, 8, res, g_key);
|
||||||
|
if(is_full_ascii(res))
|
||||||
|
return g_notify(g_user, g_key, res);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool search_stupid_rec(int rem_digit, int rem_letter, int pos)
|
||||||
|
{
|
||||||
|
if(pos == 8)
|
||||||
|
return check_stupid();
|
||||||
|
if(rem_digit > 0)
|
||||||
|
{
|
||||||
|
for(int i = '0'; i <= '9'; i += 2)
|
||||||
|
{
|
||||||
|
g_key[pos] = i;
|
||||||
|
if(search_stupid_rec(rem_digit - 1, rem_letter, pos + 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(rem_letter > 0)
|
||||||
|
{
|
||||||
|
#ifdef HEX_MAJ
|
||||||
|
for(int i = 'a' - 1; i <= 'f'; i += 2)
|
||||||
|
#else
|
||||||
|
for(int i = 'A' - 1; i <= 'F'; i += 2)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
g_key[pos] = i;
|
||||||
|
if(search_stupid_rec(rem_digit, rem_letter - 1, pos + 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool search_stupid(int rem_digit, int rem_letter)
|
||||||
|
{
|
||||||
|
return search_stupid_rec(rem_digit, rem_letter, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keysig_search_ascii_stupid(uint8_t *cipher, keysig_notify_fn_t notify, void *user)
|
||||||
|
{
|
||||||
|
keysig_search_init();
|
||||||
|
memcpy(g_cipher, cipher, 8);
|
||||||
|
g_notify = notify;
|
||||||
|
g_user = user;
|
||||||
|
#if 1
|
||||||
|
return search_stupid(4, 4) ||
|
||||||
|
search_stupid(3, 5) || search_stupid(5, 3) ||
|
||||||
|
search_stupid(2, 6) || search_stupid(6, 2) ||
|
||||||
|
search_stupid(1, 7) || search_stupid(7, 1) ||
|
||||||
|
search_stupid(0, 8) || search_stupid(8, 0);
|
||||||
|
#else
|
||||||
|
#define do(i) for(int a##i = 0; a##i < sizeof(hex_digits); a##i++) { g_key[i] = hex_digits[a##i];
|
||||||
|
#define od() }
|
||||||
|
|
||||||
|
do(0)do(1)do(2)do(3)do(4)do(5)do(6)do(7)
|
||||||
|
if(check_stupid()) return true;
|
||||||
|
od()od()od()od()od()od()od()od()
|
||||||
|
#undef do
|
||||||
|
#undef od
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keysig_search_ascii_brute(uint8_t *cipher, keysig_notify_fn_t notify, void *user)
|
||||||
|
{
|
||||||
|
keysig_search_init();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct keysig_search_desc_t keysig_search_desc[KEYSIG_SEARCH_LAST] =
|
||||||
|
{
|
||||||
|
[KEYSIG_SEARCH_NONE] =
|
||||||
|
{
|
||||||
|
.name = "none",
|
||||||
|
.fn = NULL,
|
||||||
|
.comment = "don't use",
|
||||||
|
},
|
||||||
|
[KEYSIG_SEARCH_ASCII_STUPID] =
|
||||||
|
{
|
||||||
|
.name = "ascii-stupid",
|
||||||
|
.fn = keysig_search_ascii_stupid,
|
||||||
|
.comment = "Try to find a balance ascii key ignoring lsb"
|
||||||
|
},
|
||||||
|
[KEYSIG_SEARCH_ASCII_BRUTE] =
|
||||||
|
{
|
||||||
|
.name = "ascii-brute",
|
||||||
|
.fn = keysig_search_ascii_brute,
|
||||||
|
.comment = "Brute force all ASCII keys"
|
||||||
|
},
|
||||||
|
};
|
50
utils/nwztools/upgtools/keysig_search.h
Normal file
50
utils/nwztools/upgtools/keysig_search.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef __keysig_search_h__
|
||||||
|
#define __keysig_search_h__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum keysig_search_method_t
|
||||||
|
{
|
||||||
|
KEYSIG_SEARCH_NONE = 0,
|
||||||
|
KEYSIG_SEARCH_FIRST,
|
||||||
|
KEYSIG_SEARCH_ASCII_STUPID = KEYSIG_SEARCH_FIRST,
|
||||||
|
KEYSIG_SEARCH_ASCII_BRUTE,
|
||||||
|
KEYSIG_SEARCH_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
/* notify returns true if the key seems ok */
|
||||||
|
typedef bool (*keysig_notify_fn_t)(void *user, uint8_t key[8], uint8_t sig[8]);
|
||||||
|
/* returns true if a key was accepted by notify */
|
||||||
|
typedef bool (*keysig_search_fn_t)(uint8_t *cipher, keysig_notify_fn_t notify, void *user);
|
||||||
|
|
||||||
|
struct keysig_search_desc_t
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
const char *comment;
|
||||||
|
keysig_search_fn_t fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct keysig_search_desc_t keysig_search_desc[KEYSIG_SEARCH_LAST];
|
||||||
|
|
||||||
|
#endif /* __keysig_search_h__ */
|
67
utils/nwztools/upgtools/mg.cpp
Normal file
67
utils/nwztools/upgtools/mg.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "mg.h"
|
||||||
|
#include <crypto++/cryptlib.h>
|
||||||
|
#include <crypto++/modes.h>
|
||||||
|
#include <crypto++/des.h>
|
||||||
|
#include <crypto++/aes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace CryptoPP;
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
ECB_Mode< DES >::Decryption g_dec;
|
||||||
|
ECB_Mode< DES >::Encryption g_enc;
|
||||||
|
|
||||||
|
inline int dec_des_ecb(void *in, int size, void *out, uint8_t *key)
|
||||||
|
{
|
||||||
|
g_dec.SetKey(key, 8);
|
||||||
|
g_dec.ProcessData((byte*)out, (byte*)in, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int enc_des_ecb(void *in, int size, void *out, uint8_t *key)
|
||||||
|
{
|
||||||
|
g_enc.SetKey(key, 8);
|
||||||
|
g_enc.ProcessData((byte*)out, (byte*)in, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int mg_decrypt_fw(void *in, int size, void *out, uint8_t *key)
|
||||||
|
{
|
||||||
|
return dec_des_ecb(in, size, out, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mg_encrypt_fw(void *in, int size, void *out, uint8_t *key)
|
||||||
|
{
|
||||||
|
return enc_des_ecb(in, size, out, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mg_decrypt_pass(void *in, int size, void *out, uint8_t *key)
|
||||||
|
{
|
||||||
|
return dec_des_ecb(in, size, out, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mg_encrypt_pass(void *in, int size, void *out, uint8_t *key)
|
||||||
|
{
|
||||||
|
return enc_des_ecb(in, size, out, key);
|
||||||
|
}
|
37
utils/nwztools/upgtools/mg.h
Normal file
37
utils/nwztools/upgtools/mg.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef __mg_h__
|
||||||
|
#define __mg_h__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
int mg_decrypt_fw(void *in, int size, void *out, uint8_t *key);
|
||||||
|
int mg_encrypt_fw(void *in, int size, void *out, uint8_t *key);
|
||||||
|
int mg_decrypt_pass(void *in, int size, void *out, uint8_t *key);
|
||||||
|
int mg_encrypt_pass(void *in, int size, void *out, uint8_t *key);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __mg_h__ */
|
53
utils/nwztools/upgtools/misc.c
Normal file
53
utils/nwztools/upgtools/misc.c
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
|
||||||
|
|
||||||
|
char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
|
||||||
|
char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
|
||||||
|
char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
|
||||||
|
char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
|
||||||
|
char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
|
||||||
|
|
||||||
|
static bool g_color_enable = true;
|
||||||
|
|
||||||
|
void *xmalloc(size_t s)
|
||||||
|
{
|
||||||
|
void * r = malloc(s);
|
||||||
|
if(!r) bugp("malloc");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_color(bool enable)
|
||||||
|
{
|
||||||
|
g_color_enable = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void color(color_t c)
|
||||||
|
{
|
||||||
|
if(g_color_enable)
|
||||||
|
printf("%s", (char *)c);
|
||||||
|
}
|
46
utils/nwztools/upgtools/misc.h
Normal file
46
utils/nwztools/upgtools/misc.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef __MISC_H__
|
||||||
|
#define __MISC_H__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define _STR(a) #a
|
||||||
|
#define STR(a) _STR(a)
|
||||||
|
|
||||||
|
#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
|
||||||
|
#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0)
|
||||||
|
|
||||||
|
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
|
||||||
|
|
||||||
|
typedef char color_t[];
|
||||||
|
|
||||||
|
extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE;
|
||||||
|
void *xmalloc(size_t s);
|
||||||
|
void color(color_t c);
|
||||||
|
void enable_color(bool enable);
|
||||||
|
|
||||||
|
#define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0)
|
||||||
|
|
||||||
|
#define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0)
|
||||||
|
|
||||||
|
#endif /* __MISC_H__ */
|
542
utils/nwztools/upgtools/upgtool.c
Normal file
542
utils/nwztools/upgtools/upgtool.c
Normal file
|
@ -0,0 +1,542 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "misc.h"
|
||||||
|
#include "elf.h"
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <openssl/md5.h>
|
||||||
|
#include "crypt.h"
|
||||||
|
#include "fwp.h"
|
||||||
|
#include "keysig_search.h"
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool g_debug = false;
|
||||||
|
static char *g_out_prefix = NULL;
|
||||||
|
static char *g_in_file = NULL;
|
||||||
|
bool g_force = false;
|
||||||
|
static const char *g_model = NULL;
|
||||||
|
static int g_model_index = -1;
|
||||||
|
static char *g_kas = NULL;
|
||||||
|
static char *g_key = NULL;
|
||||||
|
static char *g_sig = NULL;
|
||||||
|
|
||||||
|
enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE;
|
||||||
|
|
||||||
|
|
||||||
|
#define let_the_force_flow(x) do { if(!g_force) return x; } while(0)
|
||||||
|
#define continue_the_force(x) if(x) let_the_force_flow(x)
|
||||||
|
|
||||||
|
#define check_field(v_exp, v_have, str_ok, str_bad) \
|
||||||
|
if((v_exp) != (v_have)) \
|
||||||
|
{ cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \
|
||||||
|
else { cprintf(RED, str_ok); }
|
||||||
|
|
||||||
|
static void print_hex(void *p, int size, int unit)
|
||||||
|
{
|
||||||
|
uint8_t *p8 = p;
|
||||||
|
uint16_t *p16 = p;
|
||||||
|
uint32_t *p32 = p;
|
||||||
|
for(int i = 0; i < size; i += unit, p8++, p16++, p32++)
|
||||||
|
{
|
||||||
|
if(i != 0 && (i % 16) == 0)
|
||||||
|
printf("\n");
|
||||||
|
if(unit == 1)
|
||||||
|
printf(" %02x", *p8);
|
||||||
|
else if(unit == 2)
|
||||||
|
printf(" %04x", *p16);
|
||||||
|
else
|
||||||
|
printf(" %08x", *p32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* key and signature */
|
||||||
|
struct nwz_kas_t
|
||||||
|
{
|
||||||
|
char kas[NWZ_KAS_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HAS_KAS (1 << 0)
|
||||||
|
#define HAS_KEY (1 << 1)
|
||||||
|
#define HAS_SIG (1 << 2)
|
||||||
|
#define CONFIRMED (1 << 3)
|
||||||
|
|
||||||
|
struct nwz_model_t
|
||||||
|
{
|
||||||
|
const char *model;
|
||||||
|
unsigned flags;
|
||||||
|
struct nwz_kas_t kas;
|
||||||
|
char key[8];
|
||||||
|
char sig[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct upg_md5_t
|
||||||
|
{
|
||||||
|
uint8_t md5[16];
|
||||||
|
}__attribute__((packed));
|
||||||
|
|
||||||
|
struct upg_header_t
|
||||||
|
{
|
||||||
|
char sig[8];
|
||||||
|
uint32_t nr_files;
|
||||||
|
uint32_t unk;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct upg_entry_t
|
||||||
|
{
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t size;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct nwz_model_t g_model_list[] =
|
||||||
|
{
|
||||||
|
{ "nwz-e463", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, {"89d813f8f966efdebd9c9e0ea98156d2"}, "eb4431eb", "4f1d9cac" },
|
||||||
|
{ "nwz-a86x", HAS_KEY | HAS_SIG, {""}, "c824e4e2", "7c262bb0" },
|
||||||
|
{ "nw-a82x", HAS_KEY | HAS_SIG, {""}, "4df06482", "07fa0b6e" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int digit_value(char c)
|
||||||
|
{
|
||||||
|
if(c >= '0' && c <= '9') return c - '0';
|
||||||
|
if(c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
|
if(c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char hex_digit(unsigned v)
|
||||||
|
{
|
||||||
|
return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decrypt_keysig(char keysig[NWZ_KEYSIG_SIZE])
|
||||||
|
{
|
||||||
|
uint8_t src[16];
|
||||||
|
for(int i = 32; i < NWZ_KEYSIG_SIZE; i++)
|
||||||
|
keysig[i] = 0;
|
||||||
|
for(int index = 0; index < 16; index++)
|
||||||
|
{
|
||||||
|
int a = digit_value(keysig[index * 2]);
|
||||||
|
int b = digit_value(keysig[index * 2 + 1]);
|
||||||
|
if(a < 0 || b < 0)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "Invalid KAS !\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
src[index] = a << 4 | b;
|
||||||
|
}
|
||||||
|
fwp_setkey("ed295076");
|
||||||
|
fwp_crypt(src, sizeof(src), 1);
|
||||||
|
memcpy(keysig + 33, src, 8);
|
||||||
|
memcpy(keysig + 42, src + 8, 8);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool upg_notify_keysig(void *user, uint8_t key[8], uint8_t sig[8])
|
||||||
|
{
|
||||||
|
memcpy(user + 33, key, 8);
|
||||||
|
memcpy(user + 42, sig, 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_upg(void *buf, long size)
|
||||||
|
{
|
||||||
|
struct upg_md5_t *md5 = buf;
|
||||||
|
cprintf(BLUE, "Preliminary\n");
|
||||||
|
cprintf(GREEN, " MD5: ");
|
||||||
|
for(int i = 0; i < 16; i++)
|
||||||
|
cprintf(YELLOW, "%02x", md5->md5[i]);
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
uint8_t actual_md5[MD5_DIGEST_LENGTH];
|
||||||
|
{
|
||||||
|
MD5_CTX c;
|
||||||
|
MD5_Init(&c);
|
||||||
|
MD5_Update(&c, md5 + 1, size - sizeof(struct upg_header_t));
|
||||||
|
MD5_Final(actual_md5, &c);
|
||||||
|
}
|
||||||
|
check_field(memcmp(actual_md5, md5->md5, 16), 0, "Ok\n", "Mismatch\n");
|
||||||
|
|
||||||
|
if(g_model_index == -1 && g_keysig_search == KEYSIG_SEARCH_NONE && g_key == NULL && g_kas == NULL)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n");
|
||||||
|
cprintf(GREY, "You have the following options(see hel for more details):\n");
|
||||||
|
cprintf(GREY, "- select a model with a known KAS\n");
|
||||||
|
cprintf(GREY, "- specify an explicit KAS or key(+optional sig)\n");
|
||||||
|
cprintf(GREY, "- let me try to find the keysig(slow !)\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nwz_kas_t kas;
|
||||||
|
char keysig[NWZ_KEYSIG_SIZE];
|
||||||
|
|
||||||
|
memset(kas.kas, '?', NWZ_KAS_SIZE);
|
||||||
|
memset(keysig, '?', NWZ_KEYSIG_SIZE);
|
||||||
|
keysig[32] = keysig[41] = keysig[50] = 0;
|
||||||
|
|
||||||
|
if(g_kas)
|
||||||
|
{
|
||||||
|
if(strlen(g_kas) != NWZ_KAS_SIZE)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
memcpy(keysig, g_kas, NWZ_KAS_SIZE);
|
||||||
|
decrypt_keysig(keysig);
|
||||||
|
g_kas = keysig;
|
||||||
|
g_key = keysig + 33;
|
||||||
|
g_sig = keysig + 42;
|
||||||
|
}
|
||||||
|
else if(g_key)
|
||||||
|
{
|
||||||
|
if(strlen(g_key) != 8)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if(g_sig && strlen(g_sig) != 8)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n");
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(keysig + 33, g_key, 8);
|
||||||
|
if(!g_sig)
|
||||||
|
cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n");
|
||||||
|
else
|
||||||
|
memcpy(keysig + 42, g_sig, 8);
|
||||||
|
g_key = keysig + 33;
|
||||||
|
if(g_sig)
|
||||||
|
g_sig = keysig + 42;
|
||||||
|
}
|
||||||
|
else if(g_model_index == -1)
|
||||||
|
{
|
||||||
|
cprintf(BLUE, "keysig Search\n");
|
||||||
|
cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name);
|
||||||
|
bool ok = keysig_search_desc[g_keysig_search].fn((void *)(md5 + 1), &upg_notify_keysig, keysig);
|
||||||
|
cprintf(GREEN, " Result: ");
|
||||||
|
cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found");
|
||||||
|
if(!ok)
|
||||||
|
return 2;
|
||||||
|
g_key = keysig + 33;
|
||||||
|
g_sig = keysig + 42;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(g_model_list[g_model_index].flags & HAS_KAS)
|
||||||
|
g_kas = g_model_list[g_model_index].kas.kas;
|
||||||
|
if(g_model_list[g_model_index].flags & HAS_KEY)
|
||||||
|
g_key = g_model_list[g_model_index].key;
|
||||||
|
if(g_model_list[g_model_index].flags & HAS_SIG)
|
||||||
|
g_sig = g_model_list[g_model_index].sig;
|
||||||
|
|
||||||
|
if(g_kas)
|
||||||
|
{
|
||||||
|
memcpy(keysig, g_kas, NWZ_KAS_SIZE);
|
||||||
|
decrypt_keysig(keysig);
|
||||||
|
g_kas = keysig;
|
||||||
|
g_key = keysig + 33;
|
||||||
|
g_sig = keysig + 42;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(g_key)
|
||||||
|
{
|
||||||
|
memcpy(keysig + 33, g_key, 8);
|
||||||
|
g_key = keysig + 33;
|
||||||
|
}
|
||||||
|
if(g_sig)
|
||||||
|
{
|
||||||
|
memcpy(keysig + 42, g_sig, 8);
|
||||||
|
g_sig = keysig + 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!g_kas)
|
||||||
|
{
|
||||||
|
g_kas = keysig;
|
||||||
|
fwp_setkey("ed295076");
|
||||||
|
if(g_key)
|
||||||
|
{
|
||||||
|
memcpy(kas.kas, g_key, 8);
|
||||||
|
fwp_crypt(kas.kas, 8, 0);
|
||||||
|
for(int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
g_kas[2 * i] = hex_digit((kas.kas[i] >> 4) & 0xf);
|
||||||
|
g_kas[2 * i + 1] = hex_digit(kas.kas[i] & 0xf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(g_sig)
|
||||||
|
{
|
||||||
|
memcpy(kas.kas + 8, g_sig, 8);
|
||||||
|
fwp_crypt(kas.kas + 8, 8, 0);
|
||||||
|
for(int i = 8; i < 16; i++)
|
||||||
|
{
|
||||||
|
g_kas[2 * i] = hex_digit((kas.kas[i] >> 4) & 0xf);
|
||||||
|
g_kas[2 * i + 1] = hex_digit(kas.kas[i] & 0xf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cprintf(BLUE, "Keys\n");
|
||||||
|
cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas);
|
||||||
|
cprintf_field(" Key: ", "%s\n", g_key);
|
||||||
|
if(g_sig)
|
||||||
|
cprintf_field(" Sig: ", "%s\n", g_sig);
|
||||||
|
|
||||||
|
struct upg_header_t *hdr = (void *)(md5 + 1);
|
||||||
|
int ret = fwp_read(hdr, sizeof(struct upg_header_t), hdr, (void *)g_key);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
cprintf(BLUE, "Header\n");
|
||||||
|
cprintf_field(" Signature:", " ");
|
||||||
|
for(int i = 0; i < 8; i++)
|
||||||
|
cprintf(YELLOW, "%c", isprint(hdr->sig[i]) ? hdr->sig[i] : '.');
|
||||||
|
if(g_sig)
|
||||||
|
{
|
||||||
|
check_field(memcmp(hdr->sig, g_sig, 8), 0, " OK\n", " Mismatch\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(RED, " Can't check\n");
|
||||||
|
cprintf_field(" Files: ", "%d\n", hdr->nr_files);
|
||||||
|
cprintf_field(" Unk: ", "0x%x\n", hdr->unk);
|
||||||
|
|
||||||
|
cprintf(BLUE, "Files\n");
|
||||||
|
struct upg_entry_t *entry = (void *)(hdr + 1);
|
||||||
|
for(unsigned i = 0; i < hdr->nr_files; i++, entry++)
|
||||||
|
{
|
||||||
|
int ret = fwp_read(entry, sizeof(struct upg_entry_t), entry, (void *)g_key);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
cprintf(GREY, " File");
|
||||||
|
cprintf(RED, " %d\n", i);
|
||||||
|
cprintf_field(" Offset: ", "0x%x\n", entry->offset);
|
||||||
|
cprintf_field(" Size: ", "0x%x\n", entry->size);
|
||||||
|
|
||||||
|
if(g_out_prefix)
|
||||||
|
{
|
||||||
|
char *str = malloc(strlen(g_out_prefix) + 32);
|
||||||
|
sprintf(str, "%s/%d.bin", g_out_prefix, i);
|
||||||
|
FILE *f = fopen(str, "wb");
|
||||||
|
if(f)
|
||||||
|
{
|
||||||
|
int ret = fwp_read(buf + entry->offset, entry->size,
|
||||||
|
buf + entry->offset, (void *)g_key);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
fwrite(buf + entry->offset, 1, entry->size, f);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(GREY, "Cannot open '%s' for writing\n", str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
color(OFF);
|
||||||
|
printf("Usage: upgtool [options] firmware\n");
|
||||||
|
printf("Options:\n");
|
||||||
|
printf(" -o <prefix>\t\tSet output prefix\n");
|
||||||
|
printf(" -f/--force\t\tForce to continue on errors\n");
|
||||||
|
printf(" -?/--help\t\tDisplay this message\n");
|
||||||
|
printf(" -d/--debug\t\tDisplay debug messages\n");
|
||||||
|
printf(" -c/--no-color\t\tDisable color output\n");
|
||||||
|
printf(" -m/--model <model>\tSelect model (or ? to list them)\n");
|
||||||
|
printf(" -l/--search <method>\tTry to find the keysig\n");
|
||||||
|
printf(" -a/--kas <kas>\tForce KAS\n");
|
||||||
|
printf(" -k/--key <key>\tForce key\n");
|
||||||
|
printf(" -s/--sig <sig>\tForce sig\n");
|
||||||
|
printf("keysig search method:\n");
|
||||||
|
for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++)
|
||||||
|
printf(" %s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
static struct option long_options[] =
|
||||||
|
{
|
||||||
|
{"help", no_argument, 0, '?'},
|
||||||
|
{"debug", no_argument, 0, 'd'},
|
||||||
|
{"no-color", no_argument, 0, 'c'},
|
||||||
|
{"force", no_argument, 0, 'f'},
|
||||||
|
{"model", required_argument, 0, 'm'},
|
||||||
|
{"search", required_argument, 0, 'l'},
|
||||||
|
{"kas", required_argument, 0, 'a'},
|
||||||
|
{"key", required_argument, 0, 'k'},
|
||||||
|
{"sig", required_argument, 0, 's'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
int c = getopt_long(argc, argv, "?dcfo:m:l:a:k:s:", long_options, NULL);
|
||||||
|
if(c == -1)
|
||||||
|
break;
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
enable_color(false);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
g_debug = true;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
g_force = true;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
usage();
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
g_out_prefix = optarg;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
g_model = optarg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
g_keysig_search = KEYSIG_SEARCH_NONE;
|
||||||
|
for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++)
|
||||||
|
if(strcmp(keysig_search_desc[i].name, optarg) == 0)
|
||||||
|
g_keysig_search = i;
|
||||||
|
if(g_keysig_search == KEYSIG_SEARCH_NONE)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "Unknown keysig search method '%s'\n", optarg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
g_kas = optarg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
g_key = optarg;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
g_sig = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_model && strcmp(g_model, "?") == 0)
|
||||||
|
{
|
||||||
|
cprintf(BLUE, "Model list:\n");
|
||||||
|
for(unsigned i = 0; i < sizeof(g_model_list) / sizeof(g_model_list[0]); i++)
|
||||||
|
{
|
||||||
|
cprintf(GREEN, " %s:", g_model_list[i].model);
|
||||||
|
if(g_model_list[i].flags & HAS_KAS)
|
||||||
|
{
|
||||||
|
cprintf(RED, " kas=");
|
||||||
|
cprintf(YELLOW, "%."STR(NWZ_KAS_SIZE)"s", g_model_list[i].kas.kas);
|
||||||
|
}
|
||||||
|
if(g_model_list[i].flags & HAS_KEY)
|
||||||
|
{
|
||||||
|
cprintf(RED, " key=");
|
||||||
|
cprintf(YELLOW, "%.8s", g_model_list[i].key);
|
||||||
|
}
|
||||||
|
if(g_model_list[i].flags & HAS_SIG)
|
||||||
|
{
|
||||||
|
cprintf(RED, " sig=");
|
||||||
|
cprintf(YELLOW, "%.8s", g_model_list[i].sig);
|
||||||
|
}
|
||||||
|
if(g_model_list[i].flags & CONFIRMED)
|
||||||
|
cprintf(RED, " confirmed");
|
||||||
|
else
|
||||||
|
cprintf(RED, " guessed");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_model)
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < sizeof(g_model_list) / sizeof(g_model_list[0]); i++)
|
||||||
|
if(strcmp(g_model, g_model_list[i].model) == 0)
|
||||||
|
g_model_index = i;
|
||||||
|
if(g_model_index == -1)
|
||||||
|
cprintf(GREY, "Warning: unknown model %s\n", g_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc - optind != 1)
|
||||||
|
{
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_in_file = argv[optind];
|
||||||
|
FILE *fin = fopen(g_in_file, "r");
|
||||||
|
if(fin == NULL)
|
||||||
|
{
|
||||||
|
perror("Cannot open boot file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fseek(fin, 0, SEEK_END);
|
||||||
|
long size = ftell(fin);
|
||||||
|
fseek(fin, 0, SEEK_SET);
|
||||||
|
|
||||||
|
void *buf = malloc(size);
|
||||||
|
if(buf == NULL)
|
||||||
|
{
|
||||||
|
perror("Cannot allocate memory");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fread(buf, size, 1, fin) != 1)
|
||||||
|
{
|
||||||
|
perror("Cannot read file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fin);
|
||||||
|
|
||||||
|
int ret = do_upg(buf, size);
|
||||||
|
if(ret != 0)
|
||||||
|
{
|
||||||
|
cprintf(GREY, "Error: %d", ret);
|
||||||
|
if(!g_force)
|
||||||
|
cprintf(GREY, " (use --force to force processing)");
|
||||||
|
printf("\n");
|
||||||
|
ret = 2;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
color(OFF);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue