+/* Windows and Apple2 ransomware.
+ */
+static struct bsod_state *apple2ransomware (Display *, Window);
+
+static struct bsod_state *
+windows_ransomware (Display *dpy, Window window)
+{
+ struct bsod_state *bst = make_bsod_state (dpy, window,
+ "ransomware", "Ransomware");
+ char buf[1024];
+
+ int pix_w = 0, pix_h = 0;
+ Pixmap mask = 0;
+ Pixmap pixmap = image_data_to_pixmap (dpy, window,
+ ransomware_png, sizeof(ransomware_png),
+ &pix_w, &pix_h, &mask);
+ int i, n = 0;
+
+ /* Don't start the countdown from the start, advance the deadline by 3 - 30
+ hours */
+ int advance_deadline = (random() % 97200) + 10800;
+
+ time_t now = time(NULL);
+ const time_t stage1_deadline = now + 259200 - advance_deadline; /* 3 days */
+ const time_t stage2_deadline = now + 604800 - advance_deadline; /* 7 days */
+ char stage1_deadline_str[25], stage2_deadline_str[25];
+ char countdown_str[16];
+ int countdown_d, countdown_h, countdown_m, countdown_s, countdown_r;
+ int line_height = bst->font->ascent + bst->font->descent;
+ int line_height1 = bst->fontA->ascent + bst->fontA->descent;
+
+ const char *currencies[] = {
+ "Blitcoin",
+ "Bitcorn",
+ "Buttcorn",
+ "clicks",
+ "clicks",
+ "Ass Pennies",
+ "Ass Pennies",
+ "Dollary-doos",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "gift certificates",
+ "Creepto-Currency",
+ "secret sauce",
+ "Tribbles",
+ };
+
+ const char *currency = currencies[random() % countof(currencies)];
+
+ const char *header_quips[] = {
+ "Oops, your screens have been encrypted!",
+ "Oops, your screens have been encrypted!",
+ "Oops, your screens have been encrypted!",
+ "Oops, your screens have been encrypted!",
+ "Oops, your screen have encrypted!",
+ "Oops, you're screens have been encrypted!",
+ "Oops, your screens have been encrupted!",
+ "Oops, your screens have been encrumpet!",
+ "Oops, your screens have been encrusted!",
+ "If you don't pay this ransom, then you are a theif!",
+ "Your screen was subject to the laws of mathomatics!",
+ "Oops, your screen was shaved by Occam's Razor!",
+ "Oops, your screen was perturbated by Langford's Basilisk!",
+ "Your screen is now stored as Snapchat messages!",
+ "Oops, your screen is now stored on Betamax!",
+ "Oops, your screen is now in the clown!",
+ "Oops, your screen has been deprecated!",
+ "Oops, you're screen was seized by the FBI!",
+ "All your screen was shared with your coworkers!",
+ "All your screen are belong to us.",
+ "Well actually, your screen isn't needed anymore.",
+ "u just got popped with some 0day shit!!",
+ "M'lady,",
+ };
+
+ const char *header_quip = header_quips[random() % countof(header_quips)];
+
+ /* You got this because... */
+ const char *excuse_quips[] = {
+ "all human actions are equivalent and all are on principle doomed "
+ "to failure",
+ "you hold a diverse portfolio of cryptocurrencies",
+ "you need to get in on ransomware futures at the ground floor",
+ "your flight was overbooked",
+ "you did not apply the security update for bugs NSA keys secret from "
+ "Microsoft in your Windows(R) operating system",
+ "you are bad and you should feel bad",
+ "you used the wifi at defcon",
+ "you lack official Clown Strike[TM] threaty threat technology",
+ };
+
+ const char *excuse_quip = excuse_quips[random() % countof(excuse_quips)];
+
+ /* WELL ACTUALLY, screensavers aren't really nescessary anymore because... */
+ const char *screensaver_quips[] = {
+ "I read it on hacker news",
+ "that's official Debian policy now",
+ "that is the official policy of United Airlines",
+ "they cause global warming",
+ "they lack an eternal struggle",
+ "they lack a vapid dichotomy",
+ "those electrons could be used for gold farming instead",
+ "you can make more money in art exhibitions",
+ };
+
+ const char *screensaver_quip =
+ screensaver_quips[random() % countof(screensaver_quips)];
+
+ const char *lines[] = {
+ "*What Happened To My Computer?\n",
+ "Your important pixels are paintcrypted. All of your documents, photos, ",
+ "videos, databases, icons, dick pics are not accessible because they ",
+ "have been bitblted. Maybe you are looking for a way to get them back, ",
+ "but don't waste your time. Nobody can recover your pixels without our ",
+ "pointer motion clicker services.\n",
+ "\n",
+ "*Can I Recover My Important Dick Pix?\n",
+ "Yes. We guarantee that you can recover them safely and easily. But you ",
+ "not have much time.\n",
+ "You can expose some files for free. Try it now by pressing <The Any ",
+ "Key>.\n",
+ "But if you want to unsave all your screens, then you need to pay. ",
+ "You have only 3 days to click. After that the clicks will double. ",
+ "After 7 days your pixels will be gone forever.\n",
+ "We will have free events for cheapskates who can't pay in 6 months, ",
+ "long after all the pixels are xored.\n",
+ "\n",
+ "*How do I pay?\n",
+ "Payment is accepted in ", "[C]",
+ " only. For more information, press <About ", "[C]", ">.",
+ " Please check the current price of ", "[C]", " and buy some ", "[C]",
+ ". For more information, press <How to buy ", "[C]", ">.\n",
+ "And send the correct amount to the address specified below. After your ",
+ "payment, press <Check Payment>. Best time to check: 4-6am, Mon-Fri.\n",
+ "\n",
+ "*Why Did I Get This?\n",
+ "You got this because ", "[Q]",
+ ". Also you didn't click hard enough and now Tinkerbelle is dead.\n",
+ "\n",
+ "*But Aren't Screensavers Are Necessary?\n",
+ "WELL ACTUALLY, screensavers aren't really nescessary anymore because ",
+ "[S]", ".\n",
+ "\n",
+ "Please file complaints to @POTUS on Twitter.\n",
+ "\n"
+ "\n"
+ "\n"
+ "\n",
+ "*GREETZ TO CRASH OVERRIDE AND ALSO JOEY\n",
+ };
+
+ /* Positions of UI elements. Layout:
+
+ +---------+-+---------------------------------------+
+ | LOGO | | HEADER |
+ | | |---------------------------------------|
+ | | | NOTE TEXT |
+ | DEAD | | |
+ | LINE | | |
+ | TIMERS | | |
+ | | | |
+ | | | |
+ | | | |
+ | | | |
+ | | | |
+ +---------+ | |
+ | LINKS | +---------------------------------------+
+ | LINKS | | FOOTER |
+ +---------+-+---------------------------------------+
+
+ The right side of the UI maximises to available width.
+ The note text maximises to available height.
+ The logo, header and timers are anchored to the top left of the window.
+ The links and footer are anchored to the bottom left of the window.
+ The entire window is a fixed 4:3 scale, with a minimum margin around it.
+ */
+
+ /* main window text */
+ unsigned long fg = bst->fg;
+ unsigned long bg = bst->bg;
+ /* ransom note */
+ unsigned long fg2 = get_pixel_resource (dpy, bst->xgwa.colormap,
+ "ransomware.foreground2",
+ "Ransomware.Foreground");
+ unsigned long bg2 = get_pixel_resource (dpy, bst->xgwa.colormap,
+ "ransomware.background2",
+ "Ransomware.Background");
+ /* buttons */
+ unsigned long fg3 = get_pixel_resource (dpy, bst->xgwa.colormap,
+ "ransomware.foreground3",
+ "Ransomware.Foreground");
+ unsigned long bg3 = get_pixel_resource (dpy, bst->xgwa.colormap,
+ "ransomware.background3",
+ "Ransomware.Background");
+ /* links */
+ unsigned long link = get_pixel_resource (dpy, bst->xgwa.colormap,
+ "ransomware.link",
+ "Ransomware.Foreground");
+ /* headers */
+ unsigned long theader = get_pixel_resource (dpy, bst->xgwa.colormap,
+ "ransomware.timerheader",
+ "Ransomware.Foreground");
+ int left_column_width;
+ int right_column_width;
+ int right_column_height;
+ int stage1_countdown_y, stage2_countdown_y;
+ int margin;
+ int top_height, bottom_height;
+ int x, y;
+
+ if (bst->xgwa.width > 2560) n++; /* Retina displays */
+ for (i = 0; i < n; i++)
+ {
+ pixmap = double_pixmap (dpy, bst->xgwa.visual, bst->xgwa.depth,
+ pixmap, pix_w, pix_h);
+ mask = double_pixmap (dpy, bst->xgwa.visual, 1,
+ mask, pix_w, pix_h);
+ pix_w *= 2;
+ pix_h *= 2;
+ }
+
+ margin = line_height;
+ left_column_width = MAX (pix_w, line_height1 * 8);
+ right_column_width = MIN (line_height * 40,
+ MAX (line_height * 8,
+ bst->xgwa.width - left_column_width
+ - margin*2));
+ top_height = line_height * 2.5;
+ bottom_height = line_height * 6;
+ right_column_height = MIN (line_height * 36,
+ bst->xgwa.height - bottom_height - top_height
+ - line_height);
+
+ if ((bst->xgwa.width / 4) * 3 > bst->xgwa.height)
+ /* Wide screen: keep the big text box at 4:3, centered. */
+ right_column_height = MIN (right_column_height,
+ right_column_width * 4 / 3);
+ else if (right_column_width < line_height * 30)
+ /* Tall but narrow screen: make the text box be full height. */
+ right_column_height = (bst->xgwa.height - bottom_height - top_height
+ - line_height);
+
+ x = (bst->xgwa.width - left_column_width - right_column_width - margin) / 2;
+ y = (bst->xgwa.height - right_column_height - bottom_height) / 2;
+
+ bst->xoff = bst->left_margin = bst->right_margin = 0;
+
+ if (!(random() % 8))
+ return apple2ransomware (dpy, window);
+
+ /* Draw the main red window */
+ BSOD_INVERT (bst);
+ BSOD_RECT (bst, True, 0, 0, bst->xgwa.width, bst->xgwa.height);
+
+ if (pixmap) {
+ bst->pixmap = pixmap;
+ bst->mask = mask;
+ BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h,
+ x + (left_column_width - pix_w) / 2,
+ y);
+ }
+
+ /* Setup deadlines */
+ strftime (stage1_deadline_str, sizeof(stage1_deadline_str),
+ "%m/%d/%Y %H:%M:%S", localtime(&stage1_deadline));
+ strftime (stage2_deadline_str, sizeof(stage1_deadline_str),
+ "%m/%d/%Y %H:%M:%S", localtime(&stage2_deadline));
+
+ BSOD_INVERT (bst);
+ /* Draw header pane */
+ BSOD_FONT (bst, 0);
+
+ BSOD_MARGINS (bst,
+ x + left_column_width + margin,
+ bst->xgwa.width -
+ (x + left_column_width + margin + right_column_width));
+ BSOD_MOVETO (bst, x + left_column_width + margin,
+ y + bst->fontA->ascent);
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_WORD_WRAP (bst);
+ BSOD_TEXT (bst, CENTER, header_quip);
+ BSOD_TRUNCATE (bst);
+
+ /* Draw left-side timers */
+ BSOD_MARGINS (bst, x, bst->xgwa.width - (x + left_column_width));
+ BSOD_MOVETO (bst, x, y + pix_h + line_height);
+ BSOD_FONT (bst, 1);
+
+ BSOD_COLOR (bst, theader, bg);
+ BSOD_TEXT (bst, CENTER, "Payment will be raised on\n");
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_TEXT (bst, CENTER, stage1_deadline_str);
+
+ stage1_countdown_y = y + pix_h + line_height + line_height1 * 3;
+ BSOD_MOVETO (bst, x, stage1_countdown_y - line_height);
+ BSOD_TEXT (bst, CENTER, "Time Left");
+
+ BSOD_COLOR (bst, theader, bg);
+ BSOD_WORD_WRAP (bst);
+ BSOD_TEXT (bst, CENTER, "\n\n\n\nYour pixels will be lost on\n");
+ BSOD_TRUNCATE (bst);
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_TEXT (bst, CENTER, stage2_deadline_str);
+
+ stage2_countdown_y = stage1_countdown_y + line_height1 * 5;
+ BSOD_MOVETO (bst, x, stage2_countdown_y - line_height);
+ BSOD_TEXT (bst, CENTER, "Time Left");
+
+ BSOD_FONT (bst, 1);
+
+ /* Draw links, but skip on small screens */
+ if (right_column_height > 425) {
+ BSOD_MOVETO (bst, x,
+ y + right_column_height + top_height + bottom_height
+ - line_height1 * 5);
+ BSOD_COLOR (bst, link, bg);
+ BSOD_TEXT (bst, LEFT, "\n");
+ BSOD_TEXT (bst, LEFT, "About ");
+ BSOD_TEXT (bst, LEFT, currency);
+ BSOD_TEXT (bst, LEFT, "\n\n"
+ "How to buy ");
+ BSOD_TEXT (bst, LEFT, currency);
+ BSOD_TEXT (bst, LEFT, "\n\n"
+ "Contact us\n");
+ }
+
+ /* Ransom note text area */
+ BSOD_COLOR (bst, bg2, fg2);
+ BSOD_RECT (bst, True,
+ x + left_column_width + margin,
+ y + top_height,
+ right_column_width,
+ right_column_height);
+ BSOD_MOVETO (bst,
+ x + left_column_width + margin + line_height / 2,
+ y + top_height + line_height + line_height / 2);
+ BSOD_MARGINS (bst,
+ x + left_column_width + margin + line_height / 2,
+ bst->xgwa.width -
+ (x + left_column_width + margin + right_column_width));
+ BSOD_VERT_MARGINS (bst,
+ y + top_height + line_height / 2,
+ bottom_height - line_height);
+ BSOD_INVERT (bst);
+
+ /* Write out the ransom note itself */
+ BSOD_CROP (bst, True);
+ BSOD_WORD_WRAP (bst);
+ for (i = 0; i < countof(lines); i++)
+ {
+ const char *s = lines[i];
+ if (!strcmp(s, "[C]")) s = currency;
+ else if (!strcmp(s, "[Q]")) s = excuse_quip;
+ else if (!strcmp(s, "[S]")) s = screensaver_quip;
+
+ if (*s == '*')
+ {
+ s++;
+ BSOD_FONT (bst, 2);
+ }
+ else
+ BSOD_FONT (bst, 0);
+
+ BSOD_TEXT (bst, LEFT, s);
+ }
+ BSOD_TRUNCATE (bst);
+ BSOD_CROP (bst, False);
+ BSOD_FONT (bst, 0);
+
+ /* Draw over any overflowing ransom text. */
+ BSOD_COLOR (bst, bg, fg);
+ BSOD_RECT (bst, True,
+ x + left_column_width + margin,
+ y + top_height + right_column_height,
+ bst->xgwa.width, bst->xgwa.height);
+ BSOD_RECT (bst, True,
+ x + left_column_width + margin + right_column_width,
+ y + top_height,
+ bst->xgwa.width, bst->xgwa.height);
+
+ /* Draw the footer */
+ BSOD_COLOR (bst, theader, bg);
+ BSOD_MOVETO (bst,
+ x + left_column_width + margin,
+ y + top_height + right_column_height + line_height * 2);
+
+ sprintf(buf, "Send $%.2f of %s to this address:\n", 101+frand(888), currency);
+ BSOD_TEXT (bst, LEFT, buf);
+ BSOD_COLOR (bst, fg2, bg2);
+
+ /* address, has some extra slashes in there because it's a fake address */
+ for (i = 0; i < 40; i++) {
+ const char *s =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123459789";
+ buf[i] = s[random() % strlen(s)];
+ }
+ strncpy (buf, " //", 3);
+ buf[10] = '/';
+ buf[17] = '/';
+ buf[24] = '/';
+ strcpy (buf+33, " ");
+ BSOD_TEXT (bst, LEFT, buf);
+
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_TEXT (bst, LEFT, " ");
+ BSOD_COLOR (bst, fg3, bg3);
+ BSOD_TEXT (bst, LEFT, " Copy ");
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_TEXT (bst, LEFT, "\n\n");
+
+ BSOD_COLOR (bst, fg3, bg3);
+ BSOD_TEXT (bst, LEFT, " Demogrify Screen ");
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_TEXT (bst, LEFT, " ");
+ BSOD_COLOR (bst, fg3, bg3);
+ BSOD_TEXT (bst, LEFT, " Check Payment ");
+
+
+ /* Draw countdown timers */
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_FONT (bst, 0);
+ do {
+ /* First timer */
+ BSOD_MOVETO (bst, x, stage1_countdown_y);
+ BSOD_MARGINS (bst, x, bst->xgwa.width - (x + left_column_width));
+
+ countdown_r = stage1_deadline - now;
+ countdown_s = countdown_r % 60;
+ countdown_m = (countdown_r / 60) % 60;
+ countdown_h = (countdown_r / 3600) % 24;
+ countdown_d = (countdown_r / 86400);
+
+ sprintf (countdown_str, "%02d:%02d:%02d:%02d\n",
+ countdown_d, countdown_h, countdown_m, countdown_s);
+
+ BSOD_TEXT (bst, CENTER, countdown_str);
+
+ /* Second timer */
+ BSOD_MOVETO (bst, x, stage2_countdown_y);
+
+ countdown_r = stage2_deadline - now;
+ countdown_s = countdown_r % 60;
+ countdown_m = (countdown_r / 60) % 60;
+ countdown_h = (countdown_r / 3600) % 24;
+ countdown_d = (countdown_r / 86400);
+
+ sprintf (countdown_str, "%02d:%02d:%02d:%02d\n",
+ countdown_d, countdown_h, countdown_m, countdown_s);
+
+ BSOD_TEXT (bst, CENTER, countdown_str);
+
+ BSOD_PAUSE (bst, 1000000);
+ now++;
+
+ /* While the "correct" thing to do is create enough of a script to fill the
+ * stage2_deadline, this would be 7 days of "frames", which is quite a bit
+ * of memory. Instead, only fill the buffer with 1 hour of frames, which is
+ * enough to make the point before xscreensaver cycles us.
+ */
+ } while (stage1_deadline - now > 3600);
+
+ XClearWindow (dpy, window);
+ return bst;
+}
+