diff options
author | Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> | 2023-07-17 17:14:23 +0200 |
---|---|---|
committer | Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> | 2023-09-03 22:26:41 +0200 |
commit | 4c975c844c989384b9e979dc599d72488e9a55bc (patch) | |
tree | 7158507294ce6e95f6f5f27adf1c0f193d9a3805 | |
parent | fde17775c9ef146b23ffcf9fdfdeb9a8b7e88f31 (diff) | |
download | hardware_replicant_libsamsung-ipc-4c975c844c989384b9e979dc599d72488e9a55bc.tar.gz hardware_replicant_libsamsung-ipc-4c975c844c989384b9e979dc599d72488e9a55bc.tar.bz2 hardware_replicant_libsamsung-ipc-4c975c844c989384b9e979dc599d72488e9a55bc.zip |
tools: add tool to bruteforce sim unlock codes
This was made for the Galaxy SII (GT-I9100), and while the bruteforce
was verified against articles online, it doesn't work on Replicant yet,
probably because there is still things missing in libsamsung-ipc to do
the proper unlock.
TODO:
- make hashcat work on Guix: test: hashcat -I
=> works on Parabola where it finds opencl-icd-loader
- Handle errors
- Test on a real device, probably after implementing the missing
support in Replicant.
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | scripts/PKGBUILD | 1 | ||||
-rw-r--r-- | scripts/guix.scm | 3 | ||||
-rw-r--r-- | scripts/manifest.scm | 4 | ||||
-rw-r--r-- | tools/Makefile.am | 6 | ||||
-rw-r--r-- | tools/nv_data-sim-unlock.c | 174 | ||||
-rwxr-xr-x | tools/tests/nv_data-sim-unlock.py | 206 |
8 files changed, 398 insertions, 1 deletions
@@ -17,6 +17,8 @@ /tools/tests/nv_data-imei.trs /tools/tests/nv_data-md5.log /tools/tests/nv_data-md5.trs +/tools/tests/nv_data-sim-unlock.log +/tools/tests/nv_data-sim-unlock.trs /tools/test-suite.log valgrind.*.log diff --git a/configure.ac b/configure.ac index f164c53..908e157 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,9 @@ AC_SUBST(LIBCURL_CFLAGS) AC_SUBST(LIBCURL_LIBS) #------------------------------------------------------------------------------ +AC_CHECK_PROG([HASHCAT], [hashcat], [hashcat]) + +#------------------------------------------------------------------------------ # check for debugging AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug], [Enable debug build (default=disabled)])], diff --git a/scripts/PKGBUILD b/scripts/PKGBUILD index 155a765..43b2cac 100644 --- a/scripts/PKGBUILD +++ b/scripts/PKGBUILD @@ -16,6 +16,7 @@ makedepends=('autoconf' 'ddrescue' 'gawk' 'grep' + 'hashcat' 'libtool' 'pkg-config' 'python' diff --git a/scripts/guix.scm b/scripts/guix.scm index bc2f7c3..57a2469 100644 --- a/scripts/guix.scm +++ b/scripts/guix.scm @@ -170,6 +170,7 @@ automake ddrescue `(,(canonical-package glibc) "debug") + hashcat libtool pkg-config python @@ -214,6 +215,7 @@ found in many Samsung smartphones and tablets.") automake binutils ddrescue + hashcat libtool pkg-config python @@ -289,6 +291,7 @@ found in many Samsung smartphones and tablets.") (native-inputs (list autoconf automake ddrescue + hashcat libtool pkg-config python diff --git a/scripts/manifest.scm b/scripts/manifest.scm index dfc82c7..51e0f61 100644 --- a/scripts/manifest.scm +++ b/scripts/manifest.scm @@ -29,6 +29,8 @@ (gnu packages curl) (gnu packages disk) (gnu packages gawk) + (gnu packages opencl) + (gnu packages password-utils) (gnu packages pkg-config) (gnu packages python) (gnu packages python-xyz) @@ -47,11 +49,13 @@ gzip gcc-toolchain grep + hashcat lcov libtool gnu-make openssl pkg-config + pocl python python-sh sed diff --git a/tools/Makefile.am b/tools/Makefile.am index 4f86fc3..d318a7b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -17,6 +17,7 @@ bin_PROGRAMS = \ ipc-test \ nv_data-imei \ nv_data-md5 \ + nv_data-sim-unlock \ $(NULL) # TODO: Find a way to make test more modular and represent each run of the @@ -28,7 +29,8 @@ PY_LOG_COMPILER = $(PYTHON3) TEST_EXTENSIONS = .py TESTS = \ tests/nv_data-imei.py \ - tests/nv_data-md5.py + tests/nv_data-md5.py \ + tests/nv_data-sim-unlock.py EXTRA_DIST += $(TESTS) https_send_sms_SOURCES = https-send-sms.c @@ -42,3 +44,5 @@ nv_data_imei_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la nv_data_md5_SOURCES = nv_data-md5.c nv_data_md5_LDADD = $(top_builddir)/samsung-ipc/libsamsung-ipc.la + +nv_data_sim_unlock_SOURCES = nv_data-sim-unlock.c diff --git a/tools/nv_data-sim-unlock.c b/tools/nv_data-sim-unlock.c new file mode 100644 index 0000000..360789d --- /dev/null +++ b/tools/nv_data-sim-unlock.c @@ -0,0 +1,174 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2023 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> + * + * 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 <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +void usage(char *progname) +{ + printf("Usage:\n"); + printf("\t%s FILE command <index> # %s\n", + basename(progname), + "Get bruteforce command."); + printf("\t%s list-supported # %s\n", + basename(progname), + "List supported devices/EFS."); + printf("\t%s --help # %s\n", + basename(progname), + "Print this help."); +} + +int print_byte(int fd, off_t base, uint8_t offset) +{ + off_t file_offset; + ssize_t rd; + char buf[1]; + int rc; + + bzero(&buf, sizeof(buf)); + + file_offset = lseek(fd, base + offset, SEEK_SET); + if (file_offset == -1) { + int err = errno; + printf("%s: lseek: %s\n", __func__, strerror(err)); + return EX_OSERR; + } + + do { + rd = read(fd, &buf, 1); + if (rd == -1) { + int err = errno; + printf("%s: read: %s\n", __func__, strerror(err)); + return EX_OSERR; + } + } while (rd != 1); + + rc = printf("%02x", buf[0] & 0xff); + if (rc < 0) { + int err = errno; + printf("%s: printf: %s\n", __func__, strerror(err)); + return EX_OSERR; + } + + return 0; +} + +off_t field_offset(unsigned field_nr) +{ + if (field_nr == 0) + return 0x18146e; + else if (field_nr == 1) + return 0x18148e; + else if (field_nr == 2) + return 0x1814ce; + else if (field_nr == 3) + return 0x1814fe; + else + return 0; +} + +int cmd_list_supported(void) +{ + + printf("Supported devices:\n\t%s\n", + "Galaxy S II (GT-I9100)"); + + return 0; +} + + +int cmd_command(char* nv_data_path, int field_nr) +{ + int fd; + int rc; + int i; + off_t base; + + base = field_offset(field_nr); + if (base == 0) { + printf("%s: invalid field_offset: 0\n", __func__); + return EX_SOFTWARE; + } + + fd = open(nv_data_path, O_RDONLY); + if (fd == -1) { + printf("%s: open: %s\n", __func__, strerror(errno)); + return EX_NOINPUT; + } + + printf("hashcat -m 110 --hex-salt -a 3 "); + for (i=0; i<20 ; i++) { + rc = print_byte(fd, base, i); + if (rc) + return rc; + } + + rc = printf(":0000000000000000 ?d?d?d?d?d?d?d?d --show" + " | " + "cut -d : -f 3\n"); + if (rc == -1) { + printf("%s: printf: %s\n", __func__, strerror(errno)); + return EX_OSERR; + } + + rc = close (fd); + if (fd == -1) { + printf("%s: close: %s\n", __func__, strerror(errno)); + return EX_OSERR; + } + + return 0; +} + +int main(int argc, char * const argv[]) +{ + if (argc == 4 && !strcmp(argv[2], "command")) { + char *endptr; + int field_nr = 0; + + field_nr = strtol(argv[3], &endptr, 10); + if (errno != 0) { + usage(argv[0]); + return EX_USAGE; + } + + if (!(argv[3][0] != '\0' && *endptr == '\0')) { + usage(argv[0]); + return EX_USAGE; + } + + return cmd_command(argv[1], field_nr); + } else if (argc == 2 && !strcmp(argv[1], "list-supported")) { + return cmd_list_supported(); + } else if (argc == 2 && !strcmp(argv[1], "--help")) { + usage(argv[0]); + return 0; + } else { + usage(argv[0]); + return EX_USAGE; + } + +} diff --git a/tools/tests/nv_data-sim-unlock.py b/tools/tests/nv_data-sim-unlock.py new file mode 100755 index 0000000..6c83677 --- /dev/null +++ b/tools/tests/nv_data-sim-unlock.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python3 +# +# This file is part of libsamsung-ipc. +# +# Copyright (C) 2020 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> +# +# 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/>. + +import os +import re +import sys +import sh +import traceback + +def usage(progname): + print('{} [test]'.format(progname)) + sys.exit(1) + +def get_output(data): + return str(data).replace(os.linesep, '') + +class NvDataSimUnlock(object): + def __init__(self): + srcdir = os.environ.get('srcdir', None) + + command_path = '' + if srcdir: + command_path = '.' + os.sep + 'nv_data-sim-unlock' + # Enable to run tests without automake + else: + command_path = os.path.dirname(sys.argv[0]) \ + + os.sep \ + + '..' \ + + os.sep \ + + 'nv_data-sim-unlock' + + if 'VALGRIND' in os.environ: + self.nv_data_sim_unlock = sh.Command(os.environ['VALGRIND']) + self.nv_data_sim_unlock = self.nv_data_sim_unlock.bake( + '-v', + '--log-file=valgrind.%p.log', + '--leak-check=full', + command_path) + else: + self.nv_data_sim_unlock = sh.Command(command_path) + def test_help(self): + try: + self.nv_data_sim_unlock() + except sh.ErrorReturnCode_64: + pass + else: + raise Exception() + + def field_offset(self, field_nr): + if field_nr == 0: + return 0x18146e; + elif field_nr == 1: + return 0x18148e; + elif field_nr == 2: + return 0x1814ce; + elif field_nr == 3: + return 0x1814fe; + else: + raise Exception() + + # nv_data_bin is the path of the file. + # config is an array of size 4 with either None or the data to + # write at each offset. Offset 0 => data written at 0x18146e, + # offset 1 => data written at 0x18148e, etc. The data is expected + # to be in bytes. + # example: [bytes([0xef, 0x63, 0xbF, 0x26, 0xe2, 0x38, 0x29, 0x17, + # 0xd9, 0x68, 0x50, 0xCC, 0xf9, 0x63, 0x24, 0x58, + # 0xee, 0x6e, 0x6c, 0x77]), + # None, + # None, + # None] + def create_file(self, nv_data_bin, config): + if len(config) != 4: + raise Exception() + + # Create nv_data.bin + NV_DATA_SIZE = 0x200000 + sh.ddrescue('/dev/zero', nv_data_bin, '-s', str(NV_DATA_SIZE)) + + # Add hash inside if requested + index = 0 + for offset_config in config: + if offset_config == None: + pass + else: + assert (len(offset_config) == 20) + f = open(nv_data_bin, 'rb+') + assert (f.seekable) + f.seek(self.field_offset(index), 0) + f.write(offset_config); + f.close() + + index += 1 + + def test_commands_with_empty_file(self): + expected_output = " ".join([ + "hashcat", + "-m", "110", "--hex-salt", + "-a", "3", + "0000000000000000000000000000000000000000:0000000000000000", + "?d?d?d?d?d?d?d?d", + "--show", + "|", "cut", "-d", ":", "-f", "3"]) + + nv_data_bin = get_output(sh.mktemp()) + self.create_file(nv_data_bin, [None, None, None, None]) + + for index in range(0,4): + output = get_output(self.nv_data_sim_unlock(nv_data_bin, + "command", str(index))) + if output != expected_output: + raise Exception() + + # Try invalid offset + try: + self.nv_data_sim_unlock(nv_data_bin, "command", "4") + except sh.ErrorReturnCode_70: + pass + else: + raise Exception() + + os.unlink(nv_data_bin) + + def test_commands_with_example_file(self): + expected_output = " ".join([ + "hashcat", + "-m", "110", "--hex-salt", + "-a", "3", + "ef63bf26e2382917d96850ccf9632458ee6e6c77:0000000000000000", + "?d?d?d?d?d?d?d?d", + "--show", + "|", "cut", "-d", ":", "-f", "3"]) + + nv_data_bin = get_output(sh.mktemp()) + # 7D 3E 17 CF CD 81 6C AC D4 E0 25 FA A6 50 04 FD D1 7D 51 F8 # skip + # EF 63 BF 26 E2 38 29 17 D9 68 50 CC F9 63 24 58 EE 6E 6C 77 # example + # `+-> 50681318 + self.create_file(nv_data_bin, + [bytes([0xef, 0x63, 0xbF, 0x26, + 0xe2, 0x38, 0x29, 0x17, + 0xd9, 0x68, 0x50, 0xCC, + 0xf9, 0x63, 0x24, 0x58, + 0xee, 0x6e, 0x6c, 0x77]), + None, + None, + None]) + + output = get_output(self.nv_data_sim_unlock(nv_data_bin, + "command", "0")) + assert(output == expected_output) + + os.unlink(nv_data_bin) + + def test_hashcat(self): + command = sh.hashcat( + ["-m", "110", + "--hex-salt", + "-a", "3", + "ef63bf26e2382917d96850ccf9632458ee6e6c77:0000000000000000", + "?d?d?d?d?d?d?d?d", + "--show"]) + print ("hashcat " + " ".join(["-m", "110", + "--hex-salt", + "-a", "3", + "ef63bf26e2382917d96850ccf9632458ee6e6c77:0000000000000000", + "?d?d?d?d?d?d?d?d", + "--show"])) + code = get_output(command).split(":")[2] + assert(code == "50681318") + +def run_test(test): + try: + test() + except Exception as e: + print("[ !! ] nv_data_sim_unlock.py: {} failed:".format(test.__name__)) + traceback.print_exc() + else: + print("[ OK ] nv_data_sim_unlock.py: {}".format(test.__name__)) + +def main(): + nv_data_sim_unlock = NvDataSimUnlock() + + run_test(nv_data_sim_unlock.test_help) + run_test(nv_data_sim_unlock.test_commands_with_empty_file) + run_test(nv_data_sim_unlock.test_commands_with_example_file) + run_test(nv_data_sim_unlock.test_hashcat) + +if __name__ == '__main__': + rc = main() + sys.exit(rc) |