1 /* 2 * The Sleuth Kit 3 * 4 * Contact: Brian Carrier [carrier <at> sleuthkit [dot] org] 5 * Copyright (c) 2011-2012 Basis Technology Corporation. All Rights 6 * reserved. 7 * 8 * This software is distributed under the Common Public License 1.0 9 */ 10 11 /** 12 * \file SummaryReport.cpp 13 * Contains the implementation of a function that creates a blackboard artifacts report. 14 */ 15 16 // TSK Framework includes 17 #include "tsk/framework/utilities/TskUtilities.h" 18 #include "tsk/framework/services/TskServices.h" 19 20 // Poco includes 21 #include "Poco/FileStream.h" 22 23 // C/C++ standard library includes 24 #include <string> 25 #include <sstream> 26 27 namespace 28 { 29 // Convert reserved HTML characters to HTML entities HTMLEncode(const std::string & str)30 std::string HTMLEncode(const std::string &str) 31 { 32 std::string convertedStr; 33 for (size_t i = 0; i < str.size(); i++) 34 { 35 if (str[i] == '<') 36 convertedStr.append("<"); 37 else if (str[i] == '>') 38 convertedStr.append(">"); 39 else if (str[i] == '&') 40 convertedStr.append("&"); 41 else if (str[i] == '"') 42 convertedStr.append("""); 43 else if (str[i] == '\'') 44 convertedStr.append("'"); 45 else 46 convertedStr += str[i]; 47 } 48 return convertedStr; 49 } 50 addStyle(Poco::FileOutputStream & out)51 void addStyle(Poco::FileOutputStream &out) 52 { 53 out << "<style type=\"text/css\">" << std::endl << 54 "table.gridtable {" << std::endl << 55 "font-family: verdana,arial,sans-serif;" << std::endl << 56 "font-size:11px;" << std::endl << 57 "color:#333333;" << std::endl << 58 "border-width: 1px;" << std::endl << 59 "border-color: #666666;" << std::endl << 60 "border-collapse: collapse;" << std::endl << 61 "}" << std::endl << 62 "table.gridtable th {" << std::endl << 63 "border-width: 1px;" << std::endl << 64 "padding: 8px;" << std::endl << 65 "border-style: solid;" << std::endl << 66 "border-color: #666666;" << std::endl << 67 "background-color: #dedede;" << std::endl << 68 "}" << std::endl << 69 "table.gridtable td {" << std::endl << 70 "border-width: 1px;" << std::endl << 71 "padding: 8px;" << std::endl << 72 "border-style: solid;" << std::endl << 73 "border-color: #666666;" << std::endl << 74 "background-color: #ffffff;" << std::endl << 75 "}" << std::endl << 76 "h1 {" << std::endl << 77 "font-size: 1.5em;" << std::endl << 78 "color: #000000;" << std::endl << 79 "font-family: Arial, sans-serif;" << std::endl << 80 "}" << std::endl << 81 82 "h2 {" << std::endl << 83 "font-size: 1.2em;" << std::endl << 84 "color: #000000;" << std::endl << 85 "font-family: Arial, sans-serif;" << std::endl << 86 "}" << std::endl << 87 88 "h3 {" << std::endl << 89 "margin-left: 0;" << std::endl << 90 "margin-bottom: 0;" << std::endl << 91 "font-size: 1.0em;" << std::endl << 92 "color: #000000;" << std::endl << 93 "font-family: Arial, sans-serif;" << std::endl << 94 "}" << std::endl << 95 "</style>" << std::endl; 96 } 97 writeReport(Poco::FileOutputStream & out)98 void writeReport(Poco::FileOutputStream &out) 99 { 100 out << "<html>" << std::endl; 101 out << "<head>" << std::endl; 102 out << "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />" << std::endl; 103 addStyle(out); 104 105 out << "<title>Report</title>" << std::endl; 106 out << "</head>" << std::endl; 107 out << "<body>" << std::endl; 108 109 TskBlackboard &blackboard = TskServices::Instance().getBlackboard(); 110 TskImgDB &imgdb = TskServices::Instance().getImgDB(); 111 std::stringstream condition; 112 113 out << "<h1>Sleuth Kit Framework Summary Report</h1>" << std::endl; 114 std::vector<std::string> names = imgdb.getImageNames(); 115 out << "<h2>Image Path: " << names.front() << "</h2>" << std::endl; 116 117 out << "<h2>Image Layout</h2>" << std::endl; 118 std::list<TskVolumeInfoRecord> volumeInfoList; 119 imgdb.getVolumeInfo(volumeInfoList); 120 121 std::list<TskFsInfoRecord> fsInfoList; 122 imgdb.getFsInfo(fsInfoList); 123 TskFsInfoRecord fsInfo; 124 125 if (fsInfoList.size() == 0) 126 { 127 out << "<em>NO FILE SYSTEMS FOUND IN THE DISK IMAGE.</em>" << std::endl; 128 } 129 130 out << "<table class=\"gridtable\">" << std::endl; 131 out << "<thead>" << std::endl; 132 out << "<tr>" << std::endl; 133 out << "<th>Start Sector</th>" << std::endl; 134 out << "<th>End Sector</th>" << std::endl; 135 out << "<th>Partition Type</th>" << std::endl; 136 out << "<th>Detected FS</th>" << std::endl; 137 out << "</tr>" << std::endl; 138 out << "</thead>" << std::endl; 139 140 for (list<TskVolumeInfoRecord>::const_iterator iter = volumeInfoList.begin(); iter != volumeInfoList.end(); iter++) 141 { 142 const TskVolumeInfoRecord & vol_info = *iter; 143 out << "<tr>" << std::endl; 144 out << "<td>" << vol_info.sect_start << "</td>" << std::endl; 145 out << "<td>" << (vol_info.sect_start + vol_info.sect_len) - 1 << "</td>" << std::endl; 146 out << "<td>" << vol_info.description << "</td>" << std::endl; 147 148 for (list<TskFsInfoRecord>::const_iterator iter2 = fsInfoList.begin(); iter2 != fsInfoList.end(); iter2++) 149 { 150 fsInfo = (*iter2); 151 if(fsInfo.vol_id == vol_info.vol_id) 152 { 153 const char* fsName = tsk_fs_type_toname((TSK_FS_TYPE_ENUM)fsInfo.fs_type); 154 if (!fsName) 155 { 156 out << "<td>Name of file system type is unknown.</td>" << std::endl; 157 LOGERROR("writeReport: Name of file system type is unknown."); 158 } 159 else 160 { 161 out << "<td>" << fsName << "</td>" << std::endl; 162 } 163 } 164 } 165 166 out << "</tr>" << std::endl; 167 } 168 out << "</table>" << std::endl; 169 170 out << "<h2>File Categories</h2>" << std::endl; 171 out << "<table class=\"gridtable\">" << std::endl; 172 173 out << "<tr>" << std::endl; 174 condition.str(""); 175 condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG 176 << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_FS; 177 out << "<td><b>File System:</b></td>"; 178 out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl; 179 out << "</tr>" << std::endl; 180 181 out << "<tr>" << std::endl; 182 condition.str(""); 183 condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG 184 << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_DERIVED; 185 out << "<td><b>Derived:</b></td>"; 186 out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl; 187 out << "</tr>" << std::endl; 188 189 out << "<tr>" << std::endl; 190 condition.str(""); 191 condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG 192 << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_CARVED; 193 out << "<td><b>Carved:</b></td>"; 194 out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl; 195 out << "</tr>" << std::endl; 196 197 out << "<tr>" << std::endl; 198 condition.str(""); 199 condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG 200 << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_UNUSED; 201 out << "<td><b>Contiguous Unallocated Sectors:</b></td>"; 202 out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl; 203 out << "</tr>" << std::endl; 204 205 out << "<tr>" << std::endl; 206 condition.str(""); 207 condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG; 208 out << "<td><b>Total Files:</b></td>"; 209 out << "<td><b>" << imgdb.getFileCount(condition.str()) << "</b></td>" << std::endl; 210 out << "</tr>" << std::endl; 211 212 out << "<tr>" << std::endl; 213 out << "</table>" << std::endl; 214 215 std::vector<TskBlackboardArtifact> artifacts = blackboard.getMatchingArtifacts("ORDER BY artifact_type_id"); 216 std::vector<TskBlackboardArtifact>::iterator it; 217 int currentArtType = -1; 218 std::vector<int> attrTypeIDs; 219 out << "<h2>Blackboard Artifacts</h2>" << std::endl; 220 for (it = artifacts.begin(); it != artifacts.end(); it++) 221 { 222 if (currentArtType != it->getArtifactTypeID()) 223 { 224 if (currentArtType != -1) 225 { 226 out << "</tbody>" << std::endl << "</table>" << std::endl; 227 } 228 currentArtType = it->getArtifactTypeID(); 229 out << "<h3>" << it->getDisplayName() << "</h3>" << std::endl; 230 attrTypeIDs = blackboard.findAttributeTypes(currentArtType); 231 out << "<table class=\"gridtable\">" << std::endl; 232 out << "<thead>" << std::endl; 233 out << "<tr>" << std::endl; 234 out << "<th>File Name</th>" << std::endl; 235 for (size_t i = 0; i < attrTypeIDs.size(); i++) 236 { 237 out << "<th>" << blackboard.attrTypeIDToTypeDisplayName(attrTypeIDs[i]) << "</th>" << std::endl; 238 } 239 out << "</tr>" << std::endl << "</thead>" << std::endl; 240 out << "<tbody>" << std::endl; 241 } 242 out << "<tr>" << std::endl; 243 out << "<td>" << imgdb.getFileName(it->getObjectID()) << "</td>" << std::endl; 244 std::vector<TskBlackboardAttribute> attrs = it->getAttributes(); 245 246 for (size_t j = 0; j < attrTypeIDs.size(); j++) 247 { 248 TskBlackboardAttribute * attr; 249 bool found = false; 250 for (size_t k = 0; k < attrs.size(); k++) 251 { 252 if (attrs[k].getAttributeTypeID() == attrTypeIDs[j]) 253 { 254 attr = &attrs[k]; 255 found = true; 256 break; 257 } 258 } 259 if (!found) 260 { 261 out << "<td/>" << std::endl; 262 } 263 else 264 { 265 out << "<td>"; 266 std::vector<unsigned char> bytes; 267 switch(attr->getValueType()) 268 { 269 case TSK_BYTE: 270 bytes = attr->getValueBytes(); 271 for(size_t k = 0; k < bytes.size(); k++) 272 out << bytes[k]; 273 out << "</td>" << std::endl; 274 break; 275 276 case TSK_DOUBLE: 277 out << attr->getValueDouble() << "</td>" << std::endl; 278 break; 279 280 case TSK_INTEGER: 281 out << attr->getValueInt() << "</td>" << std::endl; 282 break; 283 284 case TSK_LONG: 285 out << attr->getValueLong() << "</td>" << std::endl; 286 break; 287 288 case TSK_STRING: 289 std::string encoded = HTMLEncode(attr->getValueString()); 290 out << encoded << "</td>" << std::endl; 291 break; 292 } 293 } 294 } 295 out << "</tr>" << std::endl; 296 } 297 if (artifacts.size() > 0) 298 { 299 out << "</tbody>" << std::endl << "</table>" << std::endl; 300 } 301 out << "</body>" << std::endl; 302 out << "</html>" << std::endl; 303 } 304 } 305 306 namespace TskSummaryReport 307 { generateReport(const std::string & reportPath)308 void generateReport(const std::string &reportPath) 309 { 310 Poco::FileOutputStream out(reportPath, std::ios::out | std::ios::trunc); 311 writeReport(out); 312 } 313 } 314