Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First public release of sandy (version 0.1.0).

  • Loading branch information...
commit 90e00cf3f6dbe3662f702f2610b19b8a96afee3a 1 parent 53894c0
@donctl authored
Showing with 3,887 additions and 0 deletions.
  1. +53 −0 .gitignore
  2. +1 −0  adb/__init__.py
  3. +460 −0 adb/adb.py
  4. +24 −0 config.cfg
  5. BIN  dump_android_memory/dump_android_memory
  6. +69 −0 dump_android_memory/dump_android_memory.c
  7. +9 −0 gdb/README
  8. +10 −0 gdb/gdb
  9. BIN  gdb/gdb-kali
  10. BIN  gdb/gdb-osx
  11. BIN  gdb/gdbserver
  12. +221 −0 jtr_plugin/sandcrypt_fmt_plug.c
  13. +7 −0 keyctl/README
  14. BIN  keyctl/keyctl
  15. +21 −0 main.py
  16. +1 −0  modules/__init__.py
  17. +1 −0  modules/sand2john/__init__.py
  18. +81 −0 modules/sand2john/sand2john.py
  19. +1 −0  modules/sandgetdek/__init__.py
  20. +213 −0 modules/sandgetdek/sandgetdek.py
  21. +1 −0  modules/sandgetfooter/__init__.py
  22. +148 −0 modules/sandgetfooter/sandgetfooter.py
  23. +1 −0  modules/sandgetfooterfromdd/__init__.py
  24. +75 −0 modules/sandgetfooterfromdd/sandgetfooterfromdd.py
  25. +1 −0  modules/sandgetpwdhash/__init__.py
  26. +112 −0 modules/sandgetpwdhash/sandgetpwdhash.py
  27. +1 −0  modules/sandgetsdcard/__init__.py
  28. +63 −0 modules/sandgetsdcard/sandgetsdcard.py
  29. +1 −0  modules/sandmountddfromkey/__init__.py
  30. +88 −0 modules/sandmountddfromkey/sandmountddfromkey.py
  31. +1 −0  modules/sandmountddfrompwd/__init__.py
  32. +114 −0 modules/sandmountddfrompwd/sandmountddfrompwd.py
  33. +1 −0  modules/sandmountsdcardfromkey/__init__.py
  34. +120 −0 modules/sandmountsdcardfromkey/sandmountsdcardfromkey.py
  35. +1 −0  modules/sandmountsdcardfrompwd/__init__.py
  36. +73 −0 modules/sandmountsdcardfrompwd/sandmountsdcardfrompwd.py
  37. +1 −0  modules/sands4getedk/__init__.py
  38. +287 −0 modules/sands4getedk/sands4getedk.py
  39. +1 −0  modules/sandsdckeyctl/__init__.py
  40. +102 −0 modules/sandsdckeyctl/sandsdckeyctl.py
  41. +66 −0 printer.py
  42. +70 −0 recovery/HowTo_S4_recovery.txt
  43. +298 −0 recovery/default.prop
  44. +107 −0 recovery/init.rc
  45. +181 −0 sandutils.py
  46. 0  sandy/__init__.py
  47. +1 −0  sandy/actions/__init__.py
  48. +6 −0 sandy/actions/action.py
  49. +8 −0 sandy/actions/back.py
  50. +37 −0 sandy/actions/dumpfooter.py
  51. +24 −0 sandy/actions/dumpfooterfromdd.py
  52. +11 −0 sandy/actions/exit.py
  53. +39 −0 sandy/actions/getdek.py
  54. +37 −0 sandy/actions/getpwdhash.py
  55. +27 −0 sandy/actions/getsdcardfile.py
  56. +23 −0 sandy/actions/mountddkey.py
  57. +22 −0 sandy/actions/mountddpwd.py
  58. +25 −0 sandy/actions/mountsdcardkey.py
  59. +21 −0 sandy/actions/mountsdcardpwd.py
  60. +42 −0 sandy/actions/phonemenu.py
  61. +27 −0 sandy/actions/phonemountmenu.py
  62. +23 −0 sandy/actions/phonesand2john.py
  63. +38 −0 sandy/actions/s4getedk.py
  64. +32 −0 sandy/actions/sandsdckeyctl.py
  65. +33 −0 sandy/actions/sdcardmenu.py
  66. +27 −0 sandy/actions/sdcardmountmenu.py
  67. +22 −0 sandy/actions/sdcardsand2john.py
  68. +41 −0 sandy/banner.py
  69. +23 −0 sandy/console.py
  70. +26 −0 sandy/gui.py
  71. +73 −0 sandy/menu.py
  72. +10 −0 sandy/sandy.py
  73. +32 −0 sandy/sandyutils.py
  74. BIN  seek_and_read/seek_and_read
  75. +71 −0 seek_and_read/seek_and_read.c
View
53 .gitignore
@@ -0,0 +1,53 @@
+# Compiled source #
+###################
+*.com
+*.class
+*.dll
+*.exe
+*.o
+*.so
+#dump_android_memory
+notes
+results
+trash
+busybox
+vold
+secure_storage_daemon
+screenlock
+sdcmount
+results_old*
+*.pyc
+Slide4.docx
+crosscompile.sh
+
+
+# Packages #
+############
+# it's better to unpack these files and commit the raw source
+# git has its own built in compression methods
+*.7z
+*.dmg
+*.gz
+*.iso
+*.jar
+*.rar
+*.tar
+*.zip
+
+# Logs and databases #
+######################
+*.log
+*.sqlite
+
+# OS generated files #
+######################
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+Icon?
+ehthumbs.db
+Thumbs.db
+*.swp
+*.pyc
View
1  adb/__init__.py
@@ -0,0 +1 @@
+import printer
View
460 adb/adb.py
@@ -0,0 +1,460 @@
+# Author: Chema Garcia (aka sch3m4)
+# Contact: chema@safetybits.net | http://safetybits.net/contact
+# Homepage: http://safetybits.net
+# Project Site: http://github.com/sch3m4/pyadb
+
+#Modified by donctl. The push_local_file now returns with self.__error.
+#The adb push writes the messages to the standard error, so we can check
+#wether the push was successfull or not.
+
+try:
+ import sys
+ from os import popen3 as pipe
+except ImportError,e:
+ # should never be reached
+ print "[f] Required module missing. %s" % e.args[0]
+ sys.exit(-1)
+
+class ADB():
+
+ PYADB_VERSION = "0.1.1"
+
+ __adb_path = None
+ __output = None
+ __error = None
+ __devices = None
+ __target = None
+
+ # reboot modes
+ REBOOT_RECOVERY = 1
+ REBOOT_BOOTLOADER = 2
+
+ # default TCP/IP port
+ DEFAULT_TCP_PORT = 5555
+ # default TCP/IP host
+ DEFAULT_TCP_HOST = "localhost"
+
+ def pyadb_version(self):
+ return self.PYADB_VERSION
+
+ def __init__(self,adb_path=None):
+ self.__adb_path = adb_path
+
+ def __clean__(self):
+ self.__output = None
+ self.__error = None
+
+ def __read_output__(self,fd):
+ ret = ''
+ while 1:
+ line = fd.readline()
+ if not line:
+ break
+ ret += line
+
+ if len(ret) == 0:
+ ret = None
+
+ return ret
+
+ def __build_command__(self,cmd):
+ if self.__devices is not None and len(self.__devices) > 1 and self.__target is None:
+ self.__error = "Must set target device first"
+ return None
+ return self.__adb_path + ' ' + cmd if self.__target is None else self.__adb_path + ' ' + ' -s ' + self.__target + ' ' + cmd
+
+ def get_output(self):
+ return self.__output
+
+ def get_error(self):
+ return self.__error
+
+ def lastFailed(self):
+ """
+ Was failed the last command?
+ """
+ if self.__output is None and self.__error is not None:
+ return True
+ return False
+
+ def run_cmd(self,cmd):
+ """
+ Run a command against adb tool ($ adb <cmd>)
+ """
+ self.__clean__()
+
+ if self.__adb_path is None:
+ self.__error = "ADB path not set"
+ return
+
+ try:
+ w,r,e = pipe(self.__build_command__(cmd), mode='r')
+ self.__output = self.__read_output__(r)
+ self.__error = self.__read_output__(e)
+ r.close()
+ w.close()
+ e.close()
+ except:
+ pass
+
+ return
+
+ def get_version(self):
+ """
+ Returns ADB tool version
+ adb version
+ """
+ self.run_cmd("version")
+ try:
+ ret = self.__output.split()[-1:][0]
+ except:
+ ret = None
+ return ret
+
+ def check_path(self):
+ """
+ Intuitive way to verify the ADB path
+ """
+ if self.get_version() is None:
+ return False
+ return True
+
+ def set_adb_path(self,adb_path):
+ """
+ Set ADB tool path
+ """
+ self.__adb_path = adb_path
+
+ def get_adb_path(self):
+ """
+ Returns ADB tool path
+ """
+ return self.__adb_path
+
+ def start_server(self):
+ """
+ Starts ADB server
+ adb start-server
+ """
+ self.__clean__()
+ self.run_cmd('start-server')
+ return self.__output
+
+ def kill_server(self):
+ """
+ Kills ADB server
+ adb kill-server
+ """
+ self.__clean__()
+ self.run_cmd('kill-server')
+
+ def restart_server(self):
+ """
+ Restarts ADB server
+ """
+ self.kill_server()
+ return self.start_server()
+
+ def restore_file(self,file_name):
+ """
+ Restore device contents from the <file> backup archive
+ adb restore <file>
+ """
+ self.__clean__()
+ self.run_cmd('restore %s' % file_name)
+ return self.__output
+
+ def wait_for_device(self):
+ """
+ Block until device is online
+ adb wait-for-device
+ """
+ self.__clean__()
+ self.run_cmd('wait-for-device')
+ return self.__output
+
+ def get_help(self):
+ """
+ Returns ADB help
+ adb help
+ """
+ self.__clean__()
+ self.run_cmd('help')
+ return self.__output
+
+ def get_devices(self):
+ """
+ Return a list of connected devices
+ adb devices
+ """
+ error = 0
+ self.run_cmd("devices")
+ if self.__error is not None:
+ return ''
+ try:
+ self.__devices = self.__output.partition('\n')[2].replace('device','').split()
+
+ if self.__devices[1:] == ['no','permissions']:
+ error = 2
+ self.__devices = None
+ except:
+ self.__devices = None
+ error = 1
+
+ return (error,self.__devices)
+
+ def set_target_device(self,device):
+ """
+ Select the device to work with
+ """
+ self.__clean__()
+ if device is None or not device in self.__devices:
+ self.__error = 'Must get device list first'
+ return False
+ self.__target = device
+ return True
+
+ def get_target_device(self):
+ """
+ Returns the selected device to work with
+ """
+ return self.__target
+
+ def get_state(self):
+ """
+ Get ADB state
+ adb get-state
+ """
+ self.__clean__()
+ self.run_cmd('get-state')
+ return self.__output
+
+ def get_serialno(self):
+ """
+ Get serialno from target device
+ adb get-serialno
+ """
+ self.__clean__()
+ self.run_cmd('get-serialno')
+ return self.__output
+
+ def reboot_device(self,mode):
+ """
+ Reboot the target device
+ adb reboot recovery/bootloader
+ """
+ self.__clean__()
+ if not mode in (self.REBOOT_RECOVERY,self.REBOOT_BOOTLOADER):
+ self.__error = "mode must be REBOOT_RECOVERY/REBOOT_BOOTLOADER"
+ return self.__output
+ self.run_cmd("reboot %s" % "recovery" if mode == self.REBOOT_RECOVERY else "bootloader")
+ return self.__output
+
+ def set_adb_root(self,mode):
+ """
+ restarts the adbd daemon with root permissions
+ adb root
+ """
+ self.__clean__()
+ self.run_cmd('root')
+ return self.__output
+
+ def set_system_rw(self):
+ """
+ Mounts /system as rw
+ adb remount
+ """
+ self.__clean__()
+ self.run_cmd("remount")
+ return self.__output
+
+ def get_remote_file(self,remote,local):
+ """
+ Pulls a remote file
+ adb pull remote local
+ """
+ self.__clean__()
+ self.run_cmd('pull \"%s\" \"%s\"' % (remote,local) )
+ if "bytes in" in self.__error:
+ self.__output = self.__error
+ self.__error = None
+ return self.__output
+
+ def push_local_file(self,local,remote):
+ """
+ Push a local file
+ adb push local remote
+ """
+ self.__clean__()
+ self.run_cmd('push \"%s\" \"%s\"' % (local,remote) )
+ return self.__error
+
+ def shell_command(self,cmd):
+ """
+ Executes a shell command
+ adb shell <cmd>
+ """
+ self.__clean__()
+ self.run_cmd('shell %s' % cmd)
+ return self.__output
+
+ def listen_usb(self):
+ """
+ Restarts the adbd daemon listening on USB
+ adb usb
+ """
+ self.__clean__()
+ self.run_cmd("usb")
+ return self.__output
+
+ def listen_tcp(self,port=DEFAULT_TCP_PORT):
+ """
+ Restarts the adbd daemon listening on the specified port
+ adb tcpip <port>
+ """
+ self.__clean__()
+ self.run_cmd("tcpip %s" % port)
+ return self.__output
+
+ def get_bugreport(self):
+ """
+ Return all information from the device that should be included in a bug report
+ adb bugreport
+ """
+ self.__clean__()
+ self.run_cmd("bugreport")
+ return self.__output
+
+ def get_jdwp(self):
+ """
+ List PIDs of processes hosting a JDWP transport
+ adb jdwp
+ """
+ self.__clean__()
+ self.run_cmd("jdwp")
+ return self.__output
+
+ def get_logcat(self,lcfilter=""):
+ """
+ View device log
+ adb logcat <filter>
+ """
+ self.__clean__()
+ self.run_cmd("logcat %s" % lcfilter)
+ return self.__output
+
+ def run_emulator(self,cmd=""):
+ """
+ Run emulator console command
+ """
+ self.__clean__()
+ self.run_cmd("emu %s" % cmd)
+ return self.__output
+
+ def connect_remote (self,host=DEFAULT_TCP_HOST,port=DEFAULT_TCP_PORT):
+ """
+ Connect to a device via TCP/IP
+ adb connect host:port
+ """
+ self.__clean__()
+ self.run_cmd("connect %s:%s" % ( host , port ) )
+ return self.__output
+
+ def disconnect_remote (self , host=DEFAULT_TCP_HOST , port=DEFAULT_TCP_PORT):
+ """
+ Disconnect from a TCP/IP device
+ adb disconnect host:port
+ """
+ self.__clean__()
+ self.run_cmd("disconnect %s:%s" % ( host , port ) )
+ return self.__output
+
+ def ppp_over_usb(self,tty=None,params=""):
+ """
+ Run PPP over USB
+ adb ppp <tty> <params>
+ """
+ self.__clean__()
+ if tty is None:
+ return self.__output
+
+ cmd = "ppp %s" % tty
+ if params != "":
+ cmd += " %s" % params
+
+ self.run_cmd(cmd)
+ return self.__output
+
+ def sync_directory(self,directory=""):
+ """
+ Copy host->device only if changed (-l means list but don't copy)
+ adb sync <dir>
+ """
+ self.__clean__()
+ self.run_cmd("sync %s" % directory )
+ return self.__output
+
+ def forward_socket(self,local=None,remote=None):
+ """
+ Forward socket connections
+ adb forward <local> <remote>
+ """
+ self.__clean__()
+ if local is None or remote is None:
+ return self.__output
+ self.run_cmd("forward %s %s" % (local,remote) )
+ return self.__error
+
+
+ def uninstall(self,package=None,keepdata=False):
+ """
+ Remove this app package from the device
+ adb uninstall [-k] package
+ """
+ self.__clean__()
+ if package is None:
+ return self.__output
+ cmd = "uninstall %s" % (package if keepdata is True else "-k %s" % package )
+ self.run_cmd(cmd)
+ return self.__output
+
+ def install(self,fwdlock=False,reinstall=False,sdcard=False,pkgapp=None):
+ """
+ Push this package file to the device and install it
+ adb install [-l] [-r] [-s] <file>
+ -l -> forward-lock the app
+ -r -> reinstall the app, keeping its data
+ -s -> install on sdcard instead of internal storage
+ """
+
+ self.__clean__()
+ if pkgapp is None:
+ return self.__output
+
+ cmd = "install "
+ if fwdlock is True:
+ cmd += "-l "
+ if reinstall is True:
+ cmd += "-r "
+ if sdcard is True:
+ cmd += "-s "
+
+ self.run_cmd("%s %s" % (cmd , pkgapp) )
+ return self.__output
+
+ def find_binary(self,name=None):
+ """
+ Look for a binary file on the device
+ """
+
+ self.shell_command("which %s" % name)
+
+ if self.__output is None: # not found
+ self.__error = "'%s' was not found" % name
+ elif self.__output.strip() == "which: not found": # which binary not available
+ self.__output = None
+ self.__error = "which binary not found"
+ else:
+ self.__output = self.__output.strip()
+
+ return self.__output
View
24 config.cfg
@@ -0,0 +1,24 @@
+[ADB]
+path=adb
+[GT-I9300 4.1.2]
+data=/dev/block/mmcblk0p12
+footer=y
+footer_offest=12381569024
+footer_file=
+sdcard_file=/data/system/edk_p_sd
+[GT-I9100 4.0.3]
+data=/dev/block/mmcblk0p11
+footer=n
+footer_offset=0
+footer_file=/efs/metadata
+sdcard_file=/data/system/edk_p_sd
+data=/dev/block/mmcblk0p11
+efs=/dev/block/mmcblk0p1
+[GT-I9505 4.2.2]
+data=/dev/block/mmcblk0p29
+footer=y
+sdcard_file=/data/system/edk_p_sd
+[GT-I9300 4.2.2]
+data=/dev/block/mmcblk0p12
+footer=y
+sdcard_file=/data/system/edk_p_sd
View
BIN  dump_android_memory/dump_android_memory
Binary file not shown
View
69 dump_android_memory/dump_android_memory.c
@@ -0,0 +1,69 @@
+/*
+ * =====================================================================================
+ *
+ * Filename: dump_android_memory.c
+ *
+ * Description: Process memory dumper for andorid. It is based on the following code:
+ * http://tthtlc.wordpress.com/2011/12/10/how-to-dump-memory-of-any-running-processes-in-android-2/
+ * It is part of the sandy framework, thus the same license applies.
+ *
+ * Version: 1.0
+ * Created: 09/24/2013 15:37:39
+ * Revision: none
+ * Compiler: gcc
+ *
+ * Author: Laszlo Toth
+ * Organization:
+ *
+ * =====================================================================================
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+
+char* filename;
+
+int main(int argc, char **argv) {
+
+ if (argc == 5) {
+ int pid = atoi(argv[1]);
+ unsigned int start_address;
+ sscanf(argv[2], "0x%x", &start_address);
+
+ unsigned int total_bytes;
+ sscanf(argv[3], "%d", &total_bytes);
+
+ filename=argv[4];
+
+ ptrace(PTRACE_ATTACH, pid, NULL, NULL);
+ wait(NULL);
+ dump_memory(pid, start_address, total_bytes);
+ ptrace(PTRACE_CONT, pid, NULL, NULL);
+ ptrace(PTRACE_DETACH, pid, NULL, NULL);
+ } else {
+ printf("%s <pid> <start_address> <number of bytes> <filename>\nwhere <start_address> is in hexadecimal (remember the \"0x\" in front is needed - by sscanf()\n", argv[0]);
+ exit(0);
+ }
+}
+
+dump_memory(int pid, unsigned int start_address, unsigned int total_bytes) {
+
+ unsigned int address;
+ unsigned int number = 0;
+ FILE* fh;
+
+ fh=fopen(filename,"w");
+ if(fh==NULL){
+ printf("ERROR: Could not open file: %s!", filename);
+ return;
+ }
+
+ for (address=start_address;address<start_address+total_bytes;address+=4) {
+ number=ptrace(PTRACE_PEEKDATA, pid, (void *)address, (void *)number);
+ fwrite(&number, sizeof(int), 1, fh);
+ }
+ fclose(fh);
+}
+
View
9 gdb/README
@@ -0,0 +1,9 @@
+The gdbserver was compiled to the ARM platform with the following:
+ ./configure --host=arm-linux-androideabi --target=arm-linux-androideabi
+
+You should compile your gdb with the following:
+ ./configure --target=arm-linux-androideabi
+
+It worked for me quite well on OSX 10.8 and on Kali.
+
+
View
10 gdb/gdb
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+os=`uname`
+
+if [ $os = "Linux" ];
+then
+ ./gdb/gdb-kali
+else
+ ./gdb/gdb-osx
+fi
View
BIN  gdb/gdb-kali
Binary file not shown
View
BIN  gdb/gdb-osx
Binary file not shown
View
BIN  gdb/gdbserver
Binary file not shown
View
221 jtr_plugin/sandcrypt_fmt_plug.c
@@ -0,0 +1,221 @@
+/*
+ * =====================================================================================
+ *
+ * Filename: sandcrypt_fmt_plug.c
+ *
+ * Description: Implements a bruteforcer to the samsung way of android disk
+ * encryption. It is part of the sandy framework, thus the same license
+ * applies.
+ *
+ * Version: 0.1
+ * Created: 09/24/2013 15:49:10
+ * Revision: none
+ * Compiler: gcc
+ *
+ * Author: Laszlo Toth
+ * Organization:
+ *
+ * =====================================================================================
+ */
+
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+#include <openssl/HMAC.h>
+#if OPENSSL_VERSION_NUMBER >= 0x00908000
+
+#include <string.h>
+
+#include "arch.h"
+#include "misc.h"
+#include "common.h"
+#include "formats.h"
+#include <openssl/sha.h>
+
+#define FORMAT_LABEL "sandcrypt"
+#define FORMAT_NAME "Samsung phone encryption"
+
+#define ALGORITHM_NAME "32/" ARCH_BITS_STR
+
+#define BENCHMARK_COMMENT ""
+#define BENCHMARK_LENGTH 0
+
+#define PLAINTEXT_LENGTH 125
+
+#define BINARY_SIZE 32
+#define SALT_SIZE 48
+#define SALT_SIZE_REAL 16
+#define ENC_KEY_SIZE 32
+#define CIPHERTEXT_LENGTH (ENC_KEY_SIZE * 2 + BINARY_SIZE * 2 + SALT_SIZE_REAL*2)
+
+#define MIN_KEYS_PER_CRYPT 1
+#define MAX_KEYS_PER_CRYPT 1
+
+static struct fmt_tests tests[] = {
+ {"37257bc9136d9da22756780fc8e6f5675a040adccbe92048e985e21a82f043a08172ee2f0f06cc7c3c8e0faad4bbaa3ff15a94f74c1cd5962ff496096bc6d8dea0a014b7b81c655baf725fb94cb2aada", "qwerty1"},
+ {NULL}
+};
+
+static char crypt_key[BINARY_SIZE+1];
+static unsigned char cursalt[SALT_SIZE_REAL];
+static unsigned char curenckey[BINARY_SIZE];
+static char saved_plain[PLAINTEXT_LENGTH + 1];
+
+static int valid(char *ciphertext, struct fmt_main *self)
+{
+ int i;
+
+ if (strlen(ciphertext) != CIPHERTEXT_LENGTH) return 0;
+ for (i = 0; i < CIPHERTEXT_LENGTH; i++)
+ {
+ if (!( (('0' <= ciphertext[i])&&(ciphertext[i] <= '9')) ||
+ (('a' <= ciphertext[i])&&(ciphertext[i] <= 'f'))
+ || (('A' <= ciphertext[i])&&(ciphertext[i] <= 'F'))))
+ return 0;
+ }
+ return 1;
+}
+
+
+static char *split(char *ciphertext, int index)
+{
+ static char out[CIPHERTEXT_LENGTH + 1];
+
+ strnzcpy(out, ciphertext, CIPHERTEXT_LENGTH + 1);
+ strlwr(out);
+
+ return out;
+}
+
+static void set_salt(void *salt)
+{
+ memcpy(curenckey, salt, BINARY_SIZE);
+ memcpy(cursalt, salt+BINARY_SIZE, SALT_SIZE_REAL);
+}
+
+static void set_key(char *key, int index)
+{
+ int len;
+ int i;
+ len = strlen(key);
+ memcpy(saved_plain, key, len);
+ saved_plain[len] = 0;
+}
+
+static char *get_key(int index)
+{
+ return saved_plain;
+}
+
+static int cmp_all(void *binary, int count)
+{
+ return !memcmp(binary, crypt_key, BINARY_SIZE);
+}
+
+static int cmp_exact(char *source, int count)
+{
+ return (1);
+}
+
+static int cmp_one(void *binary, int index)
+{
+ return !memcmp(binary, crypt_key, BINARY_SIZE);
+}
+
+static void crypt_all(int count)
+{
+ static unsigned char key[64];
+ unsigned char fixed_hex_1[17]="\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
+ unsigned char fixed_hex_2[17]="\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
+ int i;
+ int out_len;
+
+ out_len=32;
+ PKCS5_PBKDF2_HMAC(saved_plain, strlen(saved_plain), cursalt, 16, 4096, EVP_sha256(), 32, key);
+ HMAC(EVP_sha256(), key, 32, curenckey, 32, crypt_key, NULL);
+}
+
+static void *binary(char *ciphertext)
+{
+ static unsigned char realcipher[BINARY_SIZE];
+ int i;
+
+ for(i=0;i<BINARY_SIZE;i++)
+ realcipher[i] = atoi16[ARCH_INDEX(ciphertext[i*2+64])]*16 + atoi16[ARCH_INDEX(ciphertext[i*2+1+64])];
+
+ return (void*)realcipher;
+}
+
+static void *salt(char *ciphertext)
+{
+ static unsigned char salt[BINARY_SIZE+SALT_SIZE_REAL];
+ int i;
+
+ memset(salt, 0, sizeof(salt));
+ for(i=0;i<BINARY_SIZE;i++)
+ salt[i] = atoi16[ARCH_INDEX(ciphertext[i*2])]*16 + atoi16[ARCH_INDEX(ciphertext[i*2+1])];
+ for(i=32;i<SALT_SIZE_REAL+32;i++)
+ salt[i] = atoi16[ARCH_INDEX(ciphertext[i*2+64])]*16 + atoi16[ARCH_INDEX(ciphertext[i*2+1+64])];
+ return salt;
+}
+
+void print_hex(unsigned char* d, int len){
+ int i;
+
+ for(i=0; i < len; i++){
+ printf("%02x", d[i]);
+ }
+}
+
+struct fmt_main fmt_sandcrypt = {
+ {
+ FORMAT_LABEL,
+ FORMAT_NAME,
+ ALGORITHM_NAME,
+ BENCHMARK_COMMENT,
+ BENCHMARK_LENGTH,
+ PLAINTEXT_LENGTH,
+ BINARY_SIZE,
+ SALT_SIZE,
+ MIN_KEYS_PER_CRYPT,
+ MAX_KEYS_PER_CRYPT,
+ FMT_CASE | FMT_8_BIT | FMT_SPLIT_UNIFIES_CASE,
+ tests
+ }, {
+ fmt_default_init,
+ fmt_default_prepare,
+ valid,
+ split,
+ binary,
+ salt,
+ {
+ fmt_default_binary_hash,
+ fmt_default_binary_hash,
+ fmt_default_binary_hash,
+ fmt_default_binary_hash,
+ fmt_default_binary_hash
+ },
+ fmt_default_salt_hash,
+ set_salt,
+ set_key,
+ get_key,
+ fmt_default_clear_keys,
+ crypt_all,
+ {
+ fmt_default_get_hash,
+ fmt_default_get_hash,
+ fmt_default_get_hash,
+ fmt_default_get_hash,
+ fmt_default_get_hash
+ },
+ cmp_all,
+ cmp_one,
+ cmp_exact
+ }
+};
+
+#else
+#ifdef __GNUC__
+#warning Note: sandcrypt format disabled - it needs OpenSSL 0.9.8 or above
+#endif
+
+#endif
View
7 keyctl/README
@@ -0,0 +1,7 @@
+How to crosscompile keyctl utility:
+
+1. Download from http://people.redhat.com/~dhowells/keyutils/
+2. Setup your cross compile environment for androideabi
+3. make keyctl #Ignore the error messages
+4. arm-linux-androideabi-gcc --static --sysroot=[your ndk install path]/android-ndk-r8e/platforms/android-8/arch-arm/ -static -L. -g -Wall -o keyctl keyctl.o keyutils.o
+
View
BIN  keyctl/keyctl
Binary file not shown
View
21 main.py
@@ -0,0 +1,21 @@
+import argparse
+from sandy.sandy import Sandy
+
+# Handling command line arguments
+parser = argparse.ArgumentParser(prog="main.py")
+#parser.add_argument("-G", action="store_true", help="start the GUI (wxPython)")
+#parser.add_argument("-C", action="store_true", help="start the interactive console mode")
+parser.add_argument("-p", action="store", required=True, metavar="project_name", help="The name of the actual project")
+
+args = parser.parse_args()
+
+Sandy._settings['projectname']=args.p
+sandy = Sandy()
+sandy.start_console()
+
+#if (args.C):
+# console = Console()
+# console.run()
+#elif (args.G):
+# print "XX"
+
View
1  modules/__init__.py
@@ -0,0 +1 @@
+import printer
View
1  modules/sand2john/__init__.py
@@ -0,0 +1 @@
+import printer
View
81 modules/sand2john/sand2john.py
@@ -0,0 +1,81 @@
+import re
+import sys
+import string
+import printer
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+
+class Sand2John:
+
+
+ def __init__(self, printer, project, mode="phone"):
+ self.printer=printer
+ self.project=project
+ self.mode=mode
+ if(self.mode=="sdcard"):
+ key_file="edk_p_sd"
+ else:
+ key_file="footer"
+ self.params={
+ "out_dir":{"description":"Where to generate the results on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "key_file":{"description":"The footer file or the SD card file that kontains the encrypted key.",
+ "value":"%s_%s" % (self.project, key_file),
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+ def setparams(self, params):
+ self.params=params
+ self.out_dir = self.params["out_dir"]["value"]
+ self.key_file = self.params["key_file"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def convert2john(self):
+ toconvert="%s/%s" % (self.out_dir, self.key_file)
+ if(self.fileconvert2john(toconvert)==-1):
+ return -1
+ return 1
+
+ def fileconvert2john(self, file):
+ mode="phone"
+ try:
+ f = open(file,"rb")
+ f.seek(0x24)
+ check=f.read(3)
+ if(check=="aes"):
+ mode="phone"
+ else:
+ mode="sdcard"
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1}: {2}".format(e.errno, e.strerror, file))
+ return -1
+ self.printer.print_info("Converting %s encryption file to sandcrypt jtr format." % mode)
+ if(mode=="sdcard"):
+ offset=0x20
+ else:
+ offset=0x84
+
+ f.seek(offset)
+ binary=f.read(80)
+ f.close()
+ john=hexlify(binary)
+ self.printer.print_ok("Convert - Done")
+ self.printer.print_info("This will be written to file %s/%s_sanddek.jtr, for jtr:" % (self.out_dir, self.project))
+ self.printer.print_info("%s%s:%s" % (self.project, mode, john))
+ self.printer.print_ok("Write - Done")
+ try:
+ f= open("%s/%s_sanddek.jtr" % (self.out_dir, self.project), "a")
+ f.write("%s%s:%s\n" % (self.project, mode, john))
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1}: {2}/{3}_sanddek.jtr".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+ return 1
+
View
1  modules/sandgetdek/__init__.py
@@ -0,0 +1 @@
+import printer
View
213 modules/sandgetdek/sandgetdek.py
@@ -0,0 +1,213 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+
+class GetKey:
+
+ def __init__(self, printer, config, project, adb_path="adb"):
+ self.printer=printer
+ self.params={"adbpath":{"description":"Path of the adb command",
+ "value":adb_path,
+ "required":True
+ },
+ "dumpfile":{"description":"Where to save the memory dumpfile with the filename",
+ "value":"dumpfile",
+ "required":True
+ },
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "dekfile":{"description":"Where to generate the results and download files on the computer.",
+ "value":"dek.bin",
+ "required":True
+ },
+ "phonewithos":{"description":"The samsung hardware and the android version",
+ "value":"GT-I9300 4.1.2",
+ "required":True
+ },
+
+ }
+ self.adb = ADB(self.params["adbpath"]["value"])
+ self.out_dir=self.params["out_dir"]["value"]
+ self.dumpfile = self.params["dumpfile"]["value"]
+ self.dekfile = self.params["dekfile"]["value"]
+ self.project=project
+
+ def setparams(self, params):
+ self.params=params
+ self.adb = ADB(self.params["adbpath"]["value"])
+ self.dumpfile = self.params["dumpfile"]["value"]
+ self.dekfile = self.params["dekfile"]["value"]
+ self.phone = self.params["phonewithos"]["value"]
+ self.out_dir = self.params["out_dir"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def get_vold_data_segment(self):
+ self.printer.print_debug("Check for su!")
+ su=checkforsu(self.adb)
+ if (su==""):
+ self.printer.print_err("The su comand was not found, hope adb have immediate root access!")
+ su=""
+
+ #No magic here, the phone should be fully booted for this module
+ self.dest_dir="/data/local/tmp"
+
+ ps=self.adb.shell_command("su -c ps")
+ for process in ps.splitlines():
+ if(process.rfind("vold") != -1 ):
+ process=re.sub("\s+", ' ' , process)
+ self.voldpid=process.split(' ')[1]
+
+ self.printer.print_debug("Found vold process id: %s!" % self.voldpid)
+ memsegments=self.adb.shell_command("su -c cat /proc/%s/maps" % self.voldpid).splitlines()
+ for segment in memsegments:
+ if(re.match(".*w-p.*vold.*", segment)!=None):
+ addresses=segment.split(" ")[0].split("-")
+ self.datastart=addresses[0]
+ self.dataend=addresses[1]
+ self.numberofbytes=int(addresses[1],16)-int(addresses[0],16)
+
+ self.printer.print_debug("The data segment addresses are: %s - %s" % (self.datastart, self.dataend))
+
+ self.printer.print_info("Copy the memory dumper to %s." % (self.dest_dir))
+
+ push=self.adb.push_local_file("dump_android_memory/dump_android_memory","%s" % self.dest_dir)
+ if(push.find("bytes")==-1):
+ self.print_info_adb(push, False)
+ return -1
+
+ self.printer.print_ok("Copy - Done")
+ self.print_info_adb(push.rstrip("\n"))
+
+ self.printer.print_info("Run the memory dumper.")
+
+ dump=self.adb.shell_command("su -c /data/local/tmp/dump_android_memory %s 0x%s %d %s/dumpfile" % (self.voldpid, self.datastart, self.numberofbytes, self.dest_dir))
+ if(dump):
+ self.printer.print_info_adb(dump,False)
+ return -1
+ self.printer.print_ok("Memory dumber - Done")
+
+ self.printer.print_info("Download the dump file")
+
+ pull=self.adb.get_remote_file("/data/local/tmp/dumpfile","%s/%s_%s" % (self.out_dir, self.project, self.dumpfile))
+ if(pull.find("bytes")==-1):
+ self.print_info_adb(pull,False)
+ return -1
+
+ self.printer.print_ok("Download - Done")
+ self.print_info_adb(pull.rstrip("\n"))
+
+ #Cleanup
+ self.printer.print_info("Cleaning up! Please check the %s folder. Unsuccessull cleanup weakens the security of the phone!!!!" % self.dest_dir)
+ out=self.adb.shell_command(su+"rm %s/dumpfile" % self.dest_dir)
+ out=self.adb.shell_command(su+"rm %s/dump_android_memory" % self.dest_dir)
+ self.printer.print_ok("Clean up - Done")
+
+ def getpin(self):
+ buff=""
+ strings=self.strings("%s/%s_%s" % (self.out_dir, self.project, self.dumpfile));
+ self.printer.print_info("Following strings found in the vold memory segment:")
+ for entry in strings:
+ #self.printer.print_info(" %s:%d" % (entry.string, entry.pos))
+ self.printer.print_info(" %s" % (entry.string))
+ self.printer.print_info("Assuming the last one is the pin/password, let's find the DEK")
+ last_entry=strings[len(strings)-1]
+ index=len(last_entry.string)+last_entry.pos
+ try:
+ f=open("%s/%s_%s" % (self.out_dir, self.project, self.dumpfile),"rb")
+ try:
+ buff=f.read(4096)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}".format(e.errno, e.strerror, "%s/%s_%s" % (self.out_dir, self.project, self.dumpfile)))
+ return -1
+
+ for i in range(index+1,index+200):
+ if(buff[i]!='\0'):
+ break
+
+ #Because we search for the first non zero, the search can be broken.
+ dek1=buff[i:i+32]
+ self.printer.print_info("The first possible key is:")
+ self.printer.print_ok(hexlify(dek1))
+ dek2=buff[i-1:i-1+32]
+ self.printer.print_info("The second possible key is:")
+ self.printer.print_ok(hexlify(dek2))
+
+ self.printer.print_info("Creating two files:")
+ self.printer.print_ok("%s/%s_%s.1" % (self.out_dir, self.project, self.dekfile))
+ self.printer.print_ok("%s/%s_%s.2" % (self.out_dir, self.project, self.dekfile))
+
+ self.printer.print_info("If they are not working, analyze the dumpfile manually and you will find the key. It works for S2 and S3 until 4.1.2.")
+
+ try:
+ f=open("%s/%s_%s.1" % (self.out_dir, self.project, self.dekfile),"wb")
+ try:
+ f.write(dek1)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}_footer".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+
+ try:
+ f=open("%s/%s_%s.2" % (self.out_dir, self.project, self.dekfile),"wb")
+ try:
+ f.write(dek2)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}_footer".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+
+
+ return 1
+
+
+
+
+ def print_info_adb(self,message, ok=True):
+ if(ok):
+ self.printer.print_info("OK! Received the following from adb: %s" %message)
+ else:
+ self.printer.print_err("ERROR! Received the following from adb: %s" %message)
+
+ def strings(self,filename):
+ pos=0
+ strings=[]
+ s_entry=namedtuple("s_entry","string pos")
+ printable=set(string.printable)
+ found_str=""
+ fh=open(filename,"rb")
+ data=fh.read(4096)
+ fh.close()
+ pos=0
+ for char in data:
+ pos+=1
+ if char in printable:
+ found_str+=char
+ elif len(found_str) >= 4:
+ strings.append(s_entry(found_str, pos))
+ found_str=""
+ else:
+ found_str=""
+ return strings
+
+#prn=printer.Printer()
+#getkey = GetKey(prn)
+#if(getkey.get_vold_data_segment()==-1):
+# print "Could not get vold memory."
+#getkey.printer.print_info("Extract the strings from the memory dump. The password or pin should be there.")
+#getkey.getpin()
+
View
1  modules/sandgetfooter/__init__.py
@@ -0,0 +1 @@
+import printer
View
148 modules/sandgetfooter/sandgetfooter.py
@@ -0,0 +1,148 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+
+class SandGetFooter:
+
+
+ def __init__(self, printer, config, project, adb_path="adb"):
+ self.printer=printer
+ self.config=config
+ self.project=project
+ self.params={"adbpath":{"description":"Path of the adb command",
+ "value":adb_path,
+ "required":True
+ },
+ "footer":{"description":"Is the key is stored in footer?",
+ "value":"True",
+ "required":True
+ },
+ "phonewithos":{"description":"The samsung hardware and the android version",
+ "value":"GT-I9300 4.1.2",
+ "required":True
+ },
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "footer_file":{"description":"The DEK is stored in this file on the phone.",
+ "value":"/efs/metadata",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+ def setparams(self, params):
+ self.params=params
+ self.adb = ADB(self.params["adbpath"]["value"])
+ self.phone = self.params["phonewithos"]["value"]
+ self.out_dir = self.params["out_dir"]["value"]
+ self.footer_file = self.params["footer_file"]["value"]
+
+ def getparams(self):
+ return self.params
+
+
+ def get_footer_from_phone(self):
+
+ '''
+ Uploads the seek_and_read to /tmp or /data/local/tmp and runs it. Then it downloads the result footer file.
+ It dumps the last 16K of the data partition, configure in the config.cfg file. Please check the given
+ directories on the phone to make sure the cleanup was ok.
+ '''
+
+ partition=self.config.get(self.phone, "data")
+ self.printer.print_debug(partition)
+ self.printer.print_debug("Check for su!")
+ su=checkforsu(self.adb)
+ if (su==""):
+ self.printer.print_err("The su comand was not found, hope the phone in a recovery with root access!")
+ su=""
+
+ #dd was too slow on the phone (5min on s3), thus we implemented a seek and read program.
+
+ dest_dir=check_tmp(self.printer,self.adb,su)
+ self.printer.print_info("Uploading the footer reader to %s..." % (dest_dir))
+ push=self.adb.push_local_file("seek_and_read/seek_and_read","%s" % dest_dir)
+ if(push.find("bytes")==-1):
+ self.printer.print_err("Could not upload the file reader: %s" % push)
+ return -1
+ self.printer.print_ok("Upload - Done")
+
+ self.printer.print_debug("Running the following command:")
+ command=su+"%s/seek_and_read %s %s/footer" % (dest_dir, partition, dest_dir)
+ self.printer.print_debug(command)
+ out=self.adb.shell_command(command)
+ if(out.find("16384")==-1):
+ self.printer.print_err("File reader did not work: %s" % out)
+ self.printer.print_info("Cleaning up! Please check the %s folder. Unsuccessull cleanup weakens the security of the phone!!!!" % dest_dir)
+ out=self.adb.shell_command(su+"rm %s/footer" % dest_dir)
+ out=self.adb.shell_command(su+"rm %s/seek_and_read" % dest_dir)
+ return -1
+
+ self.printer.print_info("Downloading the footer file...")
+ pull=self.adb.get_remote_file("%s/footer" % dest_dir,"%s/%s_footer" % (self.out_dir, self.project))
+ if(pull.find("bytes")==-1):
+ self.printer.print_err("Could not download footer file: %s" % pull)
+ self.printer.print_info("Cleaning up! Please check the %s folder. Unsuccessull cleanup weakens the security of the phone!!!!" % dest_dir)
+ out=self.adb.shell_command(su+"rm %s/footer" % dest_dir)
+ out=self.adb.shell_command(su+"rm %s/seek_and_read" % dest_dir)
+ return -1
+ self.printer.print_ok("Download - Done")
+ self.printer.print_info(pull.rstrip("\n"))
+
+ #Cleanup
+ self.printer.print_info("Cleaning up! Please check the %s folder. Unsuccessull cleanup weakens the security of the phone!!!!" % dest_dir)
+ out=self.adb.shell_command(su+"rm %s/footer" % dest_dir)
+ out=self.adb.shell_command(su+"rm %s/seek_and_read" % dest_dir)
+
+ self.printer.print_ok("Download - Done")
+ return 1
+
+ def get_footer_file(self):
+
+ '''
+ Downloads the footer_file (typical /efs/metadata) that contains the DEK on S2. It copies the file to /tmp
+ or /data/local/tmp. Changes the access right to adb pull and downloads it.
+ '''
+
+ self.printer.print_debug("Check for su!")
+ su=checkforsu(self.adb)
+ if (su==""):
+ self.printer.print_err("The su comand was not found, hope the phone in a recovery with root access!")
+ su=""
+
+ self.printer.print_info("Downloading the footer [ %s ] file" % self.params["footer_file"])
+ pull = get_file(self.printer, self.adb, su, self.params["footer_file"], "%s/%s_footer"%(self.out_dir, self.project))
+ if (pull!=-1):
+ self.printer.print_ok("Download - Done")
+ return pull
+
+ def getfooter(self):
+
+ '''
+ Decides whether the DEK is stored in file or at the end of data partition. The decision is based on the
+ config.cg file.
+ '''
+
+ if(self.params["footer"]["value"]=="n"):
+ if(self.get_footer_file()==-1):
+ return -1
+ else:
+ if(self.get_footer_from_phone()==-1):
+ return -1
+ return 1
+
+
+ def print_info_adb(self,message, ok=True):
+ if(ok):
+ self.printer.printer.print_info("OK! Received the following from adb: %s" %message)
+ else:
+ self.printer.print_error("ERROR! Received the following from adb: %s" %message)
View
1  modules/sandgetfooterfromdd/__init__.py
@@ -0,0 +1 @@
+import printer
View
75 modules/sandgetfooterfromdd/sandgetfooterfromdd.py
@@ -0,0 +1,75 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+
+class SandGetFooterFromdd:
+
+
+ def __init__(self, printer, project):
+ self.printer=printer
+ self.project=project
+ self.params={
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "image_file":{"destion":"The dd image of the encrypted phone.",
+ "value":"%s_data.dd" % self.project,
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+ def setparams(self, params):
+ self.params=params
+ self.image_file = self.params["image_file"]["value"]
+ self.out_dir = self.params["out_dir"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def get_footer_from_dd(self,image_file):
+
+ '''
+ Extract the last 16k from the image file. The DEK should be there.
+ '''
+ buff=""
+ self.printer.print_info("Opening the dd image file: %s..." % image_file)
+ try:
+ f=open(image_file,"rb")
+ try:
+ f.seek(-0x4000, os.SEEK_END)
+ buff=f.read(0x4000)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}".format(e.errno, e.strerror, image_file))
+ return -1
+
+ self.printer.print_ok("Open - Done")
+
+ self.printer.print_info("Writing the last 16k to the following file: %s/%s_footer.." % (self.out_dir, self.project))
+ try:
+ f=open("%s/%s_footer" % (self.out_dir, self.project),"wb")
+ try:
+ f.write(buff)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}_footer".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+
+ self.printer.print_ok("Write - Done")
+ return 1
+
+ def do(self):
+ return self.get_footer_from_dd("%s/%s" % (self.out_dir, self.image_file))
+
+
View
1  modules/sandgetpwdhash/__init__.py
@@ -0,0 +1 @@
+import printer
View
112 modules/sandgetpwdhash/sandgetpwdhash.py
@@ -0,0 +1,112 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+import sqlite3
+
+class SandGetPasswordHash:
+
+ def __init__(self, printer, config, project, adb_path="adb"):
+ self.printer=printer
+ self.config=config
+ self.project=project
+ self.params={"adbpath":{"description":"Path of the adb command",
+ "value":adb_path,
+ "required":True
+ },
+ "phonewithos":{"description":"The samsung hardware and the android version",
+ "value":"GT-I9505 4.2.2",
+ "required":True
+ },
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+ self.salt=""
+ self.hash=""
+
+ def setparams(self, params):
+ self.params=params
+ self.adb = ADB(self.params["adbpath"]["value"])
+ self.phone = self.params["phonewithos"]["value"]
+ self.out_dir = self.params["out_dir"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def get_salt(self):
+ self.printer.print_debug("Check for su!")
+ su=checkforsu(self.adb)
+ if (su==""):
+ self.printer.print_err("The su comand was not found, hope the phone in a recovery with root access!")
+ su=""
+
+ ''' Download locksettings.db '''
+ self.printer.print_info("Downloading the locksettings.db-shm file...")
+ get_file(self.printer,self.adb,su,"/data/system/locksettings.db-shm","%s/%s_locksettings.db-shm" % (self.out_dir, self.project))
+ self.printer.print_ok("Download - Done")
+
+ self.printer.print_info("Downloading the locksettings.db-wal file...")
+ get_file(self.printer,self.adb,su,"/data/system/locksettings.db-wal","%s/%s_locksettings.db-wal" % (self.out_dir, self.project))
+ self.printer.print_ok("Download - Done")
+
+ self.printer.print_info("Downloading the locksettings.db file...")
+ get_file(self.printer,self.adb,su,"/data/system/locksettings.db","%s/%s_locksettings.db" % (self.out_dir, self.project))
+ self.printer.print_ok("Download - Done")
+
+ ''' Extract the salt from the sqlite database '''
+ try:
+ database = "%s/%s_locksettings.db" % (self.out_dir, self.project)
+ con = sqlite3.connect(database)
+ cur = con.cursor()
+ cur.execute("SELECT value FROM locksettings WHERE name = 'lockscreen.password_salt'")
+ data = cur.fetchone()
+ self.salt=data[0]
+ except Exception as error:
+ self.printer.print_err("Could not extract the hash from the sqlite database: %d" % error.returncode)
+ self.printer.print_err(error.output)
+ return -1
+
+ def get_hash(self):
+ self.printer.print_info("Check for su!")
+ su=checkforsu(self.adb)
+ if (su==""):
+ self.printer.print_err("The su comand was not found, hope the phone in a recovery with root access!")
+ su=""
+
+ self.printer.print_info("Downloading the password.key file...")
+ get_file(self.printer,self.adb,su,"/data/system/password.key","%s/%s_password.key" % (self.out_dir, self.project))
+ self.printer.print_ok("Download - Done")
+
+ '''Extract the hash from password.key file'''
+ filename = "%s/%s_password.key" % (self.out_dir, self.project)
+ infile = open(filename, 'r')
+ self.hash = infile.readline()
+
+ def dump_hash(self):
+ self.get_salt()
+ self.get_hash()
+ buff = "%s:%s\n" % (self.hash, self.salt)
+ '''FORMAT: hash:salt '''
+ self.printer.print_info("Writing the salt and the hash to the following file: %s/%s_pwdhash" % (self.out_dir, self.project))
+ try:
+ f=open("%s/%s_pwdhash" % (self.out_dir, self.project),"wb")
+ try:
+ f.write(buff)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}_pwdhash".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+
+ self.printer.print_ok("Write - Done")
+
+ return 1
View
1  modules/sandgetsdcard/__init__.py
@@ -0,0 +1 @@
+import printer
View
63 modules/sandgetsdcard/sandgetsdcard.py
@@ -0,0 +1,63 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+
+class SandGetSDCard:
+
+
+ def __init__(self, printer, config, project, adb_path="adb"):
+ self.printer=printer
+ self.config=config
+ self.project=project
+ self.params={"adbpath":{"description":"Path of the adb command",
+ "value":adb_path,
+ "required":True
+ },
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "sdcard_file":{"description":"The DEK is stored in this file on the phone.",
+ "value":"/data/system/edk_p_sd",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+ def setparams(self, params):
+ self.params=params
+ self.adb = ADB(self.params["adbpath"]["value"])
+ self.sdcard_file = os.path.basename(self.params["sdcard_file"]["value"])
+ self.out_dir = self.params["out_dir"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def get_sdcard_file(self):
+ '''
+ Downloads the sdcard_file (typically /data/system/edk_p_sd).
+ It copies the file to /tmp or /data/local/tmp. Changes the access right to adb pull and downloads it.
+ '''
+
+ self.printer.print_debug("Check for su!")
+ su=checkforsu(self.adb)
+ if (su==""):
+ self.printer.print_err("The su comand was not found, hope the phone in a recovery with root access!")
+ su=""
+
+
+ self.printer.print_info("Download key file")
+ pull = get_file(self.printer,self.adb,su,"%s" %(self.params["sdcard_file"]["value"]),"%s/%s_%s" % (self.out_dir, self.project, self.sdcard_file))
+ self.printer.print_ok("Download - Done")
+ self.printer.print_info(pull.rstrip("\n"))
+
+ return 1
+
+
View
1  modules/sandmountddfromkey/__init__.py
@@ -0,0 +1 @@
+import printer
View
88 modules/sandmountddfromkey/sandmountddfromkey.py
@@ -0,0 +1,88 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+import subprocess
+
+class SandMountDDFromKey:
+
+
+ def __init__(self, printer, project):
+ self.printer=printer
+ self.project=project
+ self.params={
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "image_file":{"description":"The dd image of the encrypted phone.",
+ "value":"%s_data.dd" % self.project,
+ "required":True
+ },
+ "dekfile":{"description":"Where to generate the results and download files on the computer.",
+ "value":"%s_dek.bin.1" % self.project,
+ "required":True
+ },
+ "mnt_dest":{"description":"Where to mount.",
+ "value":"/mnt/userdata",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+
+ def setparams(self, params):
+ self.params=params
+ self.out_dir = self.params["out_dir"]["value"]
+ self.dekfile = self.params["dekfile"]["value"]
+ self.image_file = self.params["image_file"]["value"]
+ self.mnt_dest = self.params["mnt_dest"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def mountddfromkey(self, image_file, dekfile, mnt_dest):
+
+ self.printer.print_info("Trying to mount the dd file...")
+
+ command=["cryptsetup", "-h", "plain", "-c",
+ "aes-cbc-essiv:sha256", "--readonly", "-d", dekfile, "create", "userdata",image_file]
+ self.printer.print_debug("Set up the dm-crypt with the following command: ")
+ self.printer.print_debug(" ".join(command))
+ try:
+ a=subprocess.check_output(command,stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as error:
+ self.printer.print_err("cryptsetup failed: %d" % error.returncode)
+ self.printer.print_err(error.output)
+ return -1
+ except Exception as error:
+ self.printer.print_err("cryptsetup failed: %s" % error.strerror)
+ self.printer.print_err("cryptsetup is installed?")
+ return -1
+
+ command=["mount", "-r", "/dev/mapper/userdata", "%s" % mnt_dest]
+ self.printer.print_debug(" ".join(command))
+
+ try:
+ a=subprocess.check_output(command,stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as error:
+ self.printer.print_err("mount failed: %d" % error.returncode)
+ self.printer.print_err(error.output)
+ return -1
+ except Exception as error:
+ self.printer.print_err("mount failed: %s" % error.strerror)
+ return -1
+
+ self.printer.print_ok("Mount - Done")
+ self.printer.print_ok("Mount destination: %s" % mnt_dst)
+ return 1
+
+ def do(self):
+ return self.mountddfromkey("%s/%s" % (self.out_dir, self.image_file), "%s/%s" % (self.out_dir, self.dekfile), self.mnt_dest)
+
View
1  modules/sandmountddfrompwd/__init__.py
@@ -0,0 +1 @@
+import printer
View
114 modules/sandmountddfrompwd/sandmountddfrompwd.py
@@ -0,0 +1,114 @@
+import re
+import sys
+import string
+import printer
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+import subprocess
+from modules.sandmountddfromkey.sandmountddfromkey import *
+
+class SandMountDDFromPwd(SandMountDDFromKey):
+
+
+ def __init__(self, printer, project):
+ self.printer=printer
+ self.project=project
+ self.params={
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "image_file":{"description":"The dd image of the encrypted phone.",
+ "value":"%s_data.dd" % self.project,
+ "required":True
+ },
+ "password":{"description":"Password or pin to decrypt the phone",
+ "value":"qwertz2",
+ "required":True
+ },
+ "mnt_dest":{"description":"Where to mount.",
+ "value":"/mnt/userdata",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+ def setparams(self, params):
+ self.params=params
+ self.out_dir = self.params["out_dir"]["value"]
+ self.password = self.params["password"]["value"]
+ self.image_file = self.params["image_file"]["value"]
+ self.mnt_dest = self.params["mnt_dest"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def get_footer_from_dd(self):
+
+ '''
+ Extract the DEK from dd. If it is S4 tries to open project_footer file,
+ generated by the sands4getdek.
+ '''
+
+ keypaddingsalt=""
+ self.printer.print_debug("Open the dd image file: %s/%s" % (self.out_dir, self.image_file))
+ try:
+ f=open("%s/%s" % (self.out_dir, self.image_file),"rb")
+ try:
+ f.seek(-0x4000, os.SEEK_END)
+ f.seek(0x84,1)
+ keypaddingsalt=f.read(80)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}".format(e.errno, e.strerror, self.out_dir, self.image_file))
+ return ""
+
+ if(keypaddingsalt[0:5]=="\0\0\0\0\0"):
+ self.printer.print_info("The first five bytes are zero, assuming it is S4.")
+ self.printer.print_debug("Open the footer file: %s/%s_footer" % (self.out_dir, self.project))
+ try:
+ f=open("%s/%s_footer" % (self.out_dir, self.project),"rb")
+ try:
+ f.seek(0x84)
+ keypaddingsalt=f.read(80)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}_footer".format(e.errno, e.strerror, self.out_dir, self.project))
+ return ""
+
+ return keypaddingsalt
+
+
+ def mountddfrompwd(self, image_file, password, mnt_dest):
+ keypaddingsalt=self.get_footer_from_dd()
+ if(keypaddingsalt==""):
+ self.printer.print_err("Could not mount dd image: %s/%s" % (self.out_dir, self.image_file))
+ return -1
+ binkey,mkey = decrypt_key(keypaddingsalt[:32], keypaddingsalt[64:], password)
+ padding=create_padding(keypaddingsalt[:32], mkey)
+ if(padding!=keypaddingsalt[32:64]):
+ self.printer.print_err("The given password is wrong!")
+ self.printer.print_err("Could not mount dd image: %s/%s" % (self.out_dir, self.image_file))
+ return -1
+
+ try:
+ f=open("%s/%s_dek_formount" % (self.out_dir, self.project),"wb")
+ try:
+ f.write(binkey)
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}_footer".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+
+ return self.mountddfromkey("%s/%s" % (self.out_dir, self.image_file), "%s/%s_dek_formount" % (self.out_dir, self.project), self.mnt_dest)
+
+
+
+ def do(self):
+ return self.mountddfrompwd("%s/%s" % (self.out_dir, self.image_file), self.password, self.mnt_dest)
+
View
1  modules/sandmountsdcardfromkey/__init__.py
@@ -0,0 +1 @@
+import printer
View
120 modules/sandmountsdcardfromkey/sandmountsdcardfromkey.py
@@ -0,0 +1,120 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+import subprocess
+import time
+
+class SandMountSdcardFromKey:
+
+
+ def __init__(self, printer, project):
+ self.printer=printer
+ self.project=project
+ self.params={
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "source_dir":{"description":"Directory contains the files from an encrypted sdcard.",
+ "value":"%s_sdcard/" % self.project,
+ "required":True
+ },
+ "sdckey":{"description":"The file contains the decrypted key for the SD card.",
+ "value":"%s_sdckey.bin" % self.project,
+ "required":True
+ },
+ "mnt_dest":{"description":"Where to mount.",
+ "value":"/mnt/sdcard",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+
+ def setparams(self, params):
+ self.params=params
+ self.out_dir = self.params["out_dir"]["value"]
+ self.source_dir = self.params["source_dir"]["value"]
+ self.sdckey = self.params["sdckey"]["value"]
+ self.mnt_dest = self.params["mnt_dest"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def getkeybin(self, file):
+ try:
+ f=open(file,"rb")
+ try:
+ binkey=f.read()
+ finally:
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1} {2}/{3}".format(e.errno, e.strerror, self.out_dir, self.image_file))
+ return ""
+ return binkey
+
+
+ def mountsdcardfromkey(self, source_dir, sdckey, mnt_dest):
+
+ """
+ Runs the following two commands to mount a directory that conatins files from an encrypted SD card
+ keyctl padd user 6f373de316226c3d @u < s4_sdckey.bin
+ mount -r -i -t ecryptfs sdcard/ /mnt/sdcard/ -o ecryptfs_sig=5c6f31e3a9376cff,ecryptfs_cipher=aes,\
+ ecryptfs_key_bytes=32,ecryptfs_unlink_sigs,ecryptfs_enable_filename_crypto=n,no_sig_cache,ecryptfs_passthrough
+ """
+
+ binkey=self.getkeybin(sdckey)
+
+ #Key signature from the dumped key file
+ keyid=binkey[712:].rstrip("\0")
+ command=["keyctl", "padd", "user", "%s" % keyid, "@u"]
+ self.printer.print_debug("Add the key to your keyring with the following command")
+ self.printer.print_debug(" ".join(command))
+ try:
+ keyctl=subprocess.Popen(command,stderr=subprocess.STDOUT, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ out=keyctl.communicate(binkey)
+ except subprocess.CalledProcessError as error:
+ self.printer.print_err("keyctl failed: %d" % error.returncode)
+ self.printer.print_err(error.output)
+ return -1
+ except Exception as error:
+ self.printer.print_err("keyctl failed: %s" % error.strerror)
+ self.printer.print_err("keyctl is installed?")
+ return -1
+
+ if(out[1]!=None):
+ self.printer.print_err("keyctl failed: %s" % out[1])
+ self.printer.print_err("keyctl is installed?")
+ return -1
+
+ self.printer.print_ok("Key was added to the keyring. The keyid is %s" % out[0].rstrip("\n"))
+
+ command=['mount', '-r', '-i', '-t', 'ecryptfs', source_dir, mnt_dest, '-o',
+ 'ecryptfs_sig=%s,ecryptfs_cipher=aes,ecryptfs_key_bytes=32,ecryptfs_unlink_sigs,ecryptfs_enable_filename_crypto=n,no_sig_cache,ecryptfs_passthrough' % keyid]
+ self.printer.print_debug("Mount the %s directory with the following command:" % (source_dir))
+ self.printer.print_debug(" ".join(command))
+ try:
+ mount=subprocess.check_output(command,stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as error:
+ self.printer.print_err("mount failed: %d" % error.returncode)
+ self.printer.print_err(error.output)
+ return -1
+ except Exception as error:
+ self.printer.print_err("mount failed: %s" % error.strerror)
+ return -1
+
+ self.printer.print_ok("Mount - Done")
+ self.printer.print_ok("Mount destination: %s" % self.mnt_dest)
+
+ return 1
+
+ def do(self):
+ return self.mountsdcardfromkey( "%s/%s" % (self.out_dir,self.source_dir), "%s/%s" % (self.out_dir, self.sdckey), self.mnt_dest)
+
View
1  modules/sandmountsdcardfrompwd/__init__.py
@@ -0,0 +1 @@
+import printer
View
73 modules/sandmountsdcardfrompwd/sandmountsdcardfrompwd.py
@@ -0,0 +1,73 @@
+import re
+import sys
+import string
+import printer
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+import subprocess
+from modules.sandmountsdcardfromkey.sandmountsdcardfromkey import *
+
+class SandMountSdcardFromPwd(SandMountSdcardFromKey):
+
+
+ def __init__(self, printer, project):
+ self.printer=printer
+ self.project=project
+ self.params={
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ "source_dir":{"description":"Directory contains the files from an encrypted sdcard.",
+ "value":"%s_sdcard/" % self.project,
+ "required":True
+ },
+ "sdcard_file":{"description":"The file contains the encrypted key for the SD card.",
+ "value":"%s_edk_p_sd" % self.project,
+ "required":True
+ },
+ "mnt_dest":{"description":"Where to mount.",
+ "value":"/mnt/sdcard",
+ "required":True
+ },
+ "password":{"description":"Password for the sdcard key decryption.",
+ "value":"qwertz2",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+ def setparams(self, params):
+ self.params=params
+ self.out_dir = self.params["out_dir"]["value"]
+ self.password = self.params["password"]["value"]
+ self.sdcard_file = self.params["sdcard_file"]["value"]
+ self.mnt_dest = self.params["mnt_dest"]["value"]
+ self.source_dir = self.params["source_dir"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def getkeybin(self,file):
+
+ """
+ Redifine the function here to decrypt the edk_p_sd file with tha password.
+ """
+
+ edk=footer2binkey(file, self.password)
+ binkey="\x04"+"\0"*11+"\x20"+"\0"*627+"\x20"+"\0"*3+"\x02"+"\0"*3+edk+"\0"*32+hexlify(edk[0:8])+"\0"*12
+ return binkey
+
+ def mountsdcardfrompwd(self, source_dir, sdcard_file, password, mnt_dest):
+ self.password=password
+ return self.mountsdcardfromkey(source_dir, sdcard_file, mnt_dest)
+
+
+ def do(self):
+ return self.mountsdcardfrompwd("%s/%s" % (self.out_dir,self.source_dir), "%s/%s" % (self.out_dir, self.sdcard_file), self.password, self.mnt_dest)
+
+ #def do(self):
+ # return self.mountddfrompwd("%s/%s" % (self.out_dir, self.image_file), self.password, self.mnt_dest)
+
View
1  modules/sands4getedk/__init__.py
@@ -0,0 +1 @@
+import printer
View
287 modules/sands4getedk/sands4getedk.py
@@ -0,0 +1,287 @@
+from adb.adb import ADB
+import re
+import sys
+import string
+import printer
+import ConfigParser
+from collections import namedtuple
+from binascii import *
+from sandutils import *
+import os
+import subprocess
+import shlex
+import threading
+import pexpect
+
+
+class SandS4GetEDK:
+
+
+ def __init__(self, printer, config, project, adb_path="adb"):
+ self.printer=printer
+ self.config=config
+ self.project=project
+ self.params={"adbpath":{"description":"Path of the adb command",
+ "value":adb_path,
+ "required":True
+ },
+ "phonewithos":{"description":"The samsung hardware and the android version",
+ "value":"GT-I9505 4.3.2",
+ "required":True
+ },
+ "out_dir":{"description":"Where to generate the results and download files on the computer.",
+ "value":"results",
+ "required":True
+ },
+ }
+ self.setparams(self.params)
+
+ def setparams(self, params):
+ self.params=params
+ self.adb = ADB(self.params["adbpath"]["value"])
+ self.phone = self.params["phonewithos"]["value"]
+ self.out_dir = self.params["out_dir"]["value"]
+
+ def getparams(self):
+ return self.params
+
+ def downloadforgdb(self,fullpath):
+
+ """
+ Downloads the fullpath for gdb. It puts the file in lib or in bin,
+ Depends on the fullpath is a lib directory or not.
+ """
+
+ path, filename = os.path.split(fullpath)
+ if(path.find("lib")!=-1):
+ out=self.adb.get_remote_file(fullpath, "recovery/s4/system/lib/%s" % (filename))
+ else:
+ out=self.adb.get_remote_file(fullpath, "recovery/s4/system/bin/%s" % (filename))
+ return out
+
+ def write2john(self,edk):
+
+ """
+ Simple save the edk into the prject_sanddek.jtr file to jonh the ripper
+ cracking
+ """
+
+ self.printer.print_info("This will be written to file %s/%s_sanddek.jtr, for jtr:" % (self.out_dir, self.project))
+ self.printer.print_ok("%s_s4:%s" % (self.project, edk))
+ try:
+ f= open("%s/%s_sanddek.jtr" % (self.out_dir, self.project), "a")
+ f.write("%s_s4:%s\n" % (self.project, edk))
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1}: {2}/{3}_sanddek.jtr".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+
+ def write2footer(self,edk):
+
+ """
+ Save the EDK to a footer file. The we can use the mount modules, that
+ uses the password
+ """
+
+ self.printer.print_info("Footer will be created: %s/%s_footer" % (self.out_dir, self.project))
+ footer='\0'*0x84+unhexlify(edk)
+ try:
+ f= open("%s/%s_footer" % (self.out_dir, self.project), "wb")
+ f.write(footer)
+ f.close()
+ except IOError as e:
+ self.printer.print_err("I/O error({0}): {1}: {2}/{3}_footer".format(e.errno, e.strerror, self.out_dir, self.project))
+ return -1
+
+ def cleanup(self, gdb=None, gdbserver=None):
+
+ """
+ Tries to gently stop gdb, kill gdbserver and delete it from /data/local/tmp or /tmp
+ """