├── License.md ├── README.md ├── SdbaParser.au3 └── sigscan.ps1 /License.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Arsenal Consulting, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | Sdba Parser ("the Software") is provided "AS IS" and "WITH ALL FAULTS," without warranty of any kind, including without limitation the warranties of merchantability, fitness for a particular purpose and non-infringement. Arsenal Consulting, Inc. (d/b/a "Arsenal Recon") makes no warranty that the Software is free of defects or is suitable for any particular purpose. In no event shall Arsenal Consulting, Inc. be responsible for loss or damages arising from the installation or use of the Software, including but not limited to any indirect, punitive, special, incidental or consequential damages of any character including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. The entire risk as to the quality and performance of the Software is borne by you. Should the Software prove defective, you and not Arsenal Consulting, Inc. assume the entire cost of any service and repair. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Intro ## 2 | 3 | Arsenal's Sdba Parser carves and parses (hereafter, parses) Sdba memory pool tags (produced by Windows 7) from any input file. Sdba memory pool tags are related to Windows Application Compatibility Database functionality and seem to be generated each time a new executable (based on analysis of MFT record and sequence numbers) is run. Most importantly for digital forensics practitioners, Sdba memory pool tags contain executable file paths and NTFS last written timestamps (at time of execution). Arsenal has found Sdba memory pool tags from Windows hibernation (from both the active and slack space within hibernation) to be extremely important in our casework - more specifically, they provided insight not available through other artifacts within the same evidence. Sdba memory pool tags may also be found in memory captures, crash dumps, swap files, and (under the right circumstances) unallocated space. 4 | 5 | ## Requirements: ## 6 | 7 | Appropriate PowerShell execution policy (temporarily enabling the "Unrestricted" policy) 8 | 9 | ## Usage: ## 10 | 11 | Sdba Parser can be run with a GUI by simply executing SdbaParser64.exe. Output is in CSV (pipe separated) format. 12 | 13 | If you intend to parse Sdba memory pool tags from Windows hibernation, Arsenal recommends using the Hibernation Recon output files "ActiveMemory.bin" and "AllSlack.bin". 14 | 15 | Sdba Parser can also be run from a command prompt: 16 | 17 | ``` 18 | SdbaParser64.exe /Input: /Output: /Arch: 19 | ``` 20 | 21 | * Input = Full path to the file to parse 22 | * Output = Optionally set path for the output. Defaults to program directory. 23 | * Arch = The source architecture. Must be 32 or 64. 24 | 25 | ### Examples: ### 26 | 27 | ``` 28 | SdbaParser64.exe /Input:D:\temp\ActiveMemory.bin /Output:D:\temp /Arch:32 29 | SdbaParser64.exe /Input:D:\temp\pagefile.sys /Arch:64 30 | ``` 31 | 32 | ## Contributions: ## 33 | 34 | Contributions and improvements to the code are welcomed. 35 | 36 | ## License: ## 37 | 38 | Distributed under the MIT License. See License.md for details. 39 | 40 | ## More Information: ## 41 | 42 | To learn more about Arsenal’s digital forensics software and training, please visit https://ArsenalRecon.com and follow us on Twitter @ArsenalRecon (https://twitter.com/ArsenalRecon). 43 | 44 | To learn more about Arsenal’s digital forensics consulting services, please visit https://ArsenalExperts.com and follow us on Twitter @ArsenalArmed (https://twitter.com/ArsenalArmed). -------------------------------------------------------------------------------- /SdbaParser.au3: -------------------------------------------------------------------------------- 1 | #Region ;**** Directives created by AutoIt3Wrapper_GUI **** 2 | #AutoIt3Wrapper_Icon=C:\Program Files (x86)\AutoIt3\Icons\au3.ico 3 | #AutoIt3Wrapper_Outfile=SdbaParser32.exe 4 | #AutoIt3Wrapper_Outfile_x64=SdbaParser64.exe 5 | #AutoIt3Wrapper_Compile_Both=y 6 | #AutoIt3Wrapper_Change2CUI=y 7 | #AutoIt3Wrapper_Res_Fileversion=1.0.0.1 8 | #AutoIt3Wrapper_Res_ProductVersion=1.0.0.1 9 | #AutoIt3Wrapper_Res_Comment=Sdba pool tag parser 10 | #AutoIt3Wrapper_Res_Description=Sdba pool tag parser 11 | #AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 5 12 | #AutoIt3Wrapper_Run_Au3Stripper=y 13 | #Au3Stripper_Parameters=/sf /sv /rm /pe 14 | #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #Include 24 | 25 | Global $de = "|", $sTimestamp, $filepathLength, $isX64, $blocksizetimestamp 26 | Global $csv_columns = "offset"&$de&"source"&$de&"size_previous"&$de&"size_current"&$de&"timestamp"&$de&"filepath" 27 | Global $stringArray2[] = ["[\x06]Sdba"] 28 | 29 | Global $hexRegExArray2[] = ["[\x03|\x06]\x53\x64\x62\x61"] 30 | Global $arr_hits[0][0] 31 | 32 | Global $blocksize, $charmove, $tagSdba 33 | 34 | Global $DateTimeFormat = 6 ; 1=YYYYMMDDHHMM, 2=MM/DD/YYYY HH:MM, 3=DD/MM/YYYY HH:MM, 4=Month DD, YYYY HH:MM, 5=DD Month YYYY HH:MM, 6=YYYY-MM-DD-HH:MM 35 | Global $TimestampPrecision = 3 ; 3=nansec, 2=millisec, 1=sec 36 | Global $PrecisionSeparator = ".", $PrecisionSeparator2 = "" 37 | Global $_COMMON_KERNEL32DLL=DllOpen("kernel32.dll") 38 | Global $TimestampErrorVal = "0000-00-00 00:00:00" 39 | Global $tDelta = _WinTime_GetUTCToLocalFileTimeDelta() 40 | 41 | Global $AdlibInterval = 5000 ;Millisec for the script to halt and update progress bar 42 | Global $ProgressBar2, $CurrentProgress2 = 0, $ProgressTotal2 = 0 43 | Global $ProgressBar3, $CurrentProgress3 = 0, $ProgressTotal3 = 0 44 | 45 | Global $ButtonColor = 0x2f4e57, $active = False 46 | Global $myctredit, $ButtonCancel, $ButtonStart, $ButtonOpenOutput, $LabelProgress3, $ButtonOutput, $OutputField, $LabelOutput 47 | Global $ButtonInput, $InputField, $Form, $radio32,$radio64 48 | Global $file_input, $folder_output = @ScriptDir, $OutPutPath = @ScriptDir 49 | Global $CommandlineMode, $mainlogfile, $TargetInput, $hCsv 50 | 51 | If $cmdline[0] > 0 Then 52 | $CommandlineMode = 1 53 | _GetInputParams() 54 | _Init() 55 | Exit 56 | Else 57 | DllCall("kernel32.dll", "bool", "FreeConsole") 58 | $CommandlineMode = 0 59 | OnAutoItExitRegister("_GuiExitMessage") 60 | 61 | Opt("GUIOnEventMode", 1) 62 | $Form = GUICreate("Sdba parser", 830, 500, -1, -1) 63 | GUISetOnEvent($GUI_EVENT_CLOSE, "_HandleExit") 64 | 65 | $LabelInput = GUICtrlCreateLabel("Select input file:", 20, 20, 120, 20) 66 | $InputField = GUICtrlCreateInput("", 140, 20, 510, 20) 67 | GUICtrlSetState($InputField, $GUI_DISABLE) 68 | $ButtonInput = GUICtrlCreateButton("Browse", 700, 20, 100, 30) 69 | GUICtrlSetOnEvent($ButtonInput, "_HandleEvent") 70 | GUICtrlSetBkColor(-1, $ButtonColor) 71 | GUICtrlSetFont(-1, 9, $FW_SEMIBOLD, $GUI_FONTNORMAL, "", $CLEARTYPE_QUALITY) 72 | GUICtrlSetColor(-1, 0xFFFFFF) 73 | 74 | 75 | $LabelOutput = GUICtrlCreateLabel("Select output folder:", 20, 70, 120, 20) 76 | $OutputField = GUICtrlCreateInput("Optional. Defaults to program directory", 140, 70, 510, 20) 77 | GUICtrlSetState($OutputField, $GUI_DISABLE) 78 | $ButtonOutput = GUICtrlCreateButton("Browse", 700, 70, 100, 30) 79 | GUICtrlSetOnEvent($ButtonOutput, "_HandleEvent") 80 | GUICtrlSetBkColor(-1, $ButtonColor) 81 | GUICtrlSetFont(-1, 9, $FW_SEMIBOLD, $GUI_FONTNORMAL, "", $CLEARTYPE_QUALITY) 82 | GUICtrlSetColor(-1, 0xFFFFFF) 83 | 84 | $radio32 = GUICtrlCreateRadio("Source is x32", 30, 110, 100, 20) 85 | $radio64 = GUICtrlCreateRadio("Source is x64", 30, 140, 100, 20) 86 | 87 | $LabelProgress2 = GUICtrlCreateLabel("Progress regex scan:", 10, 210, 200, 20) 88 | $ProgressBar2 = GUICtrlCreateProgress(10, 230, 810, 30) 89 | $LabelProgress3 = GUICtrlCreateLabel("Progress tag parsing:", 10, 270, 200, 20) 90 | $ProgressBar3 = GUICtrlCreateProgress(10, 290, 810, 30) 91 | 92 | $ButtonStart = GUICtrlCreateButton("Start Parsing", 20, 450, 150, 40, $BS_BITMAP) 93 | GUICtrlSetOnEvent($ButtonStart, "_HandleEvent") 94 | GUICtrlSetBkColor(-1, $ButtonColor) 95 | GUICtrlSetFont(-1, 9, $FW_SEMIBOLD, $GUI_FONTNORMAL, "", $CLEARTYPE_QUALITY) 96 | GUICtrlSetColor(-1, 0xFFFFFF) 97 | $ButtonCancel = GUICtrlCreateButton("Exit", 175, 450, 150, 40) 98 | GUICtrlSetOnEvent($ButtonCancel, "_HandleCancel") 99 | GUICtrlSetBkColor(-1, $ButtonColor) 100 | GUICtrlSetFont(-1, 9, $FW_SEMIBOLD, $GUI_FONTNORMAL, "", $CLEARTYPE_QUALITY) 101 | GUICtrlSetColor(-1, 0xFFFFFF) 102 | $ButtonOpenOutput = GUICtrlCreateButton("Open Output", 330, 450, 150, 40) 103 | GUICtrlSetOnEvent($ButtonOpenOutput, "_HandleOpenOutput") 104 | GUICtrlSetBkColor(-1, $ButtonColor) 105 | GUICtrlSetFont(-1, 9, $FW_SEMIBOLD, $GUI_FONTNORMAL, "", $CLEARTYPE_QUALITY) 106 | GUICtrlSetColor(-1, 0xFFFFFF) 107 | 108 | $myctredit = GUICtrlCreateEdit("", 0, 330, 830, 100, BitOR($ES_AUTOVSCROLL,$WS_VSCROLL)) 109 | _GUICtrlEdit_SetLimitText($myctredit, 128000) 110 | 111 | GUISetState(@SW_SHOW) 112 | 113 | While Not $active 114 | ;Wait for event. The $active variable is set when parsing and reset when done in order for multiple parsing executions to run subsequently 115 | 116 | Sleep(500) 117 | If $active Then 118 | _HandleParsing() 119 | $active = False 120 | EndIf 121 | WEnd 122 | 123 | EndIf 124 | 125 | Func _Init() 126 | 127 | $sTimestamp = "" 128 | $filepathLength = 0 129 | $CurrentProgress3 = 0 130 | ReDim $arr_hits[0][0] 131 | _ResetProgress($ProgressBar2) 132 | _ResetProgress($ProgressBar3) 133 | 134 | Local $sTimestampStart = @YEAR & "-" & @MON & "-" & @MDAY & "_" & @HOUR & "-" & @MIN & "-" & @SEC 135 | $OutPutPath = $folder_output & "\SdbaParser-" & $sTimestampStart 136 | If DirCreate($OutputPath) = 0 Then 137 | _DisplayWrapper("Error creating: " & $OutputPath & @CRLF) 138 | Return 139 | EndIf 140 | $mainlogfile = FileOpen($OutPutPath & "\" & "logfile.txt", 2+32) 141 | If @error Then 142 | _DisplayWrapper("Error: Could not open logfile" & @CRLF) 143 | Return 144 | EndIf 145 | _DumpOut("Parsing " & $TargetInput & @CRLF) 146 | _DisplayWrapper("Parsing " & $TargetInput & @CRLF) 147 | 148 | _DisplayWrapper("Writing output to: " & $OutPutPath & @CRLF) 149 | 150 | $hCsv = FileOpen($OutPutPath & "\sdba.csv", 2) 151 | FileWriteLine($hCsv, $csv_columns) 152 | 153 | ; set some variables used in _main that depends on arch 154 | If $isX64 Then 155 | $blocksize = 16 156 | $charmove = 13 157 | $tagSdba = "byte;byte;byte;byte;char[4];byte[56];ushort;ushort;byte[12];uint64;uint;uint;byte[8]" 158 | $blocksizetimestamp = 7 159 | _DumpOut("Architecture: x64 " & @CRLF) 160 | Else 161 | $blocksize = 8 162 | $charmove = 5 163 | $tagSdba = "byte;byte;byte;byte;char[4];byte[24];ushort;ushort;byte[4];uint64;uint;uint;byte[8]" 164 | $blocksizetimestamp = 8 165 | _DumpOut("Architecture: x32 " & @CRLF) 166 | EndIf 167 | 168 | Local $Timerstart = TimerInit() 169 | 170 | Global $coreFileName = _GetFilenameFromPath($TargetInput) 171 | 172 | Global $arr_hits[0][2] 173 | Local $matches, $totalMatches 174 | 175 | _DisplayWrapper("Searching for signatures..." & @CRLF) 176 | 177 | For $i = 0 To UBound($hexRegExArray2) - 1 178 | $matches = _Signature2Array_v2($TargetInput, $arr_hits, $stringArray2[$i], $hexRegExArray2[$i]) 179 | $totalMatches += $matches 180 | Next 181 | 182 | GUICtrlSetData($ProgressBar2, 100) 183 | 184 | AdlibRegister("_UpdateProgress3", $AdlibInterval) 185 | 186 | Local $hFile = _WinAPI_CreateFile($TargetInput, 2, 6, 7) 187 | If Not $hFile Then 188 | ConsoleWrite("Error in CreateFile: " & _WinAPI_GetLastErrorMessage() & @CRLF) 189 | Exit 190 | EndIf 191 | 192 | Global $fileSize = _WinAPI_GetFileSizeEx($hFile) 193 | _DumpOut("fileSize: " & $fileSize & @CRLF) 194 | 195 | _DumpOut("found signatures: " & $totalMatches & @CRLF) 196 | _DisplayWrapper("found signatures: " & $totalMatches & @CRLF) 197 | 198 | ;Local $nBytes 199 | _WinAPI_SetFilePointerEx($hFile, 0, $FILE_BEGIN) 200 | 201 | $ProgressTotal3 = UBound($arr_hits) 202 | 203 | For $i = 0 To UBound($arr_hits) - 1 204 | $CurrentProgress3 = $i 205 | _main($hFile, $i) 206 | Next 207 | 208 | 209 | _DumpOut("Job took " & _WinAPI_StrFromTimeInterval(TimerDiff($Timerstart)) & @CRLF) 210 | _DisplayWrapper("Job took " & _WinAPI_StrFromTimeInterval(TimerDiff($Timerstart)) & @CRLF) 211 | 212 | _WinAPI_CloseHandle($hFile) 213 | FileClose($mainlogfile) 214 | FileClose($hCsv) 215 | 216 | GUICtrlSetData($ProgressBar3, 100) 217 | AdlibUnRegister("_UpdateProgress3") 218 | EndFunc 219 | 220 | Func _GetInputParams() 221 | Local $TmpInputPath, $TmpOutPath, $TmpArch 222 | For $i = 1 To $cmdline[0] 223 | ;ConsoleWrite("Param " & $i & ": " & $cmdline[$i] & @CRLF) 224 | If StringLeft($cmdline[$i],2) = "/?" Or StringLeft($cmdline[$i],2) = "-?" Or StringLeft($cmdline[$i],2) = "-h" Then _PrintHelp() 225 | If StringLeft($cmdline[$i],7) = "/Input:" Then $TmpInputPath = StringMid($cmdline[$i],8) 226 | If StringLeft($cmdline[$i],8) = "/Output:" Then $TmpOutPath = StringMid($cmdline[$i],9) 227 | If StringLeft($cmdline[$i],6) = "/Arch:" Then $TmpArch = StringMid($cmdline[$i],7) 228 | Next 229 | 230 | If StringLen($TmpOutPath) > 0 Then 231 | 232 | If FileExists($TmpOutPath) Then 233 | $folder_output = $TmpOutPath 234 | Else 235 | ConsoleWrite("Warning: The specified Output path could not be found: " & $TmpOutPath & @CRLF) 236 | ConsoleWrite("Relocating output to current directory: " & @ScriptDir & @CRLF) 237 | $folder_output = @ScriptDir 238 | EndIf 239 | EndIf 240 | 241 | If StringLen($TmpInputPath) > 0 Then 242 | 243 | If Not FileExists($TmpInputPath) And StringInStr($TmpInputPath, "*") = 0 Then 244 | ConsoleWrite("Error: Could not find input: " & $TmpInputPath & @CRLF) 245 | Exit 246 | EndIf 247 | $TargetInput = $TmpInputPath 248 | Else 249 | ConsoleWrite("Error: missing input" & @CRLF) 250 | Exit 251 | EndIf 252 | 253 | If StringLen($TmpArch) > 0 Then 254 | 255 | Select 256 | Case $TmpArch = "32" 257 | $isX64 = 0 258 | Case $TmpArch = "64" 259 | $isX64 = 1 260 | Case Else 261 | ConsoleWrite("Error: Could not validate arch: " & $TmpArch & @CRLF) 262 | Exit 263 | EndSelect 264 | Else 265 | ConsoleWrite("Error: missing arch" & @CRLF) 266 | Exit 267 | EndIf 268 | 269 | 270 | EndFunc 271 | 272 | Func _HandleCancel() 273 | Exit 274 | EndFunc 275 | 276 | Func _HandleExit() 277 | Exit 278 | EndFunc 279 | 280 | Func _ResetProgress($ProgressBar) 281 | GUICtrlSetData($ProgressBar, 0) 282 | EndFunc 283 | 284 | 285 | Func _UpdateProgress3() 286 | GUICtrlSetData($ProgressBar3, 100 * $CurrentProgress3 / $ProgressTotal3) 287 | EndFunc 288 | 289 | Func _PrintBeforeExit($input) 290 | _DumpOut($input) 291 | _DisplayWrapper($input) 292 | EndFunc 293 | 294 | Func _DisplayWrapper($input) 295 | 296 | If $CommandlineMode Then 297 | ConsoleWrite($input) 298 | Else 299 | _DisplayInfo($input) 300 | EndIf 301 | 302 | EndFunc 303 | 304 | Func _DumpOut($text) 305 | ; ConsoleWrite($text) 306 | If $mainlogfile Then FileWrite($mainlogfile, $text) 307 | EndFunc 308 | 309 | Func _DisplayInfo($DebugInfo) 310 | GUICtrlSetData($myctredit, $DebugInfo, 1) 311 | EndFunc 312 | 313 | Func _GuiExitMessage() 314 | If Not $CommandlineMode Then 315 | If @exitCode Then 316 | MsgBox(0, "Error", "An error was triggered. Check the output buffer.") 317 | EndIf 318 | EndIf 319 | EndFunc 320 | 321 | Func _HandleEvent() 322 | If Not $active Then 323 | Switch @GUI_CtrlId 324 | Case $ButtonInput 325 | _HandleFileInput() 326 | ; Case $ButtonFolder 327 | ; _HandleFolderInput() 328 | Case $ButtonOutput 329 | _HandleOutput() 330 | Case $ButtonStart 331 | $active = True 332 | Case $ButtonCancel 333 | _HandleCancel() 334 | Case $ButtonOpenOutput 335 | _HandleOpenOutput() 336 | Case $GUI_EVENT_CLOSE 337 | _HandleExit() 338 | EndSwitch 339 | EndIf 340 | EndFunc 341 | 342 | Func _HandleFileInput() 343 | $file_input = FileOpenDialog("Select input file", @ScriptDir, "All (*.*)") 344 | If $file_input Then 345 | GUICtrlSetData($InputField, $file_input) 346 | EndIf 347 | 348 | _ResetProgress($ProgressBar2) 349 | _ResetProgress($ProgressBar3) 350 | EndFunc 351 | 352 | 353 | Func _HandleOpenOutput() 354 | Run("explorer.exe " & $OutPutPath) 355 | EndFunc 356 | 357 | Func _HandleOutput() 358 | $folder_output = FileSelectFolder("Select output folder", @ScriptDir) 359 | If $folder_output Then 360 | GUICtrlSetData($OutputField, $folder_output) 361 | EndIf 362 | 363 | _ResetProgress($ProgressBar2) 364 | _ResetProgress($ProgressBar3) 365 | EndFunc 366 | 367 | Func _HandleParsing() 368 | _ResetProgress($ProgressBar2) 369 | _ResetProgress($ProgressBar3) 370 | If _GuiGetSettings() Then 371 | _Init() 372 | EndIf 373 | EndFunc 374 | 375 | Func _GuiGetSettings() 376 | 377 | If Int(GUICtrlRead($radio32) + GUICtrlRead($radio64)) <> 5 Then 378 | _DisplayInfo("Error: You must configure source architecture (x32 or x64)" & @CRLF) 379 | Return 380 | EndIf 381 | 382 | Select 383 | Case Int(GUICtrlRead($radio32)) = 1 384 | $isX64 = 0 385 | _DisplayInfo("Architecture: x32" & @CRLF) 386 | Case Int(GUICtrlRead($radio64)) = 1 387 | $isX64 = 1 388 | _DisplayInfo("Architecture: x64" & @CRLF) 389 | EndSelect 390 | 391 | $TargetInput = $file_input 392 | If Not FileExists($TargetInput) Then 393 | _DisplayInfo("Error: input not found: " & $TargetInput & @CRLF) 394 | Return 395 | EndIf 396 | 397 | If Not FileExists($OutPutPath) Then 398 | _DisplayInfo("Error: output directory not found: " & $OutPutPath & @CRLF) 399 | Return 400 | EndIf 401 | 402 | Return 1 403 | 404 | EndFunc 405 | 406 | Func _GUI_Disable_Control() 407 | GUICtrlSetData($myctredit, "Processing started.." & @CRLF) 408 | GUICtrlSetState($ButtonInput, $GUI_DISABLE) 409 | GUICtrlSetState($ButtonOutput, $GUI_DISABLE) 410 | GUICtrlSetState($ButtonStart, $GUI_DISABLE) 411 | EndFunc 412 | 413 | Func _GUI_Enable_Controls() 414 | GUICtrlSetState($ButtonInput, $GUI_ENABLE) 415 | GUICtrlSetState($ButtonOutput, $GUI_ENABLE) 416 | GUICtrlSetState($ButtonStart, $GUI_ENABLE) 417 | EndFunc 418 | 419 | Func _main($hFile, $row) 420 | 421 | Local $nBytes 422 | Local $startOffset = $arr_hits[$row][0] 423 | 424 | _DumpOut("Trying signature " & $row & " at 0x" & Hex($startOffset, 8) & @CRLF) 425 | 426 | Local $pTmpBuff1 = DllStructCreate($tagSdba) 427 | 428 | _WinAPI_SetFilePointerEx($hFile, $startOffset - 3, $FILE_BEGIN) 429 | _WinAPI_ReadFile($hFile, DllStructGetPtr($pTmpBuff1), DllStructGetSize($pTmpBuff1), $nBytes) 430 | 431 | ;Local $testChunk = DllStructGetData($pTmpBuff1, 1) 432 | ;ConsoleWrite(_HexEncode($testChunk)) 433 | 434 | Local $prevSize = DllStructGetData($pTmpBuff1, 1) ; prev_size 435 | ; Local $unk1 = DllStructGetData($pTmpBuff1, 2) 436 | Local $currSize = DllStructGetData($pTmpBuff1, 3) ; curr_size 437 | ; Local $fixedStartByte = DllStructGetData($pTmpBuff1, 4) ; 0x06 438 | Local $poolTag = DllStructGetData($pTmpBuff1, 5) ; signature - Sdba 439 | ; Local $unk2 = DllStructGetData($pTmpBuff1, 6) 440 | Local $filepathSize1 = DllStructGetData($pTmpBuff1, 7); the filepath bytes 441 | ; Local $filepathSize2 = DllStructGetData($pTmpBuff1, 8) 442 | Local $timestampVal = DllStructGetData($pTmpBuff1, 10) ; timestamp 443 | ; Local $executableType = DllStructGetData($pTmpBuff1, 11) ; 7=exe, 6=admin/shortname, 5=dll, E=exe/office ?, 444 | ; Local $unk3 = DllStructGetData($pTmpBuff1, 12) 445 | 446 | If $poolTag <> "Sdba" Then 447 | ; ConsoleWrite("Error: Wrong signature" & @CRLF) 448 | Return 449 | EndIf 450 | 451 | Local $sFilePath 452 | 453 | If $currSize < 4 Then 454 | FileWriteLine($hCsv, "0x"&Hex($startOffset - 3, 8) & $de & $coreFileName & $de & $prevSize & $de & $currSize & $de & $sTimestamp & $de & $sFilePath & @CRLF) 455 | Return 456 | EndIf 457 | 458 | ; sanity check on the tiemstamp to filter out corrupt or invalid data 459 | If $timestampVal < 112589990684262400 Or $timestampVal > 139611588448485376 Then 460 | ; ConsoleWrite("Error: Bad timestamp" & @CRLF) 461 | $entrySize = $currSize * $blocksize 462 | ; ConsoleWrite("Testing filepath with size: " & $entrySize & @CRLF) 463 | Local $pTmpBuff2 = DllStructCreate("byte[" & $entrySize & "]") 464 | _WinAPI_SetFilePointerEx($hFile, $startOffset + $charmove, $FILE_BEGIN) 465 | _WinAPI_ReadFile($hFile, DllStructGetPtr($pTmpBuff2), DllStructGetSize($pTmpBuff2), $nBytes) 466 | $pFilePath = DllStructCreate("wchar[" & ($entrySize - $blocksize) / 2 & "]", DllStructGetPtr($pTmpBuff2)) 467 | $sFilePath = DllStructGetData($pFilePath, 1) 468 | If StringMid($sFilePath, 1, 4) <> "\??\" Then 469 | $sFilePath = "" 470 | FileWriteLine($hCsv, "0x"&Hex($startOffset - 3, 8) & $de & $coreFileName & $de & $prevSize & $de & $currSize & $de & $sTimestamp & $de & $sFilePath & @CRLF) 471 | Else 472 | If ($prevSize <> 1 And $prevSize <> $blocksizetimestamp And $prevSize <> 58) Or $filepathLength/2 <> StringLen($sFilePath) Then 473 | ; a check if the previous entry was a timestamp. if not then reset it 474 | $sTimestamp = "" 475 | EndIf 476 | FileWriteLine($hCsv, "0x"&Hex($startOffset - 3, 8) & $de & $coreFileName & $de & $prevSize & $de & $currSize & $de & $sTimestamp & $de & $sFilePath & @CRLF) 477 | $sTimestamp = "" 478 | EndIf 479 | ; ConsoleWrite("$sFilePath: " & $sFilePath & @CRLF) 480 | Return 481 | Else 482 | $sTimestamp = _DecodeTimestampDecimal($timestampVal) 483 | ; ConsoleWrite("$sTimestamp: " & $sTimestamp & @CRLF) 484 | $filepathLength = $filepathSize1 485 | EndIf 486 | 487 | FileWriteLine($hCsv, "0x"&Hex($startOffset - 3, 8) & $de & $coreFileName & $de & $prevSize & $de & $currSize & $de & $sTimestamp & $de & $sFilePath & @CRLF) 488 | 489 | Return 490 | 491 | EndFunc 492 | 493 | 494 | Func _Signature2Array_v2($FilePath, ByRef $arr, $TargetString, $RegexString) 495 | 496 | Local $sPSScript = '"' & @ScriptDir & "\sigscan.ps1" & '"' 497 | 498 | Local $sCMD = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File " & $sPSScript & " -hex " & $RegexString & " -filepath " & '"' & $FilePath & '"' 499 | 500 | Local $pid = Run($sCMD, @SystemDir, @SW_HIDE, $STDIN_CHILD + $STDOUT_CHILD + $STDERR_CHILD) 501 | If @error Then 502 | _DumpOut("Error: Could not execute external script" & @CRLF) 503 | Exit 504 | EndIf 505 | 506 | StdinWrite($pid) 507 | Local $AllOutput = "", $sOutput = "" 508 | Local $hTimer = TimerInit() 509 | While 1 510 | $sOutput = StdoutRead($pid) 511 | If @error Then ExitLoop 512 | If $sOutput <> "" Then $AllOutput &= $sOutput 513 | If Not ProcessExists($pid) Then ExitLoop 514 | ; exit the loop if processing is +10 min 515 | If TimerDiff($hTimer) > 600000 Then ExitLoop 516 | WEnd 517 | 518 | ; ConsoleWrite("$AllOutput" & @CRLF) 519 | ; ConsoleWrite($AllOutput & @CRLF) 520 | 521 | If StringInStr($AllOutput, "Error") Then 522 | _DumpOut("Error: Something went wrong in the parsing of input" & @CRLF) 523 | Return 0 524 | EndIf 525 | 526 | 527 | Local $OutputArray = StringSplit($AllOutput, @CRLF) 528 | ;_ArrayDisplay($OutputArray, "$OutputArray") 529 | 530 | Local $counter = 0 531 | Local $currentArraySize = UBound($arr) 532 | ReDim $arr[$currentArraySize + $OutputArray[0]][2] 533 | For $i = 1 To $OutputArray[0] 534 | If $OutputArray[$i] = "" Then 535 | ContinueLoop 536 | EndIf 537 | If StringLeft($OutputArray[$i], 2) <> "0x" Then 538 | ContinueLoop 539 | EndIf 540 | If StringLen($OutputArray[$i]) <> 18 Then 541 | ContinueLoop 542 | EndIf 543 | $arr[$currentArraySize + $counter][0] = Number($OutputArray[$i]) 544 | $arr[$currentArraySize + $counter][1] = $TargetString 545 | $counter += 1 546 | Next 547 | 548 | ReDim $arr[$currentArraySize + $counter][2] 549 | ; _ArrayDisplay($arr, "$arr") 550 | Return $counter 551 | EndFunc 552 | 553 | Func _SwapEndian($iHex) 554 | Return StringMid(Binary(Dec($iHex,2)),3, StringLen($iHex)) 555 | EndFunc 556 | 557 | Func _HexEncode($bInput) 558 | Local $tInput = DllStructCreate("byte[" & BinaryLen($bInput) & "]") 559 | DllStructSetData($tInput, 1, $bInput) 560 | Local $a_iCall = DllCall("crypt32.dll", "int", "CryptBinaryToString", _ 561 | "ptr", DllStructGetPtr($tInput), _ 562 | "dword", DllStructGetSize($tInput), _ 563 | "dword", 11, _ 564 | "ptr", 0, _ 565 | "dword*", 0) 566 | 567 | If @error Or Not $a_iCall[0] Then 568 | Return SetError(1, 0, "") 569 | EndIf 570 | Local $iSize = $a_iCall[5] 571 | Local $tOut = DllStructCreate("char[" & $iSize & "]") 572 | $a_iCall = DllCall("crypt32.dll", "int", "CryptBinaryToString", _ 573 | "ptr", DllStructGetPtr($tInput), _ 574 | "dword", DllStructGetSize($tInput), _ 575 | "dword", 11, _ 576 | "ptr", DllStructGetPtr($tOut), _ 577 | "dword*", $iSize) 578 | If @error Or Not $a_iCall[0] Then 579 | Return SetError(2, 0, "") 580 | EndIf 581 | Return SetError(0, 0, DllStructGetData($tOut, 1)) 582 | EndFunc 583 | 584 | Func _DecodeTimestamp($StampDecode) 585 | $StampDecode = _SwapEndian($StampDecode) 586 | $StampDecode_tmp = _WinTime_UTCFileTimeToLocalFileTime("0x" & $StampDecode) 587 | $StampDecode = _WinTime_UTCFileTimeFormat(Dec($StampDecode,2) - $tDelta, $DateTimeFormat, $TimestampPrecision) 588 | If @error Then 589 | $StampDecode = $TimestampErrorVal 590 | ElseIf $TimestampPrecision = 3 Then 591 | $StampDecode = $StampDecode & $PrecisionSeparator2 & _FillZero(StringRight($StampDecode_tmp, 4)) 592 | EndIf 593 | Return $StampDecode 594 | EndFunc 595 | 596 | Func _WinTime_GetUTCToLocalFileTimeDelta() 597 | Local $iUTCFileTime=864000000000 ; exactly 24 hours from the origin (although 12 hours would be more appropriate (max variance = 12)) 598 | $iLocalFileTime=_WinTime_UTCFileTimeToLocalFileTime($iUTCFileTime) 599 | If @error Then Return SetError(@error,@extended,-1) 600 | Return $iLocalFileTime-$iUTCFileTime ; /36000000000 = # hours delta (effectively giving the offset in hours from UTC/GMT) 601 | EndFunc 602 | 603 | Func _WinTime_UTCFileTimeToLocalFileTime($iUTCFileTime) 604 | If $iUTCFileTime<0 Then Return SetError(1,0,-1) 605 | Local $aRet=DllCall($_COMMON_KERNEL32DLL,"bool","FileTimeToLocalFileTime","uint64*",$iUTCFileTime,"uint64*",0) 606 | If @error Then Return SetError(2,@error,-1) 607 | If Not $aRet[0] Then Return SetError(3,0,-1) 608 | Return $aRet[2] 609 | EndFunc 610 | 611 | Func _WinTime_UTCFileTimeFormat($iUTCFileTime,$iFormat=4,$iPrecision=0,$bAMPMConversion=False) 612 | ;~ If $iUTCFileTime<0 Then Return SetError(1,0,"") ; checked in below call 613 | 614 | ; First convert file time (UTC-based file time) to 'local file time' 615 | Local $iLocalFileTime=_WinTime_UTCFileTimeToLocalFileTime($iUTCFileTime) 616 | If @error Then Return SetError(@error,@extended,"") 617 | ; Rare occassion: a filetime near the origin (January 1, 1601!!) is used, 618 | ; causing a negative result (for some timezones). Return as invalid param. 619 | If $iLocalFileTime<0 Then Return SetError(1,0,"") 620 | 621 | ; Then convert file time to a system time array & format & return it 622 | Local $vReturn=_WinTime_LocalFileTimeFormat($iLocalFileTime,$iFormat,$iPrecision,$bAMPMConversion) 623 | Return SetError(@error,@extended,$vReturn) 624 | EndFunc 625 | 626 | Func _WinTime_LocalFileTimeFormat($iLocalFileTime,$iFormat=4,$iPrecision=0,$bAMPMConversion=False) 627 | ;~ If $iLocalFileTime<0 Then Return SetError(1,0,"") ; checked in below call 628 | 629 | ; Convert file time to a system time array & return result 630 | Local $aSysTime=_WinTime_LocalFileTimeToSystemTime($iLocalFileTime) 631 | If @error Then Return SetError(@error,@extended,"") 632 | 633 | ; Return only the SystemTime array? 634 | If $iFormat=0 Then Return $aSysTime 635 | 636 | Local $vReturn=_WinTime_FormatTime($aSysTime[0],$aSysTime[1],$aSysTime[2],$aSysTime[3], _ 637 | $aSysTime[4],$aSysTime[5],$aSysTime[6],$aSysTime[7],$iFormat,$iPrecision,$bAMPMConversion) 638 | Return SetError(@error,@extended,$vReturn) 639 | EndFunc 640 | 641 | Func _WinTime_LocalFileTimeToSystemTime($iLocalFileTime) 642 | Local $aRet,$stSysTime,$aSysTime[8]=[-1,-1,-1,-1,-1,-1,-1,-1] 643 | 644 | ; Negative values unacceptable 645 | If $iLocalFileTime<0 Then Return SetError(1,0,$aSysTime) 646 | 647 | ; SYSTEMTIME structure [Year,Month,DayOfWeek,Day,Hour,Min,Sec,Milliseconds] 648 | $stSysTime=DllStructCreate("ushort[8]") 649 | 650 | $aRet=DllCall($_COMMON_KERNEL32DLL,"bool","FileTimeToSystemTime","uint64*",$iLocalFileTime,"ptr",DllStructGetPtr($stSysTime)) 651 | If @error Then Return SetError(2,@error,$aSysTime) 652 | If Not $aRet[0] Then Return SetError(3,0,$aSysTime) 653 | Dim $aSysTime[8]=[DllStructGetData($stSysTime,1,1),DllStructGetData($stSysTime,1,2),DllStructGetData($stSysTime,1,4),DllStructGetData($stSysTime,1,5), _ 654 | DllStructGetData($stSysTime,1,6),DllStructGetData($stSysTime,1,7),DllStructGetData($stSysTime,1,8),DllStructGetData($stSysTime,1,3)] 655 | Return $aSysTime 656 | EndFunc 657 | 658 | Func _WinTime_FormatTime($iYear,$iMonth,$iDay,$iHour,$iMin,$iSec,$iMilSec,$iDayOfWeek,$iFormat=4,$iPrecision=0,$bAMPMConversion=False) 659 | Local Static $_WT_aMonths[12]=["January","February","March","April","May","June","July","August","September","October","November","December"] 660 | Local Static $_WT_aDays[7]=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"] 661 | 662 | If Not $iFormat Or $iMonth<1 Or $iMonth>12 Or $iDayOfWeek>6 Then Return SetError(1,0,"") 663 | 664 | ; Pad MM,DD,HH,MM,SS,MSMSMSMS as necessary 665 | Local $sMM=StringRight(0&$iMonth,2),$sDD=StringRight(0&$iDay,2),$sMin=StringRight(0&$iMin,2) 666 | ; $sYY = $iYear ; (no padding) 667 | ; [technically Year can be 1-x chars - but this is generally used for 4-digit years. And SystemTime only goes up to 30827/30828] 668 | Local $sHH,$sSS,$sMS,$sAMPM 669 | 670 | ; 'Extra precision 1': +SS (Seconds) 671 | If $iPrecision Then 672 | $sSS=StringRight(0&$iSec,2) 673 | ; 'Extra precision 2': +MSMSMSMS (Milliseconds) 674 | If $iPrecision>1 Then 675 | ; $sMS=StringRight('000'&$iMilSec,4) 676 | $sMS=StringRight('000'&$iMilSec,3);Fixed an erronous 0 in front of the milliseconds 677 | Else 678 | $sMS="" 679 | EndIf 680 | Else 681 | $sSS="" 682 | $sMS="" 683 | EndIf 684 | If $bAMPMConversion Then 685 | If $iHour>11 Then 686 | $sAMPM=" PM" 687 | ; 12 PM will cause 12-12 to equal 0, so avoid the calculation: 688 | If $iHour=12 Then 689 | $sHH="12" 690 | Else 691 | $sHH=StringRight(0&($iHour-12),2) 692 | EndIf 693 | Else 694 | $sAMPM=" AM" 695 | If $iHour Then 696 | $sHH=StringRight(0&$iHour,2) 697 | Else 698 | ; 00 military = 12 AM 699 | $sHH="12" 700 | EndIf 701 | EndIf 702 | Else 703 | $sAMPM="" 704 | $sHH=StringRight(0 & $iHour,2) 705 | EndIf 706 | 707 | Local $sDateTimeStr,$aReturnArray[3] 708 | 709 | ; Return an array? [formatted string + "Month" + "DayOfWeek"] 710 | If BitAND($iFormat,0x10) Then 711 | $aReturnArray[1]=$_WT_aMonths[$iMonth-1] 712 | If $iDayOfWeek>=0 Then 713 | $aReturnArray[2]=$_WT_aDays[$iDayOfWeek] 714 | Else 715 | $aReturnArray[2]="" 716 | EndIf 717 | ; Strip the 'array' bit off (array[1] will now indicate if an array is to be returned) 718 | $iFormat=BitAND($iFormat,0xF) 719 | Else 720 | ; Signal to below that the array isn't to be returned 721 | $aReturnArray[1]="" 722 | EndIf 723 | 724 | ; Prefix with "DayOfWeek "? 725 | If BitAND($iFormat,8) Then 726 | If $iDayOfWeek<0 Then Return SetError(1,0,"") ; invalid 727 | $sDateTimeStr=$_WT_aDays[$iDayOfWeek]&', ' 728 | ; Strip the 'DayOfWeek' bit off 729 | $iFormat=BitAND($iFormat,0x7) 730 | Else 731 | $sDateTimeStr="" 732 | EndIf 733 | 734 | If $iFormat<2 Then 735 | ; Basic String format: YYYYMMDDHHMM[SS[MSMSMSMS[ AM/PM]]] 736 | $sDateTimeStr&=$iYear&$sMM&$sDD&$sHH&$sMin&$sSS&$sMS&$sAMPM 737 | Else 738 | ; one of 4 formats which ends with " HH:MM[:SS[:MSMSMSMS[ AM/PM]]]" 739 | Switch $iFormat 740 | ; /, : Format - MM/DD/YYYY 741 | Case 2 742 | $sDateTimeStr&=$sMM&'/'&$sDD&'/' 743 | ; /, : alt. Format - DD/MM/YYYY 744 | Case 3 745 | $sDateTimeStr&=$sDD&'/'&$sMM&'/' 746 | ; "Month DD, YYYY" format 747 | Case 4 748 | $sDateTimeStr&=$_WT_aMonths[$iMonth-1]&' '&$sDD&', ' 749 | ; "DD Month YYYY" format 750 | Case 5 751 | $sDateTimeStr&=$sDD&' '&$_WT_aMonths[$iMonth-1]&' ' 752 | Case 6 753 | $sDateTimeStr&=$iYear&'-'&$sMM&'-'&$sDD 754 | $iYear='' 755 | Case Else 756 | Return SetError(1,0,"") 757 | EndSwitch 758 | $sDateTimeStr&=$iYear&' '&$sHH&':'&$sMin 759 | If $iPrecision Then 760 | $sDateTimeStr&=':'&$sSS 761 | ; If $iPrecision>1 Then $sDateTimeStr&=':'&$sMS 762 | If $iPrecision>1 Then $sDateTimeStr&=$PrecisionSeparator&$sMS 763 | EndIf 764 | $sDateTimeStr&=$sAMPM 765 | EndIf 766 | If $aReturnArray[1]<>"" Then 767 | $aReturnArray[0]=$sDateTimeStr 768 | Return $aReturnArray 769 | EndIf 770 | Return $sDateTimeStr 771 | EndFunc 772 | 773 | Func _FillZero($inp) 774 | Local $out, $tmp = "" 775 | Local $inplen = StringLen($inp) 776 | For $i = 1 To 4 - $inplen 777 | $tmp &= "0" 778 | Next 779 | $out = $tmp & $inp 780 | Return $out 781 | EndFunc 782 | 783 | Func _DecodeTimestampDecimal($TheTime) 784 | $TheTime_tmp = _WinTime_UTCFileTimeToLocalFileTime("0x" & Hex($TheTime,16)) 785 | $TheTime = _WinTime_UTCFileTimeFormat($TheTime - $tDelta, $DateTimeFormat, $TimestampPrecision) 786 | If @error Then 787 | $TheTime = $TimestampErrorVal 788 | ElseIf $TimestampPrecision = 3 Then 789 | $TheTime = $TheTime & $PrecisionSeparator2 & _FillZero(StringRight($TheTime_tmp, 4)) 790 | EndIf 791 | Return $TheTime 792 | EndFunc 793 | 794 | Func _GetFilenameFromPath($FileNamePath) 795 | $stringlength = StringLen($FileNamePath) 796 | If $stringlength = 0 Then Return SetError(1,0,0) 797 | $TmpOffset = StringInStr($FileNamePath, "\", 1, -1) 798 | If $TmpOffset = 0 Then Return $FileNamePath 799 | Return StringMid($FileNamePath,$TmpOffset+1) 800 | EndFunc 801 | 802 | Func _PrintHelp() 803 | ConsoleWrite("Syntax:" & @CRLF) 804 | ConsoleWrite("SdbaParser.exe /Input: /Output: /Arch:" & @CRLF) 805 | ConsoleWrite(" Input: Full path to the file to parse" & @CRLF) 806 | ConsoleWrite(" Output: Optionally set path for the output. Defaults to program directory." & @CRLF) 807 | ConsoleWrite(" Arch: The source architecture. Must be 32 or 64." & @CRLF & @CRLF) 808 | ConsoleWrite("Examples:" & @CRLF) 809 | ConsoleWrite("SdbaParser.exe /Input:D:\temp\ActiveMemory.bin /Output:D:\temp /Arch:32" & @CRLF) 810 | ConsoleWrite("SdbaParser.exe /Input:D:\temp\pagefile.sys /Arch:64" & @CRLF) 811 | Exit 812 | EndFunc -------------------------------------------------------------------------------- /sigscan.ps1: -------------------------------------------------------------------------------- 1 | param([string]$hex, [string]$filepath) 2 | 3 | $filepath = [WildcardPattern]::Escape($filepath) 4 | 5 | If([string]::IsNullOrEmpty($filepath)){ 6 | Write-Host "Error: No filepath supplied" 7 | Exit 8 | } 9 | 10 | If(!(Test-Path "$filepath")){ 11 | Write-Host "Error: File not found: $filepath" 12 | #Exit 13 | } 14 | 15 | If([string]::IsNullOrEmpty($hex)){ 16 | Write-Host "Error: No hex supplied" 17 | Exit 18 | } 19 | 20 | $fileInfo = New-Object System.IO.FileInfo $filepath 21 | $Stream = New-Object System.IO.FileStream -ArgumentList ((Convert-Path -Path $filepath), 'Open', 'Read') 22 | 23 | $Encoding = [Text.Encoding]::GetEncoding(28591) 24 | 25 | $BinaryReader = New-Object System.IO.BinaryReader -ArgumentList $Stream, $Encoding 26 | 27 | # determine the size of the file 28 | $file_size = (Get-Item $filepath).length 29 | 30 | $MyRegex = [Regex]::New($hex) 31 | 32 | $step = 0 33 | 34 | $Matches = foreach($chunk in (0..[math]::Ceiling($file_size/4096))){ 35 | # reset data 36 | $BinaryText = $null 37 | # Set offset to read from the file 38 | $BinaryReader.BaseStream.Position = [UInt64]($step*4096) 39 | # Initialize the buffer to be save size as the data block 40 | $buffer = [System.Byte[]]::new(4096) 41 | 42 | # Read each offset to the buffer 43 | [Void]$BinaryReader.Read($buffer,0,4096) 44 | # Convert the buffer data to byte 45 | $BinaryText = [System.Text.Encoding]::GetEncoding(28591).getstring($buffer) 46 | if($step -gt 0){ 47 | if(!!$MyRegex.Matches($BinaryText).success){foreach($index in $MyRegex.Matches($BinaryText).index){$index + $step*4096}} 48 | } 49 | else{if(!!$MyRegex.Matches($BinaryText).success){$MyRegex.Matches($BinaryText).index}} 50 | $step=$step+1 51 | } 52 | 53 | 54 | $BinaryReader.Close() 55 | $Stream.Close() 56 | 57 | 58 | $MatchCount = $Matches.Count 59 | 60 | If ($MatchCount -eq 0){ 61 | Write-Host "Error: Nothing to parse." 62 | Exit 63 | } 64 | $Matches | ForEach-Object {"0x$(([uint64]$_).ToString('X16'))" } 65 | --------------------------------------------------------------------------------