├── .gitignore ├── Makefile ├── README.md └── src ├── console.h ├── macpwdpwn.c ├── macpwdpwn.h ├── plist.c ├── plist.h ├── res.h ├── strutils.c ├── strutils.h ├── util.c └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | macpwdpwn 3 | _* 4 | .vscode -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #Build script for macpwdpwn 2 | 3 | CC=gcc 4 | CCPARAMS=-Wall 5 | 6 | default: macpwdpwn 7 | 8 | check: 9 | $(shell [ ! -e obj ] && mkdir obj) 10 | 11 | clean: 12 | $(shell echo Cleaning up...) 13 | $(shell rm -rf obj) 14 | 15 | macpwdpwn: check plist.o util.o strutils.o macpwdpwn.o 16 | $(CC) obj/plist.o obj/util.o obj/strutils.o obj/macpwdpwn.o $(CCPARAMS) -o macpwdpwn 17 | 18 | macpwdpwn.o: src/macpwdpwn.h 19 | $(CC) -c src/macpwdpwn.c -o obj/macpwdpwn.o 20 | 21 | strutils.o: src/strutils.h 22 | $(CC) -c src/strutils.c -o obj/strutils.o 23 | 24 | util.o: src/util.h 25 | $(CC) -c src/util.c -o obj/util.o 26 | 27 | plist.o: src/plist.h 28 | $(CC) -c src/plist.c -o obj/plist.o -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # macpwdpwn 2 | 3 | Copyright (C) rlacd 2019 - 2021. 4 | 5 | macOS Account Unlocking Tool for Mojave and up. 6 | 7 | ## Important Notice 8 | 9 | Please note that this tool may only be used for personal use; it is 100% illegal to unlock accounts on machines that you do not own (this includes college owned laptops and whatnot). 10 | 11 | The author of this software is not responsible from any damage caused from this tool, proceed at your own risk! 12 | 13 | The tool is currently in beta stage and is unfinished. Once again, proceed at your own risk. 14 | 15 | ## What is it? 16 | 17 | macpwdpwn is a command line tool which will allow you to unlock password protected accounts on your local Mac machine (even T2 secured Macs). This is very useful if you have forgotten the password to your own user account. 18 | 19 | Please note that this tool will not attempt to extract/crack user passwords. 20 | 21 | ## How do I use it? 22 | 23 | To use the tool, download the latest binary release (from the Releases tab) or compile from source (requires XCode command line tools). Once finished, copy the binary file to a USB flash drive. 24 | 25 | Once the binary has been copied, reboot your mac into recovery mode by pressing `COMMAND+R` on startup. Once booted, open Terminal and run the program from the flash drive. If the program does not run, use chmod to fix permissions or copy it to a temporary folder on your hard disk. 26 | 27 | From there, follow the instructions displayed by the tool. 28 | 29 | ## Tested Macs 30 | 31 | * MacBook Pro (13-inch, 2017, 2 TB3 ports) with Mojave 10.14.1 32 | 33 | ## Known Issues 34 | 35 | * On Macs with T2 and startup security, if an administrator password is modified, it will not change the startup password (your old password will still be required). 36 | 37 | ## Reporting Bugs 38 | 39 | Simply open an issue on GitHub. 40 | 41 | ## Planned Features 42 | 43 | * Option to reverse unlock from backup. 44 | * General code fixes 45 | 46 | ## License 47 | 48 | Licensed under GNU GPLv3. 49 | -------------------------------------------------------------------------------- /src/console.h: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #ifndef __CONSOLE_H 9 | #define __CONSOLE_H 10 | 11 | /* 12 | Console ANSI Codes Definitions for styling 13 | A = ANSI, CL = COLOR, FN = FUNCTION, BG = BACKGROUND, FG = FOREGROUND, CT = CONTROL 14 | */ 15 | 16 | //Foreground colors (Basic 8 color set) 17 | 18 | #define ACL_FG_BLACK "\x1b[30m" 19 | #define ACL_FG_RED "\x1b[31m" 20 | #define ACL_FG_GREEN "\x1b[32m" 21 | #define ACL_FG_YELLOW "\x1b[33m" 22 | #define ACL_FG_BLUE "\x1b[34m" 23 | #define ACL_FG_MAGENTA "\x1b[35m" 24 | #define ACL_FG_CYAN "\x1b[36m" 25 | #define ACL_FG_WHITE "\x1b[37m" 26 | 27 | //Background colors (Also 8 colors) 28 | 29 | #define ACL_BG_BLACK "\x1b[40m" 30 | #define ACL_BG_RED "\x1b[41m" 31 | #define ACL_BG_GREEN "\x1b[42m" 32 | #define ACL_BG_YELLOW "\x1b[43m" 33 | #define ACL_BG_BLUE "\x1b[44m" 34 | #define ACL_BG_MAGENTA "\x1b[45m" 35 | #define ACL_BG_CYAN "\x1b[46m" 36 | #define ACL_BG_WHITE "\x1b[47m" 37 | 38 | //Color Modifiers 39 | 40 | #define ACL_MD_BRIGHT ";1m" 41 | 42 | //Decorations 43 | #define ACL_DC_BOLD "\x1b[1m" 44 | #define ACL_DC_UNDL "\x1b[4m" 45 | #define ACL_DC_REV "\x1b[7m" 46 | 47 | //Reset style 48 | 49 | #define ACT_RESET "\x1b[0m" 50 | 51 | /* Additional ANSI Codes/Function Macros */ 52 | 53 | #define ACT_FN_CUR_UP(x) "\x1b[#xA" 54 | #define ACT_FN_CUR_DOWN(x) "\x1b[#xB" 55 | #define ACT_FN_CUR_RIGHT(x) "\x1b[#xC" 56 | #define ACT_FN_CUR_LEFT(x) "\x1b[#xD" 57 | 58 | 59 | #endif -------------------------------------------------------------------------------- /src/macpwdpwn.c: -------------------------------------------------------------------------------- 1 | /* 2 | MACPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019-2020. 6 | Licensed under GNU GPL v3. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "util.h" 15 | #include "macpwdpwn.h" 16 | #include "strutils.h" 17 | #include "res.h" 18 | #include "console.h" 19 | #include "plist.h" 20 | 21 | int main(int argc, char* argv[]) { //TODO add command line arguments 22 | if(argc > 1) { //User supplied arguments, check it 23 | if(strcmp(argv[1], "help") == 0) { 24 | fprintf(stdout, "\033[1;36mmacpwdpwn version 1.0. Copyright (C) r3vl0d (R3V) 2020.\033[0m\nGeneral Usage: macpwdpwn [command] [options]\n\n\033[33mCommands:\033[0m\n help - View this help page.\n\n"); 25 | return 0; 26 | } else { 27 | fprintf(stderr, "%s", "\033[0;31mInvalid argument: rerun mpwdpwn with `help` for help.\033[0m\n"); 28 | return 1; 29 | } 30 | } 31 | 32 | //Display copyrights and APP_LOGO 33 | 34 | fprintf(stdout, "\033[0;35m%s\033[0m", APP_LOGO); 35 | fprintf(stdout, "%s", "\033[1;36mmacpwdpwn version 1.0. Copyright (C) r3vl0d (R3V) 2020.\033[0m\n\n"); 36 | 37 | //Check if root access is available 38 | 39 | if(geteuid() != 0) { 40 | fprintf(stderr, "%s", "\033[0;31mError: Missing permissions, rerun as root.\033[0m\n"); 41 | return 1; 42 | } 43 | 44 | //Look through /Volumes for volumes to use 45 | 46 | fprintf(stdout, "%s", "Scanning volumes...\n"); 47 | struct dirent *dEntry; 48 | DIR *vDir = opendir("/Volumes"); 49 | if(vDir == NULL) { 50 | fprintf(stderr, "%s", "\033[0;31mError: /Volumes directory does not exist, is this a Mac or is the file system corrupt?\033[0m\n"); 51 | return 1; 52 | } 53 | 54 | //Prompt user for volume name 55 | fprintf(stdout, "\033[0;33mPlease enter the name of a system volume from which you want to unlock an account from.\033[0m\nAvailable Volumes are:\n"); 56 | while((dEntry = readdir(vDir)) != NULL) { 57 | if(strncmp(dEntry->d_name, "..", strlen(dEntry->d_name)) == 0) continue; 58 | else if(strncmp(dEntry->d_name, ".", strlen(dEntry->d_name)) == 0) continue; 59 | else fprintf(stdout, " %s\n", dEntry->d_name); 60 | } 61 | 62 | fprintf(stdout, "\n"); 63 | closedir(vDir); 64 | PTARGET * target = malloc(sizeof(PTARGET)); 65 | int validVolumeDetected = -1; 66 | while(validVolumeDetected != 0) { //Perform checks whether specified volume is valid 67 | fprintf(stdout, "%s ", ">"); 68 | fgets(target->volumeName, sizeof(target->volumeName), stdin); 69 | strtok(target->volumeName, "\n"); // Remove trailing new line 70 | if(string_empty(target->volumeName) == 0) { 71 | fprintf(stderr, "%s", "\033[0;31mError: Volume name cannot be empty!\033[0m\n"); 72 | continue; 73 | } 74 | char fullPath[256]; 75 | strcpy(fullPath, "/Volumes/"); 76 | strncat(fullPath, target->volumeName, 9 + strlen(target->volumeName)); 77 | fprintf(stdout, "Selecting volume %s...\n", fullPath); 78 | strcpy(target->volumePath, fullPath); 79 | if(dir_exists(fullPath) != 0) { 80 | fprintf(stderr, "%s", "\033[0;31mError: Volume does not exist!\033[0m\n"); 81 | continue; 82 | } 83 | validVolumeDetected = 0; 84 | } 85 | 86 | //Go though all user plists in database and prompt user for username 87 | 88 | char userDirPath[256]; 89 | char dbPathInFS[256]; 90 | strcpy(dbPathInFS, "/var/db/dslocal/nodes/Default/users"); 91 | strcpy(userDirPath, target->volumePath); 92 | strncat(userDirPath, dbPathInFS, strlen(dbPathInFS) + strlen(userDirPath)); 93 | fprintf(stdout, "Checking %s for user plists...\n", userDirPath); 94 | struct dirent * pluEntry; 95 | DIR * pluDir = opendir(userDirPath); 96 | 97 | if(pluDir == NULL) { 98 | fprintf(stderr, "%s", "\033[0;31mError: User database is corrupt, inaccessible, or this is not a valid volume.\033[0m\n"); 99 | return 1; 100 | } 101 | 102 | fprintf(stdout, "\033[0;33mEnter the name of the user account you would like to unlock:\033[0m\nAvailable Users:\n"); 103 | 104 | while((pluEntry = readdir(pluDir)) != NULL) { 105 | if(strncmp(pluEntry->d_name, "..", strlen(pluEntry->d_name)) == 0) continue; 106 | else if(strncmp(pluEntry->d_name, ".", strlen(pluEntry->d_name)) == 0) continue; 107 | else if(pluEntry->d_name[0] == '_') continue; //These are hidden users, do not list them. 108 | else { 109 | char username[128]; 110 | strcpy(username, pluEntry->d_name); 111 | strtok(username, "."); 112 | fprintf(stdout, " %s\n", username); 113 | } 114 | } 115 | 116 | fprintf(stdout, "\n"); 117 | closedir(pluDir); 118 | 119 | // Prompt the user for a user name now 120 | 121 | int validUserSelected = -1; 122 | while(validUserSelected != 0) { 123 | fprintf(stdout, "%s ", ">"); 124 | fgets(target->userName, sizeof(target->userName), stdin); 125 | strtok(target->userName, "\n"); // Remove trailing new line 126 | if(string_empty(target->userName) == 0) { 127 | fprintf(stderr, "%s", "\033[0;31mError: User name cannot be empty!\033[0m\n"); 128 | continue; 129 | } 130 | char userPlistPath[256]; 131 | strcpy(userPlistPath, userDirPath); 132 | strncat(userPlistPath, "/", 1); 133 | char userPlistFileName[128]; 134 | strcpy(userPlistFileName, target->userName); 135 | strncat(userPlistFileName, ".plist", strlen(target->userName) + 6); 136 | strncat(userPlistPath, userPlistFileName, strlen(userPlistPath) + strlen(userPlistFileName)); 137 | if(access(userPlistPath, F_OK) == -1) { 138 | fprintf(stderr, "\033[0;31mError: User \"%s\" does not exist!\033[0m\n", target->userName); 139 | continue; 140 | } 141 | fprintf(stdout, "Found plist %s\n", userPlistPath); 142 | strcpy(target->userPlist, userPlistPath); 143 | validUserSelected = 0; 144 | } 145 | 146 | // Ask user to confirm changes 147 | 148 | fprintf(stdout, "\n\033[0;33mPlease review the following to check if it is correct.\033[0m\n\033[0;31m>> WARNING: This is a potentially destructive action if not performed correctly! <<\033[0m\n[Summary]\n"); 149 | fprintf(stdout, " Target Volume: %s\n Target User: %s\n\n", target->volumeName, target->userName); 150 | fprintf(stdout, "Are you sure you want to continue? [y/N]: "); 151 | if(prompt_confirm('N') == -1) { 152 | fprintf(stderr, "\033[0;31mUser abort operation, exiting...\033[0m\n"); 153 | return 1; 154 | } 155 | 156 | //Backup user file just in case something goes wrong - (if at any point the program fails, it will restore from backup) 157 | 158 | fprintf(stdout, "\nBacking up user file...\n"); 159 | char backupPath[256]; 160 | strcpy(backupPath, target->volumePath); 161 | strncat(backupPath, "/var/mpwd_backup.plist", strlen(target->volumePath) + strlen(backupPath)); 162 | if(fcopy_bin(target->userPlist, backupPath) != 0) { 163 | fprintf(stderr, "\033[0;31mError: Failed to create file \"%s\"\033[0m\n", backupPath); 164 | return 1; 165 | } else fprintf(stdout, "Created user plist backup at %s\n", backupPath); 166 | 167 | //Create temporary copy of user plist for editing 168 | 169 | char tempPlistPath[256]; 170 | strcpy(tempPlistPath, target->volumePath); 171 | strncat(tempPlistPath, "/Temp.plist", strlen(target->volumePath) + strlen(tempPlistPath)); 172 | if(fcopy_bin(target->userPlist, tempPlistPath) != 0) { 173 | fprintf(stderr, "\033[0;31mError: Failed to create file \"%s\"\033[0m\n", tempPlistPath); 174 | return 1; 175 | } else fprintf(stdout, "Created temporary plist for editing at %s\n", tempPlistPath); 176 | 177 | //Convert bplist to user readable XML 178 | 179 | fprintf(stdout, "Converting user plist into format \"%s\"...\n", PLIST_FORMAT_XML); 180 | if(plist_convert(tempPlistPath, PLIST_FORMAT_XML) != 0) { 181 | fprintf(stderr, "\033[0;31mError: Could not convert user plist into appropriate format.\033[0m\n"); 182 | return 1; 183 | } else fprintf(stdout, "Conversion successful!\n"); 184 | 185 | //Read the plist and insert the new ShadowHashData 186 | 187 | fprintf(stdout, "Modifying ShadowHashData...\n"); 188 | if(plist_replace_xml(tempPlistPath, "ShadowHashData", "") != 0) { 189 | fprintf(stderr, "\033[0;31mError: Could not replace ShadowHashData with empty array!\033[0m\n"); 190 | return 1; 191 | } 192 | 193 | if(plist_insert(tempPlistPath, "ShadowHashData.0", PLIST_DTYPE_DATAB64, SHADOW_HASH_DATA_UNLOCK) != 0) { 194 | fprintf(stderr, "\033[0;31mError: Failed to update ShadowHashData with new password!\033[0m\n"); 195 | return 1; 196 | } 197 | fprintf(stdout, "Successfully injected new password into ShadowHashData!\n"); 198 | 199 | //ShadowHashData has been modified, now copy back the plist and let the user know their new password is 12345 200 | 201 | fprintf(stdout, "Reformatting plist to binary...\n"); 202 | if(plist_convert(tempPlistPath, PLIST_FORMAT_BINARY) != 0) { 203 | fprintf(stderr, "\033[0;31mError: Could not convert user plist into appropriate format.\033[0m\n"); 204 | return 1; 205 | } else fprintf(stdout, "Plist succesfully converted to binary!\n"); 206 | 207 | fprintf(stdout, "Copying back user plist...\n"); 208 | if(fcopy_bin(tempPlistPath, target->userPlist) != 0) { 209 | fprintf(stderr, "\033[0;31mError: Failed to create file \"%s\"\033[0m\n", tempPlistPath); 210 | return 1; 211 | } else fprintf(stdout, "Plist successfully copied back! A backup of the old plist is kept at VolumeRoot/var/mpwd_backup.plist\n"); 212 | 213 | fprintf(stdout, "Deleting temporary file...\n"); 214 | int status = remove(tempPlistPath); 215 | if(status != 0) { 216 | fprintf(stderr, "\033[0;31mError NON FATAL: Could not delete file \"%s\"! Could the file be in use?\033[0m\n", tempPlistPath); 217 | } 218 | 219 | fprintf(stdout, "\n\nThe account unlocking procedure has completed successfully!\nTo log in, reboot your Mac and enter password '12345' as password for the specified account.\n\nNote: Please change your password as soon as possible to avoid glitches!\n"); 220 | return 0; 221 | } -------------------------------------------------------------------------------- /src/macpwdpwn.h: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #ifndef __MPWDPWN_H 9 | #define __MPWDPWN_H 10 | 11 | // A structure defining a target for account unlock 12 | typedef struct PTARGET { 13 | char volumeName[256]; 14 | char volumePath[256]; 15 | char userName[128]; 16 | char userPlist[256]; 17 | } PTARGET; 18 | 19 | #endif -------------------------------------------------------------------------------- /src/plist.c: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #include 9 | #include 10 | #include "plist.h" 11 | 12 | int plist_convert(const char* path, const char* format) { 13 | char command[256]; 14 | sprintf(command, "plutil -convert %s \"%s\"", format, path); 15 | return system(command); 16 | } 17 | 18 | int plist_replace_xml(const char* path, const char* k, const char* xmlData) { 19 | char command[256]; 20 | sprintf(command, "plutil -replace %s -xml \"%s\" \"%s\"", k, xmlData, path); 21 | return system(command); 22 | } 23 | 24 | int plist_insert(const char* path, const char* k, const char* type, const char* data) { 25 | char command[1536]; 26 | sprintf(command, "plutil -insert %s -%s \"%s\" \"%s\"", k, type, data, path); 27 | return system(command); 28 | } -------------------------------------------------------------------------------- /src/plist.h: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #ifndef __PLIST_H 9 | #define __PLIST_H 10 | 11 | #define PLIST_DTYPE_STRING "string" 12 | #define PLIST_DTYPE_DATAB64 "data" 13 | #define PLIST_DTYPE_JSON "json" 14 | #define PLIST_FORMAT_XML "xml1" 15 | #define PLIST_FORMAT_BINARY "binary1" 16 | 17 | int plist_convert(const char* path, const char* format); 18 | int plist_replace_xml(const char* path, const char* k, const char* xmlData); 19 | int plist_insert(const char* path, const char* k, const char* type, const char* data); 20 | 21 | #endif -------------------------------------------------------------------------------- /src/res.h: -------------------------------------------------------------------------------- 1 | /* 2 | MACPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #define APP_LOGO " .___ \n _____ _____ ____ ________ _ ____| _/_______ _ ______ \n / \\\\__ \\ _/ ___\\\\____ \\ \\/ \\/ / __ |\\____ \\ \\/ \\/ / \\ \n| Y Y \\/ __ \\\\ \\___| |_> > / /_/ || |_> > / | \\\n|__|_| (____ /\\___ > __/ \\/\\_/\\____ || __/ \\/\\_/|___| /\n \\/ \\/ \\/|__| \\/|__| \\/ \n" 9 | #define SHADOW_HASH_DATA_UNLOCK "YnBsaXN0MDDSAQIDCl8QHlNSUC1SRkM1MDU0LTQwOTYtU0hBNTEyLVBCS0RGMl8QFFNBTFRFRC1TSEE1MTItUEJLREYy0wQFBgcICVh2ZXJpZmllclRzYWx0Wml0ZXJhdGlvbnNPEQIAIC5DcM0gFwwJgFKDpreW3wIbsH19H4aYnsNpAhyuJSFmOmaxK/WZxvVk+vDQu4SXgf/V5vstxRDvE3c4fGBKw3nUlqvq7dmh6d6HeuHwSn61A35s54flSxLZHaBT6dCVtzihnGcLtnzKMLeorBZvs8DDeZWoSoN8IbMg2GyR5+dia6gHD0BjAElRlW/3ua0YSU+WWBQ3KpoaoL2Onu2SnWGhqOCdVdzT7mgvvVxWX8+TS/J2bAaow5/L+g8UHjfvZm52EmjDAD4FaWbU04pmtuLLjnjL8qkJbGr9p5ySWXD+lDhYsUpTujD3ZS0qVavVQGJOd7fdIGPlcgZD1++bdWVC/lZnt6R6J32NhJIuCF2ZCd9O1RMqtIIsQdU1fdfW+UB4fi8wboBJGa7N+xuxiWtJjIPaau42GQglqX28RNmJbCcEbP+36X1iYU43COMD3ewPOz0mEF7OzDg0KuyxM8RL9+Kgt62Kfr4edk0g5oS+W1i2yfA8i3jMwHPhP+M18wpPtNRS+/fI+wJrzsExMzNzLtDEHSC42xpteIsHTDS8o2UGtAp/dtbbHgwsSo5ydiq5AZtxhSKLEUtnF3c1zZjEDm/clHGaHzc1PkSskRNaKwSCnrYFI/AP2VTChoNqEx2MGby3DNISqxV0C/JfAEj6fVFayCpu9WMy4k5Gl+hPECBzdLDjMwXrul5rsM0HzYwV8dhjfesDRcvevXYJQOJRwhHBYNMLBQYMDQ5XZW50cm9weU8QgIPpxn0yBKbKwdXs8X7QDyJg1xLtXSp0MgKpGxx9fLdth5ZP5tWcF36xZvzjXKqitrUTHt0LJJyujoK0gWQWi2diUwA2GJ+7Fl0rA9U0N1/OxhXd++2H+To301qkxrPsCYQR8Lj9GVteWjmwMP9erqTdi8KJ84XjVO7JlB64XqncTxAgL0/uvrOA5xxDzx1JIxgD3MVLtPkmyibWVKcGCQIzn7QRrNcACAANAC4ARQBMAFUAWgBlAmkCjAKPApYCngMhA0QAAAAAAAACAQAAAAAAAAAPAAAAAAAAAAAAAAAAAAADRw==" //Default pwd 12345 10 | -------------------------------------------------------------------------------- /src/strutils.c: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) rlacd 2021. All rights reserved. 6 | */ 7 | 8 | #include "strutils.h" 9 | 10 | int string_empty(const char* input) { 11 | for(int i=0; input[i]!='\0'; i++) 12 | if((input[i] != ' ') && (input[i] != '\n') && (input[i] != '\r') && (input[i] != '\0')) 13 | return -1; 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/strutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #ifndef __STRUTILS_H 9 | #define __STRUTILS_H 10 | 11 | int string_empty(const char* input); 12 | 13 | #endif -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #include "util.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #define FCOPY_BIN_BUFSZ 2048 14 | 15 | int dir_exists(const char* path) { 16 | struct stat st; 17 | if(stat(path,&st) == 0 && S_ISDIR(st.st_mode)) 18 | return 0; 19 | else return 1; 20 | } 21 | 22 | int prompt_confirm(char defChar) { 23 | char response; 24 | char input[2]; 25 | do { 26 | fgets(input, sizeof(1), stdin); 27 | response = input[0]; 28 | if(response == '\n') response = defChar; 29 | if((response == 'N') || (response == 'n')) return -1; 30 | else if((response == 'Y') || (response == 'y')) return 0; 31 | else { 32 | fprintf(stdout, "\033[0;31mError: Selected choice is not valid, try again.\033[0m\n"); 33 | continue; 34 | } 35 | } while((response != 'Y') || (response != 'y')); 36 | return 0; 37 | } 38 | 39 | int fcopy_bin(const char* src, const char* dest) { 40 | char buff[FCOPY_BIN_BUFSZ]; 41 | FILE *in, *out; 42 | size_t n; 43 | in = fopen(src, "rb"); 44 | if(in == NULL) return -1; 45 | out = fopen(dest, "wb"); 46 | if(out == NULL) return -1; 47 | while ((n=fread(buff,1,BUFSIZ,in)) != 0) 48 | fwrite(buff, 1, n, out); 49 | fclose(in); 50 | fclose(out); 51 | return 0; 52 | } -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | MPWDPWN (Mac Password Pwn) Account Unlocking Tool 3 | For Mojave and above. 4 | 5 | Copyright (C) techspider 2019. All rights reserved. 6 | */ 7 | 8 | #ifndef __UTIL_H 9 | #define __UTIL_H 10 | 11 | int dir_exists(const char* path); 12 | int prompt_confirm(char defChar); 13 | int fcopy_bin(const char* src, const char* dest); 14 | int plist_convert(const char* path, const char* format); 15 | 16 | #endif --------------------------------------------------------------------------------