/* * * Autopsy Forensic Browser * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com * Project Contact/Architect: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sleuthkit.autopsy.recentactivity; import java.io.File; import java.io.*; import java.sql.ResultSet; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JPanel; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.openide.modules.InstalledFileLocator; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.ingest.IngestImageWorkerController; import org.sleuthkit.autopsy.ingest.IngestManagerProxy; import org.sleuthkit.autopsy.ingest.IngestServiceImage; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.*; /** * * @author Alex \System32\Config */ public class ExtractRegistry implements IngestServiceImage { public Logger logger = Logger.getLogger(this.getClass().getName()); private String RR_PATH; boolean rrFound = false; private int sysid; ExtractRegistry() { final File rrRoot = InstalledFileLocator.getDefault().locate("rr", ExtractRegistry.class.getPackage().getName(), false); if (rrRoot == null) { logger.log(Level.SEVERE, "RegRipper not found"); rrFound = false; return; } else { rrFound = true; } // try { // Case currentCase = Case.getCurrentCase(); // get the most updated case // SleuthkitCase tempDb = currentCase.getSleuthkitCase(); // ResultSet artset = tempDb.runQuery("SELECT * from blackboard_artifact_types WHERE type_name = 'TSK_SYS_INFO'"); // // while (artset.next()) { // sysid = artset.getInt("artifact_type_id"); // } // } catch (Exception e) { // } final String rrHome = rrRoot.getAbsolutePath(); logger.log(Level.INFO, "RegRipper home: " + rrHome); RR_PATH = rrHome + File.separator + "rip.exe"; } private void getregistryfiles(Image image, IngestImageWorkerController controller) { try { Case currentCase = Case.getCurrentCase(); // get the most updated case SleuthkitCase tempDb = currentCase.getSleuthkitCase(); Collection imageFS = tempDb.getFileSystems(image); List fsIds = new LinkedList(); for (FileSystem img : imageFS) { Long tempID = img.getId(); fsIds.add(tempID.toString()); } String allFS = new String(); for (int i = 0; i < fsIds.size(); i++) { if (i == 0) { allFS += " AND (0"; } allFS += " OR fs_obj_id = '" + fsIds.get(i) + "'"; if (i == fsIds.size() - 1) { allFS += ")"; } } List Regfiles = new ArrayList(); try { ResultSet rs = tempDb.runQuery("select * from tsk_files where lower(name) = 'ntuser.dat' OR lower(parent_path) LIKE '%/system32/config%' and (name LIKE 'system' OR name LIKE 'software' OR name = 'SECURITY' OR name = 'SAM' OR name = 'default')" + allFS); Regfiles = tempDb.resultSetToFsContents(rs); } catch (Exception ex) { logger.log(Level.WARNING, "Error while trying to read into a sqlite db.{0}", ex); } int j = 0; while (j < Regfiles.size()) { boolean Success; Content orgFS = Regfiles.get(j); long orgId = orgFS.getId(); String temps = currentCase.getTempDirectory() + "\\" + Regfiles.get(j).getName().toString(); try { ContentUtils.writeToFile(Regfiles.get(j), new File(currentCase.getTempDirectory() + "\\" + Regfiles.get(j).getName())); } catch (Exception ex) { logger.log(Level.WARNING, "Error while trying to read into a sqlite db.{0}", ex); } File regFile = new File(temps); String txtPath = executeRegRip(temps, j); if (txtPath.length() > 0) { Success = parseReg(txtPath, orgId); } else { Success = false; } //At this point pasco2 proccessed the index files. //Now fetch the results, parse them and the delete the files. if (Success) { //Delete dat file since it was succcessful regFile.delete(); } j++; } } catch (Exception ex) { logger.log(Level.WARNING, "Error while trying to get Registry files", ex); } } // TODO: Hardcoded command args/path needs to be removed. Maybe set some constants and set env variables for classpath // I'm not happy with this code. Can't stand making a system call, is not an acceptable solution but is a hack for now. private String executeRegRip(String regFilePath, int fileIndex) { String txtPath = regFilePath + Integer.toString(fileIndex) + ".txt"; String type = ""; try { if (regFilePath.toLowerCase().contains("system")) { type = "autopsysystem"; } if (regFilePath.toLowerCase().contains("software")) { type = "autopsysoftware"; } if (regFilePath.toLowerCase().contains("ntuser")) { type = "autopsy"; } if (regFilePath.toLowerCase().contains("default")) { type = "1default"; } if (regFilePath.toLowerCase().contains("sam")) { type = "1sam"; } if (regFilePath.toLowerCase().contains("security")) { type = "1security"; } String command = "\"" + RR_PATH + "\" -r \"" + regFilePath + "\" -f " + type + " > \"" + txtPath + "\" 2> NUL"; JavaSystemCaller.Exec.execute("\"" + command + "\""); } catch (Exception e) { logger.log(Level.SEVERE, "ExtractRegistry::executeRegRip() -> ", e.getMessage()); } return txtPath; } private boolean parseReg(String regRecord, long orgId) { Case currentCase = Case.getCurrentCase(); // get the most updated case SleuthkitCase tempDb = currentCase.getSleuthkitCase(); try { File regfile = new File(regRecord); FileInputStream fstream = new FileInputStream(regfile); InputStreamReader fstreamReader = new InputStreamReader(fstream, "UTF-8"); BufferedReader input = new BufferedReader(fstreamReader); //logger.log(Level.INFO, "using encoding " + fstreamReader.getEncoding()); String regString = new Scanner(input).useDelimiter("\\Z").next(); regfile.delete(); String startdoc = ""; String result = regString.replaceAll("----------------------------------------", ""); result = result.replaceAll("\\n", ""); result = result.replaceAll("\\r", ""); result = result.replaceAll("'", "'"); result = result.replaceAll("&", "&"); String enddoc = ""; String stringdoc = startdoc + result + enddoc; SAXBuilder sb = new SAXBuilder(); Document document = sb.build(new StringReader(stringdoc)); Element root = document.getRootElement(); List types = root.getChildren(); Iterator iterator = types.iterator(); while (iterator.hasNext()) { String etime = ""; String context = ""; Element tempnode = iterator.next(); // Element tempnode = types.get(i); context = tempnode.getName(); Element timenode = tempnode.getChild("time"); etime = timenode.getTextTrim(); Long time = null; try { Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(etime).getTime(); time = epochtime.longValue(); String Tempdate = time.toString(); time = Long.valueOf(Tempdate)/1000; } catch (ParseException e) { logger.log(Level.SEVERE, "RegRipper::Conversion on DateTime -> ", e.getMessage()); } Element artroot = tempnode.getChild("artifacts"); List artlist = artroot.getChildren(); String winver = ""; String installdate = ""; if (artlist.isEmpty()) { } else { Iterator aiterator = artlist.iterator(); while (aiterator.hasNext()) { Element artnode = aiterator.next(); String name = artnode.getAttributeValue("name"); String value = artnode.getTextTrim(); Collection bbattributes = new ArrayList(); if ("recentdocs".equals(context)) { // BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_RECENT_OBJECT); // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", context, time)); // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "RecentActivity", context, name)); // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), "RecentActivity", context, value)); // bbart.addAttributes(bbattributes); } else if ("usb".equals(context)) { Long utime = null; try { utime = Long.parseLong(name); String Tempdate = utime.toString(); utime = Long.valueOf(Tempdate); utime = utime; } catch (Exception e) { logger.log(Level.SEVERE, "RegRipper::Conversion on DateTime -> ", e.getMessage()); } BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), "RecentActivity", context, utime)); String dev = artnode.getAttributeValue("dev"); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID(), "RecentActivity", context, dev)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID.getTypeID(), "RecentActivity", context, value)); bbart.addAttributes(bbattributes); } else if ("uninstall".equals(context)) { Long ftime = null; try { Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(name).getTime(); ftime = epochtime.longValue(); ftime = ftime/1000; } catch (ParseException e) { logger.log(Level.SEVERE, "RegRipper::Conversion on DateTime -> ", e.getMessage()); } bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", context, time)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "RecentActivity", context, value)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), "RecentActivity", context, ftime)); BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG); bbart.addAttributes(bbattributes); } else if ("WinVersion".equals(context)) { if (name.contains("ProductName")) { winver = value; } if (name.contains("CSDVersion")) { winver = winver + " " + value; } if (name.contains("InstallDate")) { installdate = value; Long installtime = null; try { Long epochtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy").parse(value).getTime(); installtime = epochtime.longValue(); String Tempdate = installtime.toString(); installtime = Long.valueOf(Tempdate)/1000; } catch (ParseException e) { logger.log(Level.SEVERE, "RegRipper::Conversion on DateTime -> ", e.getMessage()); } bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "RecentActivity", context, winver)); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), "RecentActivity", context, installtime)); BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG); bbart.addAttributes(bbattributes); } } else { // BlackboardArtifact bbart = tempDb.getContentById(orgId).newArtifact(sysid); // bbart.addAttributes(bbattributes); } } } } } catch (Exception ex) { logger.log(Level.WARNING, "Error while trying to read into a registry file." + ex); } return true; } @Override public void process(Image image, IngestImageWorkerController controller) { this.getregistryfiles(image, controller); } @Override public void init(IngestManagerProxy managerProxy) { throw new UnsupportedOperationException("Not supported yet."); } @Override public void complete() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void stop() { throw new UnsupportedOperationException("Not supported yet."); } @Override public String getName() { return "Registry"; } @Override public String getDescription() { return "Extracts activity from the Windows registry utilizing RegRipper."; } @Override public ServiceType getType() { return ServiceType.Image; } @Override public boolean hasSimpleConfiguration() { return false; } @Override public boolean hasAdvancedConfiguration() { return false; } @Override public javax.swing.JPanel getSimpleConfiguration() { return null; } @Override public javax.swing.JPanel getAdvancedConfiguration() { return null; } @Override public void saveAdvancedConfiguration() { } @Override public void saveSimpleConfiguration() { } @Override public boolean hasBackgroundJobsRunning() { return false; } }