home *** CD-ROM | disk | FTP | other *** search
- First ToolMe challenge solution
- by the_dux
-
- So, nice work to do this time...
- As I read on the disclaimer the goal for this is to code a
- simple tool that is able to encrypt a name (and a serial)
- in a bitmap file (using the steganography technique).
- First of all, we've to know a bit what's steganography is
- so get out there and try to get some infos about it and
- then after you read what it is and how it work search for
- a text on how a bitmap file is composed (header, various
- infos, etc.). You'll need these infos cause the program
- read the name and the key from a bitmap and from its pixels
- so...
- Well, I can't explain all the disassembled code line by line
- because it's huge and I think it's not so usefull, also
- because I assume you can at any time read and translate it.
- Here is the algo used to read the name and the key from the
- file:
-
- first of all we get infos from the header to know where the
- infos about pixel start in the bmp file.
-
- a)then we read 3 bytes from the file (the RGB infos) and we
- xor them ( first_byte XOR second_byte XOR third_byte ). As
- you know steganography usually take last bit and so the
- program do ANDing the result of XORs with 1 (=> we get the
- last bit).
-
- We repeat 8 times this loop
-
-
- b)Now we have 8 bits taken from 8 pixel, we must merge them
- to get a single byte (first letter of name).
-
- We repeat 100 times a) and b) till we get an array (length 100)
- with the name, a zero byte (0x00), the key, a zero byte(0x00)
- and some others garbage we could trash.
-
- The program goes on and extract from this string the name and
- the key.
- Till now it does nothing more than reading some bits from the
- bitmap that could have an irrilevant importance (because even
- if we haven't a real name encrypted in the file it can reigster
- anyway) so there's a simple algo that check the relation between
- name and key.
- The algo simply XOR the key with the phrase "Obscurity is not
- security!" and verify if the result contain the name.
-
- Now we've to do a sort of keygen that will consist in two part:
- the first that ask the user a name and then compute the regkey
- from it (it's very simple... we've only to xor the name with
- the phrase above);
- the second part it's the longer and it's where we write the name
- and the code into the file.
- I wrote the program in C and here is the source
- (it's not very good, but it work)
-
- ----------------------------=CUT HERE=--------------------------
- // Stega Tool Name/Key Encoder
-
- #include <stdio.h>
- #include <stdlib.h>
-
- // Header
- #define BMPHEADER 14
-
- typedef struct {
- long bmpIHSize;
- long bmpCUsed;
- long bmpCType;
- int bmpBPP;
- long bmpHeight;
- long bmpWidth;
- } bmpInfo;
-
- char magic[] = "Obscurity is not security!";
-
- long func_40160E( FILE *fbmp )
- {
- int cx;
- long res;
-
- fseek( fbmp, BMPHEADER+10, SEEK_SET );
- fread( &cx, 2, 1, fbmp );
- if ( cx > 8 ) return 0;
- res = cx * 2;
- res += res*2;
- return res;
- }
-
- long func_40162C( FILE *fbmp )
- {
- int cx;
-
- fseek( fbmp, BMPHEADER+14, SEEK_SET );
- fread( &cx, 2, 1, fbmp );
- if ( cx > 8 ) return 0;
- return (cx*8);
- }
-
- int main()
- {
- char nfile[256], regkey[100], cp, c, cn, nome[26], reg[26];
- FILE *fbmp;
- bmpInfo bi;
- long bmpPStart, ft;
- int AddStart=0, i, b, bits[8], ci, counter;
-
- printf( "File to patch: " );
- scanf( "%s", (char*)&nfile );
- // Get name and create the key
- memset( ®, 0, sizeof(reg) );
- memset( &nome, 0, sizeof(nome) );
- printf( "Name to encode: " );
- scanf( "%s", (char*)&nome );
- // Simplest encryption algo...
- for (i=0; i<strlen((char*)&nome); i++ ) reg[i] = nome[i] ^ magic[i];
-
- fbmp = fopen( (char*)&nfile, "r+" );
- // si posiziona all'inizio dell'infoheader
- fseek( fbmp, BMPHEADER, SEEK_SET );
- // dimensione header
- fread( &bi.bmpIHSize, sizeof(long), 1, fbmp );
- switch( bi.bmpIHSize )
- {
- case 12:
- bmpPStart = func_40160E( fbmp );
- break;
- case 40:
- fseek( fbmp, BMPHEADER+16, SEEK_SET );
- fread( &bi.bmpCType, sizeof(long), 1, fbmp );
- if ( bi.bmpCType == 3 ) AddStart = 12;
- fseek( fbmp, BMPHEADER+32, SEEK_SET );
- fread( &bi.bmpCUsed, sizeof(long), 1, fbmp );
- if ( bi.bmpCUsed ) bmpPStart = bi.bmpCUsed*4;
- else bmpPStart = func_40162C( fbmp );
- break;
- case 108:
- fseek( fbmp, BMPHEADER+32, SEEK_SET );
- fread( &bi.bmpCUsed, sizeof(long), 1, fbmp );
- if ( bi.bmpCUsed ) bmpPStart = bi.bmpCUsed*4;
- else bmpPStart = func_40162C( fbmp );
- break;
- }
- // 401644h
- // Get the bmp pixel's infos entry point
- bmpPStart+=AddStart+14+bi.bmpIHSize;
- // Bit Per Pixel
- fseek( fbmp, BMPHEADER+14, SEEK_SET );
- fread( &bi.bmpBPP, 2, 1, fbmp );
- bi.bmpBPP/=8;
- // Height
- fseek( fbmp, BMPHEADER+8, SEEK_SET );
- fread( &bi.bmpHeight, sizeof(long), 1, fbmp );
- // Width
- fseek( fbmp, BMPHEADER+4, SEEK_SET );
- fread( &bi.bmpWidth, sizeof(long), 1, fbmp );
- bi.bmpWidth*=bi.bmpBPP;
- memset( ®key, 0, sizeof(regkey) );
- bi.bmpWidth+=2;
- fseek( fbmp, bmpPStart, SEEK_SET );
- /* Encrypt the name and the code in the file
- Rules: the last bit of RGB's byte are xored
- and the result is the bit to be extracted
- */
- ft = ftell(fbmp);
- // Start with the name
- for( i=0; i<strlen((char*)&nome); i++ )
- {
- ci = (int)nome[i];
- memset( &bits, 0, sizeof(bits) );
- // Get every single bit of current char
- for( counter=7; counter!=0; counter-- )
- {
- bits[counter] = ci % 2;
- ci/=2;
- }
- // Decide wich byte to modify
- for( counter=0; counter<8; counter++ )
- {
- fseek( fbmp, ft, SEEK_SET );
- fread( &cp, 1, 1, fbmp );
- fread( &c, 1, 1, fbmp );
- fread( &cn, 1, 1, fbmp );
- cp = cp^cn;
- c = c^cp;
- c &= 1;
- if ( (int)c != bits[counter] ) cn--;
- if ((int)cn == -1 ) cn=1;
- fseek( fbmp, -1, SEEK_CUR );
- fwrite( &cn, 1, 1, fbmp );
- ft = ftell(fbmp);
- fclose(fbmp);
- fbmp=fopen((char*)&nfile, "r+" );
- }
- }
- // Zero at the end of name
- for( counter=0; counter<8; counter++ )
- {
- fseek( fbmp, ft, SEEK_SET );
- fread( &cp, 1, 1, fbmp );
- fread( &c, 1, 1, fbmp );
- fread( &cn, 1, 1, fbmp );
- cp = cp^cn;
- c ^= cp;
- c &= 1;
- if ( (int)c ) cn--;
- if ((int)cn==-1) cn=1;
- // write it
- fseek( fbmp, -1, SEEK_CUR );
- fwrite( &cn, 1, 1, fbmp );
- ft = ftell(fbmp);
- fclose(fbmp);
- fbmp=fopen((char*)&nfile, "r+" );
- }
- // write reg key
- for( i=0; i<strlen((char*)®); i++ )
- {
- ci = (int)reg[i];
- memset( &bits, 0, sizeof(bits) );
- // Get every single bit of current char
- for( counter=7; counter!=0; counter-- )
- {
- bits[counter] = ci % 2;
- ci/=2;
- }
- // Decide wich byte to modify
- for( counter=0; counter<8; counter++ )
- {
- fseek( fbmp, ft, SEEK_SET );
- fread( &cp, 1, 1, fbmp );
- fread( &c, 1, 1, fbmp );
- fread( &cn, 1, 1, fbmp );
- cp = cp^cn;
- c = c^cp;
- c &= 1;
- if ( (int)c != bits[counter] ) cn--;
- if ((int)cn==-1) cn=1;
- // write it
- fseek( fbmp, -1, SEEK_CUR );
- fwrite( &cn, 1, 1, fbmp );
- ft = ftell(fbmp);
- fclose(fbmp);
- fbmp=fopen((char*)&nfile, "r+" );
- }
- }
- // Zero at the end of key
- for( counter=0; counter<8; counter++ )
- {
- fseek( fbmp, ft, SEEK_SET );
- fread( &cp, 1, 1, fbmp );
- fread( &c, 1, 1, fbmp );
- fread( &cn, 1, 1, fbmp );
- cp = cp^cn;
- c ^= cp;
- c &= 1;
- if ( (int)c ) cn--;
- if ((int)cn==-1) cn=1;
- // write it
- fseek( fbmp, -1, SEEK_CUR );
- fwrite( &cn, 1, 1, fbmp );
- ft = ftell(fbmp);
- fclose(fbmp);
- fbmp=fopen((char*)&nfile, "r+" );
- }
- fclose(fbmp);
- return 0;
- }
- ----------------------------=AND HERE=--------------------------
-
- final notes:
- this program work well with 24bit bitmaps but i think it couldn't
- work with other resolutions.
- To make it work simply put, at the end of each for loop with fread
- some lines to recalculate the position inside the file (ie. if you
- have 24bit you read 3byte at times but less if you're in a smaller
- resolution).
-
- the_dux, 25 April 2001
-