├── Makefile ├── INSTALL.txt ├── cpnt.c ├── hash.c ├── syskey.txt ├── README.txt ├── reged.c ├── sampasswd.c ├── samusrgrp.c ├── sam.h ├── regedit.txt ├── HISTORY.txt ├── GPL.txt ├── COPYING.txt ├── MANUAL.txt ├── ntreg.h ├── edlib.c └── WinReg.txt /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for the Offline NT Password Editor 3 | # 4 | # 5 | # Change here to point to the needed OpenSSL libraries & .h files 6 | # See INSTALL for more info. 7 | # 8 | 9 | #SSLPATH=/usr/local/ssl 10 | OSSLPATH=/usr 11 | OSSLINC=$(OSSLPATH)/include 12 | 13 | CC=gcc 14 | 15 | # Force 32 bit 16 | CFLAGS= -DUSEOPENSSL -g -I. -I$(OSSLINC) -Wall -m32 17 | OSSLLIB=$(OSSLPATH)/lib 18 | 19 | # 64 bit if default for compiler setup 20 | #CFLAGS= -DUSEOPENSSL -g -I. -I$(OSSLINC) -Wall 21 | #OSSLLIB=$(OSSLPATH)/lib64 22 | 23 | 24 | # This is to link with whatever we have, SSL crypto lib we put in static 25 | #LIBS=-L$(OSSLLIB) $(OSSLLIB)/libcrypto.a 26 | LIBS=-L$(OSSLLIB) 27 | 28 | 29 | all: chntpw chntpw.static cpnt reged reged.static samusrgrp samusrgrp.static sampasswd sampasswd.static 30 | 31 | chntpw: chntpw.o ntreg.o edlib.o libsam.o 32 | $(CC) $(CFLAGS) -o chntpw chntpw.o ntreg.o edlib.o libsam.o $(LIBS) 33 | 34 | chntpw.static: chntpw.o ntreg.o edlib.o libsam.o 35 | $(CC) -static $(CFLAGS) -o chntpw.static chntpw.o ntreg.o edlib.o libsam.o $(LIBS) 36 | 37 | cpnt: cpnt.o 38 | $(CC) $(CFLAGS) -o cpnt cpnt.o $(LIBS) 39 | 40 | reged: reged.o ntreg.o edlib.o 41 | $(CC) $(CFLAGS) -o reged reged.o ntreg.o edlib.o 42 | 43 | reged.static: reged.o ntreg.o edlib.o 44 | $(CC) -static $(CFLAGS) -o reged.static reged.o ntreg.o edlib.o 45 | 46 | samusrgrp.static: samusrgrp.o ntreg.o libsam.o 47 | $(CC) -static $(CFLAGS) -o samusrgrp.static samusrgrp.o ntreg.o libsam.o 48 | 49 | samusrgrp: samusrgrp.o ntreg.o libsam.o 50 | $(CC) $(CFLAGS) -o samusrgrp samusrgrp.o ntreg.o libsam.o 51 | 52 | sampasswd: sampasswd.o ntreg.o libsam.o 53 | $(CC) $(CFLAGS) -o sampasswd sampasswd.o ntreg.o libsam.o 54 | 55 | sampasswd.static: sampasswd.o ntreg.o libsam.o 56 | $(CC) -static $(CFLAGS) -o sampasswd.static sampasswd.o ntreg.o libsam.o 57 | 58 | 59 | 60 | #ts: ts.o ntreg.o 61 | # $(CC) $(CFLAGS) -nostdlib -o ts ts.o ntreg.o $(LIBS) 62 | 63 | # -Wl,-t 64 | 65 | .c.o: 66 | $(CC) -c $(CFLAGS) $< 67 | 68 | clean: 69 | rm -f *.o chntpw chntpw.static cpnt reged reged.static samusrgrp samusrgrp.static sampasswd sampasswd.static *~ 70 | 71 | -------------------------------------------------------------------------------- /INSTALL.txt: -------------------------------------------------------------------------------- 1 | 2 | The Offline NT Password & Registry Editor 3 | 4 | (c) 1997-2014 Petter Nordahl-Hagen 5 | 6 | This file is meant for developers. 7 | 8 | General usage is via the provided boot CD images, but 9 | static 32 bit linux builds of the tools are also available 10 | in the "static" zip file available on my website. 11 | 12 | See REAMDE for general instructions and license info, 13 | HISTORY.txt for version info. 14 | 15 | If you want to build yourself, it should compile 16 | with most gcc compilers. However, I am not particulary good 17 | with types, so there may be some warnings. 18 | 19 | Unlike earlier, crypto stuff is not compiled in by default any more, 20 | but that only disables function to set new specific password, 21 | which does not seem to work well on newer Windows anyway. 22 | 23 | However, you can enable it in the Makefile, if so 24 | you may have to install the openssl-devel package from you 25 | linux distro to compile/link, since I need the static variant. 26 | (change the makefile to link dynamic if you wish) 27 | I link statically with libcrypto.a from OpenSSL. 28 | (chntpw only, other tools does not require crypto) 29 | 30 | Thanks to Denis Ducamp for modifying chntpw to use OpenSSL. 31 | 32 | Thanks to Mike Doty, via Alon Bar-Lev for 64 bit build compatible patch. 33 | (from http://bugs.gentoo.org/show_bug.cgi?id=185411) 34 | which I may or may not have broken again i 2013... 35 | 36 | Look into Makefile, you may need to change things to fit your env. 37 | also if you need 64 bit. 38 | Warning: I mostly build on 32-bit and may not have tested on 64 bit 39 | in every version! (32-bit binaries run fine on 64-bit systems anyway, 40 | and it does not matter if Windows it edits registry from is 32- or 64-bit) 41 | 42 | If make goes well, you should have: 43 | chntpw - interactive password tool 44 | chntpw.static - Completely static passord tool 45 | reged - Registry edit tool, dynamic linked with libc. No crypto. 46 | reged.static - Registry tool, statically linked. 47 | sampasswd - user list and password reset commandline util 48 | sampasswd.static - same but statically linked 49 | samusrgrp - group list and group membership tool 50 | samusrgrp.static - static version of same 51 | cpnt - Simple copy utility, does not truncate file on write 52 | Now deprecated, was at least needed earlier for NTFS writes. 53 | 54 | Also, the floppies and CDs are build under a different 55 | environment for small libc size (uClibc), see website 56 | for details. (build scripts not currently available..) 57 | 58 | Good luck. 59 | -------------------------------------------------------------------------------- /cpnt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cpnt.c - Copy over file without truncating. 3 | * For use on my current floppy, since it's 'cp' insist 4 | * on truncating first, and NTFS doesn't like that yet. 5 | * 6 | * 2003-apr: First version 7 | * 8 | ***** 9 | * 10 | * Copyright (c) 1997-2007 Petter Nordahl-Hagen. 11 | * 12 | * This program is free software; you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation; version 2 of the License. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * See file GPL.txt for the full license. 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | #define BUFSIZE 16384 37 | 38 | int main(int argc, char **argv) 39 | { 40 | 41 | void *buf; 42 | int sf,df,rb,wb; 43 | int going = 1; 44 | int e = 0; 45 | 46 | if (argc != 3) { 47 | printf("usage: cpnt \n"); 48 | printf(" sorry, only one file at a time yet.\n"); 49 | return(1); 50 | } 51 | 52 | #if 0 53 | printf("input : %s\n",argv[1]); 54 | printf("output: %s\n",argv[2]); 55 | #endif 56 | 57 | buf = malloc(BUFSIZE); 58 | if (!buf) { 59 | printf("cpnt: could not allocate buffer\n"); 60 | return(1); 61 | } 62 | 63 | sf = open(argv[1],O_RDONLY); 64 | if (sf < 0) { 65 | e = errno; 66 | printf("cpnt: %s: %s\n",argv[1],strerror(e)); 67 | return(1); 68 | } 69 | 70 | df = open(argv[2],O_WRONLY|O_CREAT,00666); 71 | if (df < 0) { 72 | e = errno; 73 | printf("cpnt: %s: %s\n",argv[2],strerror(e)); 74 | return(1); 75 | } 76 | 77 | while (going) { 78 | rb = read(sf,buf,BUFSIZE); 79 | if (rb < 0) { 80 | e = errno; 81 | printf("cpnt: error while reading: %s\n",strerror(e)); 82 | going = 0; 83 | break; 84 | } 85 | if (rb == 0) going = 0; 86 | wb = write(df,buf,rb); 87 | if (wb < 0) { 88 | e = errno; 89 | printf("cpnt: error while writing: %s\n",strerror(e)); 90 | going = 0; 91 | } 92 | 93 | } 94 | 95 | close(sf); 96 | close(df); 97 | free(buf); 98 | 99 | return(e ? 1 : 0); 100 | } 101 | -------------------------------------------------------------------------------- /hash.c: -------------------------------------------------------------------------------- 1 | /* Mickeysoft hashroutine in XP 'lh' key index lists */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | static const unsigned char charset2upper[] = { 9 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ 10 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ 11 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ 12 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ 13 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ 14 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ 15 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ 16 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ 17 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ 18 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ 19 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ 20 | 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ 21 | 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ 22 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ 23 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ 24 | 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ 25 | 26 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ 27 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ 28 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ 29 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ 30 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ 31 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ 32 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ 33 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ 34 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ 35 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ 36 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ 37 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ 38 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ 39 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ 40 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ 41 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xf8-0xff */ 42 | }; 43 | 44 | 45 | 46 | 47 | int main(void) 48 | { 49 | 50 | char str[500]; 51 | long hash = 0; 52 | int i; 53 | FILE *f; 54 | 55 | f = fdopen(0,"r"); 56 | 57 | fgets(str, 499, f); 58 | 59 | str[strlen(str)-1] = 0; 60 | 61 | for (i = 0; i < strlen(str); i++) { 62 | hash *= 37; 63 | hash += charset2upper[(unsigned char)str[i]]; 64 | } 65 | printf("hash = %08x\n",hash); 66 | } 67 | -------------------------------------------------------------------------------- /syskey.txt: -------------------------------------------------------------------------------- 1 | The Offline NT Password Editor 2 | 3 | (c) 1997-2002 Petter Nordahl-Hagen 4 | 5 | Update: 08 dec 2002 6 | 7 | What happens when syskey is installed, and how to get rid of it 8 | --------------------------------------------------------------- 9 | 10 | Background: 11 | ----------- 12 | 13 | Syskey was added to NT with Service Pack 3 as a way to prevent easy 14 | access to the actual password hashes in the SAM (Security Accounts Manager) 15 | The original methods of making and storing the hashes makes it 16 | rather easy to bruteforce or dictionary-attack it to find the plaintext 17 | passwords. (mostly caused by a somewhat flawed implementation & use 18 | of the cryptoalgorithms involved, but that's discussed elsewhere) 19 | Enabling syskey is optional, the administrator must run syskey.exe and 20 | answer some dialog-boxes to turn it on. On Windows 2000 it's not optional 21 | anymore, it's enabled by default at installation time. 22 | 23 | When syskey is active, the hashes are encrypted/obfuscated yet 24 | another time before being stored in the SAM registry. 25 | However, they're stored in the old form in memory after boot 26 | (pwdump2 demonstrates this), 27 | since the old form is needed for NTLM authentication on the network etc. 28 | 29 | The key that obfuscates the hashes, or rather it looks like something 30 | that decrypts the key, can be stored on floppy, generated from a 31 | passphrase to be entered at boot, or stored (obfuscated again) in 32 | the registry. 33 | 34 | There's no official supported method to switch off syskey 35 | once activated, except restoring the registry from a rescuefloppy 36 | made before activation of syskey. 37 | 38 | So.. what's this got to do with my utility? 39 | ------------------------------------------- 40 | 41 | My utility doesn't try to crack passwords, it puts new hashes into 42 | the SAM, thus changing a users password. And it does this offline. 43 | Syskey was a showstopper for this. 44 | As far as I can see, there's 2 ways to solve this: 45 | 46 | 1) Find the key in registry, get user to enter it, or get hold of floppy 47 | then use the syskey on the new password too. However, it's not documented 48 | and I haven't found any reverse engineering of it anyplace. 49 | 50 | 2) Try to turn it off. This has one drawback, and one good side: 51 | Bad: all passwords must be reset, since the old hashes will be invalid. 52 | VeryBAD: SWITHCHING OFF IN WINDOWS 2000 AND XP NOT PERFECT, 53 | WILL CAUSE TROUBLE, but you can access the computer 54 | afterwards. Domain relationships & syskey may be 55 | impossible to change after this, requiring a reinstall 56 | (or possibly only an upgrade) 57 | Good: There's no need for the key (which may be lost). 58 | 59 | 3) (NEW 2000-04-01, no, not a joke) Insert old styles password-hashes 60 | into the SAM, will be converted to syskey-hashes on next boot. 61 | This is how syskey is enabled on NT4, the hashes won't be touched 62 | until the first reboot after turning on syskey. 63 | 64 | I've found out how to do #2 and #3. 65 | 66 | What happens when syskey is turned on, and how to turn it off again: 67 | -------------------------------------------------------------------- 68 | 69 | - 1 - 70 | Serveral new keys are added to HKLM\System\CurrentControlSet\Control\Lsa, 71 | it seems that most of the keys/values is used for the obfuscation of the key 72 | they change when syskey is updated. 73 | However the value named 'SecureBoot' holds the mode of syskey: 74 | 1 - Key in registry 75 | 2 - Enter passphrase 76 | 3 - Key on floppy 77 | 78 | But removing this key (or setting it to 0) isn't enough to disable 79 | syskey. There's more.. 80 | 81 | - 2 - 82 | HKLM\SAM\Domains\Account\F is a binary structure usually containing the computer 83 | SID and some other stuff related to that. 84 | When syskey is installed it's expanded (about twice the size), with something 85 | I guess is the key heavily encrypted + some flags and other values. 86 | One of these other flag/values also contains the same mode as SecureBoot above. 87 | 88 | So.. resetting this mode flag and SecureBoot to 0 is all that's needed 89 | to switch off syskey in NT4 (up to SP6 at time of writing). Changing only one of them 90 | results in a warning about inconsistencies between the SAM and system settings 91 | on completed boot, and syskey is re-invoked. 92 | 93 | - 3 - 94 | On Windows 2000 there's yet another place info about syskey is stored: 95 | 96 | HKLM\security\Policy\PolSecretEncryptionKey\ 97 | which also is a binary structure, but also there the mode is stored. 98 | Reset this to 0, and syskey is gone on win2k. 99 | (if there's a mismatch between the three, it silently resets them 100 | to the most likely value on boot) 101 | 102 | - 4 - 103 | Then there's the password hashes. 104 | The usual (old) hashlength is 16 bytes, but all hashes are expanded to 20 bytes 105 | with syskey, the first 4 bytes looks like some kind of counter. (maybe 106 | history-counter?). 107 | Strangely, they're not updated at once when syskey is turned on, 108 | update of the hashes happens during next reboot after syskey has been turned on. 109 | And when the key is later updated, the hashes are also updated? 110 | NO!! Strangely it SEEMS like the password hashes REMAINS THE SAME! 111 | (however, the binaries in the 3 keys noted above changes..) 112 | I'll try to dig more into this. Help wanted :) 113 | 114 | When syskey has been switched off, all passwords must be reset. 115 | My utility will write and adjust hash-lengths of the users (usually 116 | administrator) that you reset the password for. 117 | NT itself will fix the rest of the hashes when you set new passwords 118 | from NT. 119 | 120 | And yes, it's possible to re-enable syskey after turning it off. 121 | (not on win2k, yet!) 122 | 123 | So, anybody reverse engineered the whole syskeystuff? 124 | (yes, I know something's on it's way..) 125 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 2 | The Offline Windows Password Editor 3 | 4 | (c) 1997-2014 Petter Nordahl-Hagen 5 | 6 | This is free software, licensed under the following: 7 | 8 | "ntreg" (the registry library) and 9 | "libsam" (SAM manipulation library, user, groups etc) 10 | is licensed under the GNU Lesser Public License. See LGPL.txt. 11 | 12 | "chntpw" (the password reset / registry editor frontend) 13 | "reged" (registry editor, export and import tool) 14 | "sampasswd" (password reset command line program) 15 | "samusrgrp" (user and group command line program) 16 | is licensed under the GNU General Public License, see GPL.txt. 17 | 18 | 19 | For manual to the different commands, see MANUAL.txt 20 | Also, all have some help built in, just use the -h option. 21 | 22 | See INSTALL.txt for compile instructions. 23 | 24 | 25 | Where to get more info: 26 | ----------------------- 27 | 28 | http://pogostick.net/~pnh/ntpasswd/ 29 | 30 | At that site there's a floppy and a bootable CD that use chntpw to 31 | access the NT/2k/XP/Vista/Win7/Win8 system it is booted on to edit password etc. 32 | The instructions below are for the standalone program itself, not the floppy. 33 | 34 | What does chntpw do? 35 | -------------------- 36 | 37 | This little program will enable you to view some information and 38 | change user passwords, change user/group memberships 39 | in a Windows (NT/XP/Vista/win7/win8) etc SAM userdatabase file. 40 | You do not need to know the old passwords. 41 | However, you need to get at the registry files some way or another yourself. 42 | In addition it contains a simple registry editor with full write support, 43 | and hex-editor which enables you to 44 | fiddle around with bits&bytes in the file as you wish yourself. 45 | 46 | Also have registry import or export 47 | ----------------------------------- 48 | 49 | "reged" is a program that can do import and export of .reg files into 50 | the registry hive (binary) files. Also has an editor, but still 51 | rudimentary text based command line type thing. 52 | 53 | And by popular request 54 | Even have programs that can be used in scripts! 55 | ----------------------------------------------- 56 | "sampasswd" can be used in scripts to get lists 57 | of users or reset passwords automatically 58 | "samusrgrp" can be used in scripts to list or change 59 | memberships in groups automatically. 60 | 61 | 62 | 63 | Why? 64 | ---- 65 | 66 | I often forget passwords. Especially on test installations (that 67 | I just _must_ have some stuff out of half a year later..) 68 | On most unix-based boxes you just boot the thingy off some kind 69 | of rescue bootmedia (cd/floppy etc), and simply edit the 70 | password file. 71 | On Windows however, as far as I know, there is no way except reinstalling 72 | the userdatabase, losing all users except admin. 73 | (ok, some companies let you pay lotsa $$$$$ for some rescue service..) 74 | (ok, from Windows Vista or something you can make a password reset 75 | file, but you have to remember to do that BEFORE you forget your password...) 76 | 77 | How? 78 | ---- 79 | 80 | Currently, this thing only runs under linux, but it may just happen 81 | to compile on other platforms, too. 82 | 83 | So, to set a new adminpassword on your Windows installation you either: 84 | 85 | 1) Take the harddrive and mount it on a linux-box 86 | 87 | or 88 | 89 | 2) Boot a "live" linux CD with full GUI (many available: Ubuntu, 90 | Knoppix and more. Search for them) 91 | 92 | In both those cases, use the "chntpw.static" program found in the 93 | "static" zip file on my website. 94 | or 95 | 96 | 3) Use my linux boot CD (or USB) at: http://pogostick.net/~pnh/ntpasswd/ 97 | 98 | Usage: 99 | ------ 100 | 101 | For manual to the different commands, see MANUAL.txt 102 | Also, all have some help built in, just use the -h option. 103 | 104 | Some old tech babble on how the password is stored 105 | -------------------------------------------------- 106 | (still mostly valid, but should be moved somewhere else than this file) 107 | 108 | 109 | A struct, called the V value of a key in the NT registry 110 | was suddenly somewhat documented through the pwdump utility 111 | included in the unix Samba distribution. 112 | This struct contains some info on a user of the NT machine, 113 | along with 2 crypted versions of the password associated 114 | with the account. 115 | 116 | One password is the NT console login password, 117 | the other the LANMAN network share password 118 | (which essentially is the first one in uppercase only, 119 | and no unicode) 120 | 121 | This is how NT encrypts the passwords: 122 | 123 | The logon cleartext password a user enters is: 124 | 1) Converted to unicode 125 | 2) A MD4 hash is made out of the unicode string 126 | 3) Then the hash is crypted with DES, using the RID (lower 127 | part of the SID, userid) as the crypt key. 128 | This is the so called "obfuscation" step, so 129 | it's not obvious on a hex dump of the file 130 | that two or more users have the same password. 131 | 4) The result of stage 3 (16 bytes) is put into the V struct. 132 | 133 | For the LANMAN password: 134 | 1) Uppercased (and illegal characters probably removed) 135 | 14 bytes max, if less the remaining bytes are zeroed. 136 | 2) A known (constant) string is DES-encrypted 137 | using 7 first characters of the password as the key. 138 | Another constant is encrypted using the last 7 chars 139 | as the key. 140 | The result of these two crypts are simply appended, 141 | resulting in a 16 byte string. 142 | 3) The same obfuscation DES stage as 3 above. 143 | 4) 16 bytes result put into the V struct. 144 | 145 | Since the number of possible combinations in the lanman 146 | password is relatively low compared to the other one, 147 | and it's easy to see if it's shorter than 8 chars or not 148 | it's used first in brute-force-crackers. 149 | 150 | This program, however, don't care at all what the old 151 | one is, it just overwrites it with the new one. 152 | 153 | Ok. So, how do we find and identify the V struct? 154 | Yeah.. that was the hard part.. The files structure 155 | is not documented (as far as I know..) 156 | 157 | But, with help from an unnamed German, and a lot of testing 158 | and guesswork from myself, it's now possible to follow 159 | the actual registry tree. (see source code for struct-defines 160 | and comments on the registry structure) 161 | 162 | The usernames are listed in: 163 | \SAM\Domains\Account\Users\Names\ 164 | 165 | [2d18] \SAM\Domains\Account\Users\Names> l 166 | ls of node at offset 0x2d1c 167 | Node has 4 subkeys and 1 values 168 | nk-offset name 169 | 0x003290 - 170 | 0x003630 - 171 | 0x001c88 - 172 | 0x003428 - 173 | 174 | Each name is a subkey, with one namless value containing 175 | the RID. 176 | 177 | [2d18] \SAM\Domains\Account\Users\Names> cd pnh 178 | 179 | [3428] \SAM\Domains\Account\Users\Names\pnh> l 180 | ls of node at offset 0x342c 181 | Node has 0 subkeys and 1 values 182 | vk-offs size type name 183 | 0x003688 0 (unknown) <> INLINE: val (in type field?): 1000 (0x3e8) 184 | 185 | To get the userinfo (V struct), access 186 | \SAM\Domains\Account\Users\\V 187 | 188 | [2c90] \SAM\Domains\Account\Users> l 189 | ls of node at offset 0x2c94 190 | Node has 5 subkeys and 1 values 191 | nk-offset name 192 | 0x003320 - <000001F4> 193 | 0x0036b8 - <000001F5> 194 | 0x003550 - <000003E8> 195 | 0x001d00 - <000003E9> 196 | 0x002d18 - 197 | 198 | [2c90] \SAM\Domains\Account\Users> cd 000003E8 199 | 200 | [3550] \SAM\Domains\Account\Users\000003E8> l 201 | ls of node at offset 0x3554 202 | Node has 0 subkeys and 2 values 203 | vk-offs size type name 204 | 0x0035a8 80 REG_BINARY 205 | 0x003228 508 REG_BINARY 206 | 207 | For more techincal info, look it up in the source code. 208 | -------------------------------------------------------------------------------- /reged.c: -------------------------------------------------------------------------------- 1 | /* 2 | * reged.c - Simple Registry Edit Utility for Windows registry hives. 3 | * 4 | * Frontend command line utility which uses registry library to: 5 | * - Export (parts) of registry hive to .reg file 6 | * - Import .reg file into registry hive 7 | * - Do interactive registry edit 8 | * 9 | * Changes: 10 | * 2011 - may: Trace flags moved here. 11 | * 2011 - apr: Added options for import and flags for safe modes.. 12 | * 13 | * 14 | ***** 15 | * 16 | * Copyright (c) 1997-2014 Petter Nordahl-Hagen. 17 | * 18 | * This program is free software; you can redistribute it and/or modify 19 | * it under the terms of the GNU General Public License as published by 20 | * the Free Software Foundation; version 2 of the License. 21 | * 22 | * This program is distributed in the hope that it will be useful, 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | * GNU General Public License for more details. 26 | * 27 | * See file GPL.txt for the full license. 28 | * 29 | ***** 30 | */ 31 | 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | #include "ntreg.h" 39 | 40 | 41 | const char reged_version[] = "reged version 0.1 140201, (c) Petter N Hagen"; 42 | 43 | 44 | /* Global verbosity flag */ 45 | int gverbose = 0; 46 | 47 | /* Array of loaded hives */ 48 | #define MAX_HIVES 10 49 | struct hive *hive[MAX_HIVES+1]; 50 | int no_hives = 0; 51 | 52 | 53 | void usage(void) 54 | { 55 | printf("\nModes:\n" 56 | "-x \n" 57 | " Xport. Where for example is HKEY_LOCAL_MACHINE\\SOFTWARE\n" 58 | " is key to dump (recursively), \\ or \\\\ means all keys in hive\n" 59 | " Only one .reg and one hive file supported at the same time\n" 60 | "-I \n" 61 | " Import from .reg file. Where for example is HKEY_LOCAL_MACHINE\\SOFTWARE\n" 62 | " Only one .reg and one hive file supported at the same time\n" 63 | "-e ...\n" 64 | " Interactive edit one or more of registry files\n\n" 65 | "Options:\n" 66 | "-L : Log changed filenames to /tmp/changed, also auto-saves\n" 67 | "-C : Auto-save (commit) changed hives without asking\n" 68 | "-N : No allocate mode, only allow edit of existing values with same size\n" 69 | "-E : No expand mode, do not expand hive file (safe mode)\n" 70 | "-t : Debug trace of allocated blocks\n" 71 | "-v : Some more verbose messages\n" 72 | ); 73 | } 74 | 75 | 76 | int main(int argc, char **argv) 77 | { 78 | 79 | int export = 0, edit = 0, import = 0; 80 | int d = 0; 81 | int autocommit = 0, update = 0; 82 | int logchange = 0, mode = 0, dd = 0; 83 | int il; 84 | extern int optind; 85 | extern char* optarg; 86 | char *hivename, *prefix, *key, *outputname, *inputname; 87 | char c; 88 | char yn[10]; 89 | FILE *ch; 90 | 91 | char *options = "vhtxCLeINE"; 92 | 93 | printf("%s\n",reged_version); 94 | while((c=getopt(argc,argv,options)) > 0) { 95 | switch(c) { 96 | case 'e': edit = 1; break; 97 | case 'x': export = 1; break; 98 | case 'I': import = 1; break; 99 | case 'C': autocommit = 1; break; 100 | case 'L': logchange = 1; break; 101 | case 'v': mode |= HMODE_VERBOSE; gverbose = 1; break; 102 | case 'N': mode |= HMODE_NOALLOC; break; 103 | case 'E': mode |= HMODE_NOEXPAND; break; 104 | case 't': mode |= HMODE_TRACE; break; 105 | case 'h': usage(); exit(0); break; 106 | default: usage(); exit(1); break; 107 | } 108 | } 109 | if (!export && !edit && !import) { 110 | usage(); 111 | exit(1); 112 | } 113 | if ( import && export ) { 114 | fprintf(stderr,"Import and export cannot be done at same time\n"); 115 | usage(); 116 | exit(1); 117 | } 118 | if (export) { /* Call export. Works only on one hive at a time */ 119 | hivename=argv[optind]; 120 | prefix=argv[optind+1]; 121 | key=argv[optind+2]; 122 | outputname=argv[optind+3]; 123 | if (gverbose) { 124 | printf("hivename: %s, prefix: %s, key: %s, output: %s\n",hivename,prefix,key,outputname); 125 | } 126 | 127 | if (!hivename || !*hivename || !prefix || !*prefix || !key || !*key || !outputname || !*outputname) { 128 | usage(); exit(1); 129 | } 130 | 131 | if (!(hive[no_hives] = openHive(hivename,HMODE_RO|mode))) { 132 | fprintf(stderr,"Unable to open/read hive %s, exiting..\n",hivename); 133 | exit(1); 134 | } 135 | 136 | export_key(hive[no_hives], 0, key, outputname, prefix); 137 | 138 | no_hives++; 139 | 140 | } 141 | 142 | if (import) { /* Call import. Works only on one hive at a time */ 143 | hivename=argv[optind]; 144 | prefix=argv[optind+1]; 145 | inputname=argv[optind+2]; 146 | if (gverbose) { 147 | printf("hivename: %s, prefix: %s\n",hivename,prefix); 148 | } 149 | 150 | if (!hivename || !*hivename || !prefix || !*prefix || !inputname || !*inputname) { 151 | usage(); exit(1); 152 | } 153 | 154 | if (!(hive[no_hives] = openHive(hivename,HMODE_RW|mode))) { 155 | fprintf(stderr,"Unable to open/read hive %s, exiting..\n",hivename); 156 | exit(1); 157 | } 158 | 159 | import_reg(hive[no_hives], inputname, prefix); 160 | 161 | no_hives++; 162 | update = 1; 163 | if (edit) regedit_interactive(hive, no_hives); 164 | edit = 0; 165 | 166 | } 167 | 168 | if (edit) { /* Call editor. Rest of arguments are considered hives to load */ 169 | hivename = argv[optind+no_hives]; 170 | do { 171 | if (!(hive[no_hives] = openHive(hivename, 172 | HMODE_RW|mode))) { 173 | printf("Unable to open/read a hive, exiting..\n"); 174 | exit(1); 175 | } 176 | no_hives++; 177 | hivename = argv[optind+no_hives]; 178 | } while (hivename && *hivename && no_hives < MAX_HIVES); 179 | regedit_interactive(hive, no_hives); 180 | update = 1; 181 | } 182 | 183 | 184 | if (update) { /* run for functions that can have changed things */ 185 | printf("\nHives that have changed:\n # Name\n"); 186 | for (il = 0; il < no_hives; il++) { 187 | if (hive[il]->state & HMODE_DIRTY) { 188 | if (!logchange && !autocommit) { 189 | printf("%2d <%s>",il,hive[il]->filename); 190 | if (hive[il]->state & HMODE_DIDEXPAND) 191 | printf(" WARNING: File was expanded! Experimental! Use at own risk!\n"); 192 | printf("\n"); 193 | } 194 | d = 1; 195 | } 196 | } 197 | if (d) { 198 | /* Only prompt user if logging of changed files has not been set */ 199 | /* Thus we assume confirmations are done externally if they ask for a list of changes */ 200 | if (!logchange && !autocommit) fmyinput("Commit changes to registry? (y/n) [n] : ",yn,3); 201 | if (*yn == 'y' || logchange || autocommit) { 202 | if (logchange) { 203 | ch = fopen("/tmp/changed","w"); 204 | } 205 | for (il = 0; il < no_hives; il++) { 206 | if (hive[il]->state & HMODE_DIRTY) { 207 | printf("%2d <%s> - ",il,hive[il]->filename); 208 | if (!writeHive(hive[il])) { 209 | printf("OK "); 210 | if (hive[il]->state & HMODE_DIDEXPAND) 211 | printf(" WARNING: File was expanded! Experimental! Use at own risk!\n"); 212 | printf("\n"); 213 | if (logchange) fprintf(ch,"%s ",hive[il]->filename); 214 | dd = 2; 215 | } 216 | } 217 | } 218 | if (logchange) { 219 | fprintf(ch,"\n"); 220 | fclose(ch); 221 | } 222 | } else { 223 | printf("Not written!\n\n"); 224 | } 225 | } else { 226 | printf("None!\n\n"); 227 | } 228 | } 229 | while (no_hives > 0) 230 | closeHive(hive[--no_hives]); 231 | return(dd); 232 | } 233 | 234 | -------------------------------------------------------------------------------- /sampasswd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sampasswd.c - SAM database, add or remove user in a group 3 | * 4 | * Command line utility, non-interactive to reset user password and/or 5 | * account bits for a user in the SAM database 6 | * 7 | * Changes: 8 | * 2013 - aug: cleaned up a bit for release, some debug still there 9 | * 2013 - apr-may: reset one, all and first features 10 | * 2012 - oct: First version, some code from earlier chntpw.c. Not released. 11 | * 12 | ***** 13 | * 14 | * Copyright (c) 1997-2014 Petter Nordahl-Hagen. 15 | * 16 | * This program is free software; you can redistribute it and/or modify 17 | * it under the terms of the GNU General Public License as published by 18 | * the Free Software Foundation; version 2 of the License. 19 | * 20 | * This program is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * See file GPL.txt for the full license. 26 | * 27 | ***** 28 | */ 29 | 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "ntreg.h" 37 | #include "sam.h" 38 | 39 | 40 | const char sampasswd_version[] = "sampasswd version 0.2 140201, (c) Petter N Hagen"; 41 | 42 | 43 | /* Global verbosity flag */ 44 | int gverbose = 0; 45 | 46 | /* Array of loaded hives */ 47 | #define MAX_HIVES 10 48 | struct hive *hive[MAX_HIVES+1]; 49 | int no_hives = 0; 50 | 51 | int H_SAM = -1; 52 | 53 | 54 | 55 | int do_reset(char *user, int inrid, int verb) 56 | { 57 | int rid = 0; 58 | int ret; 59 | char *resolvedname = NULL; 60 | char s[200]; 61 | 62 | if ((H_SAM < 0) || (!user && !inrid) ) return(1); 63 | 64 | if (inrid) { 65 | rid = inrid; 66 | } else { 67 | if (*user == '0' && *(user+1) == 'x') sscanf(user,"%i",&rid); 68 | } 69 | 70 | if (!rid) { /* Look up username */ 71 | /* Extract the unnamed value out of the username-key, value is RID */ 72 | snprintf(s,180,"\\SAM\\Domains\\Account\\Users\\Names\\%s\\@",user); 73 | rid = get_dword(hive[H_SAM],0,s, TPF_VK_EXACT|TPF_VK_SHORT); 74 | if (rid == -1) { 75 | printf("ERROR: User <%s> not found\n",user); 76 | return(1); 77 | } 78 | } 79 | 80 | /* At this point we have a RID, so get the real username it maps to just to show it */ 81 | resolvedname = sam_get_username(hive[H_SAM], rid); 82 | 83 | if (!resolvedname) return(1); /* RID lookup failed, no such user */ 84 | 85 | if (gverbose) printf("do_reset: Username: %s, RID = %d (0x%0x)\n",resolvedname,rid,rid); 86 | 87 | ret = sam_reset_pw(hive[H_SAM], rid); 88 | 89 | if (!ret && verb) printf("Password reset for user %s, RID = %d [0x%0x]\n",resolvedname,rid,rid); 90 | 91 | FREE(resolvedname); 92 | return(ret); 93 | 94 | } 95 | 96 | 97 | 98 | void usage(void) 99 | { 100 | printf(" [-r|-l] [-H] -u \n" 101 | "Reset password or list users in SAM database\n" 102 | "Mode:\n" 103 | " -r = reset users password\n" 104 | " -l = list users in sam\n" 105 | "Parameters:\n" 106 | " can be given as a username or a RID in hex with 0x in front\n" 107 | " Example:\n" 108 | " -r -u theboss -> resets password of user named 'theboss' if found\n" 109 | " -r -u 0x3ea -> resets password for user with RID 0x3ea (hex)\n" 110 | " -r -a -> Reset password of all users in administrators group (0x220)\n" 111 | " -r -f -> Reset password of admin user with lowest RID\n" 112 | " not counting built-in admin (0x1f4) unless it is the only admin\n" 113 | " Usernames with international characters usually fails to be found,\n" 114 | " please use RID number instead\n" 115 | " If success, there will be no output, and exit code is 0\n" 116 | "Options:\n" 117 | " -H : For list: Human readable listing (default is parsable table)\n" 118 | " -H : For reset: Will output confirmation message if success\n" 119 | " -N : No allocate mode, only allow edit of existing values with same size\n" 120 | " -E : No expand mode, do not expand hive file (safe mode)\n" 121 | " -t : Debug trace of allocated blocks\n" 122 | " -v : Some more verbose messages/debug\n" 123 | ); 124 | } 125 | 126 | 127 | int main(int argc, char **argv) 128 | { 129 | 130 | extern int optind; 131 | extern char* optarg; 132 | 133 | int what = 0; 134 | int reset = 0; 135 | int list = 0; 136 | int mode = 0; 137 | int human = 0; 138 | int adm = 0; 139 | int all = 0; 140 | int first = 0; 141 | int ret, wret, il; 142 | char *hivename; 143 | char c; 144 | char *usr = NULL; 145 | 146 | char *options = "rlHu:vNEthaf"; 147 | 148 | while((c=getopt(argc,argv,options)) > 0) { 149 | switch(c) { 150 | case 'r': reset = 1; break; 151 | case 'l': list = 2; break; 152 | case 'u': usr = optarg; break; 153 | case 'a': all = 1; break; 154 | case 'f': first = 1; break; 155 | case 'H': human = 1; break; 156 | case 'v': mode |= HMODE_VERBOSE; gverbose = 1; break; 157 | case 'N': mode |= HMODE_NOALLOC; break; 158 | case 'E': mode |= HMODE_NOEXPAND; break; 159 | case 't': mode |= HMODE_TRACE; break; 160 | case 'h': printf("%s\n%s ",sampasswd_version,argv[0]); usage(); exit(0); break; 161 | default: printf("%s\n%s ",sampasswd_version,argv[0]); usage(); exit(1); break; 162 | } 163 | } 164 | 165 | if (!reset && !list && !what) { 166 | fprintf(stderr,"%s: ERROR: Mode -r or -l must be specified. -h for help\n",argv[0]); 167 | exit(1); 168 | } 169 | 170 | #if 0 /* Should both be allowed at same time?? */ 171 | if (list && reset) { 172 | fprintf(stderr,"%s: ERROR: Mode -r and -l impossible at the same time. -h for help\n",argv[0]); 173 | exit(1); 174 | } 175 | #endif 176 | 177 | if (reset && !all && !first && (!usr || !*usr)) { 178 | fprintf(stderr,"%s: ERROR: Need a user for reset, -u must be specified.\n",argv[0]); 179 | exit(1); 180 | } 181 | 182 | 183 | /* Load hives. Only first SAM hive will be used however */ 184 | 185 | hivename = argv[optind+no_hives]; 186 | if (!hivename || !*hivename) { 187 | fprintf(stderr,"%s: ERROR: You must specify a SAM registry hive filename.\n",argv[0]); 188 | exit(1); 189 | } 190 | do { 191 | if (!(hive[no_hives] = openHive(hivename, 192 | HMODE_RW|mode))) { 193 | fprintf(stderr,"%s: ERROR: Unable to open/read registry hive, cannot continue\n",argv[0]); 194 | exit(1); 195 | } 196 | switch(hive[no_hives]->type) { 197 | case HTYPE_SAM: H_SAM = no_hives; break; 198 | // case HTYPE_SOFTWARE: H_SOF = no_hives; break; 199 | // case HTYPE_SYSTEM: H_SYS = no_hives; break; 200 | // case HTYPE_SECURITY: H_SEC = no_hives; break; 201 | } 202 | no_hives++; 203 | hivename = argv[optind+no_hives]; 204 | } while (hivename && *hivename && no_hives < MAX_HIVES); 205 | 206 | if (H_SAM == -1) { 207 | fprintf(stderr,"%s: WARNING: Hive file does not look like SAM, but continuing anyway in case detection was wrong\n" 208 | "%s: WARNING: If it really is not a SAM file you will get strange errors or bad results\n",argv[0],argv[0]); 209 | H_SAM = 0; 210 | } 211 | 212 | 213 | /* Do logic */ 214 | 215 | if (list) { 216 | adm = sam_list_users(hive[H_SAM], human); 217 | if (gverbose) printf(" sam_list_users found admin to be 0x%x\n",adm); 218 | } 219 | 220 | if (reset) { 221 | if (all) { 222 | ret = sam_reset_all_pw(hive[H_SAM], human); 223 | if (ret) { 224 | fprintf(stderr,"%s: ERROR: Failed reset password of ALL users\n",argv[0]); 225 | } 226 | } else if (first) { 227 | adm = sam_list_users(hive[H_SAM], 2); 228 | if (!adm) { 229 | fprintf(stderr,"%s: ERROR: Unable to reset, no admin users found\n",argv[0]); 230 | } else { 231 | // printf("Resetting password of user with RID %x\n",adm); 232 | ret = do_reset(usr, adm, human); 233 | } 234 | } else { 235 | ret = do_reset(usr, 0, human); 236 | if (ret) { 237 | fprintf(stderr,"%s: ERROR: Failed reset password for %s\n",argv[0],usr); 238 | } 239 | } 240 | } 241 | 242 | /* write registry hive (if needed) */ 243 | 244 | wret = 0; 245 | for (il = 0; il < no_hives; il++) { 246 | // wret |= writeHive(hive[il]); 247 | if (hive[il]->state & HMODE_DIDEXPAND) 248 | fprintf(stderr," WARNING: Registry file %s was expanded! Experimental! Use at own risk!\n",hive[il]->filename); 249 | while (no_hives > 0) 250 | closeHive(hive[--no_hives]); 251 | } 252 | 253 | return(ret | wret); 254 | } 255 | 256 | -------------------------------------------------------------------------------- /samusrgrp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * samusrgrp.c - SAM database, add or remove user in a group 3 | * 4 | * Command line utility, non-inreractive to add or remove a user to/from 5 | * a local group in the SAM database, list groups with memberships etc 6 | * 7 | * When run as: 8 | * samusrtogrp - add user to group 9 | * samusrfromgrp - remove user from a group 10 | * or as any other name, option of what to do must be specified 11 | * 12 | * Changes: 13 | * 2013 - aug: cleaned up for release, still some debug & strangeness left 14 | * 2013 - apr-may: add, remove, list working (more or less) 15 | * 2012 - oct: First version, never released 16 | * 17 | ***** 18 | * 19 | * Copyright (c) 1997-2014 Petter Nordahl-Hagen. 20 | * 21 | * This program is free software; you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation; version 2 of the License. 24 | * 25 | * This program is distributed in the hope that it will be useful, 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 | * GNU General Public License for more details. 29 | * 30 | * See file GPL.txt for the full license. 31 | * 32 | ***** 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "ntreg.h" 42 | #include "sam.h" 43 | 44 | 45 | const char samusrgrp_version[] = "samusrgrp version 0.2 140201, (c) Petter N Hagen"; 46 | 47 | 48 | /* Global verbosity flag */ 49 | int gverbose = 0; 50 | 51 | /* Array of loaded hives */ 52 | #define MAX_HIVES 10 53 | struct hive *hive[MAX_HIVES+1]; 54 | int no_hives = 0; 55 | 56 | int H_SAM = -1; 57 | 58 | 59 | /* Print machine SID. Put into here since no better place for now */ 60 | 61 | void cmd_machinesid(void) 62 | { 63 | struct sid_binary sid; 64 | char *sidstr; 65 | 66 | if (sam_get_machine_sid(hive[H_SAM], (char *)&sid)) { 67 | sidstr = sam_sid_to_string(&sid); 68 | puts(sidstr); 69 | FREE(sidstr); 70 | } 71 | } 72 | 73 | /* Get and parse parameters for group changes */ 74 | 75 | int cmd_usrgrp(char *user, char *grp, int what, int human) 76 | { 77 | int numgrp; 78 | int rid = 0; 79 | char *resolveduser = NULL; 80 | char *resolvedgroup = NULL; 81 | char s[200]; 82 | 83 | numgrp = strtol(grp, NULL, 0); 84 | 85 | if ((H_SAM < 0) || (!user)) return(1); 86 | 87 | if (*user == '0' && *(user+1) == 'x') sscanf(user,"%i",&rid); 88 | 89 | if (!rid) { /* Look up username */ 90 | /* Extract the unnamed value out of the username-key, value is RID */ 91 | snprintf(s,180,"\\SAM\\Domains\\Account\\Users\\Names\\%s\\@",user); 92 | rid = get_dword(hive[H_SAM],0,s, TPF_VK_EXACT|TPF_VK_SHORT); 93 | if (rid == -1) { 94 | printf("User <%s> not found\n",user); 95 | return(1); 96 | } 97 | } 98 | 99 | /* At this point we have a RID, so get the real username it maps to just to show it */ 100 | resolveduser = sam_get_username(hive[H_SAM], rid); 101 | if (!resolveduser) return(1); /* Fails if RID does not exists */ 102 | 103 | resolvedgroup = sam_get_groupname(hive[H_SAM], numgrp); 104 | if (!resolvedgroup) return(1); /* Fails if GID does not exists */ 105 | 106 | 107 | if (human) printf("%s user <%s> with RID = %d (0x%0x) %s group <%s> with GID = %d (0x%x)\n", 108 | (what == 1 ? "Add" : "Remove"), 109 | resolveduser, 110 | rid, rid, 111 | (what == 1 ? "to" : "from"), 112 | resolvedgroup, 113 | numgrp, numgrp ); 114 | 115 | FREE(resolveduser); 116 | FREE(resolvedgroup); 117 | 118 | switch (what) { 119 | case 1: return(!sam_add_user_to_grp(hive[H_SAM] ,rid, numgrp)); break; 120 | case 2: return(!sam_remove_user_from_grp(hive[H_SAM] ,rid, numgrp)); break; 121 | } 122 | 123 | 124 | return(0); 125 | 126 | } 127 | 128 | 129 | 130 | void usage(void) 131 | { 132 | printf(" [-a|-r] -u -g \n" 133 | "Add or remove a (local) user to/from a group\n" 134 | "Mode:" 135 | " -a = add user to group\n" 136 | " -r = remove user from group\n" 137 | " -l = list groups\n" 138 | " -L = list groups and also their members\n" 139 | " -s = Print machine SID\n" 140 | "Parameters:\n" 141 | " can be given as a username or a RID in hex with 0x in front\n" 142 | " is the group number, in hex with 0x in front\n" 143 | " Example:\n" 144 | " -a -u theboss -g 0x220 -> add user named 'theboss' group hex 220 (administrators)\n" 145 | " -a -u 0x3ea -g 0x221 -> add user with RID (hex) 3ea group hex 221 (users)\n" 146 | " -r -u 0x3ff -g 0x220 -> remove user RID 0x3ff from grp 0x220\n" 147 | " Usernames with international characters usually fails to be found,\n" 148 | " please use RID number instead\n" 149 | " If success, there will be no output, and exit code is 0\n" 150 | " Also, success if user already in (or not in if -r) the group\n" 151 | "Options:\n" 152 | " -H : Human readable output, else parsable\n" 153 | " -N : No allocate mode, only allow edit of existing values with same size\n" 154 | " -E : No expand mode, do not expand hive file (safe mode)\n" 155 | " -t : Debug trace of allocated blocks\n" 156 | " -v : Some more verbose messages/debug\n" 157 | "Multi call binary, if program is named:\n" 158 | " samusrtogrp -- Assume -a mode: Add a user into a group\n" 159 | " samusrfromgrp -- Assume -r mode: Remove user from a group\n" 160 | ); 161 | } 162 | 163 | 164 | int main(int argc, char **argv) 165 | { 166 | 167 | extern int optind; 168 | extern char* optarg; 169 | 170 | int what = 0; 171 | int add = 0; 172 | int rem = 0; 173 | int mode = 0; 174 | int m = 0; 175 | int list = 0; 176 | int human = 0; 177 | int ret, wret, il; 178 | char *hivename; 179 | char c; 180 | char *usr = NULL; 181 | char *grp = NULL; 182 | 183 | char *options = "aru:g:vNEthlLHs"; 184 | 185 | if (!strcmp(argv[0],"samusrtogrp")) what = 1; 186 | if (!strcmp(argv[0],"samusrfromgrp")) what = 2; 187 | if (!strcmp(argv[0],"samgrplist")) what = 3; 188 | 189 | while((c=getopt(argc,argv,options)) > 0) { 190 | switch(c) { 191 | case 'a': add = 1; m++; break; /* Add user */ 192 | case 'r': rem = 2; m++; break; /* Remove user */ 193 | case 'l': list = 1; m++; break; /* List groups */ 194 | case 'L': list = 2; m++; break; /* List groups + members */ 195 | case 's': list = 3; m++; break; /* Print machine sid */ 196 | case 'u': usr = optarg; break; 197 | case 'g': grp = optarg; break; 198 | case 'H': human = 1; break; 199 | case 'v': mode |= HMODE_VERBOSE; gverbose = 1; break; 200 | case 'N': mode |= HMODE_NOALLOC; break; 201 | case 'E': mode |= HMODE_NOEXPAND; break; 202 | case 't': mode |= HMODE_TRACE; break; 203 | case 'h': printf("%s\n%s ",samusrgrp_version,argv[0]); usage(); exit(0); break; 204 | default: printf("%s\n%s ",samusrgrp_version,argv[0]); usage(); exit(1); break; 205 | } 206 | } 207 | 208 | if (m == 0) { 209 | fprintf(stderr,"%s: ERROR: One of mode -a -r -l -L must be specified\n",argv[0]); 210 | printf("%s\n%s ",samusrgrp_version,argv[0]); 211 | usage(); 212 | exit(1); 213 | } 214 | 215 | if (m > 1) { 216 | fprintf(stderr,"%s: ERROR: Please select only one of modes -a -r -l -L\n",argv[0]); 217 | exit(1); 218 | } 219 | 220 | if (!list && (!usr || !grp || !*usr || !*grp) ) { 221 | fprintf(stderr,"%s: ERROR: Both -u and -g must be specified.\n",argv[0]); 222 | exit(1); 223 | } 224 | 225 | 226 | /* Implicit mode parameter overrides mode based on binary name */ 227 | if (add) what = 1; 228 | if (rem) what = 2; 229 | if (list) what = 3; 230 | 231 | // printf("add = %d, rem = %d, list = %d, what = %d\n",add,rem,list,what); 232 | 233 | 234 | /* Load hives. Only first SAM hive will be used however */ 235 | 236 | hivename = argv[optind+no_hives]; 237 | if (!hivename || !*hivename) { 238 | fprintf(stderr,"%s: ERROR: You must specify a SAM registry hive filename.\n",argv[0]); 239 | exit(1); 240 | } 241 | do { 242 | if (!(hive[no_hives] = openHive(hivename, 243 | HMODE_RW|mode))) { 244 | fprintf(stderr,"%s: ERROR: Unable to open/read registry hive, cannot continue\n",argv[0]); 245 | exit(1); 246 | } 247 | switch(hive[no_hives]->type) { 248 | case HTYPE_SAM: H_SAM = no_hives; break; 249 | // case HTYPE_SOFTWARE: H_SOF = no_hives; break; 250 | // case HTYPE_SYSTEM: H_SYS = no_hives; break; 251 | // case HTYPE_SECURITY: H_SEC = no_hives; break; 252 | } 253 | no_hives++; 254 | hivename = argv[optind+no_hives]; 255 | } while (hivename && *hivename && no_hives < MAX_HIVES); 256 | 257 | if (H_SAM == -1) { 258 | fprintf(stderr,"%s: WARNING: Registry hive does not look like SAM!\n" 259 | "%s: WARNING: Continuing anyway, may lead to strange messages/failures!\n",argv[0],argv[0]); 260 | H_SAM = 0; 261 | } 262 | 263 | 264 | /* Do logic */ 265 | 266 | if (list == 3) { 267 | cmd_machinesid(); 268 | ret = 0; 269 | } else { 270 | if (list) { 271 | sam_list_groups(hive[H_SAM], list - 1, human); 272 | ret = 0; 273 | } else { 274 | ret = cmd_usrgrp(usr, grp, what, human); 275 | if (!ret && human) printf("Success!\n"); 276 | } 277 | } 278 | 279 | /* write registry hive (if needed) */ 280 | 281 | wret = 0; 282 | for (il = 0; il < no_hives; il++) { 283 | wret |= writeHive(hive[il]); 284 | if (hive[il]->state & HMODE_DIDEXPAND) 285 | fprintf(stderr," WARNING: Registry file %s was expanded! Experimental! Use at own risk!\n",hive[il]->filename); 286 | while (no_hives > 0) 287 | closeHive(hive[--no_hives]); 288 | } 289 | 290 | return(ret | wret); 291 | } 292 | 293 | -------------------------------------------------------------------------------- /sam.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sam.h - known structures in the SAM hive of NT registry 3 | * 4 | ***** 5 | * 6 | * NTREG - Window registry file reader / writer library 7 | * Copyright (c) 1997-2012 Petter Nordahl-Hagen. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; 12 | * version 2.1 of the License. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * See file LGPL.txt for the full license. 19 | * 20 | */ 21 | 22 | #ifndef _INCLUDE_SAM_H 23 | #define _INCLUDE_SAM_H 1 24 | 25 | #include 26 | #include 27 | 28 | 29 | /* Account V, contains machine SID and a lot of unknonw stuff */ 30 | 31 | #define SID_BIN_LEN 24 /* Lenght of binary machine SID, incl header */ 32 | #define SID_STR_MAX 50 /* Max string lenght of S-1-5-xxx-xxx-xxx-xxx type SID */ 33 | 34 | #define ACCOUNTDB_V_PATH "\\SAM\\Domains\\Account\\V" 35 | 36 | struct accountdb_V { 37 | char unknown1[0x38]; /* No idea what it does */ 38 | uint32_t sid_ofs; /* 38 - Offset to machine SID */ 39 | uint32_t sid_len; /* 3c - Lenght of sid (should be 0x14?) */ 40 | // char unknown2[0x4]; /* 40 */ 41 | /* Data start at 0x40 ?? */ 42 | char data[4]; 43 | }; 44 | 45 | /* This contains some policy settings for the account database */ 46 | 47 | #define ACCOUNTDB_F_PATH "\\SAM\\Domains\\Account\\F" 48 | 49 | 50 | struct accountdb_F { 51 | char unknown1[8]; /* 0 */ 52 | char unknown2[8]; /* 8 */ 53 | uint32_t updatecnt; /* 10 Number of times policy data updated */ 54 | char unknown3[4]; /* 14 */ 55 | char t_maxpwage[8]; /* 18 Maximum password age, GUI shows only days */ 56 | char t_minpwage[8]; /* 20 Minimum password age, GUI shows only days */ 57 | char unknown4[8]; /* 28 */ 58 | char t_lockdur[8]; /* 30 Account lockout duration, GUI shows minutes */ 59 | char t_lockrel[8]; /* 38 Release account lockout after, GUI show minutes */ 60 | char unknown5[8]; /* 40 */ 61 | uint32_t rid; /* 48 RID of user doing last edit? */ 62 | uint32_t flags; /* 4c Some flags & options, see below */ 63 | unsigned short minpwlen; /* 50 Minimum password lenght */ 64 | unsigned short numhist; /* 52 How many passwords to keep in history */ 65 | unsigned short locklimit; /*54 How many tries before lockout */ 66 | char unknown6[0x9a]; /* Rest is unknown */ 67 | }; /* Total size 0xF0 bytes, seems to be constant */ 68 | 69 | /* Known bits in flags field */ 70 | 71 | #define ACF_COMPLEX 0x0001 /* Pass must meet complexity req. */ 72 | #define ACF_REVERSIBLE 0x0010 /* Store password using reversible encryption */ 73 | 74 | 75 | /* This is users F value, contains account type & state etc */ 76 | 77 | #define USER_F_PATH "\\SAM\\Domains\\Account\\Users\\%08X\\F" 78 | 79 | struct user_F { 80 | char unknown1[8]; 81 | char t_lockout[8]; /* Time of lockout */ 82 | char unknown2[8]; 83 | char t_creation[8]; /* Time of account creation */ 84 | char unknown3[8]; 85 | char t_login[8]; /* Time of last login */ 86 | int32_t rid; 87 | char unknown4[4]; 88 | unsigned short ACB_bits; /* Account type and status flags */ 89 | char unknown5[6]; 90 | unsigned short failedcnt; /* Count of failed logins, if > than policy it is locked */ 91 | unsigned short logins; /* Total logins since creation */ 92 | char unknown6 [0xc]; 93 | }; 94 | 95 | #define ACB_DISABLED 0x0001 /* Act disabled */ 96 | #define ACB_HOMDIRREQ 0x0002 /* Home directory required */ 97 | #define ACB_PWNOTREQ 0x0004 /* User password not req */ 98 | #define ACB_TEMPDUP 0x0008 /* Temporary duplicate account?? */ 99 | #define ACB_NORMAL 0x0010 /* Normal user account */ 100 | #define ACB_MNS 0x0020 /* MNS logon user account */ 101 | #define ACB_DOMTRUST 0x0040 /* Interdomain trust account */ 102 | #define ACB_WSTRUST 0x0080 /* Workstation trust account */ 103 | 104 | #define ACB_SVRTRUST 0x0100 /* Server trust account */ 105 | #define ACB_PWNOEXP 0x0200 /* User password does not expire */ 106 | /* Seems not to be used on failed console logins at least */ 107 | #define ACB_AUTOLOCK 0x0400 /* Account auto locked */ 108 | 109 | /* Account Bits Fields strings (defined in libsam.c) 110 | 111 | char *acb_fields[16] = { 112 | "Disabled" , 113 | "Homedir req." , 114 | "Passwd not req." , 115 | "Temp. duplicate" , 116 | "Normal account" , 117 | "NMS account" , 118 | "Domain trust act." , 119 | "Wks trust act." , 120 | "Srv trust act" , 121 | "Pwd don't expire" , 122 | "Auto lockout" , 123 | "(unknown 0x08)" , 124 | "(unknown 0x10)" , 125 | "(unknown 0x20)" , 126 | "(unknown 0x40)" , 127 | "(unknown 0x80)" , 128 | }; 129 | 130 | */ 131 | 132 | 133 | /* Users V data struct */ 134 | /* First 0xCC bytes is pointer & len table, rest is data which 135 | * the table points to 136 | * String data is unicode, not zero terminated (must use len) 137 | */ 138 | 139 | struct user_V { 140 | 141 | int unknown1_1; /* 0x00 - always zero? */ 142 | int unknown1_2; /* 0x04 - points to username? */ 143 | int unknown1_3; /* 0x08 - always 0x02 0x00 0x01 0x00 ? */ 144 | 145 | int username_ofs; /* 0x0c */ 146 | int username_len; /* 0x10 */ 147 | 148 | int unknown2_1; /* 0x14 - always zero? */ 149 | 150 | int fullname_ofs; /* 0x18 */ 151 | int fullname_len; /* 0x1c */ 152 | 153 | int unknown3_1; /* 0x20 - always zero? */ 154 | 155 | int comment_ofs; /* 0x24 */ 156 | int comment_len; /* 0x28 */ 157 | 158 | int unknown4_1; /* 0x2c - alway zero? */ 159 | int unknown4_2; /* 0x30 - points 4 or 8 byte field before hashes */ 160 | int unknown4_3; /* 0x34 - zero? or size? */ 161 | int unknown4_4; /* 0x38 - zero? */ 162 | int unknown4_5; /* 0x3c - to field 8 bytes before hashes */ 163 | int unknown4_6; /* 0x40 - zero? or size of above? */ 164 | int unknown4_7; /* 0x44 - zero? */ 165 | 166 | int homedir_ofs; /* 0x48 */ 167 | int homedir_len; /* 0x4c */ 168 | 169 | int unknown5_1; /* 0x50 - zero? */ 170 | 171 | int drvletter_ofs; /* 0x54 - drive letter for home dir */ 172 | int drvletter_len; /* 0x58 - len of above, usually 4 */ 173 | 174 | int unknown6_1; /* 0x5c - zero? */ 175 | 176 | int logonscr_ofs; /* 0x60 - users logon script path */ 177 | int logonscr_len; /* 0x64 - length of string */ 178 | 179 | int unknown7_1; /* 0x68 - zero? */ 180 | 181 | int profilep_ofs; /* 0x6c - profile path string */ 182 | int profilep_len; /* 0x70 - profile path stringlen */ 183 | 184 | char unknown7[0x90-0x74]; /* 0x74 */ 185 | 186 | int unknown8_1; /* 0x90 - pointer to some place before hashes, after comments */ 187 | int unknown8_2; /* 0x94 - size of above? */ 188 | int unknown8_3; /* 0x98 - unknown? always 1? */ 189 | 190 | int lmpw_ofs; /* 0x9c */ 191 | int lmpw_len; /* 0xa0 */ 192 | 193 | int unknown9_1; /* 0xa4 - zero? */ 194 | 195 | int ntpw_ofs; /* 0xa8 */ 196 | int ntpw_len; /* 0xac */ 197 | 198 | int unknowna_1; /* 0xb0 */ 199 | int unknowna_2; /* 0xb4 - points to field after hashes */ 200 | int unknowna_3; /* 0xb8 - size of above field */ 201 | int unknowna_4; /* 0xbc - zero? */ 202 | int unknowna_5; /* 0xc0 - points to field after that */ 203 | int unknowna_6; /* 0xc4 - size of above */ 204 | int unknowna_7; /* 0xc8 - zero ? */ 205 | 206 | char data[4]; /* Data starts here. All pointers above is relative to this, 207 | that is V + 0xCC */ 208 | 209 | }; 210 | 211 | /* Groups C data struct 212 | * First 0x34 bytes is pointer & len table, rest is data which 213 | * the table points to 214 | * String data is unicode, not zero terminated (must use len) 215 | */ 216 | 217 | struct group_C { 218 | 219 | int groupid; /* 0x00 - Seems to be the group ID */ 220 | int unknown1_1; /* 0x04 - always zero? */ 221 | int unknown1_2; /* 0x08 - points to groupname? */ 222 | int unknown1_3; /* 0x0c - always 0x02 0x00 0x01 0x00 ? */ 223 | 224 | int grpname_ofs; /* 0x10 */ 225 | int grpname_len; /* 0x14 */ 226 | 227 | int unknown2_1; /* 0x18 - always zero? */ 228 | 229 | int fullname_ofs; /* 0x1c */ 230 | int fullname_len; /* 0x20 */ 231 | 232 | int unknown3_1; /* 0x24 - always zero? */ 233 | 234 | int members_ofs; /* 0x28 - offset to member list, which is SIDs */ 235 | int members_len; /* 0x2c - member list size */ 236 | 237 | int grp_members; /* 0x30 - number of group members */ 238 | 239 | /* 0x34 - data starts here. pointers above are offset from this */ 240 | 241 | char data[]; 242 | 243 | }; 244 | 245 | /* Variable length binary structure that most SIDs are stored in 246 | */ 247 | 248 | struct sid_binary { 249 | uint8_t revision; /* 0x0 - Don't know. Always 1? Revision level? number of SIDs following? */ 250 | uint8_t sections; /* 0x1 - Number of parts, 4 bytes each (unsigne integer) */ 251 | uint8_t unknown2; /* 0x2 - Unknown, seems to be null padding */ 252 | uint8_t unknown3; /* 0x3 - Unknown, seems to be null padding */ 253 | 254 | uint8_t unknown4; /* 0x4 - Unknown */ 255 | uint8_t unknown5; /* 0x5 - Unknown */ 256 | uint8_t unknown6; /* 0x6 - Unknown */ 257 | uint8_t authority; /* 0x7 - Unknown, often 5 (could this be 8bit authority number?) */ 258 | 259 | 260 | uint32_t array[8]; /* As many as sections value says it is */ 261 | }; 262 | 263 | /* Array of SIDs */ 264 | 265 | struct sid_array { 266 | int len; 267 | struct sid_binary *sidptr; 268 | }; 269 | 270 | 271 | /* libsam.c functions */ 272 | 273 | int sam_get_lockoutinfo(struct hive *hdesc, int show); 274 | short sam_handle_accountbits(struct hive *hdesc, int rid, int mode); 275 | int sam_get_machine_sid(struct hive *hdesc, char *sidbuf); 276 | char *sam_sid_to_string(struct sid_binary *sidbuf); 277 | struct sid_array *sam_make_sid_array(struct sid_binary *sidbuf, int size); 278 | void sam_free_sid_array(struct sid_array *array); 279 | int sam_sid_cmp(struct sid_binary *s1, struct sid_binary *s2); 280 | int sam_get_grp_members_sid(struct hive *hdesc, int grp, struct sid_array **sarray); 281 | int sam_put_grp_members_sid(struct hive *hdesc, int grp, struct sid_array *sarray); 282 | struct keyval *sam_get_user_grpids(struct hive *hdesc, int rid); 283 | int sam_put_user_grpids(struct hive *hdesc, int rid, struct keyval *val); 284 | int sam_add_user_to_grp(struct hive *hdesc, int rid, int grp); 285 | int sam_remove_user_from_grp(struct hive *hdesc, int rid, int grp); 286 | char *sam_get_username(struct hive *hdesc, int rid); 287 | char *sam_get_groupname(struct hive *hdesc, int grpid); 288 | int sam_list_users(struct hive *hdesc, int readable); 289 | int sam_list_user_groups(struct hive *hdesc, int rid, int check); 290 | int sam_reset_pw(struct hive *hdesc, int rid); 291 | void sam_list_groups(struct hive *hdesc, int listmembers, int human); 292 | int sam_reset_all_pw(struct hive *hdesc, int list); 293 | 294 | 295 | 296 | #endif 297 | -------------------------------------------------------------------------------- /regedit.txt: -------------------------------------------------------------------------------- 1 | The Offline NT Password Editor 2 | 3 | (c) 1997-2011 Petter Nordahl-Hagen 4 | 5 | Registry Editor Usermanual/docs 6 | 7 | See COPYING for copyright & credits. 8 | See INSTALL for compile/installation instructions. 9 | See README for docs on the passwordpart (or website for bootdisk) 10 | 11 | Some known limitations as of first half 2011: 12 | This release features full basic registry edit with 13 | add/del keys and values and resizing values, and also 14 | expanding the file. 15 | Renaming keys and values is not implemented yet. 16 | Import is slow. Export is fast. 17 | 18 | Program "reged" is used for interactive registry edit 19 | (rudimentary command prompt type interface) 20 | or to export or import .reg files. 21 | Import and export can also be scripted (non-interactive) 22 | 23 | The "chntpw" program which is for password edits, also 24 | contains the editor, but not the import / export. 25 | 26 | Usage of "reged": 27 | 28 | reged version 0.1 110504, (c) Petter N Hagen 29 | 30 | Modes: 31 | -x 32 | Xport. Where for example is HKEY_LOCAL_MACHINE\SOFTWARE 33 | is key to dump (recursively), . or \ or \\ means all keys in hive 34 | Only one .reg and one hive file supported at the same time 35 | -I 36 | Import from .reg file. Where for example is HKEY_LOCAL_MACHINE\SOFTWARE 37 | Only one .reg and one hive file supported at the same time 38 | -e ... 39 | Interactive edit one or more of registry files 40 | 41 | Options: 42 | -L : Log changed filenames to /tmp/changed, also auto-saves 43 | -C : Auto-save (commit) changed hives without asking 44 | -N : No allocate mode, only allow edit of existing values with same size 45 | -E : No expand mode, do not expand hive file (safe mode) 46 | -t : Debug trace of allocated blocks 47 | -v : Some more verbose messages 48 | 49 | 50 | -x will do export to .reg file. 51 | It will create files that seems to be compatible with regedit.exe in 52 | Windows. 53 | The prefix is the first part of the key names that windows shows/uses, 54 | it is not stored in the hive files, so you can actually put in 55 | anything unless you have to import in Windows. 56 | Current version only handles one set of files at a time (and also only 57 | one point to start export from in it) 58 | 59 | -I does import of .reg files into the specified hive file. 60 | It supports .reg files from Windows regedit.exe, they are usually 61 | UTF-16 (16 bit characters) and in the few cases I tested it will 62 | import with correct characters. Please note that the key and value 63 | names always are 8 bit in the registry, but strings the values store 64 | are 16 bit characters. 65 | Will also work with latin-1 (8 bit) character files, like the export 66 | functions creates, but again some character conversions may be wrong. 67 | Note that the current versions are pretty slow, since they are not 68 | optimized or well written in any way. Around 90000 keys with 120000 69 | values just took around 10 minutes on my pretty fast machine. 70 | (I am lazy! You don't write hex reads with one byte at a time do you? :) 71 | 72 | -e goes into interactive editor (see below for old example) 73 | -e can be combined with -I so that the editor is entered before saving 74 | -after an import. 75 | 76 | -N and -E are safe modes, can be used with any mode. 77 | -C must be used when importing to auto-save, else it will ask first if 78 | import succeeds. 79 | The -L option will write changed hive file names to /tmp/changed, 80 | I use it for scripts that need to know. 81 | 82 | 83 | ------------------------ 84 | 85 | 86 | Here is an old demo of registry edit, via the chntpw program, 87 | but regedit is the same (except some new stuff is in there) 88 | 89 | 90 | You can navigate the registry almost like a filesystem (only difference 91 | being that the "files" actually are of a special datatype, instead of 92 | just a bytestream) 93 | Note that this demo is just some random editing, will likely 94 | cause windows to not boot if written back to it. 95 | 96 | >chntpw -h 97 | chntpw version 0.99.0 030111, (c) Petter N Hagen 98 | chntpw: change password of a user in a NT SAM file, or invoke registry editor. 99 | chntpw [OPTIONS] [systemfile] [securityfile] [otherreghive] [...] 100 | -h This message 101 | -u Username to change, Administrator is default 102 | -l list all users in SAM file 103 | -i Interactive. List users (as -l) then ask for username to change 104 | -e Registry editor. Now with full write support! 105 | -d Enter buffer debugger instead (hex editor), 106 | -t Trace. Show hexdump of structs/segments. (deprecated debug function) 107 | -L Write names of changed files to /tmp/changed 108 | -N No allocation mode. Only (old style) same length overwrites possible 109 | 110 | (example edit of a SYSTEM-hive) 111 | >chntpw -e system 112 | chntpw version 0.99.0 030111, (c) Petter N Hagen 113 | Hive's name (from header): 114 | ROOT KEY at offset: 0x001020 115 | This is probably not a sam HIVE 116 | Simple registry editor. ? for help. 117 | 118 | [1020] > ? 119 | 120 | Simple registry editor: 121 | hive [] - list loaded hives or switch to hive numer n' 122 | cd - change key 123 | ls | dir [] - show subkeys & values, 124 | cat | type - show key value 125 | st [] - show struct info 126 | nk - add key 127 | dk - delete key (must be empty. recursion not supported yet) 128 | ed - Edit value 129 | nv - Add value 130 | dv - Delete value 131 | delallv - Delete all values in current key 132 | debug - enter buffer hexeditor 133 | q - quit 134 | 135 | (list the contents of the current key) 136 | 137 | [1020] > l 138 | ls of node at offset 0x1024 139 | Node has 6 subkeys and 0 values 140 | offs key name 141 | [ 11b8] 142 | [ dff88] 143 | [1c2040] 144 | [ de448] 145 | [ de998] 342 | [ deab8] 343 | 344 | (now let's make a subkey here) 345 | 346 | [1020] > nk DemoKey 347 | 348 | [1020] > l 349 | ls of node at offset 0x1024 350 | Node has 7 subkeys and 0 values 351 | offs key name 352 | [ 11b8] 353 | [ dff88] 354 | [1c2ef8] 355 | [1c2040] 356 | [ de448] 357 | [ de998] 399 | [ deab8] 400 | 401 | (and delete the key) 402 | 403 | [1020] > dk DemoKey 404 | 405 | [1020] > l 406 | ls of node at offset 0x1024 407 | Node has 6 subkeys and 0 values 408 | offs key name 409 | [ 11b8] 410 | [ dff88] 411 | [1c2040] 412 | [ de448] 413 | [ de998]