Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F6780268
mountewf.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
20 KB
Referenced Files
None
Subscribers
None
mountewf.c
View Options
/*******************************************************************************
* mountewf (c) 2008 by Gillen Daniel <Daniel.GILLEN@police.etat.lu> *
* *
* mountewf is a small tool to "fuse mount" ewf images as dd or vdi files *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <libewf.h>
#include <semaphore.h>
#include <endian.h>
#include <stdint.h>
#include "mountewf.h"
#define MOUNTEWF_VERSION "0.1.0"
#define IMAGE_INFO_HEADER "The following values have been extracted from " \
"mounted ewf file:\n\n\0"
#define VDI_FILE_COMMENT "<<< This is an emulated vdi image based upon an " \
"ewf image >>>\0"
#define VDI_HEADER_COMMENT "This VDI was emulated using mountewf v" \
MOUNTEWF_VERSION"\0"
static char *pImagePathDD="/image.dd";
static char *pImagePathVDI="/image.vdi";
static char *pImagePath;
static const char *pImageInfoPath="/image.info";
static LIBEWF_HANDLE *hEwfFile;
static char *pInfoFile=NULL;
static VDIFILEHEADER *pVdiFileHeader;
static char *pVdiBlockMap;
static int VdiBlockMapSize=0;
// Command line ptions
static short int DEBUG=0;
static MOUNTMETHODS MOUNTMETHOD=MOUNT_AS_DD;
// Semaphores
static sem_t SEM_EWF_READ;
static sem_t SEM_VDIHEADER_READ;
static sem_t SEM_VDIBLOCKMAP_READ;
static sem_t SEM_INFO_READ;
/*
* FUSE getattr implementation
*/
static int mountewf_getattr(const char *path,
struct stat *stbuf)
{
int res=0;
memset(stbuf,0,sizeof(struct stat));
if(strcmp(path,"/")==0) {
stbuf->st_mode=S_IFDIR | 0755;
stbuf->st_nlink=2;
} else if(strcmp(path,pImagePath)==0) {
stbuf->st_mode=S_IFREG | 0444;
stbuf->st_nlink=1;
if(MOUNTMETHOD==MOUNT_AS_DD) {
sem_wait(&SEM_EWF_READ);
if(libewf_get_media_size(hEwfFile,&(stbuf->st_size))!=1) {
res=-ENOENT;
}
sem_post(&SEM_EWF_READ);
} else if(MOUNTMETHOD==MOUNT_AS_VDI) {
if(libewf_get_media_size(hEwfFile,&(stbuf->st_size))!=1) {
res=-ENOENT;
}
stbuf->st_size+=sizeof(VDIFILEHEADER);
stbuf->st_size+=VdiBlockMapSize;
}
} else if(strcmp(path,pImageInfoPath)==0) {
stbuf->st_mode=S_IFREG | 0444;
stbuf->st_nlink=1;
sem_wait(&SEM_INFO_READ);
if(pInfoFile!=NULL) stbuf->st_size=strlen(pInfoFile);
else stbuf->st_size=0;
sem_post(&SEM_INFO_READ);
} else res=-ENOENT;
return res;
}
/*
* FUSE readdir implementation
*/
static int mountewf_readdir(const char *path,
void *buf,
fuse_fill_dir_t filler,
off_t offset,
struct fuse_file_info *fi)
{
(void)offset;
(void)fi;
if(strcmp(path,"/")!=0) return -ENOENT;
filler(buf,".",NULL,0);
filler(buf, "..",NULL,0);
filler(buf,pImagePath+1,NULL,0);
filler(buf,pImageInfoPath+1,NULL,0);
return 0;
}
/*
* FUSE open implementation
*/
static int mountewf_open(const char *path,
struct fuse_file_info *fi)
{
if(strcmp(path,pImagePath)!=0 &&
strcmp(path,pImageInfoPath)!=0)
{
return -ENOENT;
}
if((fi->flags & 3)!=O_RDONLY) return -EACCES;
return 0;
}
/*
* FUSE read implementation
*/
static int mountewf_read(const char *path,
char *buf,
size_t size,
off_t offset,
struct fuse_file_info *fi)
{
size_t len;
size64_t len2;
ssize_t ssize;
(void) fi;
if(DEBUG!=0) {
printf("DEBUG: Reading %u bytes from offset %" PRId64 "\n",
size,
offset);
}
if(strcmp(path,pImagePath)==0) {
if(MOUNTMETHOD==MOUNT_AS_DD) {
// Read data from emulated dd image
if(libewf_get_media_size(hEwfFile,&len2)==1) {
if(offset<len2) {
if(offset+size>len2) size=len2-offset;
if(DEBUG==1)
printf("DEBUG: Raw read %" PRId64 " bytes from offset %" PRId64 "\n",
size,offset);
sem_wait(&SEM_EWF_READ);
if(libewf_seek_offset(hEwfFile,offset)!=-1) {
ssize=libewf_read_buffer(hEwfFile,buf,size);
if(ssize==-1) {
if(DEBUG==1) printf("DEBUG: Couldn't read data from ewf file!\n");
size=0;
} else size=ssize;
} else size=0;
// BUG: Seems as I have spotted a libewf bug!
// The following code segfaults
//if((ssize=libewf_read_random(hEwfFile,buf,size,offset))==-1) {
// if(DEBUG==1) printf("DEBUG: Couldn't read data from ewf file!\n");
// size=0;
//} else size=ssize;
sem_post(&SEM_EWF_READ);
} else size=0;
} else size=0;
} else if(MOUNTMETHOD==MOUNT_AS_VDI) {
// Read data from emulated vdi file
if(libewf_get_media_size(hEwfFile,&len2)==1) {
if(offset<(sizeof(VDIFILEHEADER)+VdiBlockMapSize+len2)) {
off_t tmp_off=offset;
size_t tmp_size=size;
off_t BeginCurSection=0;
off_t EndCurSection=sizeof(VDIFILEHEADER);
size_t ReadBytes=0;
if(offset<EndCurSection) {
// Begin read in vdi header
tmp_off=offset;
tmp_size=size;
if(offset+size>EndCurSection) {
// Adjust offset and size for reading later
// from BlockMap
offset=EndCurSection;
tmp_size=EndCurSection-tmp_off;
size-=tmp_size;
}
sem_wait(&SEM_VDIHEADER_READ);
memcpy(buf,((char*)pVdiFileHeader)+tmp_off,tmp_size);
sem_post(&SEM_VDIHEADER_READ);
buf+=tmp_size;
ReadBytes+=tmp_size;
}
BeginCurSection=sizeof(VDIFILEHEADER);
EndCurSection=sizeof(VDIFILEHEADER)+VdiBlockMapSize;
if(size>0 && offset<EndCurSection) {
// Begin or continue read in BlockMap
tmp_off=offset;
tmp_size=size;
if(offset+size>EndCurSection) {
// Adjust offset and size for reading later
// from ewf data
offset=EndCurSection;
tmp_size=(EndCurSection-sizeof(VDIFILEHEADER))-
(tmp_off-sizeof(VDIFILEHEADER));
size-=tmp_size;
}
sem_wait(&SEM_VDIBLOCKMAP_READ);
memcpy(buf,(char*)pVdiBlockMap+(tmp_off-sizeof(VDIFILEHEADER)),
tmp_size);
sem_post(&SEM_VDIBLOCKMAP_READ);
buf+=tmp_size;
ReadBytes+=tmp_size;
}
BeginCurSection=sizeof(VDIFILEHEADER)+VdiBlockMapSize;
EndCurSection=sizeof(VDIFILEHEADER)+VdiBlockMapSize+len2;
if(size>0 && offset<EndCurSection) {
tmp_off=offset;
tmp_size=size;
if(offset+size>EndCurSection) {
// Read past EOF! Adjust offset and size to end at EOF
offset=EndCurSection;
tmp_size=(EndCurSection-BeginCurSection)-
(tmp_off-BeginCurSection);
size-=tmp_size;
}
sem_wait(&SEM_EWF_READ);
if(libewf_seek_offset(hEwfFile,tmp_off-BeginCurSection)!=-1) {
if((ssize=libewf_read_buffer(hEwfFile,buf,tmp_size))==-1) {
printf("ERROR: Couldn't read data from ewf file!\n");
ReadBytes=0;
} else ReadBytes+=ssize;
} else {
printf("ERROR: Couldn't seek in ewf file!\n");
ReadBytes=0;
}
sem_post(&SEM_EWF_READ);
}
size=ReadBytes;
} else size=0;
} else size=0;
} else size=0;
} else if(strcmp(path,pImageInfoPath)==0) {
// Read data from info file
len=strlen(pInfoFile);
if(offset<len) {
if(offset+size>len) size=len-offset;
sem_wait(&SEM_INFO_READ);
memcpy(buf,pInfoFile+offset,size);
sem_post(&SEM_INFO_READ);
} else size=0;
} else return -ENOENT;
if(DEBUG!=0) printf("DEBUG: Read %u bytes\n",size);
return size;
}
/*
* Init VDI header
*/
int init_vdi_header() {
// See http://forums.virtualbox.org/viewtopic.php?t=8046 for a
// "description" of the various header fields
uint64_t offset;
uint32_t i;
if((pVdiFileHeader=malloc(sizeof(VDIFILEHEADER)))==NULL) {
printf("ERROR: Couldn't allocate memmory for VDIFILEHEADER!\n");
return 1;
}
memset(pVdiFileHeader,0x00,sizeof(VDIFILEHEADER));
strncpy(pVdiFileHeader->szFileInfo,VDI_FILE_COMMENT,
strlen(VDI_FILE_COMMENT)+1);
pVdiFileHeader->u32Signature=0xBEDA107F; // 1:1 copy from hp
pVdiFileHeader->u32Version=0x00010001; // Vers 1.1
pVdiFileHeader->cbHeader=0x00000180; // No idea what this is for! Testimage had same value
pVdiFileHeader->u32Type=0x00000002; // Type 2 (fixed size)
pVdiFileHeader->fFlags=0;
strncpy(pVdiFileHeader->szComment,VDI_HEADER_COMMENT,
strlen(VDI_HEADER_COMMENT)+1);
pVdiFileHeader->offBlocks=sizeof(VDIFILEHEADER);
pVdiFileHeader->cCylinders=0; // Legacy info
pVdiFileHeader->cHeads=0; // Legacy info
pVdiFileHeader->cSectors=0; // Legacy info
pVdiFileHeader->cbSector=512; // Legacy info
pVdiFileHeader->u32Dummy=0;
if(libewf_get_media_size(hEwfFile,&(pVdiFileHeader->cbDisk))!=1) {
printf("ERROR: libewf_get_media_size failed!\n");
return 1;
}
// TODO: Calculate blocksize depending on image size
// Seems that VBox is always using 1MB as blocksize so no calc is needed
pVdiFileHeader->cbBlock=0x00100000;
pVdiFileHeader->cbBlockExtra=0;
pVdiFileHeader->cBlocks=pVdiFileHeader->cbDisk/pVdiFileHeader->cbBlock;
pVdiFileHeader->cBlocksAllocated=pVdiFileHeader->cBlocks;
// Just generate some random UUIDS
// VBox won't accept immages where create and modify UUIDS aren't set
*((int*)(&(pVdiFileHeader->uuidCreate_l)))=rand();
*((int*)(&(pVdiFileHeader->uuidCreate_l))+4)=rand();
*((int*)(&(pVdiFileHeader->uuidCreate_h)))=rand();
*((int*)(&(pVdiFileHeader->uuidCreate_h))+4)=rand();
*((int*)(&(pVdiFileHeader->uuidModify_l)))=rand();
*((int*)(&(pVdiFileHeader->uuidModify_l))+4)=rand();
*((int*)(&(pVdiFileHeader->uuidModify_h)))=rand();
*((int*)(&(pVdiFileHeader->uuidModify_h))+4)=rand();
// Block map
VdiBlockMapSize=4*(pVdiFileHeader->cbDisk/1024/1024);
pVdiBlockMap=(char*)malloc(VdiBlockMapSize);
memset(pVdiBlockMap,0x00,VdiBlockMapSize);
pVdiFileHeader->offData=sizeof(VDIFILEHEADER)+VdiBlockMapSize;
offset=0;
for(i=0;i<VdiBlockMapSize;i+=4) {
*((uint32_t*)(pVdiBlockMap+i))=offset;
offset++;
}
return 0;
}
/*
* Parse command line options
*/
int parse_cmdline(const int argc,
char **argv,
int *pNargc,
char ***pppNargv,
int *pFilenameCount,
char ***pppFilenames,
char **ppMountpoint) {
int i=1;
int files=0,opts=0;
// add argv[0] to pppNargv
opts++;
(*pppNargv)=(char**)realloc((*pppNargv),opts*sizeof(char*));
if((*pppNargv)==NULL) {
printf("ERROR: Couldn't allocate memmory for argv[0]!\n");
return 1;
}
(*pppNargv)[opts-1]=(char*)malloc((strlen(argv[0])+1)*sizeof(char));
if((*pppNargv)[opts-1]==NULL) {
printf("ERROR: Couldn't allocate memmory for argv[0]!\n");
return 1;
}
strncpy((*pppNargv)[opts-1],argv[0],strlen(argv[0])+1);
// Parse options
while(i<argc && *argv[i]=='-') {
if(strlen(argv[i])>1 && *(argv[i]+1)!='-') {
opts++;
(*pppNargv)=(char**)realloc((*pppNargv),opts*sizeof(char*));
if((*pppNargv)==NULL) {
printf("ERROR: Couldn't allocate memmory for fuse options!\n");
return 1;
}
(*pppNargv)[opts-1]=(char*)malloc((strlen(argv[i])+1)*sizeof(char));
if((*pppNargv)[opts-1]==NULL) {
printf("ERROR: Couldn't allocate memmory for fuse options!\n");
return 1;
}
strncpy((*pppNargv)[opts-1],argv[i],strlen(argv[i])+1);
// React too on fuse's debug flag (-d)
if(strcmp(argv[i],"-d")==0) DEBUG=1;
} else {
// Options beginning with -- are mountewf specific
if(strcmp(argv[i],"--vdi")==0) {
MOUNTMETHOD=MOUNT_AS_VDI;
} else {
if(DEBUG!=0) printf("DEBUG: Unknown command line option \"%s\"\n",
argv[i]);
}
}
i++;
}
// Parse EWF filenames
while(i<(argc-1)) {
files++;
(*pppFilenames)=(char**)realloc((*pppFilenames),files*sizeof(char*));
if((*pppFilenames)==NULL) {
printf("ERROR: Couldn't allocate memmory for ewf filename(s)!\n");
return 1;
}
(*pppFilenames)[files-1]=(char*)malloc((strlen(argv[i])+1)*sizeof(char));
if((*pppFilenames)[files-1]==NULL) {
printf("ERROR: Couldn't allocate memmory for ewf filename(s)!\n");
return 1;
}
strncpy((*pppFilenames)[files-1],argv[i],strlen(argv[i])+1);
i++;
}
*pFilenameCount=files;
// Extract mountpoint
if(argc>1) {
(*ppMountpoint)=(char*)malloc((strlen(argv[argc-1])+1)*sizeof(char));
if((*ppMountpoint)==NULL) {
printf("ERROR: Couldn't allocate memmory for mountpoint string!\n");
return 1;
}
strncpy(*ppMountpoint,argv[argc-1],strlen(argv[argc-1])+1);
opts++;
(*pppNargv)=(char**)realloc((*pppNargv),opts*sizeof(char*));
if((*pppNargv)==NULL) {
printf("ERROR: Couldn't allocate memmory for mountpoint string!\n");
return 1;
}
(*pppNargv)[opts-1]=(char*)malloc((strlen(argv[i])+1)*sizeof(char));
if((*pppNargv)[opts-1]==NULL) {
printf("ERROR: Couldn't allocate memmory for mountpoint string!\n");
return 1;
}
strncpy((*pppNargv)[opts-1],*ppMountpoint,strlen((*ppMountpoint))+1);
}
*pNargc=opts;
return 0;
}
/*
* Create virtual image.info file
*/
int init_image_info() {
char buf[200];
int ret;
#define M_CHECK_ALLOC { \
if(pInfoFile==NULL) { \
printf("ERROR: Couldn't allocate memmory!\n"); \
return 1; \
} \
}
pInfoFile=(char*)realloc(pInfoFile,
(strlen(IMAGE_INFO_HEADER)+1)*sizeof(char));
M_CHECK_ALLOC
strncpy(pInfoFile,IMAGE_INFO_HEADER,strlen(IMAGE_INFO_HEADER)+1);
#define M_SAVE_VALUE(DESC) { \
if(ret==1) { \
pInfoFile=(char*)realloc(pInfoFile, \
(strlen(pInfoFile)+strlen(buf)+strlen(DESC)+2)*sizeof(char));\
strncpy((pInfoFile+strlen(pInfoFile)),DESC,strlen(DESC)+1); \
strncpy((pInfoFile+strlen(pInfoFile)),buf,strlen(buf)+1); \
strncpy((pInfoFile+strlen(pInfoFile)),"\n\0",2); \
} else if(ret==-1) return 1; \
}
// Extract various infos from ewf file and add them to the virtual image.info
// file content.
ret=libewf_get_header_value_case_number(hEwfFile,buf,200);
M_SAVE_VALUE("Case number: \0")
ret=libewf_get_header_value_description(hEwfFile,buf,200);
M_SAVE_VALUE("Description: \0")
ret=libewf_get_header_value_examiner_name(hEwfFile,buf,200);
M_SAVE_VALUE("Examiner: \0")
ret=libewf_get_header_value_evidence_number(hEwfFile,buf,200);
M_SAVE_VALUE("Evidence number: \0")
ret=libewf_get_header_value_notes(hEwfFile,buf,200);
M_SAVE_VALUE("Notes: \0")
ret=libewf_get_header_value_acquiry_date(hEwfFile,buf,200);
M_SAVE_VALUE("Acquiry date: \0")
ret=libewf_get_header_value_system_date(hEwfFile,buf,200);
M_SAVE_VALUE("System date: \0")
ret=libewf_get_header_value_acquiry_operating_system(hEwfFile,buf,200);
M_SAVE_VALUE("Acquiry os: \0")
ret=libewf_get_header_value_acquiry_software_version(hEwfFile,buf,200);
M_SAVE_VALUE("Acquiry sw version: \0")
#undef M_CHECK_ALLOC
#undef M_SAVE_VALUE
return 0;
}
/*
* Struct containing implemented FUSE functions
*/
static struct fuse_operations mountewf_oper = {
.getattr=mountewf_getattr,
.readdir=mountewf_readdir,
.open=mountewf_open,
.read=mountewf_read,
};
/*
* Main
*/
int main(int argc, char *argv[])
{
char **ppEwfFilenames=NULL;
int EwfFilenameCount=0;
int nargc=0;
char **ppNargv=NULL;
char *pMountpoint=NULL;
int ret=1;
int i=0;
// Parse and check command line options
ret=parse_cmdline(argc,
argv,
&nargc,
&ppNargv,
&EwfFilenameCount,
&ppEwfFilenames,
&pMountpoint);
if(ret!=0) {
printf("ERROR: Couldn't parse command line parameters!\n");
return 1;
}
// Basic checks
if(nargc<2 || EwfFilenameCount==0 || pMountpoint==NULL) {
printf("ERROR: Not enough command line parameters!\n");
printf("Usage:\n");
printf(" %s [[fuse options] [--vdi]] " \
"<ewf-image.E?""?> <mountpoint>\n",argv[0]);
return 1;
}
// Check for valid ewf files
for(i=0;i<EwfFilenameCount;i++) {
if(libewf_check_file_signature(ppEwfFilenames[i])!=1) {
printf("ERROR: File \"%s\" isn't a valid ewf file!\n",
ppEwfFilenames[i]);
return 1;
}
}
// TODO: Check if mountpoint is a valid dir
if(DEBUG!=0) {
if(EwfFilenameCount==1) {
printf("* Extracting infos from ewf file \"%s\"...\n",
ppEwfFilenames[0]);
} else {
printf("* Extracting infos from ewf glob \"%s .. %s\"...\n",
ppEwfFilenames[0],
ppEwfFilenames[EwfFilenameCount-1]);
}
}
// Open ewf file
hEwfFile=libewf_open(ppEwfFilenames,
EwfFilenameCount,
libewf_get_flags_read());
if(hEwfFile==NULL) {
printf("ERROR: Couldn't open ewf file!\n");
return 1;
}
// Parse EWF header
if(libewf_parse_header_values(hEwfFile,0)!=1) {
printf("ERROR: Couldn't parse ewf header values!\n");
return 1;
}
// Gather infos for info file
if(init_image_info()!=0) {
printf("ERROR: Couldn't gather infos for image.info file!\n");
return 1;
}
if(MOUNTMETHOD==MOUNT_AS_VDI) {
// When mounting as VDI, we need to construct a vdi header
if(init_vdi_header()!=0) {
printf("ERROR: Couldn't initialize vdi header!\n");
return 1;
}
}
// Set emulated image name
if(MOUNTMETHOD==MOUNT_AS_DD) pImagePath=pImagePathDD;
else pImagePath=pImagePathVDI;
// Init semaphores
sem_init(&SEM_EWF_READ,0,1);
sem_init(&SEM_VDIHEADER_READ,0,1);
sem_init(&SEM_VDIBLOCKMAP_READ,0,1);
sem_init(&SEM_INFO_READ,0,1);
// Call fuse_main to do the fuse magic
ret=fuse_main(nargc,ppNargv,&mountewf_oper,NULL);
// TODO: Perhaps wait for unposted sem's
sem_destroy(&SEM_INFO_READ);
sem_destroy(&SEM_VDIBLOCKMAP_READ);
sem_destroy(&SEM_VDIHEADER_READ);
sem_destroy(&SEM_EWF_READ);
libewf_close(hEwfFile);
// Free allocated memmory
if(MOUNTMETHOD==MOUNT_AS_VDI) {
// Free constructed VDI headers
free(pVdiFileHeader);
free(pVdiBlockMap);
}
for(i=0;i<EwfFilenameCount;i++) free(ppEwfFilenames[i]);
free(ppEwfFilenames);
for(i=0;i<nargc;i++) free(ppNargv[i]);
free(ppNargv);
return ret;
}
/*
----- Change history -----
20090131: 0.1.0 released
* Some minor things have still to be done.
* Mounting ewf as dd: Seems to work. Diff didn't complain about
changes betwenn original dd and emulated dd.
* Mounting ewf as vdi: Seems to work too. VBox accepts the emulated
vdi as valid vdi file and I was able to mount the containing fs
under Debian. INFO: Debian freezed when not using mount -r !!
*/
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Sep 16, 11:05 AM (23 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1318926
Default Alt Text
mountewf.c (20 KB)
Attached To
Mode
rXMOUNT xmount
Attached
Detach File
Event Timeline
Log In to Comment