Advertisement
Guest User

Untitled

a guest
Nov 20th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* vim: set sts=4 ts=4 et shiftwidth=4 : */
  2.  
  3. var background = "#766649";
  4.  
  5. function toHex(d) {
  6.     var rgb = d.data[2] | (d.data[1] << 8) | (d.data[0] << 16);
  7.     return '#' + (0x1000000 + rgb).toString(16).slice(1)
  8. }
  9.  
  10. function findFirstPixelX(canvas) {
  11.     var context = canvas.getContext("2d");
  12.  
  13.     for (var x = 0; x < canvas.width; x++) {
  14.         for (var y = 0; y < canvas.height; y++) {
  15.             var color = toHex(context.getImageData(x, y, 1, 1));
  16.             if (color != "#ffffff") {
  17.                 return x;
  18.             }
  19.         }
  20.     }
  21. }
  22.  
  23. function findFirstPixelY(canvas) {
  24.     var context = canvas.getContext("2d");
  25.  
  26.     for (var y = 0; y < canvas.height; y++) {
  27.         for (var x = 0; x < canvas.width; x++) {
  28.             var color = toHex(context.getImageData(x, y, 1, 1));
  29.             if (color != "#ffffff") {
  30.                 return y;
  31.             }
  32.         }
  33.     }
  34. }
  35.  
  36. function drawSolution(width, height, x, y, number, fontSize, clear) {
  37.     var canvas = document.createElement("canvas");
  38.     canvas.width = width;
  39.     canvas.height = height;
  40.     var ctx = canvas.getContext("2d");
  41.  
  42.     if (clear) {
  43.         ctx.fillStyle = "#ffffff";
  44.         ctx.fillRect(0, 0, canvas.width, canvas.height);
  45.     }
  46.  
  47.     ctx.fillStyle = "#000000";
  48.     ctx.font = "bold " + fontSize + "px Georgia";
  49.     ctx.textBaseline="hanging";
  50.     ctx.fillText(number, x, y);
  51.  
  52.     return { "canvas": canvas, width: ctx.measureText(number).width };
  53. }
  54.  
  55. function rateSolution(original, guess, x, dx) {
  56.     /* Compare pixels in original and guess in a box from x to x + dx */
  57.     var ctx1 = original.getContext("2d");
  58.     var ctx2 = guess.getContext("2d");
  59.     var count = 0;
  60.  
  61.     for (var i = x; i < x + dx; i++) {
  62.         for (var j = 0; j < original.height; j++) {
  63.             var c1 = toHex(ctx1.getImageData(i, j, 1, 1));
  64.             var c2 = toHex(ctx2.getImageData(i, j, 1, 1));
  65.  
  66.             /* Ignore background */
  67.             if ((c1 == "#ffffff") && (c2 == "#ffffff")) {
  68.                 continue;
  69.             }
  70.  
  71.             /* If both are the same, that's best */
  72.             if (c1 == c2) {
  73.                 count += 5;
  74.                 continue;
  75.             }
  76.  
  77.             /* If neither is a background pixel thats good */
  78.             if ((c1 != "#ffffff") && (c2 != "#ffffff")) {
  79.                 count += 1;
  80.                 continue;
  81.             }
  82.  
  83.             /* If original is a background pixel and guess is not, that's bad */
  84.             if ((c1 == "#ffffff") && (c2 != "#ffffff")) {
  85.                 count -= 2;
  86.                 continue;
  87.             }
  88.  
  89.             /* The other way around I am not sure... */
  90.             if ((c1 != "#ffffff") && (c2 == "#ffffff")) {
  91.                 continue;
  92.             }
  93.         }
  94.     }
  95.  
  96.     return count;
  97. }
  98.  
  99. function guessDigit(original, x, y) {
  100.     var result = {
  101.         rating: 0
  102.     };
  103.  
  104.     for (var i = 0; i < 10; i++) { // Digits
  105.         for (var dy = 0; dy <= 5; dy++) { // Y-Postion range
  106.             for (var dx = -2; dx < 3; dx++) { // X-Position range
  107.                 for (var fontSize = 12; fontSize < 18; fontSize++) { // Font size range
  108.                     var tmp = drawSolution(original.width, original.height, x + dx, y + dy, i, fontSize, true);
  109.                     var rating = rateSolution(original, tmp.canvas, x, tmp.width);
  110.                     if (rating > result.rating) {
  111.                         result.rating = rating;
  112.                         result.guess = i;
  113.                         result.width = tmp.width;
  114.                         result.x = x + dx;
  115.                         result.y = y + dy;
  116.                         result.fontSize = fontSize;
  117.                     }
  118.                 }
  119.             }
  120.         }
  121.     }
  122.  
  123.     return result;
  124. }
  125.  
  126. class CaptchaSolver {
  127.     constructor() {
  128.         this.STORAGE_KEY = "cryptic_key";
  129.         this.IMAGES_TO_USE = 3;
  130.     }
  131.  
  132.     deserialize(cb) {
  133.         var images = [];
  134.  
  135.         var tmp = sessionStorage.getItem(this.STORAGE_KEY);
  136.         if (tmp == null) {
  137.             cb(images);
  138.             return;
  139.         }
  140.  
  141.         tmp = JSON.parse(tmp);
  142.         for (var i = 0; i < tmp.length; i++) {
  143.             var img = document.createElement("img");
  144.  
  145.             $(img).on("load", function() {
  146.                 var canvas = document.createElement("canvas");
  147.                 var ctx = canvas.getContext("2d");
  148.                 canvas.width = this.width;
  149.                 canvas.height = this.height;
  150.                 ctx.drawImage(this, 0, 0);
  151.                 images.push(canvas);
  152.  
  153.                 if (images.length == tmp.length) {
  154.                     cb(images);
  155.                 }
  156.             });
  157.  
  158.             img.src = tmp[i];
  159.         }
  160.     }
  161.  
  162.     serialize(images) {
  163.         var dataUrls = [];
  164.         for (var i = 0; i < images.length; i++) {
  165.             dataUrls.push(images[i].toDataURL());
  166.         }
  167.         sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(dataUrls));
  168.     }
  169.  
  170.     getCurrentImage() {
  171.         var canvas = document.createElement("canvas");
  172.         var ctx = canvas.getContext("2d");
  173.  
  174.         var img = $("img[src*='secode.php']");
  175.         canvas.width = img.width();
  176.         canvas.height = img.height();
  177.         ctx.drawImage(img.get(0), 0, 0);
  178.  
  179.         return canvas;
  180.     }
  181.  
  182.     preProcess(images) {
  183.         var canvas = document.createElement("canvas");
  184.         var ctx = canvas.getContext("2d");
  185.         canvas.width = images[0].width;
  186.         canvas.height = images[0].height;
  187.         ctx.fillStyle = "#ffffff";
  188.         ctx.fillRect(0, 0, canvas.width, canvas.height);
  189.  
  190.         var ctx1 = images[0].getContext("2d");
  191.         var ctx2 = images[1].getContext("2d");
  192.         var ctx3 = images[2].getContext("2d");
  193.  
  194.         for (var x = 0; x < canvas.width; x++) {
  195.             for (var y = 0; y < canvas.height; y++) {
  196.                 /* TODO: Rewrite this to use IMAGES_TO_USE instead of 3. */
  197.                 var color1 = toHex(ctx1.getImageData(x, y, 1, 1));
  198.                 var color2 = toHex(ctx2.getImageData(x, y, 1, 1));
  199.                 var color3 = toHex(ctx3.getImageData(x, y, 1, 1));
  200.  
  201.                 /* Get rid of black border */
  202.                 if ((x == 0) || (y == 0) || (x == canvas.width - 1) || (y == canvas.height - 1)) {
  203.                     continue;
  204.                 }
  205.  
  206.                 /* If a pixel is background color in any of the 3 images, get rid of it */
  207.                 if ((color1 == background) || (color2 == background) || (color3 == background)) {
  208.                     continue;
  209.                 }
  210.  
  211.                 /* Any pixels that are not background and not black, must be subpixels of the font must be correct. Noise doesn't have subpixels. */
  212.                 if (color1 != "#000000") {
  213.                     ctx.fillStyle = color1;
  214.                     ctx.fillRect(x, y, 1, 1);
  215.                     continue;
  216.                 }
  217.                 if (color2 != "#000000") {
  218.                     ctx.fillStyle = color2;
  219.                     ctx.fillRect(x, y, 1, 1);
  220.                     continue;
  221.                 }
  222.                 if (color3 != "#000000") {
  223.                     ctx.fillStyle = color3;
  224.                     ctx.fillRect(x, y, 1, 1);
  225.                     continue;
  226.                 }
  227.  
  228.                 /* If a pixel has the same color in all images, it's probably correct too. */
  229.                 if ((color1 == color2) && (color1 == color3)) {
  230.                     ctx.fillStyle = color1;
  231.                     ctx.fillRect(x, y, 1, 1);
  232.                     continue;
  233.                 }
  234.             }
  235.         }
  236.  
  237.         /* Apply a simple filter that gets rid of single pixels that are left over. */
  238.         ctx.fillStyle = "#ffffff";
  239.         for (var x = 0; x < canvas.width; x++) {
  240.             for (var y = 0; y < canvas.height; y++) {
  241.                 var color = toHex(ctx.getImageData(x, y, 1, 1));
  242.  
  243.                 if (color == "#ffffff") {
  244.                     continue;
  245.                 }
  246.  
  247.                 var checks = [
  248.                              [0, 1],
  249.                     [-1, 0],         [1, 0],
  250.                              [0, -1],
  251.                 ];
  252.  
  253.                 var surroundingPixelsClear = true;
  254.  
  255.                 for (var i = 0; i < checks.length; i++) {
  256.                     var color = toHex(ctx.getImageData(x + checks[i][0], y + checks[i][1], 1, 1));
  257.  
  258.                     if (color != "#ffffff") {
  259.                         surroundingPixelsClear = false;
  260.                         break;
  261.                     }
  262.                 }
  263.  
  264.                 if (surroundingPixelsClear) {
  265.                     ctx.fillRect(x, y, 1, 1);
  266.                 }
  267.             }
  268.         }
  269.  
  270.         return canvas;
  271.     }
  272.  
  273.     _solve(canvas) {
  274.         var x = findFirstPixelX(canvas);
  275.         var y = findFirstPixelY(canvas);
  276.         var guesses = [];
  277.         var solution = "";
  278.  
  279.         /* We have up to 6 digits */
  280.         for (var i = 0; i < 6; i++) {
  281.             var guess = guessDigit(canvas, x, y);
  282.             console.log(guess);
  283.  
  284.             if (guess.rating <= 10) {
  285.                 break;
  286.             }
  287.  
  288.             guesses.push(guess);
  289.             x = guess.x + guess.width;
  290.             solution += guess.guess;
  291.         }
  292.  
  293.         return solution;
  294.     }
  295.  
  296.     solve() {
  297.         /* Deserializing images from data urls is apparently a clusterfuck, work around it with a callback function. */
  298.         var ctx = this;
  299.         this.deserialize(function(images) {
  300.             if (images.length < ctx.IMAGES_TO_USE) {
  301.                 images.push(ctx.getCurrentImage());
  302.  
  303.                 if (images.length < ctx.IMAGES_TO_USE) {
  304.                     ctx.serialize(images);
  305.  
  306.                     /* Reload after a while */
  307.                     setTimeout(function() { location.reload(); }, 2 * 1000);
  308.                     return;
  309.                 }
  310.             }
  311.  
  312.             /* Images have been collected, attempt to solve and reset history. */
  313.             sessionStorage.removeItem(ctx.STORAGE_KEY);
  314.  
  315.             var tmp = $("img[src*='secode.php']").parent();
  316.             tmp.append("<br />");
  317.  
  318.             for (var i = 0; i < images.length; i++) {
  319.                 tmp.append(images[i]);
  320.             }
  321.  
  322.             var preprocessed = ctx.preProcess(images);
  323.             tmp.append("<br />");
  324.             tmp.append(preprocessed);
  325.  
  326.             var solution = ctx._solve(preprocessed);
  327.             console.log(solution);
  328.  
  329.             $("form[action*='botpros.php'] > input[name='mode']").val(solution);
  330.         });
  331.     }
  332. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement