+ struct bsod_state *bst = make_bsod_state (dpy, window,
+ "ransomware", "Ransomware");
+ char buf[1024];
+
+ int pix_w = 0, pix_h = 0;
+ Pixmap pixmap = xpm_data_to_pixmap (dpy, window,
+ (char **) (ransomware_xpm),
+ &pix_w, &pix_h, 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 stage1_countdown_y, stage2_countdown_y;
+ int countdown_d, countdown_h, countdown_m, countdown_s, countdown_r;
+ const int line_height = bst->font->ascent + bst->font->descent;
+ int i;
+
+ const char *currencies[] = {
+ "Blitcoin",
+ "clicks",
+ "Ass Pennies",
+ "Dollary-doos",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "Dunning-Krugerrands",
+ "gift certificates",
+ "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)];
+
+ /* 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.
+ */
+
+ /* Minimum margin around the window */
+ int margin_size = 50;
+
+ /* Right side of window (header, ransom note, BTC address, buttons) */
+ const int right_pane_x = 270;
+ /* "oops" header */
+ const int header_y = 5;
+ /* Ransom note */
+ const int ransom_y = 40;
+ /* Footer area */
+ const int footer_height = 100;
+
+ /* Left pane (deadlines, countdown, links) */
+ const int left_pane_width = right_pane_x - 5;
+ /* Logo (shown at top left corner) */
+ int logo_x = (left_pane_width - pix_w) / 2;
+ int logo_y = 10;
+ /* Deadline position */
+ const int deadline_y = 130;
+ /* Links height */
+ const int links_height = 100;
+ const int links_x = 20;
+
+ /* 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");
+
+ 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",
+ };
+
+ /* Make a 4:3 ratio box inside of the workspace */
+ int box_width = bst->xgwa.width - (margin_size * 2);
+ int box_height = bst->xgwa.height - bst->yoff - (margin_size * 2);
+ int box_x = margin_size;
+ int box_y = margin_size;
+ if ((bst->xgwa.width / 4) * 3 > bst->xgwa.height) {
+ /* Widescreen, make narrow bits */
+ box_width = (bst->xgwa.height * 4 / 3) - (margin_size * 2);
+ box_x = (bst->xgwa.width - box_width) / 2;
+ } else {
+ /* Narrowscreen, make wide bits */
+ box_height = (bst->xgwa.width * 3 / 4) - (margin_size * 2);
+ box_y = (bst->xgwa.height - bst->yoff - box_height) / 2;
+ }
+
+ if (box_width < 750 && box_x == margin_size) {
+ /* Not much width... */
+ box_width = bst->xgwa.width;
+ box_x = 0;
+ }
+
+
+ bst->xoff = bst->left_margin = bst->right_margin = 0;
+
+ if (!(random() % 8))
+ return apple2ransomware (dpy, window);
+
+ /* Grab the desktop image */
+ /* BSOD_IMG (bst); */
+ bst->wrap_p = True;
+
+ /* Draw the main red window */
+ BSOD_INVERT (bst);
+ BSOD_RECT (bst, True, box_x, box_y, box_width, box_height);
+
+ if (pixmap) {
+ bst->pixmap = pixmap;
+ BSOD_PIXMAP (bst, 0, 0, pix_w, pix_h, box_x + logo_x, box_y + logo_y);
+ }
+
+ /* Setup deadlines */
+ strftime (stage1_deadline_str, sizeof(stage1_deadline_str),
+ "%m/%d/%Y %H:%M:%S\n\n", localtime(&stage1_deadline));
+ strftime (stage2_deadline_str, sizeof(stage1_deadline_str),
+ "%m/%d/%Y %H:%M:%S\n\n", localtime(&stage2_deadline));
+
+ BSOD_INVERT (bst);
+ /* Draw header pane */
+ BSOD_FONT (bst, 0);
+ BSOD_MOVETO (bst, box_x + right_pane_x, box_y + header_y + bst->fontA->ascent);
+ BSOD_MARGINS (bst, box_x + right_pane_x, box_x);
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_TEXT (bst, CENTER, header_quip);
+
+ /* Draw left-side timers */
+ BSOD_MOVETO (bst, box_x, box_y + deadline_y);
+ BSOD_MARGINS (bst, box_x, box_x + box_width - left_pane_width);
+ 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);
+
+ BSOD_TEXT (bst, CENTER, "Time Left\n");
+ stage1_countdown_y = (line_height * 4) + box_y + deadline_y;
+ BSOD_TEXT (bst, CENTER, "\n");
+ BSOD_TEXT (bst, CENTER, "\n\n");
+
+ BSOD_COLOR (bst, theader, bg);
+ BSOD_TEXT (bst, CENTER, "Your pixels will be lost on\n");
+ BSOD_COLOR (bst, fg, bg);
+ BSOD_TEXT (bst, CENTER, stage2_deadline_str);
+
+ BSOD_TEXT (bst, CENTER, "Time Left\n");
+ stage2_countdown_y = (line_height * 9) + box_y + deadline_y;
+ BSOD_TEXT (bst, CENTER, "\n");
+
+ /* Draw links */
+ BSOD_FONT (bst, 1);
+ BSOD_MOVETO (bst, box_x + links_x, box_y + box_height - links_height);
+ BSOD_MARGINS (bst, box_x + links_x, box_x + box_width - left_pane_width);
+ BSOD_COLOR (bst, link, bg);
+
+ if (box_height > 425) {
+ /* Don't show this on small screens */
+ 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, box_x + right_pane_x, box_y + ransom_y,
+ box_width - right_pane_x - 10,
+ box_height - ransom_y - footer_height);
+ BSOD_MOVETO (bst, box_x + right_pane_x + 5,
+ box_y + ransom_y + (line_height * 1.1));
+ BSOD_MARGINS (bst, box_x + right_pane_x + 5, box_x + 15);
+ /* VERT_MARGINS are a bit high, to ensure we draw as much text as we can in
+ * the box, even if the line is partially cut. We'll draw over this later.
+ */
+ BSOD_VERT_MARGINS (bst, box_y + ransom_y, box_y + (footer_height / 2));
+ BSOD_INVERT (bst);
+
+ /* Write out the ransom note itself */
+ BSOD_CROP (bst, True);
+ 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_CROP (bst, False);
+ BSOD_FONT (bst, 0);
+
+ /* Draw over any overflowing ransom text. */
+ BSOD_COLOR (bst, bg, fg);
+ BSOD_RECT (bst, True, box_x + right_pane_x,
+ box_y + box_height - footer_height,
+ box_width - right_pane_x, footer_height);
+
+ /* Draw the footer */
+ BSOD_COLOR (bst, theader, bg);
+ BSOD_MOVETO (bst, box_x + right_pane_x,
+ box_y + box_height - footer_height + line_height);
+
+ 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, box_x, stage1_countdown_y);
+ BSOD_MARGINS (bst, box_x, box_x + box_width - left_pane_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, box_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;