Windows-I의 중요한 아티팩트
이 장에서는 Microsoft Windows 포렌식과 관련된 다양한 개념과 조사자가 조사 프로세스에서 얻을 수있는 중요한 아티팩트에 대해 설명합니다.
소개
아티팩트는 컴퓨터 사용자가 수행 한 활동과 관련된 중요한 정보가있는 컴퓨터 시스템 내의 개체 또는 영역입니다. 이 정보의 유형과 위치는 운영 체제에 따라 다릅니다. 법의학 분석 중에 이러한 인공물은 조사자의 관찰을 승인하거나 비 승인하는 데 매우 중요한 역할을합니다.
포렌식을위한 Windows 아티팩트의 중요성
Windows 아티팩트는 다음과 같은 이유로 중요성을 가정합니다.
전 세계 트래픽의 약 90 %는 Windows를 운영 체제로 사용하는 컴퓨터에서 발생합니다. 그렇기 때문에 디지털 포렌식 심사관에게는 Windows 아티팩트가 매우 중요합니다.
Windows 운영 체제는 컴퓨터 시스템의 사용자 활동과 관련된 다양한 유형의 증거를 저장합니다. 이것은 디지털 포렌식에서 Windows 아티팩트의 중요성을 보여주는 또 다른 이유입니다.
수사관은 사용자가 만든 데이터와 같은 기존 영역과 기존 영역을 중심으로 조사를 진행합니다. Windows 아티팩트는 시스템 생성 데이터 또는 아티팩트와 같은 비 전통적인 영역에 대한 조사를 이끌 수 있습니다.
Windows는 조사자뿐만 아니라 비공식 조사를 수행하는 기업과 개인에게도 도움이되는 풍부한 인공물을 제공합니다.
최근 몇 년간 사이버 범죄의 증가는 Windows 아티팩트가 중요한 또 다른 이유입니다.
Windows 아티팩트 및 해당 Python 스크립트
이 섹션에서는 정보를 가져 오는 일부 Windows 아티팩트 및 Python 스크립트에 대해 설명합니다.
쓰레기통
포렌식 조사를위한 중요한 Windows 아티팩트 중 하나입니다. Windows 휴지통에는 사용자가 삭제했지만 아직 시스템에서 실제로 제거하지 않은 파일이 포함되어 있습니다. 사용자가 시스템에서 파일을 완전히 제거하더라도 중요한 조사 소스 역할을합니다. 이는 검사관이 삭제 된 파일에서 원본 파일 경로 및 휴지통으로 보낸 시간과 같은 중요한 정보를 추출 할 수 있기 때문입니다.
휴지통 증거의 저장은 Windows 버전에 따라 다릅니다. 다음 Python 스크립트에서 두 개의 파일을 생성하는 Windows 7을 다룰 것입니다.$R 재활용 된 파일의 실제 내용을 포함하는 파일 및 $I 원본 파일 이름, 경로, 파일 삭제시 파일 크기가 포함 된 파일입니다.
Python 스크립트의 경우 타사 모듈을 설치해야합니다. pytsk3, pyewf 과 unicodecsv. 우리는 사용할 수 있습니다pip설치합니다. 다음 단계에 따라 휴지통에서 정보를 추출 할 수 있습니다.
먼저 재귀 적 방법을 사용하여 $Recycle.bin 폴더로 시작하는 모든 파일을 선택하십시오. $I.
다음으로 파일의 내용을 읽고 사용 가능한 메타 데이터 구조를 구문 분석합니다.
이제 관련 $ R 파일을 검색합니다.
마지막으로 검토를 위해 결과를 CSV 파일에 기록합니다.
이 목적으로 파이썬 코드를 사용하는 방법을 살펴 보겠습니다.
먼저 다음 Python 라이브러리를 가져와야합니다.
from __future__ import print_function
from argparse import ArgumentParser
import datetime
import os
import struct
from utility.pytskutil import TSKUtil
import unicodecsv as csv
다음으로 명령 줄 처리기에 대한 인수를 제공해야합니다. 여기서는 세 가지 인수를 허용합니다. 첫 번째는 증거 파일의 경로, 두 번째는 증거 파일의 유형, 세 번째는 CSV 보고서에 대한 원하는 출력 경로입니다.
if __name__ == '__main__':
parser = argparse.ArgumentParser('Recycle Bin evidences')
parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE', help = "Evidence file format",
choices = ('ewf', 'raw'))
parser.add_argument('CSV_REPORT', help = "Path to CSV report")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.CSV_REPORT)
이제 main()모든 처리를 처리 할 함수. 검색합니다$I 다음과 같이 파일-
def main(evidence, image_type, report_file):
tsk_util = TSKUtil(evidence, image_type)
dollar_i_files = tsk_util.recurse_files("$I", path = '/$Recycle.bin',logic = "startswith")
if dollar_i_files is not None:
processed_files = process_dollar_i(tsk_util, dollar_i_files)
write_csv(report_file,['file_path', 'file_size', 'deleted_time','dollar_i_file', 'dollar_r_file', 'is_directory'],processed_files)
else:
print("No $I files found")
이제 우리가 발견하면 $I 파일을 보내야합니다. process_dollar_i() 받아 들일 기능 tsk_util 개체 및 목록 $I 아래와 같이 파일-
def process_dollar_i(tsk_util, dollar_i_files):
processed_files = []
for dollar_i in dollar_i_files:
file_attribs = read_dollar_i(dollar_i[2])
if file_attribs is None:
continue
file_attribs['dollar_i_file'] = os.path.join('/$Recycle.bin', dollar_i[1][1:])
이제 다음과 같이 $ R 파일을 검색하십시오.
recycle_file_path = os.path.join('/$Recycle.bin',dollar_i[1].rsplit("/", 1)[0][1:])
dollar_r_files = tsk_util.recurse_files(
"$R" + dollar_i[0][2:],path = recycle_file_path, logic = "startswith")
if dollar_r_files is None:
dollar_r_dir = os.path.join(recycle_file_path,"$R" + dollar_i[0][2:])
dollar_r_dirs = tsk_util.query_directory(dollar_r_dir)
if dollar_r_dirs is None:
file_attribs['dollar_r_file'] = "Not Found"
file_attribs['is_directory'] = 'Unknown'
else:
file_attribs['dollar_r_file'] = dollar_r_dir
file_attribs['is_directory'] = True
else:
dollar_r = [os.path.join(recycle_file_path, r[1][1:])for r in dollar_r_files]
file_attribs['dollar_r_file'] = ";".join(dollar_r)
file_attribs['is_directory'] = False
processed_files.append(file_attribs)
return processed_files
이제 정의 read_dollar_i() 읽는 방법 $I즉, 메타 데이터를 구문 분석합니다. 우리는 사용할 것입니다read_random()서명의 처음 8 바이트를 읽는 메서드. 서명이 일치하지 않으면 아무것도 반환하지 않습니다. 그 후, 우리는 값을 읽고 압축을 풀어야합니다.$I 유효한 파일이면 file.
def read_dollar_i(file_obj):
if file_obj.read_random(0, 8) != '\x01\x00\x00\x00\x00\x00\x00\x00':
return None
raw_file_size = struct.unpack('<q', file_obj.read_random(8, 8))
raw_deleted_time = struct.unpack('<q', file_obj.read_random(16, 8))
raw_file_path = file_obj.read_random(24, 520)
이제 이러한 파일을 추출한 후 다음을 사용하여 정수를 사람이 읽을 수있는 값으로 해석해야합니다. sizeof_fmt() 아래 표시된 기능-
file_size = sizeof_fmt(raw_file_size[0])
deleted_time = parse_windows_filetime(raw_deleted_time[0])
file_path = raw_file_path.decode("utf16").strip("\x00")
return {'file_size': file_size, 'file_path': file_path,'deleted_time': deleted_time}
이제 정의해야합니다. sizeof_fmt() 다음과 같이 기능-
def sizeof_fmt(num, suffix = 'B'):
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
이제 다음과 같이 형식화 된 날짜 및 시간으로 해석 된 정수에 대한 함수를 정의하십시오.
def parse_windows_filetime(date_value):
microseconds = float(date_value) / 10
ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(
microseconds = microseconds)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
이제 우리는 write_csv() 처리 된 결과를 다음과 같이 CSV 파일에 쓰는 방법-
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
위의 스크립트를 실행하면 $ I 및 $ R 파일에서 데이터를 가져옵니다.
스티커 메모
Windows 스티커 메모는 실제 쓰기 습관을 펜과 종이로 대체합니다. 이러한 메모는 색상, 글꼴 등에 대한 다양한 옵션을 사용하여 바탕 화면에 떠 다니는 데 사용되었습니다. Windows 7에서 스티커 메모 파일은 OLE 파일로 저장되므로 다음 Python 스크립트에서이 OLE 파일을 조사하여 스티커 메모에서 메타 데이터를 추출합니다.
이 Python 스크립트의 경우 타사 모듈을 설치해야합니다. olefile, pytsk3, pyewf및 unicodecsv. 우리는 명령을 사용할 수 있습니다pip 설치합니다.
스티커 메모 파일에서 정보를 추출하기 위해 아래에 설명 된 단계를 따를 수 있습니다. StickyNote.sn −
먼저 증거 파일을 열고 모든 StickyNote.snt 파일을 찾습니다.
그런 다음 OLE 스트림에서 메타 데이터 및 콘텐츠를 구문 분석하고 RTF 콘텐츠를 파일에 씁니다.
마지막으로이 메타 데이터에 대한 CSV 보고서를 만듭니다.
파이썬 코드
이 목적으로 파이썬 코드를 사용하는 방법을 살펴 보겠습니다.
먼저 다음 Python 라이브러리를 가져옵니다.
from __future__ import print_function
from argparse import ArgumentParser
import unicodecsv as csv
import os
import StringIO
from utility.pytskutil import TSKUtil
import olefile
다음으로,이 스크립트에서 사용될 전역 변수를 정의하십시오-
REPORT_COLS = ['note_id', 'created', 'modified', 'note_text', 'note_file']
다음으로 명령 줄 처리기에 대한 인수를 제공해야합니다. 여기서는 다음과 같이 세 가지 인수를 허용합니다. 첫 번째는 증거 파일의 경로, 두 번째는 증거 파일의 유형, 세 번째는 다음과 같이 원하는 출력 경로입니다.
if __name__ == '__main__':
parser = argparse.ArgumentParser('Evidence from Sticky Notes')
parser.add_argument('EVIDENCE_FILE', help="Path to evidence file")
parser.add_argument('IMAGE_TYPE', help="Evidence file format",choices=('ewf', 'raw'))
parser.add_argument('REPORT_FOLDER', help="Path to report folder")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT_FOLDER)
이제 우리는 main() 아래에 표시된 이전 스크립트와 유사한 함수-
def main(evidence, image_type, report_folder):
tsk_util = TSKUtil(evidence, image_type)
note_files = tsk_util.recurse_files('StickyNotes.snt', '/Users','equals')
이제 결과 파일을 반복 해 보겠습니다. 그런 다음 우리는parse_snt_file() 함수를 사용하여 파일을 처리 한 다음 RTF 파일을 write_note_rtf() 다음과 같이 방법-
report_details = []
for note_file in note_files:
user_dir = note_file[1].split("/")[1]
file_like_obj = create_file_like_obj(note_file[2])
note_data = parse_snt_file(file_like_obj)
if note_data is None:
continue
write_note_rtf(note_data, os.path.join(report_folder, user_dir))
report_details += prep_note_report(note_data, REPORT_COLS,"/Users" + note_file[1])
write_csv(os.path.join(report_folder, 'sticky_notes.csv'), REPORT_COLS,report_details)
다음으로이 스크립트에서 사용되는 다양한 함수를 정의해야합니다.
우선 우리는 create_file_like_obj() 파일 크기를 읽는 기능 pytsk파일 객체. 그런 다음 정의합니다parse_snt_file() 파일 류 객체를 입력으로 받아들이고 스티커 메모 파일을 읽고 해석하는 데 사용되는 함수입니다.
def parse_snt_file(snt_file):
if not olefile.isOleFile(snt_file):
print("This is not an OLE file")
return None
ole = olefile.OleFileIO(snt_file)
note = {}
for stream in ole.listdir():
if stream[0].count("-") == 3:
if stream[0] not in note:
note[stream[0]] = {"created": ole.getctime(stream[0]),"modified": ole.getmtime(stream[0])}
content = None
if stream[1] == '0':
content = ole.openstream(stream).read()
elif stream[1] == '3':
content = ole.openstream(stream).read().decode("utf-16")
if content:
note[stream[0]][stream[1]] = content
return note
이제 다음을 정의하여 RTF 파일을 만듭니다. write_note_rtf() 다음과 같이 기능
def write_note_rtf(note_data, report_folder):
if not os.path.exists(report_folder):
os.makedirs(report_folder)
for note_id, stream_data in note_data.items():
fname = os.path.join(report_folder, note_id + ".rtf")
with open(fname, 'w') as open_file:
open_file.write(stream_data['0'])
이제 중첩 된 사전을 CSV 스프레드 시트에 더 적합한 단순 사전 목록으로 변환합니다. 정의하여 수행됩니다.prep_note_report()함수. 마지막으로write_csv() 함수.
def prep_note_report(note_data, report_cols, note_file):
report_details = []
for note_id, stream_data in note_data.items():
report_details.append({
"note_id": note_id,
"created": stream_data['created'],
"modified": stream_data['modified'],
"note_text": stream_data['3'].strip("\x00"),
"note_file": note_file
})
return report_details
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
위의 스크립트를 실행 한 후 스티커 메모 파일에서 메타 데이터를 가져옵니다.
레지스트리 파일
Windows 레지스트리 파일에는 포렌식 분석가를위한 보물 창고와 같은 중요한 세부 정보가 많이 포함되어 있습니다. 운영 체제 구성, 사용자 활동, 소프트웨어 설치 등과 관련된 세부 정보를 포함하는 계층 적 데이터베이스입니다. 다음 Python 스크립트에서는 다음에서 공통 기준 정보에 액세스합니다.SYSTEM 과 SOFTWARE 두드러기.
이 Python 스크립트의 경우 타사 모듈을 설치해야합니다. pytsk3, pyewf 과 registry. 우리는 사용할 수 있습니다pip 설치합니다.
Windows 레지스트리에서 정보를 추출하려면 아래 단계를 따를 수 있습니다.
먼저 이름과 경로로 처리 할 레지스트리 하이브를 찾습니다.
그런 다음 StringIO 및 레지스트리 모듈을 사용하여 이러한 파일을 엽니 다.
마지막으로 모든 하이브를 처리하고 해석을 위해 구문 분석 된 값을 콘솔에 출력해야합니다.
파이썬 코드
이 목적으로 파이썬 코드를 사용하는 방법을 살펴 보겠습니다.
먼저 다음 Python 라이브러리를 가져옵니다.
from __future__ import print_function
from argparse import ArgumentParser
import datetime
import StringIO
import struct
from utility.pytskutil import TSKUtil
from Registry import Registry
이제 명령 줄 처리기에 대한 인수를 제공합니다. 여기서 두 개의 인수를받습니다. 첫 번째는 증거 파일의 경로이고 두 번째는 아래에 표시된 증거 파일의 유형입니다.
if __name__ == '__main__':
parser = argparse.ArgumentParser('Evidence from Windows Registry')
parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE', help = "Evidence file format",
choices = ('ewf', 'raw'))
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE)
이제 우리는 main() 검색 기능 SYSTEM 과 SOFTWARE 내 두드러기 /Windows/System32/config 다음과 같이 폴더-
def main(evidence, image_type):
tsk_util = TSKUtil(evidence, image_type)
tsk_system_hive = tsk_util.recurse_files('system', '/Windows/system32/config', 'equals')
tsk_software_hive = tsk_util.recurse_files('software', '/Windows/system32/config', 'equals')
system_hive = open_file_as_reg(tsk_system_hive[0][2])
software_hive = open_file_as_reg(tsk_software_hive[0][2])
process_system_hive(system_hive)
process_software_hive(software_hive)
이제 레지스트리 파일을 여는 기능을 정의하십시오. 이를 위해 파일 크기를 수집해야합니다.pytsk 메타 데이터는 다음과 같습니다-
def open_file_as_reg(reg_file):
file_size = reg_file.info.meta.size
file_content = reg_file.read_random(0, file_size)
file_like_obj = StringIO.StringIO(file_content)
return Registry.Registry(file_like_obj)
이제 다음과 같은 방법으로 처리 할 수 있습니다. SYSTEM> 하이브-
def process_system_hive(hive):
root = hive.root()
current_control_set = root.find_key("Select").value("Current").value()
control_set = root.find_key("ControlSet{:03d}".format(current_control_set))
raw_shutdown_time = struct.unpack(
'<Q', control_set.find_key("Control").find_key("Windows").value("ShutdownTime").value())
shutdown_time = parse_windows_filetime(raw_shutdown_time[0])
print("Last Shutdown Time: {}".format(shutdown_time))
time_zone = control_set.find_key("Control").find_key("TimeZoneInformation")
.value("TimeZoneKeyName").value()
print("Machine Time Zone: {}".format(time_zone))
computer_name = control_set.find_key("Control").find_key("ComputerName").find_key("ComputerName")
.value("ComputerName").value()
print("Machine Name: {}".format(computer_name))
last_access = control_set.find_key("Control").find_key("FileSystem")
.value("NtfsDisableLastAccessUpdate").value()
last_access = "Disabled" if last_access == 1 else "enabled"
print("Last Access Updates: {}".format(last_access))
이제 다음과 같이 형식화 된 날짜와 시간으로 해석 된 정수에 대한 함수를 정의해야합니다.
def parse_windows_filetime(date_value):
microseconds = float(date_value) / 10
ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds = microseconds)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
def parse_unix_epoch(date_value):
ts = datetime.datetime.fromtimestamp(date_value)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
이제 다음 방법의 도움으로 우리는 SOFTWARE 하이브-
def process_software_hive(hive):
root = hive.root()
nt_curr_ver = root.find_key("Microsoft").find_key("Windows NT")
.find_key("CurrentVersion")
print("Product name: {}".format(nt_curr_ver.value("ProductName").value()))
print("CSD Version: {}".format(nt_curr_ver.value("CSDVersion").value()))
print("Current Build: {}".format(nt_curr_ver.value("CurrentBuild").value()))
print("Registered Owner: {}".format(nt_curr_ver.value("RegisteredOwner").value()))
print("Registered Org:
{}".format(nt_curr_ver.value("RegisteredOrganization").value()))
raw_install_date = nt_curr_ver.value("InstallDate").value()
install_date = parse_unix_epoch(raw_install_date)
print("Installation Date: {}".format(install_date))
위의 스크립트를 실행 한 후 Windows 레지스트리 파일에 저장된 메타 데이터를 가져옵니다.