17#include <CoreFoundation/CoreFoundation.h>
18#include <IOKit/IOKitLib.h>
27static CFTypeRef get_ioreg_entry(
const char *path, CFStringRef name, CFTypeID
type) {
28 CFTypeRef
value = NULL;
29 io_registry_entry_t entry = IORegistryEntryFromPath(kIOMasterPortDefault, path);
31 value = IORegistryEntryCreateCFProperty(entry, name, kCFAllocatorDefault, 0);
36 printf(
"%s in %s has wrong type!\n", CFStringGetCStringPtr(name, kCFStringEncodingMacRoman), path);
39 printf(
"Failed to find to %s in %s!\n", CFStringGetCStringPtr(name, kCFStringEncodingMacRoman), path);
41 IOObjectRelease(entry);
43 printf(
"Failed to connect to %s!\n", path);
50static int32_t alpha_to_value(
char c,
int32_t *conv,
const char *blacklist) {
51 if (c <
'A' || c >
'Z')
54 while (blacklist && *blacklist !=
'\0')
55 if (*blacklist++ == c)
63 if (c >=
'0' && c <=
'9')
64 return (c -
'0') * mul;
65 if (c >=
'A' && c <=
'Z') {
66 int32_t tmp = alpha_to_value(c, AppleTblBase34, AppleBase34Blacklist);
91 while (
value > 10000000)
96 size_t offset =
sizeof(buffer);
98 buffer[--offset] =
'\0';
100 buffer[--offset] = AppleBase34Reverse[
value % 34];
101 }
while (
value /= 34);
103 strncpy(dst, &buffer[offset], sz-1);
109static bool verify_mlb_checksum(
const char *mlb,
size_t len) {
110 const char alphabet[] =
"0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
112 for (
size_t i = 0; i < len; ++i) {
113 for (
size_t j = 0; j <=
sizeof (alphabet); ++j) {
114 if (j ==
sizeof (alphabet))
116 if (mlb[i] == alphabet[j]) {
117 checksum += (((i & 1) == (len & 1)) * 2 + 1) * j;
122 return checksum % (
sizeof(alphabet) - 1) == 0;
125static int32_t get_current_model(
void) {
127 CFDataRef model = get_ioreg_entry(
"IODeviceTree:/", CFSTR(
"model"), CFDataGetTypeID());
129 const char *cptr = (
const char *)CFDataGetBytePtr(model);
130 size_t len = (
size_t)CFDataGetLength(model);
133 if (!strncmp(ApplePlatformData[i].productName, cptr, len))
145 uint32_t *years = &AppleModelYear[model][0];
151 printf(
"%d, ", years[num]);
153 printf(
"%d\n", years[num]);
157 if (ApplePreferredModelYear[model] > 0)
158 return ApplePreferredModelYear[model];
163static const char *get_model_code(
AppleModel model,
bool print) {
164 const char **codes = &AppleModelCode[model][0];
169 printf(
"%s, ", codes[i]);
171 printf(
"%s\n", codes[i]);
178static const char *get_board_code(
AppleModel model,
bool print) {
179 const char **codes = &AppleBoardCode[model][0];
184 printf(
"%s, ", codes[i]);
186 printf(
"%s\n", codes[i]);
193static bool get_serial_info(
const char *serial,
SERIALINFO *info,
bool print) {
200 size_t serial_len = strlen(serial);
210 for (
size_t i = 0; i < serial_len; i++) {
211 if (!((serial[i] >=
'A' && serial[i] <=
'Z' && serial[i] !=
'O' && serial[i] !=
'I') ||
212 (serial[i] >=
'0' && serial[i] <=
'9'))) {
213 printf(
"WARN: Invalid symbol '%c' in serial!\n", serial[i]);
218 size_t model_len = 0;
224 const char *
code = AppleModelCode[i][j];
227 model_len = strlen(
code);
233 && !strncmp(serial + serial_len - model_len,
code, model_len)) {
244 const char *
code = AppleModelDesc[i].code;
245 model_len = strlen(
code);
249 && !strncmp(serial + serial_len - model_len,
code, model_len)) {
261 strncpy(info->
model, serial + serial_len - model_len, model_len);
262 info->
model[model_len] =
'\0';
273 for (
size_t i = 0; i <
ARRAY_SIZE(AppleLocations); i++) {
274 if (!strcmp(info->
country, AppleLocations[i])) {
283 for (
size_t i = 0; i <
ARRAY_SIZE(AppleLegacyLocations); i++) {
284 if (!strcmp(info->
country, AppleLegacyLocations[i])) {
294 info->
year[0] = *serial++;
295 info->
week[0] = *serial++;
298 info->
decodedYear = alpha_to_value(info->
year[0], AppleTblYear, AppleYearBlacklist);
308 printf(
"WARN: Invalid year symbol '%c'!\n", info->
year[0]);
312 if (info->
week[0] >
'0' && info->
week[0] <=
'9')
315 info->
decodedWeek = alpha_to_value(info->
week[0], AppleTblWeek, AppleWeekBlacklist);
318 info->
decodedWeek += alpha_to_value(info->
year[0], AppleTblWeekAdd, NULL);
320 printf(
"WARN: Invalid week symbol '%c'!\n", info->
week[0]);
324 info->
year[0] = *serial++;
325 info->
week[0] = *serial++;
326 info->
week[1] = *serial++;
329 if (info->
year[0] >=
'0' && info->
year[0] <=
'2') {
331 }
else if (info->
year[0] >=
'3' && info->
year[0] <=
'9') {
335 printf(
"WARN: Invalid year symbol '%c'!\n", info->
year[0]);
339 for (
int32_t i = 0; i < 2; i++) {
340 if (info->
week[i] >=
'0' && info->
week[i] <=
'9') {
344 printf(
"WARN: Invalid week symbol '%c'!\n", info->
week[i]);
362 printf(
"WARN: Invalid year %d for model %s\n", info->
decodedYear, ApplePlatformData[info->
modelIndex].productName);
370 info->
line[i] = *serial++;
371 int32_t tmp = base34_to_value(info->
line[i], mul[i]);
375 printf(
"WARN: Invalid line symbol '%c'!\n", info->
line[i]);
385 printf(
"%14s: %4s - ",
"Country", info->
country);
391 puts(
"Unknown, please report!");
401 if (mktime(&startd) >= 0) {
402 printf(
" (%02d.%02d.%04d", startd.tm_mday, startd.tm_mon+1, startd.tm_year+1900);
403 if (info->
decodedWeek == 53 && startd.tm_mday != 31) {
404 printf(
"-31.12.%04d", startd.tm_year+1900);
408 printf(
"-%02d.%02d.%04d", startd.tm_mday, startd.tm_mon+1, startd.tm_year+1900);
415 printf(
"%14s: %4s - %d (copy %d)\n",
"Line", info->
line, info->
decodedLine,
417 printf(
"%14s: %4s - %s\n",
"Model", info->
model, info->
modelIndex >= 0 ?
418 ApplePlatformData[info->
modelIndex].productName :
"Unknown");
419 printf(
"%14s: %s\n",
"SystemModel", info->
appleModel != NULL ? info->
appleModel :
"Unknown, please report!");
420 printf(
"%14s: %s\n",
"Valid", info->
valid ?
"Possibly" :
"Unlikely");
428 printf(
"ERROR: Unable to determine model!\n");
432 if (info->
model[0] ==
'\0') {
437 size_t country_len = strlen(info->
country);
438 if (country_len == 0) {
444 strncpy(info->
country, &ApplePlatformData[info->
modelIndex].serialNumber[0], country_len);
445 info->
country[country_len] =
'\0';
475 size_t base_new_year = 2010;
477 base_new_year = 2020;
498 info->
line[0] = AppleBase34Reverse[rmin];
499 info->
line[1] = AppleBase34Reverse[(info->
decodedLine - rmin * 68) / 34];
500 info->
line[2] = AppleBase34Reverse[(info->
decodedLine - rmin * 68) % 34];
505static void get_mlb(
SERIALINFO *info,
char *dst,
size_t sz) {
508 printf(
"WARN: Unknown model, assuming default!\n");
520 char syear = info->
year[0];
521 char sweek = info->
week[0];
523 const char srcyear[] =
"CDFGHJKLMNPQRSTVWXYZ";
524 const char dstyear[] =
"00112233445566778899";
525 for (
size_t i = 0; i <
ARRAY_SIZE(srcyear)-1; i++) {
526 if (syear == srcyear[i]) {
527 year = (
uint32_t)(dstyear[i] -
'0');
532 const char overrides[] =
"DGJLNQSVXZ";
533 for (
size_t i = 0; i <
ARRAY_SIZE(overrides)-1; i++) {
534 if (syear == overrides[i]) {
540 const char srcweek[] =
"123456789CDFGHJKLMNPQRSTVWXYZ";
541 for (
size_t i = 0; i <
ARRAY_SIZE(srcweek)-1; i++) {
542 if (sweek == srcweek[i]) {
551 snprintf(dst, sz,
"FAIL-ZERO-%c", sweek);
574 const char *board = get_board_code(info->
modelIndex,
false);
580 const char *board = get_board_code(info->
modelIndex,
false);
583 snprintf(dst, sz,
"%s%d%02d%s%s%s%s", info->
country, year, week, part1, part2, board, part3);
585 }
while (!verify_mlb_checksum(dst, strlen(dst)));
588static void get_system_info(
void) {
590 CFDataRef model = get_ioreg_entry(
"IODeviceTree:/", CFSTR(
"model"), CFDataGetTypeID());
591 CFDataRef board = get_ioreg_entry(
"IODeviceTree:/", CFSTR(
"board-id"), CFDataGetTypeID());
592 CFDataRef efiver = get_ioreg_entry(
"IODeviceTree:/rom", CFSTR(
"version"), CFDataGetTypeID());
593 CFStringRef serial = get_ioreg_entry(
"IODeviceTree:/", CFSTR(
"IOPlatformSerialNumber"), CFStringGetTypeID());
594 CFStringRef hwuuid = get_ioreg_entry(
"IODeviceTree:/", CFSTR(
"IOPlatformUUID"), CFStringGetTypeID());
595 CFDataRef smuuid = get_ioreg_entry(
"IODeviceTree:/efi/platform", CFSTR(
"system-id"), CFDataGetTypeID());
596 CFDataRef rom = get_ioreg_entry(
"IODeviceTree:/options", CFSTR(
"4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:ROM"), CFDataGetTypeID());
597 CFDataRef mlb = get_ioreg_entry(
"IODeviceTree:/options", CFSTR(
"4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14:MLB"), CFDataGetTypeID());
599 CFDataRef pwr[5] = {0};
600 CFStringRef pwrname[5] = {
604 CFSTR(
"oycqAZloTNDm"),
605 CFSTR(
"abKPld1EcMni"),
609 pwr[i] = get_ioreg_entry(
"IOPower:/", pwrname[i], CFDataGetTypeID());
612 printf(
"%14s: %.*s\n",
"Model", (
int)CFDataGetLength(model), CFDataGetBytePtr(model));
617 printf(
"%14s: %.*s\n",
"Board ID", (
int)CFDataGetLength(board), CFDataGetBytePtr(board));
622 printf(
"%14s: %.*s\n",
"FW Version", (
int)CFDataGetLength(efiver), CFDataGetBytePtr(efiver));
627 printf(
"%14s: %s\n",
"Hardware UUID", CFStringGetCStringPtr(hwuuid, kCFStringEncodingMacRoman));
634 const char *cstr = CFStringGetCStringPtr(serial, kCFStringEncodingMacRoman);
635 printf(
"%14s: %s\n",
"Serial Number", cstr);
637 get_serial_info(cstr, &info,
true);
643 if (CFDataGetLength(smuuid) ==
SZUUID) {
644 const uint8_t *p = CFDataGetBytePtr(smuuid);
651 if (CFDataGetLength(rom) == 6) {
652 const uint8_t *p = CFDataGetBytePtr(rom);
653 printf(
"%14s: %02X%02X%02X%02X%02X%02X\n",
"ROM", p[0], p[1], p[2], p[3], p[4], p[5]);
659 printf(
"%14s: %.*s\n",
"MLB", (
int)CFDataGetLength(mlb), CFDataGetBytePtr(mlb));
660 if (!verify_mlb_checksum((
const char *)CFDataGetBytePtr(mlb), CFDataGetLength(mlb)))
661 printf(
"WARN: Invalid MLB checksum!\n");
667 for (
size_t i = 0; i <
ARRAY_SIZE(pwr); i++) {
669 printf(
"%14s: ", CFStringGetCStringPtr(pwrname[i], kCFStringEncodingMacRoman));
670 const uint8_t *p = CFDataGetBytePtr(pwr[i]);
671 CFIndex sz = CFDataGetLength(pwr[i]);
672 for (CFIndex j = 0; j < sz; j++)
673 printf(
"%02X", p[j]);
682 printf(
"Version %s. Use -h argument to see usage options.\n",
PROGRAM_VERSION);
685static int usage(
const char *app) {
688 " --help (-h) show this help\n"
689 " --version (-v) show program version\n"
690 " --deriv <serial> (-d) generate all derivative serials\n"
691 " --generate (-g) generate serial for current model\n"
692 " --generate-all (-a) generate serial for all models\n"
693 " --info <serial> (-i) decode serial information\n"
694 " --verify <mlb> verify MLB checksum\n"
695 " --list (-l) list known mac models\n"
696 " --list-products (-lp) list known product codes\n"
697 " --mlb <serial> generate MLB based on serial\n"
698 " --sys (-s) get system info\n\n"
700 " --model <model> (-m) mac model used for generation\n"
701 " --num <num> (-n) number of generated pairs\n"
702 " --year <year> (-y) year used for generation\n"
703 " --week <week> (-w) week used for generation\n"
704 " --country <loc> (-c) country location used for generation\n"
705 " --copy <copy> (-o) production copy index\n"
706 " --line <line> (-e) production line\n"
707 " --platform <ppp> (-p) platform code used for generation\n\n", app);
712int main(
int argc,
char *argv[]) {
714 const char *passed_serial = NULL;
724 for (
int i = 1; i < argc; i++) {
725 if (!strcmp(argv[i],
"-h") || !strcmp(argv[i],
"--help")) {
728 }
else if (!strcmp(argv[i],
"-v") || !strcmp(argv[i],
"--version")) {
731 }
else if (!strcmp(argv[i],
"-g") || !strcmp(argv[i],
"--generate")) {
733 }
else if (!strcmp(argv[i],
"-a") || !strcmp(argv[i],
"--generate-all")) {
735 }
else if (!strcmp(argv[i],
"-i") || !strcmp(argv[i],
"--info")) {
736 if (++i == argc)
return usage(argv[0]);
738 passed_serial = argv[i];
739 }
else if (!strcmp(argv[i],
"--verify")) {
740 if (++i == argc)
return usage(argv[0]);
742 passed_serial = argv[i];
743 }
else if (!strcmp(argv[i],
"-l") || !strcmp(argv[i],
"--list")) {
745 }
else if (!strcmp(argv[i],
"-lp") || !strcmp(argv[i],
"--list-products")) {
747 }
else if (!strcmp(argv[i],
"-mlb") || !strcmp(argv[i],
"--mlb")) {
749 if (++i == argc)
return usage(argv[0]);
751 passed_serial = argv[i];
752 }
else if (!strcmp(argv[i],
"-d") || !strcmp(argv[i],
"--deriv")) {
753 if (++i == argc)
return usage(argv[0]);
755 passed_serial = argv[i];
756 }
else if (!strcmp(argv[i],
"-s") || !strcmp(argv[i],
"--sys")) {
758 }
else if (!strcmp(argv[i],
"-m") || !strcmp(argv[i],
"--model")) {
760 if (++i == argc)
return usage(argv[0]);
761 if (argv[i][0] >=
'0' && argv[i][0] <=
'9') {
765 if (!strcmp(argv[i], ApplePlatformData[j].productName)) {
775 }
else if (!strcmp(argv[i],
"-n") || !strcmp(argv[i],
"--num")) {
777 if (++i == argc)
return usage(argv[0]);
778 limit = atoi(argv[i]);
780 printf(
"Cannot generate %d pairs!\n", limit);
783 }
else if (!strcmp(argv[i],
"-y") || !strcmp(argv[i],
"--year")) {
785 if (++i == argc)
return usage(argv[0]);
791 }
else if (!strcmp(argv[i],
"-w") || !strcmp(argv[i],
"--week")) {
793 if (++i == argc)
return usage(argv[0]);
799 }
else if (!strcmp(argv[i],
"-c") || !strcmp(argv[i],
"--country")) {
801 if (++i == argc)
return usage(argv[0]);
802 size_t len = strlen(argv[i]);
808 }
else if (!strcmp(argv[i],
"-p") || !strcmp(argv[i],
"--platform")) {
810 if (++i == argc)
return usage(argv[0]);
811 size_t len = strlen(argv[i]);
817 }
else if (!strcmp(argv[i],
"-o") || !strcmp(argv[i],
"--copy")) {
819 if (++i == argc)
return usage(argv[0]);
825 }
else if (!strcmp(argv[i],
"-e") || !strcmp(argv[i],
"--line")) {
827 if (++i == argc)
return usage(argv[0]);
839 get_serial_info(passed_serial, &info,
true);
841 size_t len = strlen(passed_serial);
842 if (len == 13 || len == 17) {
843 printf(
"Valid MLB length: %s\n", len == 13 ?
"legacy" :
"modern");
845 printf(
"WARN: Invalid MLB length: %u\n", (
unsigned) len);
847 if (verify_mlb_checksum(passed_serial, strlen(passed_serial))) {
848 printf(
"Valid MLB checksum.\n");
850 printf(
"WARN: Invalid MLB checksum!\n");
853 printf(
"Available models:\n");
855 printf(
"%14s: %s\n",
"Model", ApplePlatformData[j].productName);
856 printf(
"%14s: ",
"Prod years");
858 printf(
"%14s: %s\n",
"Base Serial", ApplePlatformData[j].serialNumber);
859 printf(
"%14s: ",
"Model codes");
861 printf(
"%14s: ",
"Board codes");
865 printf(
"Available legacy location codes:\n");
866 for (
size_t j = 0; j <
ARRAY_SIZE(AppleLegacyLocations); j++)
867 printf(
" - %s, %s\n", AppleLegacyLocations[j], AppleLegacyLocationNames[j]);
868 printf(
"\nAvailable new location codes:\n");
869 for (
size_t j = 0; j <
ARRAY_SIZE(AppleLocations); j++)
870 printf(
" - %s, %s\n", AppleLocations[j], AppleLocationNames[j]);
873 for (
size_t j = 0; j <
ARRAY_SIZE(AppleModelDesc); j++)
874 printf(
"%4s - %s\n", AppleModelDesc[j].
code, AppleModelDesc[j].name);
876 if (get_serial_info(passed_serial, &info,
false)) {
884 for (
int32_t i = 0; i < limit; i++) {
886 if (get_serial(&tmp)) {
895 for (
int32_t j = 0; j < limit; j++) {
897 if (get_serial(&tmp)) {
900 printf(
"%14s | %s%s%s%s%s | %s\n", ApplePlatformData[info.
modelIndex].productName,
906 if (get_serial_info(passed_serial, &info,
false)) {
908 for (
int32_t k = 0; k < 34; k++) {
912 printf(
"%s%s%s%c%c%c%s - copy %d\n", info.
country, info.
year, info.
week, AppleBase34Reverse[k],
913 AppleBase34Reverse[rem / 34], AppleBase34Reverse[rem % 34], info.
model, k - rmin + 1);
#define ARRAY_SIZE(Array)
uint32_t pseudo_random(void)
uint32_t pseudo_random_between(uint32_t from, uint32_t to)
#define memset(ptr, c, len)
@ MODE_GENERATE_DERIVATIVES
#define SERIAL_LINE_REPR_MAX
#define SERIAL_YEAR_OLD_MAX
#define MODEL_CODE_OLD_LEN
#define SERIAL_YEAR_NEW_MIN
#define SERIAL_YEAR_OLD_MIN
#define MODEL_CODE_NEW_LEN
#define SERIAL_YEAR_NEW_MAX
#define SERIAL_YEAR_NEW_MID
#define APPLE_BOARD_CODE_MAX
#define APPLE_MODEL_YEAR_MAX
#define APPLE_MODEL_CODE_MAX