Move all win32 logic to wine executable
Actions like reading the registry and serial number were being done in python even though the final decryption was done in wine. This commit moves all windows logic except architecture detection into the exe ran under wine to simplify the architecture.pull/66/head
parent
61a03fe988
commit
0cb13b9d38
@ -1,196 +1,112 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#include <dpapi.h>
|
||||
#include <fileapi.h>
|
||||
#include <direct.h>
|
||||
#include <cpuid.h>
|
||||
#include <intsafe.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#undef DEBUG
|
||||
#endif
|
||||
union CPUIDVendor {
|
||||
unsigned int reg[3];
|
||||
char vendor[13];
|
||||
};
|
||||
|
||||
int char2int(char input) {
|
||||
if (input >= '0' && input <= '9')
|
||||
return input - '0';
|
||||
if (input >= 'A' && input <= 'F')
|
||||
return input - 'A' + 10;
|
||||
if (input >= 'a' && input <= 'f')
|
||||
return input - 'a' + 10;
|
||||
|
||||
fputs("PROGOUTPUT:-3", stdout);
|
||||
exit(-3);
|
||||
}
|
||||
struct EncEntropy {
|
||||
unsigned int serial;
|
||||
char vendor[12];
|
||||
char signature[3];
|
||||
char user[13];
|
||||
};
|
||||
|
||||
void hex2bin(const char * src, char * dst) {
|
||||
while (*src && src[1]) {
|
||||
*(dst++) = char2int(*src) * 16 + char2int(src[1]);
|
||||
src += 2;
|
||||
int main() {
|
||||
// Get disk serial
|
||||
DWORD serial;
|
||||
if (GetVolumeInformation("c:\\\\", NULL, 0, &serial, NULL, NULL, NULL, 0) == 0) {
|
||||
DWORD err = GetLastError();
|
||||
fprintf(stderr, "Error with GetVolumeInformation: %ld\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void hexDump (
|
||||
const char * desc,
|
||||
const void * addr,
|
||||
const int len,
|
||||
int perLine
|
||||
) {
|
||||
// Silently ignore silly per-line values.
|
||||
|
||||
if (perLine < 4 || perLine > 64) perLine = 16;
|
||||
|
||||
int i;
|
||||
unsigned char buff[perLine+1];
|
||||
const unsigned char * pc = (const unsigned char *)addr;
|
||||
|
||||
// Output description if given.
|
||||
|
||||
if (desc != NULL) fprintf (stderr, "%s:\n", desc);
|
||||
|
||||
// Length checks.
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(stderr, " ZERO LENGTH\n");
|
||||
return;
|
||||
}
|
||||
if (len < 0) {
|
||||
fprintf(stderr, " NEGATIVE LENGTH: %d\n", len);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process every byte in the data.
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
// Multiple of perLine means new or first line (with line offset).
|
||||
|
||||
if ((i % perLine) == 0) {
|
||||
// Only print previous-line ASCII buffer for lines beyond first.
|
||||
|
||||
if (i != 0) fprintf (stderr, " %s\n", buff);
|
||||
|
||||
// Output the offset of current line.
|
||||
DWORD be_serial = htonl(serial);
|
||||
fprintf(stderr, "Disk serial (hex): %08lx\n", serial);
|
||||
|
||||
fprintf (stderr, " %04x ", i);
|
||||
}
|
||||
|
||||
// Now the hex code for the specific character.
|
||||
|
||||
fprintf (stderr, " %02x", pc[i]);
|
||||
|
||||
// And buffer a printable ASCII character for later.
|
||||
|
||||
if ((pc[i] < 0x20) || (pc[i] > 0x7e)) // isprint() may be better.
|
||||
buff[i % perLine] = '.';
|
||||
else
|
||||
buff[i % perLine] = pc[i];
|
||||
buff[(i % perLine) + 1] = '\0';
|
||||
}
|
||||
|
||||
// Pad out last line if not exactly perLine characters.
|
||||
|
||||
while ((i % perLine) != 0) {
|
||||
fprintf (stderr, " ");
|
||||
i++;
|
||||
}
|
||||
|
||||
// And print the final ASCII buffer.
|
||||
|
||||
fprintf (stderr, " %s\n", buff);
|
||||
}
|
||||
#endif
|
||||
|
||||
int get_serial() {
|
||||
DWORD serial = 0;
|
||||
int retval = GetVolumeInformation("c:\\\\", NULL, 0, &serial, NULL, NULL, NULL, 0);
|
||||
if (retval == 0) {
|
||||
fprintf(stderr, "Error with GetVolumeInformation: %d\n", GetLastError());
|
||||
return 0;
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
// Get CPUID vendor string
|
||||
union CPUIDVendor cpu_vendor;
|
||||
if (__get_cpuid(0, &eax, &cpu_vendor.reg[0], &cpu_vendor.reg[2], &cpu_vendor.reg[1]) == 0) {
|
||||
fprintf(stderr, "Error: cpuid(0) not supported");
|
||||
return 1;
|
||||
}
|
||||
return serial;
|
||||
}
|
||||
|
||||
int main() {
|
||||
char * var_data = "X_DECRYPT_DATA";
|
||||
char * var_entropy = "X_DECRYPT_ENTROPY";
|
||||
|
||||
char * data_hex = getenv(var_data);
|
||||
char * entropy_hex = getenv(var_entropy);
|
||||
|
||||
if (data_hex == NULL || entropy_hex == NULL) {
|
||||
fputs("PROGOUTPUT:-1", stdout);
|
||||
exit(-1);
|
||||
cpu_vendor.vendor[12] = '\0';
|
||||
fprintf(stderr, "CPUID Vendor: %s\n", cpu_vendor.vendor);
|
||||
// Get CPUID "signature" (eax of CPUID(1))
|
||||
unsigned int signature;
|
||||
if (__get_cpuid(1, &signature, &ebx, &ecx, &edx) == 0) {
|
||||
fprintf(stderr, "Error: cpuid(1) not supported");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * data_bytes = malloc((strlen(data_hex) / 2));
|
||||
char * entropy_bytes = malloc((strlen(entropy_hex) / 2));
|
||||
|
||||
if (data_bytes == NULL || entropy_bytes == NULL) {
|
||||
fputs("PROGOUTPUT:-2", stdout);
|
||||
exit(-2);
|
||||
unsigned int be_signature = htonl(signature);
|
||||
fprintf(stderr, "CPUID Signature (hex): %08x\n", signature);
|
||||
|
||||
|
||||
// Get windows user
|
||||
#define USERBUFSIZE 512
|
||||
TCHAR user[USERBUFSIZE];
|
||||
memset(&user, 0, sizeof(user)); // GetUserName only sets bytes as needed for length of username, but we need null bytes to fill the rest
|
||||
DWORD bufsize = USERBUFSIZE ;
|
||||
if (GetUserName(user, &bufsize) == 0) {
|
||||
DWORD err = GetLastError();
|
||||
fprintf(stderr, "Error with GetUserName: %ld\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
hex2bin(data_hex, data_bytes);
|
||||
hex2bin(entropy_hex, entropy_bytes);
|
||||
|
||||
#ifdef DEBUG
|
||||
hexDump("data", data_bytes, strlen(data_hex)/2, 16);
|
||||
hexDump("entropy", entropy_bytes, strlen(entropy_hex)/2, 16);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
DATA_BLOB input_data;
|
||||
DATA_BLOB entropy_data;
|
||||
|
||||
|
||||
DATA_BLOB output_data;
|
||||
|
||||
input_data.pbData = data_bytes;
|
||||
input_data.cbData = strlen(data_hex)/2;
|
||||
|
||||
entropy_data.pbData = entropy_bytes;
|
||||
entropy_data.cbData = strlen(entropy_hex)/2;
|
||||
|
||||
|
||||
int ret = CryptUnprotectData(
|
||||
&input_data,
|
||||
NULL,
|
||||
&entropy_data,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
&output_data);
|
||||
|
||||
|
||||
|
||||
if (ret) {
|
||||
if (output_data.cbData != 16) {
|
||||
printf("PROGOUTPUT:-5:%d", output_data.cbData);
|
||||
exit(-5);
|
||||
fprintf(stderr, "Username: %s\n", user);
|
||||
|
||||
|
||||
// Get Encrypted adobe key
|
||||
#define KEYBUFSIZE 180 // As measured
|
||||
BYTE key[KEYBUFSIZE];
|
||||
DWORD regkeysize = KEYBUFSIZE;
|
||||
LSTATUS retval = RegGetValue(HKEY_CURRENT_USER, "Software\\Adobe\\Adept\\Device", "key", RRF_RT_REG_BINARY, NULL, &key, ®keysize);
|
||||
if (retval != ERROR_SUCCESS) {
|
||||
fprintf(stderr, "Error with RegGetValue: %ld\n", retval);
|
||||
fprintf(stderr, "regkeysize: %ld\n", regkeysize);
|
||||
return retval;
|
||||
}
|
||||
// Success! Return decrypted data
|
||||
fputs("PROGOUTPUT:0:", stdout);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02x", output_data.pbData[i]);
|
||||
fprintf(stderr, "Encrypted key (hex): ");
|
||||
for (size_t i = 0; i < KEYBUFSIZE; i++ )
|
||||
{
|
||||
fprintf(stderr, "%02x", key[i]);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
else {
|
||||
|
||||
// Apparently Wine has issues with the volume serial code sometimes
|
||||
// so the code on the Linux side detects the wrong serial number.
|
||||
// Thus, if the decryption fails, we read the serial number that Wine
|
||||
// (and ADE) sees back to the Linux side for another attempt.
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
int err = GetLastError();
|
||||
|
||||
printf("PROGOUTPUT:-4:%d:%08x", err, get_serial());
|
||||
// Assemble "entropy" (passphrase) for key
|
||||
struct EncEntropy entropy;
|
||||
memcpy(&entropy.serial, &be_serial, sizeof(entropy.serial));
|
||||
memcpy(&entropy.vendor, &cpu_vendor.vendor, sizeof(entropy.vendor));
|
||||
memcpy(&entropy.signature, ((char*)(&be_signature))+1, sizeof(entropy.signature)); // Only the last 3 bytes are needed, hence the +1 ptr
|
||||
memcpy(&entropy.user, &user, sizeof(entropy.user));
|
||||
|
||||
exit(-4);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// Print entropy byte by byte in hex
|
||||
fprintf(stderr, "Entropy: ");
|
||||
for (size_t i = 0; i < sizeof(entropy); i++ )
|
||||
{
|
||||
fprintf(stderr, "%02x", ((unsigned char*)&entropy)[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
|
||||
// Run decryption API
|
||||
DATA_BLOB ciphertext_data, entropy_data, plaintext_data;
|
||||
ciphertext_data.pbData = key;
|
||||
ciphertext_data.cbData = sizeof(key);
|
||||
entropy_data.pbData = (BYTE*)(&entropy);
|
||||
entropy_data.cbData = sizeof(entropy);
|
||||
if (CryptUnprotectData(&ciphertext_data, NULL, &entropy_data, NULL, NULL, 0, &plaintext_data) != TRUE) {
|
||||
DWORD err = GetLastError();
|
||||
fprintf(stderr, "Error with CryptUnprotectData: %ld\n", err);
|
||||
return err;
|
||||
}
|
||||
fprintf(stderr, "Decrypted key length: %lu\n", plaintext_data.cbData);
|
||||
|
||||
// Print decrypted key to stdout
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02x", plaintext_data.pbData[i]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue