#include <stdint.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#define BUFFER_SIZE 64
// KEY: [0-9]{4}-[0-9]{4}-[0-9A-Z]{6}
#define KEY “1234-4321-123456”
/**
- [LICENSE_TYPE]
- Professional: 0 1 8 9
- Trial: 2 3 6 7
- Student: 4 5
- CDF Player: 10 11
- CDF Player Trial: 12 13
*/
#define LICENSE_TYPE “1”
/**
- [INIT_HASH]
- Mathematica 11.0.1: 0x25DB
- Mathematica 11.1: 0x42DD 0x29C2
- Mathematica 11.2: 0x6A91 0x29C2
- Mathematica 11.3: 0xA439 0x29F8
- Mathematica Other: 0xA68B 0xE4A8 0x2FDB 0xD227 0xDB75 0xEE71 0x44F1 0x0D00 0x72C4 0x8330 0x81DD 0x47C5 0xB4D3 0xAB0B 0x6188 0xBF47 0x1330 0xF536 0xA5CE 0x755E 0x1361
- SystemModeler 5.0: 0x8330 0x81DD 0x47C5 0xB4D3 0xAB0B 0x6188 0xBF47 0x1330
- SystemModeler 5.1.0: 0x81DD
- To find the hash for future releases,
- look up for 85 C0 7E 0E 39 3C 8D in WolframEngine.dll (32-bits),
- get the following oprand (such as 0x11D9D790, MIND THE ENDIAN),
- go to the address
- (Do a conversion from VA to File Offset,
-
(virtual address found) + (offset of .text section) - (virtual address of .text section) - (image base) = (file offset).
-
Using Address Converter in CFF Explorer is recommended),
- there are the accepted hash values (MIND THE ENDIAN as the same).
- For who want to DIY, the easiest way to find password checking call is search for 0x105C3 and etc.
*/
#define INIT_HASH 0x29F8
#define HASH_MAGIC_1 0x105C3
#define HASH_MAGIC_2 0x1064B
#define GOOD_HASH 0xA5B6
static uint_fast8_t getDigit(uint_fast32_t number, uint_fast8_t digit){
return (uint_fast8_t) ((number / (uint_fast32_t)pow(10, digit - 1)) % 10);
}
// inverse of privHash: nextHash(privHash(x, y, c), c, y, c) == x
static uint_fast32_t nextHash(uint_fast32_t hash, uint_fast8_t byte, uint_fast32_t magic) {
for (uint_fast8_t bitIndex = 0; bitIndex <= 7; bitIndex++) {
uint_fast8_t bit = (byte >> bitIndex) & 1;
if (bit + ((hash - bit) & ~1) == hash) {
hash = (hash - bit) >> 1;
} else {
hash = ((magic - bit) ^ hash) >> 1;
}
}
return hash;
}
/*
static uint_fast32_t privHash(uint_fast32_t hash, uint_fast8_t byte, uint_fast32_t magic) {
for (uint_fast8_t bitIndex = 7; bitIndex >= 0; bitIndex–) {
uint_fast8_t bit = (byte >> bitIndex) & 1;
uint_fast32_t temp = (hash << 1) + bit;
if (hash & 0x8000) {
temp ^= magic;
}
hash = temp;
}
return hash;
}
*/
void genPass(char* string, uint_fast8_t length) {
uint_fast32_t hash = INIT_HASH;
for (int byteIndex = length - 1; byteIndex >= 0; byteIndex--) {
hash = nextHash(hash, string[byteIndex], HASH_MAGIC_1);
}
uint_fast32_t n1 = 0;
while (nextHash(nextHash(hash, n1 & 0xFF, HASH_MAGIC_1), n1 >> 8, HASH_MAGIC_1) != GOOD_HASH) {
if (++n1 >= 0xFFFF) {
printf("Failed to find a key!");
return;
}
}
n1 = (uint_fast32_t) floor(((n1 + 0x72FA) & 0xFFFF) * 99999.0 / 0xFFFF);
uint_fast32_t temp = (n1/1000*1000) + n1%1000/100 + n1%100*10;
temp = (uint_fast32_t) ceil((temp / 99999.0) * 0xFFFF);
temp = nextHash(nextHash(0, temp & 0xFF, HASH_MAGIC_2), temp >> 8, HASH_MAGIC_2);
for (int byteIndex = length - 1; byteIndex >= 0; byteIndex--) {
temp = nextHash(temp, (uint_fast8_t) string[byteIndex], HASH_MAGIC_2);
}
uint_fast16_t n2 = 0;
while (nextHash(nextHash(temp, n2 & 0xFF, HASH_MAGIC_2), n2 >> 8, HASH_MAGIC_2) != GOOD_HASH) {
if (++n2 >= 0xFFFF) {
printf("Failed to find a key!");
return;
}
}
n2 = (uint_fast16_t) floor((n2 & 0xFFFF) * 99999.0 / 0xFFFF);
printf("%u%u%u%u-%u%u%u-%u%u%u::1",
getDigit(n2,2),getDigit(n1,2),getDigit(n1,4),getDigit(n1,5),
getDigit(n2,1),getDigit(n1,3),getDigit(n2,5),
getDigit(n2,3),getDigit(n1,1),getDigit(n2,4)
);
}
int main(){
char buffer[BUFFER_SIZE];
int offset = 0;
scanf("%s%n", buffer, &offset); // Input MathID here
strcpy(buffer+offset, “$” LICENSE_TYPE “&” KEY);
genPass(buffer, (uint_fast8_t) strlen(buffer));
return 0;
}