/* bmpextract.c Extracts the LSBs of a 24 bit color bitmap image. N. DeBaggis for The Honeynet SOTM 26, Feb. 2003. usage: bmpextract [bitmap-file] [extracted-data-file] [bit 0 - 7] This revision starts extracting LSBs from the first color data byte in the bitmap file and shifts them into the result byte from the highest bit to the lowest bit order. Bitmaps store the image data in the bmp file from bottom to top, this extractor extracts from top to bottom, this is an assumption and really depends on how the insertion is implemented in the stego software that generated the bmp file. In any event, we will extract something, and if that something looks very random and does not compress well then it is probably encrypted/compressed hidden data. Linux compile: Compile with gcc using the -fpack-struct flag so the bmp header struct can be read in one shot from the bmp file. Windows compile: Make a new project workspace in VC++ and add both the bmpextract.c and bmp.h files to it. Change the struct alignment in the Project Options - C/C++ - Code Generation section so you are aligning on 1 byte bounds. */ #include #include #include #include "bmp.h" #define BCOLORBITS 24 FILE *in, *out; bmpinfo bmp; int bit = 1; int tbit = -1; void printinfo(bmpinfo *bmp, char *inf, int bitn, char *outf){ fprintf(stderr, "----------------------------------------\n"); fprintf(stderr, "Bitmap info:\n"); fprintf(stderr, "----------------------------------------\n"); fprintf(stderr, "file size: %u\n", bmp->biFileSize); fprintf(stderr, "bmp image size: %u\n", bmp->biSizeImage); fprintf(stderr, "data offset: %u\n", bmp->biDataOffset); fprintf(stderr, "bmp width: %u\n", bmp->biWidth); fprintf(stderr, "bmp height: %u\n", bmp->biHeight); fprintf(stderr, "bmp bit count: %u\n", bmp->biBitCount); fprintf(stderr, "max hide bytes: %u\n\n", (dword)(bmp->biSizeImage/8)); fprintf(stderr, "Extracted %u bytes from file %s\nusing bit #%u into file %s\n", (dword)(bmp->biSizeImage/8), inf, bitn, outf); } void usage(void){ fprintf(stderr, "Usage: bmpextract [bmpfile] [extracted-file] [bit 0 - 7]\n"); } int getbits(FILE *in, FILE *out){ byte *buf = NULL; byte result = 0; size_t pos = 0; int count = 0; if((buf = (byte *)malloc(bmp.biSizeImage)) == NULL){ fprintf(stderr, "can't allocate memory, exiting\n"); return 1; } memset(buf, 0, bmp.biSizeImage); if(fread(buf, bmp.biSizeImage, 1, in) != 1){ if(buf != NULL) free(buf); return 1; } count = 7; while(pos < bmp.biSizeImage){ result |= ((buf[pos++] & bit) >> tbit) << count--; if(count == -1){ fwrite(&result, sizeof(result), 1, out); result = 0; count = 7; } } if(buf != NULL) free(buf); return 0; } int main(int argc, char *argv[]){ if(argc != 4){ usage(); exit(1); } tbit = atoi(argv[3]); if(tbit < 0 || tbit > 7){ fprintf(stderr, "bit must be in the range 0 to 7\n"); exit(1); } bit <<= tbit; if((in = fopen(argv[1], "rb")) == NULL){ fprintf(stderr, "Error opening input bmp file %s, exiting\n", argv[1]); exit(1); } if((out = fopen(argv[2], "wb")) == NULL){ fprintf(stderr, "Error opening output data file %s, exiting\n", argv[2]); fclose(in); exit(1); } if(fread(&bmp, sizeof(bmp), 1, in) != 1){ fprintf(stderr, "Error reading bmp header, exiting\n"); fclose(in); fclose(out); exit(1); } if(bmp.biType != BMAGIC){ fprintf(stderr, "Not a bitmap file, exiting\n"); fclose(in); fclose(out); exit(1); } if(bmp.biBitCount != BCOLORBITS){ fprintf(stderr, "Bitmap file is not 24 bit color, exiting\n"); fclose(in); fclose(out); exit(1); } fseek(in, bmp.biDataOffset, SEEK_SET); if(getbits(in, out)){ fprintf(stderr, "error reading bmp data, exiting\n"); fclose(in); fclose(out); exit(1); } printinfo(&bmp, argv[1], tbit, argv[2]); fclose(in); fclose(out); return 0; }