SHARE
TWEET

automosh.c

a guest Sep 1st, 2016 4,242 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* Automosher - Bruteforce by datamoshing
  2.  * Author : Ely
  3.  *
  4.  * Compile with : -lturbojpeg (sudo apt-get install libjpeg-turbo8-dev)
  5.  * run : ./automosh <muselk_orig_imgur.jpg> <sombra_reaper.jpg>
  6.  *
  7.  * In case you don't have it : https://s9.postimg.io/fkgu9v8bx/muselk_orig_imgur.jpg
  8. */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <stdint.h>
  13. #include <turbojpeg.h>
  14.  
  15. // First byte in muselk's imgur jpeg that could modify the first block
  16. #define FIRST_TRY 62010
  17.  
  18. // Offset in the decoded RGB of the first 8x8 block modified by sombra
  19. #define FIRST_BLOCK 785544
  20.  
  21. // Raw RGB pic size for 1920x1100. Too lazy to check what jpeg turbo tells me.
  22. #define PIC_SIZE 6336000
  23.  
  24. // Any block with a difference under this threshold will be considered good and not evaluated
  25. #define THRESHOLD_GOOD 300
  26.  
  27. // Maximum allowed difference when trying to solve a block with '!'
  28. #define THRESHOLD_OK_SOLUTION 240
  29.  
  30. long getFileSize(FILE* f) {
  31.     fseek(f, 0, SEEK_END);
  32.     long fsize = ftell(f);
  33.     fseek(f, 0, SEEK_SET);
  34.    
  35.     return fsize;
  36. }
  37.  
  38. unsigned char* readFile(char* filename, long* fsize) {
  39.     FILE* f = fopen(filename, "rb");
  40.     *fsize = getFileSize(f);
  41.     unsigned char *content = malloc(*fsize + 1);
  42.     fread(content, *fsize, 1, f);
  43.     fclose(f);
  44.    
  45.     printf("Read %ld bytes from %s \n", *fsize, filename);
  46.    
  47.     return content;
  48. }
  49.  
  50. void writeFile(char* filename, const unsigned char* data, long length) {
  51.     FILE* f = fopen(filename, "w+");
  52.     fwrite(data, 1, length, f);
  53.     fclose(f);
  54. }
  55.  
  56. // Quick & Dirty jpeg decode
  57. void decodeJpeg(const unsigned char *origJpeg, long sizeOrig, unsigned char* decodedOrig, long sizeDecoded) {
  58.     int jpegSubsamp, width, height;
  59.  
  60.     tjhandle _jpegDecompressor = tjInitDecompress();
  61.  
  62.     tjDecompressHeader2(_jpegDecompressor, origJpeg, sizeOrig, &width, &height, &jpegSubsamp);
  63.  
  64.     tjDecompress2(_jpegDecompressor, origJpeg, sizeOrig, decodedOrig, width, 0/*pitch*/, height, TJPF_RGB, TJFLAG_ACCURATEDCT);
  65.  
  66.     tjDestroy(_jpegDecompressor);
  67. }
  68.  
  69. // Returns the sum of the squared differences between pixels in two 8x8 blocks that share the same offset
  70. int get8x8Diff(const unsigned char* prev, const unsigned char* next, int offset) {
  71.     int diff = 0;
  72.     for (int i = 0; i < 8; ++i) {
  73.         int start = offset+i*1920*3;
  74.         for (int j = 0; j < 24; ++j) {
  75.             int index = start+j;
  76.             diff += (prev[index] - next[index])*(prev[index] - next[index]);
  77.         }
  78.     }
  79.    
  80.     return diff;
  81. }
  82.  
  83. // Tells us whether or not a block was modified by one of our attempt to add a '!' somewhere
  84. int wasModded(const unsigned char* prev, const unsigned char* next, unsigned int offset) {
  85.     int diff = 0;
  86.     for (int i = 0; i < 8; ++i) {
  87.         int start = offset+i*1920*3;
  88.         for (int j = 0; j < 24; ++j) {
  89.             int index = start+j;
  90.             if (prev[index] != next[index])
  91.                 return 1;
  92.         }
  93.     }
  94.    
  95.     return 0;
  96. }
  97.  
  98. int main (int argc, char* argv[]) {
  99.     long jpegLength;
  100.     long decodedLength;
  101.    
  102.     if (argc != 3) {
  103.         printf("USAGE : %s <muselk_orig_imgur.jpg> <sombra-datamosh.jpg>\n", argv[0]);
  104.         return EXIT_FAILURE;
  105.     }
  106.    
  107.     unsigned char* origJpeg = readFile(argv[1], &jpegLength);
  108.     const unsigned char* sombraJpeg = readFile(argv[2], &decodedLength);
  109.     const unsigned char* decodedMosh = malloc(PIC_SIZE);
  110.     decodeJpeg(sombraJpeg, decodedLength, decodedMosh, PIC_SIZE);
  111.     unsigned char* decodedPrev = malloc(PIC_SIZE);
  112.     unsigned char* decodedNext = malloc(PIC_SIZE);
  113.     char filename[32] = {0};
  114.    
  115.     unsigned int firstTry = FIRST_TRY;
  116.    
  117.     // Note : this will scan the whole image, although you won't find anything after the start.
  118.     for (unsigned int block = FIRST_BLOCK; block < PIC_SIZE ; block += 24) {
  119.         // If the condition is true, we have passed a new line. Need to add 7 lines
  120.         // to the current offset to match the next 8x8 block
  121.         if ((block / 5760) % 8) {
  122.             printf("New line !\n");
  123.             block += 40320;
  124.         }
  125.        
  126.         decodeJpeg(origJpeg, jpegLength, decodedPrev, PIC_SIZE);
  127.         int bestDiff = get8x8Diff(decodedPrev, decodedMosh, block);
  128.  
  129.         if (bestDiff <= THRESHOLD_GOOD)
  130.             continue;
  131.  
  132.         printf("Trying out block offset %u ; diff = %d\n", block, bestDiff);
  133.         int bestValue = -1;
  134.         int bestOffset = 0;
  135.         for (unsigned int i = firstTry; i < firstTry+2000; ++i) {
  136.  
  137.             unsigned char before = origJpeg[i];
  138.        
  139.             if (before == '!')
  140.                 continue;
  141.  
  142.             origJpeg[i] = '!';
  143.             decodeJpeg(origJpeg, jpegLength, decodedNext, PIC_SIZE);
  144.             if (!wasModded(decodedNext, decodedPrev, block)) {
  145.                 origJpeg[i] = before;
  146.                 continue;
  147.             }
  148.            
  149.             int newDiff = get8x8Diff(decodedNext, decodedMosh, block);
  150.  
  151.             if (newDiff <= THRESHOLD_OK_SOLUTION && newDiff < bestDiff) {
  152.                 bestValue = i;
  153.                 bestDiff = newDiff;
  154.             }
  155.            
  156.             origJpeg[i] = before;
  157.         }
  158.        
  159.         if (bestValue != -1) {
  160.             printf("Best diff at %d : %d\n", bestValue, bestDiff);
  161.             printf("Commiting '!' replacement at %08X, previous : %c (0x%02X)\n", (unsigned int)bestValue, origJpeg[bestValue], origJpeg[bestValue]);
  162.             origJpeg[bestValue] = '!';
  163.             decodeJpeg(origJpeg, jpegLength, decodedPrev, PIC_SIZE);
  164.             sprintf(filename, "out-%06X.jpg", bestValue);
  165.             writeFile(filename, origJpeg, jpegLength);
  166.             memcpy(decodedPrev, decodedNext, PIC_SIZE);
  167.             firstTry = bestValue + 1;
  168.         }
  169.     }
  170.  
  171.     return EXIT_SUCCESS;
  172.  
  173. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top