aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kocialkowsk <contact@paulk.fr>2020-07-06 10:03:43 +0200
committerDenis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>2020-10-06 18:19:02 +0200
commite19b2a0451a11d7bcc951a9b5ac93e63a659f95e (patch)
tree6c6c0198b116a61a97a14715e3c21924bc734dae
parent3a8f3819647d061603ffd82aa0f354019dc7cb2e (diff)
downloadhardware_replicant_libsamsung-ipc-e19b2a0451a11d7bcc951a9b5ac93e63a659f95e.tar.gz
hardware_replicant_libsamsung-ipc-e19b2a0451a11d7bcc951a9b5ac93e63a659f95e.tar.bz2
hardware_replicant_libsamsung-ipc-e19b2a0451a11d7bcc951a9b5ac93e63a659f95e.zip
tools: import preliminary rfs-imei implementation as-is
Knowing the format and offset of the IMEI location in nv_data.bin is a step forward to be able to to recreate nv_data.bin from scratch. This can be used to repair devices that have their EFS partition completely destroyed, without having to rely on nonfree tools to do it. When asking Paul Kocialkowsk if he knew the offset at which the IMEI were stored in the nv_data.bin files, he explained to me that he only found it for the XMM616 and also gave me an unfinished implementation for a tool to change it. In order to preserve all the information in the tool and its correct authorship, the tool source code wasn't altered. As it doesn't compile with current versions of libsamsung-ipc, it wasn't added to any of the build systems (Android.mk and autotools). This will have to be fixed in subsequent commits. Signed-off-by: Paul Kocialkowsk <contact@paulk.fr> GNUtoo: Added commit message Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
-rw-r--r--tools/rfs-imei.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/tools/rfs-imei.c b/tools/rfs-imei.c
new file mode 100644
index 0000000..b10b96c
--- /dev/null
+++ b/tools/rfs-imei.c
@@ -0,0 +1,258 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2014 Paul Kocialkowsk <contact@paulk.fr>
+ *
+ * libsamsung-ipc 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.
+ *
+ * libsamsung-ipc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include <samsung-ipc.h>
+
+#include <utils.h>
+
+#define IMEI_LENGTH 15
+
+int help(void)
+{
+ printf("Usage: rfs-imei [OPTION]...\n");
+ printf("Options:\n");
+ printf("\t--help display this help message\n");
+ printf("\t--show-imei show the current imei from nv_data\n");
+ printf("\t--store-imei=[IMEI] store imei to nv_data\n");
+ printf("\t--nv_data-path=[PATH] select nv_data path\n");
+
+ return 0;
+}
+
+int show_imei(char *nv_data_path)
+{
+ struct ipc_client *client = NULL;
+ size_t nv_data_size;
+ size_t nv_data_chunk_size;
+ void *buffer = NULL;
+ char imei[IMEI_LENGTH + 1] = { 0 };
+ unsigned char *p;
+ unsigned int i;
+ int rc;
+
+ client = ipc_client_create(IPC_CLIENT_TYPE_FMT);
+ if (client == NULL) {
+ printf("Creating client failed\n");
+ goto error;
+ }
+
+ if (nv_data_path == NULL)
+ nv_data_path = "nv_data.bin";
+
+ nv_data_size = ipc_client_nv_data_size(client);
+ nv_data_chunk_size = ipc_client_nv_data_chunk_size(client);
+
+ buffer = file_data_read(nv_data_path, nv_data_size, nv_data_chunk_size, 0);
+ if (buffer == NULL) {
+ printf("Reading nv_data failed\n");
+ goto error;
+ }
+
+ p = (unsigned char *) buffer + 0xE880;
+ i = 0;
+
+ i += snprintf(&imei[i], IMEI_LENGTH + 1 - i, "%01x", (*p & 0xf0) >> 4);
+ p += sizeof(unsigned char);
+
+ while (i < IMEI_LENGTH) {
+ i += snprintf(&imei[i], IMEI_LENGTH + 1 - i, "%02x", (*p >> 4) | ((*p & 0x0f) << 4));
+ p += sizeof(unsigned char);
+ }
+
+ printf("%s\n", imei);
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (buffer != NULL)
+ free(buffer);
+
+ if (client != NULL)
+ ipc_client_destroy(client);
+
+ return rc;
+}
+
+int store_imei(char *nv_data_path, char *imei)
+{
+ struct ipc_client *client = NULL;
+ char *nv_data_md5_path = NULL;
+ char *nv_data_secret;
+ size_t nv_data_chunk_size;
+ size_t nv_data_size;
+ char *nv_data_md5_string = NULL;
+ unsigned char buffer[(IMEI_LENGTH + 1) / 2] = { 0 };
+ size_t length;
+ unsigned char *p;
+ unsigned int v;
+ unsigned int i;
+ int rc;
+
+ if (imei == NULL || strlen(imei) < IMEI_LENGTH) {
+ printf("Provided IMEI is invalid\n");
+ goto error;
+ }
+
+ client = ipc_client_create(IPC_CLIENT_TYPE_FMT);
+ if (client == NULL) {
+ printf("Creating client failed\n");
+ goto error;
+ }
+
+ if (nv_data_path == NULL)
+ nv_data_path = "nv_data.bin";
+
+ asprintf(&nv_data_md5_path, "%s.md5", nv_data_path);
+
+ nv_data_secret = ipc_client_nv_data_secret(client);
+ nv_data_size = ipc_client_nv_data_size(client);
+ nv_data_chunk_size = ipc_client_nv_data_chunk_size(client);
+
+ p = (unsigned char *) &buffer;
+ i = 0;
+
+ sscanf(&imei[i], "%01x", &v);
+ *p++ = (v << 4) | 0xA;
+ i++;
+
+ while (i < IMEI_LENGTH) {
+ sscanf(&imei[i], "%02x", &v);
+ *p++ = v << 4 | ((v & 0xf0) >> 4);
+ i += 2;
+ }
+
+ rc = file_data_write(nv_data_path, buffer, sizeof(buffer), sizeof(buffer), 0xE880);
+ if (rc < 0) {
+ printf("Writing nv_data failed\n");
+ goto error;
+ }
+
+ nv_data_md5_string = ipc_nv_data_md5_calculate(nv_data_path, nv_data_secret, nv_data_size, nv_data_chunk_size);
+ if (nv_data_md5_string == NULL) {
+ printf("Calculating nv_data md5 failed\n");
+ goto error;
+ }
+
+ length = strlen(nv_data_md5_string);
+
+ unlink(nv_data_md5_path);
+
+ rc = file_data_write(nv_data_md5_path, nv_data_md5_string, length, length, 0);
+ if (rc < 0) {
+ printf("Writing nv_data md5 failed\n");
+ goto error;
+ }
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (nv_data_md5_path != NULL)
+ free(nv_data_md5_path);
+
+ if (client != NULL)
+ ipc_client_destroy(client);
+
+ return rc;
+}
+
+int main(int argc, const char *argv[])
+{
+ int (*show_imei_callback)(char *nv_data_path) = NULL;
+ int (*store_imei_callback)(char *nv_data_path, char *imei) = NULL;
+ char *nv_data_path = NULL;
+ char *imei = NULL;
+ int rc;
+ int i;
+
+ struct option options[] = {
+ {"help", no_argument, NULL, 0 },
+ {"nv_data-path", required_argument, NULL, 0 },
+ {"show-imei", no_argument, NULL, 0 },
+ {"store-imei", required_argument, NULL, 0 },
+ {0, 0, NULL, 0 }
+ };
+
+ if (argc < 2)
+ goto error_help;
+
+ do {
+ rc = getopt_long(argc, (char *const *) argv, "", (const struct option *) &options, &i);
+ if (rc < 0)
+ break;
+
+ if (strcmp(options[i].name, "help") == 0) {
+ rc = help();
+ goto complete;
+ } else if (strcmp(options[i].name, "nv_data-path") == 0) {
+ if (optarg == '\0')
+ goto error_help;
+
+ nv_data_path = strdup(optarg);
+ } else if (strcmp(options[i].name, "show-imei") == 0) {
+ show_imei_callback = show_imei;
+ } else if (strcmp(options[i].name, "store-imei") == 0) {
+ if (optarg == '\0')
+ goto error_help;
+
+ imei = strdup(optarg);
+ store_imei_callback = store_imei;
+ }
+ } while (rc == '\0');
+
+ rc = 0;
+
+ if (show_imei_callback != NULL)
+ rc |= show_imei_callback(nv_data_path);
+
+ if (store_imei_callback != NULL)
+ rc |= store_imei_callback(nv_data_path, imei);
+
+ goto complete;
+
+error_help:
+ help();
+
+error:
+ rc = -1;
+
+complete:
+ if (nv_data_path != NULL)
+ free(nv_data_path);
+
+ if (imei != NULL)
+ free(imei);
+
+ return rc;
+}
+
+// vim:ts=4:sw=4:expandtab \ No newline at end of file