├── EaInject.au3 ├── EaInject.exe ├── EaInject64.exe ├── EaQuery.au3 ├── EaQuery.exe ├── EaQuery64.exe ├── LICENSE.md ├── _RecFileListToArray.au3 ├── changelog.txt └── readme.txt /EaInject.au3: -------------------------------------------------------------------------------- 1 | #RequireAdmin 2 | #Region ;**** Directives created by AutoIt3Wrapper_GUI **** 3 | #AutoIt3Wrapper_UseUpx=y 4 | #AutoIt3Wrapper_Change2CUI=y 5 | #AutoIt3Wrapper_Res_Comment=Inject data into the $EA attribute 6 | #AutoIt3Wrapper_Res_Description=Inject data into the $EA attribute 7 | #AutoIt3Wrapper_Res_Fileversion=1.0.0.1 8 | #AutoIt3Wrapper_Res_LegalCopyright=Joakim Schicht 9 | #AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker 10 | #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** 11 | #include 12 | #include <_RecFileListToArray.au3> 13 | Global Const $tagOBJECTATTRIBUTES = "ulong Length;handle RootDirectory;ptr ObjectName;ulong Attributes;ptr SecurityDescriptor;ptr SecurityQualityOfService" 14 | Global Const $tagUNICODESTRING = "ushort Length;ushort MaximumLength;ptr Buffer" 15 | Global Const $tagIOSTATUSBLOCK = "ptr Status;ptr Information" 16 | Global Const $FILE_WRITE_EA = 0x10 17 | Global Const $FILE_NEED_EA = 0x00000080 18 | ;Global Const $FILE_NEED_NO_EA = 0 19 | Global Const $MaxEaEntrySize = 65510 20 | Global Const $OBJ_CASE_INSENSITIVE = 0x00000040 21 | Global Const $FILE_RANDOM_ACCESS = 0x00000800 22 | Global Const $FILE_DIRECTORY_FILE = 0x00000002 23 | Global Const $FILE_NON_DIRECTORY_FILE = 0x00000040 24 | Global $nBytes, $buffer, $TargetPayload, $RunMode, $TextIdentifier, $TargetIsDirectory, $TargetContainerPath, $SearchFilter, $RecursiveMode, $AccessAttempts=1, $TargetContainerParentPath, $EaFlag 25 | 26 | ConsoleWrite("EaInject v1.0.0.1" & @CRLF & @CRLF) 27 | _ValidateInput() 28 | ConsoleWrite("TargetPayload: " & $TargetPayload & @CRLF) 29 | $hFile0 = _WinAPI_CreateFile("\\.\" & $TargetPayload,2,6,7) 30 | If $hFile0=0 then 31 | ConsoleWrite("Error CreateFile returned: " & _WinAPI_GetLastErrorMessage() & @CRLF) 32 | Exit 33 | EndIf 34 | $FileSize = _WinAPI_GetFileSizeEx($hFile0) 35 | If @error Or $FileSize = 0 Then 36 | ConsoleWrite("Error: Payload contained no data. Nothing to do." & @CRLF) 37 | Exit 38 | EndIf 39 | If DriveSpaceFree(StringLeft($TargetContainerPath,3))*1024*1024 < $FileSize Then 40 | ConsoleWrite("Error: Not enough free space on volume" & @CRLF) 41 | Exit 42 | EndIf 43 | If $RunMode = 1 Then 44 | $TargetFile = _RecFileListToArray($TargetContainerPath,$SearchFilter,0,$RecursiveMode) 45 | If @error Then 46 | ConsoleWrite("Error: Searching failed" & @CRLF) 47 | Exit 48 | EndIf 49 | ElseIf $RunMode = 0 Then 50 | $TargetFile = StringSplit($TargetContainerPath,";") ;Just choose something not valid inside a filename 51 | EndIf 52 | 53 | If $RunMode = 1 And $TargetFile[0] * $MaxEaEntrySize < $FileSize Then 54 | ConsoleWrite("Error: Not enough containers in target path to hide payload" & @CRLF) 55 | Exit 56 | EndIf 57 | 58 | If $RunMode = 0 Or $RunMode = 1 Then 59 | If $FileSize <= $MaxEaEntrySize Then 60 | $AccessAttempts = 0 61 | For $Counter = 0 To $TargetFile[0]-1 62 | Do 63 | $szName = DllStructCreate("wchar[260]") 64 | $sUS = DllStructCreate($tagUNICODESTRING) 65 | $sOA = DllStructCreate($tagOBJECTATTRIBUTES) 66 | $sISB = DllStructCreate($tagIOSTATUSBLOCK) 67 | If $RunMode = 1 Then 68 | $TargetFileAndPath = $TargetContainerPath&"\"&$TargetFile[$Counter+1] 69 | Else 70 | $TargetFileAndPath = $TargetFile[$Counter+1] 71 | EndIf 72 | DllStructSetData($szName, 1, "\??\"&$TargetFileAndPath) 73 | ConsoleWrite("Target is: " & $TargetFileAndPath & @CRLF) 74 | FileSetAttrib($TargetFileAndPath, "-R") 75 | If StringInStr(FileGetAttrib($TargetFileAndPath),"D") Then 76 | $FileMode=$FILE_DIRECTORY_FILE 77 | Else 78 | $FileMode=$FILE_NON_DIRECTORY_FILE 79 | EndIf 80 | $ret = DllCall("ntdll.dll", "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName)) 81 | DllStructSetData($sOA, "Length", DllStructGetSize($sOA)) 82 | DllStructSetData($sOA, "RootDirectory", 0) 83 | DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS)) 84 | DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE) 85 | DllStructSetData($sOA, "SecurityDescriptor", 0) 86 | DllStructSetData($sOA, "SecurityQualityOfService", 0) 87 | 88 | $ret = DllCall("ntdll.dll", "int", "NtOpenFile", "hwnd*", "", "dword", BitOR($GENERIC_WRITE,$FILE_WRITE_EA), "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), "ulong", BitOR($FILE_SHARE_READ,$FILE_SHARE_WRITE), "ulong", BitOR($FileMode,$FILE_RANDOM_ACCESS)) 89 | If NT_SUCCESS($ret[0]) Then 90 | ConsoleWrite("NtOpenFile: Success" & @CRLF) 91 | Else 92 | ConsoleWrite("NtOpenFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 93 | _GrantFileAccess($TargetFileAndPath) 94 | EndIf 95 | $AccessAttempts+=1 96 | Until $AccessAttempts = 2 Or $ret[1] 97 | If $Counter = $TargetFile[0]-1 And Not $ret[1] Then 98 | ConsoleWrite("Error: Could not hide data." & @CRLF) 99 | Exit 100 | EndIf 101 | If Not $ret[1] Then ContinueLoop 102 | If $ret[1] Then ExitLoop 103 | Next 104 | $hFile1 = $ret[1] 105 | $tBuffer = DllStructCreate("byte[" & $FileSize & "]") 106 | $tBuffer2 = DllStructCreate("byte[" & $FileSize & "]") 107 | $read = _WinAPI_ReadFile($hFile0, DllStructGetPtr($tBuffer), $FileSize, $nBytes) 108 | If $read = 0 then 109 | ConsoleWrite("Error ReadFile failed: " & _WinAPI_GetLastErrorMessage() & @CRLF) 110 | _WinAPI_CloseHandle($hFile0) 111 | EndIf 112 | $NextEntryOffset = 0 113 | $EaName = $TextIdentifier;&"1" 114 | $EaNameLength = StringLen($EaName) 115 | $EaValue = DllStructGetData($tBuffer,1) 116 | ; ConsoleWrite(_HexEncode($EaValue) & @CRLF) 117 | $EaValueLength = BinaryLen($EaValue) 118 | $tagFILE_FULL_EA_INFORMATION = "ulong NextEntryOffset;byte Flags[1];byte EaNameLength[1];ushort EaValueLength;char EaName["&$EaNameLength&"];byte dummy[1];byte EaValue["&$EaValueLength+1&"]" ; 119 | $EaStruct = DllStructCreate($tagFILE_FULL_EA_INFORMATION) 120 | DllStructSetData($EaStruct,"NextEntryOffset",$NextEntryOffset) 121 | DllStructSetData($EaStruct,"Flags",$EaFlag) 122 | DllStructSetData($EaStruct,"EaNameLength",$EaNameLength) 123 | DllStructSetData($EaStruct,"EaValueLength",$EaValueLength+1) 124 | DllStructSetData($EaStruct,"EaName",$EaName) 125 | DllStructSetData($EaStruct,"EaValue",$EaValue) 126 | $testwrite = _NtSetEaFile($hFile1,$sISB,$EaStruct) 127 | If @error Then 128 | ConsoleWrite("Error in NtSetEaFile; " & $testwrite & @CRLF) 129 | DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile1) 130 | Else 131 | ConsoleWrite("Wrote " & $EaValueLength & " bytes into $EA entry named: " & $EaName & @CRLF) 132 | EndIf 133 | Exit 134 | Else 135 | $Remainder = Mod($FileSize,$MaxEaEntrySize) 136 | $ExpectedLoops = Floor($FileSize/$MaxEaEntrySize) 137 | If $ExpectedLoops > $TargetFile[0] Then 138 | ConsoleWrite("Error: Could not find enough files to hide data in" & @CRLF) 139 | Exit 140 | EndIf 141 | $BufferSize = $MaxEaEntrySize 142 | $Counter = 0 143 | $Counter2 = 0 144 | $nBytes = 0 145 | $BytesProcessed = 0 146 | Do 147 | Do 148 | $szName = DllStructCreate("wchar[260]") 149 | $sUS = DllStructCreate($tagUNICODESTRING) 150 | $sOA = DllStructCreate($tagOBJECTATTRIBUTES) 151 | $sISB = DllStructCreate($tagIOSTATUSBLOCK) 152 | If $TargetIsDirectory Then 153 | $TargetFileAndPath = $TargetContainerPath&"\"&$TargetFile[$Counter2+1] 154 | Else 155 | $TargetFileAndPath = $TargetFile[1] 156 | EndIf 157 | DllStructSetData($szName, 1, "\??\"&$TargetFileAndPath) 158 | ConsoleWrite("Target is: " & $TargetFileAndPath & @CRLF) 159 | FileSetAttrib($TargetFileAndPath, "-R") 160 | If StringInStr(FileGetAttrib($TargetFileAndPath),"D") Then 161 | $FileMode=$FILE_DIRECTORY_FILE 162 | Else 163 | $FileMode=$FILE_NON_DIRECTORY_FILE 164 | EndIf 165 | $ret = DllCall("ntdll.dll", "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName)) 166 | DllStructSetData($sOA, "Length", DllStructGetSize($sOA)) 167 | DllStructSetData($sOA, "RootDirectory", 0) 168 | DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS)) 169 | DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE) 170 | DllStructSetData($sOA, "SecurityDescriptor", 0) 171 | DllStructSetData($sOA, "SecurityQualityOfService", 0) 172 | $ret = DllCall("ntdll.dll", "int", "NtOpenFile", "hwnd*", "", "dword", BitOR($GENERIC_WRITE,$FILE_WRITE_EA), "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), "ulong", BitOR($FILE_SHARE_READ,$FILE_SHARE_WRITE), "ulong", BitOR($FileMode,$FILE_RANDOM_ACCESS)) 173 | If NT_SUCCESS($ret[0]) Then 174 | ; ConsoleWrite("NtOpenFile: Success" & @CRLF) 175 | Else 176 | ConsoleWrite("NtOpenFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 177 | _GrantFileAccess($TargetFileAndPath) 178 | EndIf 179 | $AccessAttempts+=1 180 | Until $AccessAttempts >= 3 Or $ret[1] 181 | If $Counter2 = $TargetFile[0]-1 And Not $ret[1] Then 182 | ConsoleWrite("Error: Could not hide data." & @CRLF) 183 | Exit 184 | EndIf 185 | If Not $ret[1] Then 186 | $Counter2+=1 187 | ContinueLoop 188 | EndIf 189 | $Counter2+=1 190 | $hFile1 = $ret[1] 191 | If $Counter=$ExpectedLoops Then $BufferSize=$Remainder 192 | $tBuffer = DllStructCreate("byte[" & $BufferSize & "]") 193 | $BytesProcessed+=$nBytes 194 | _WinAPI_SetFilePointer($hFile0, $BytesProcessed) 195 | $read = _WinAPI_ReadFile($hFile0, DllStructGetPtr($tBuffer), $BufferSize, $nBytes) 196 | If $read = 0 then 197 | ConsoleWrite("Error ReadFile failed: " & _WinAPI_GetLastErrorMessage() & @CRLF) 198 | _WinAPI_CloseHandle($hFile0) 199 | Exit 200 | EndIf 201 | $NextEntryOffset = 0 202 | $EaName = $TextIdentifier&$Counter 203 | $EaNameLength = StringLen($EaName) 204 | $EaValue = DllStructGetData($tBuffer,1) 205 | ; ConsoleWrite(_HexEncode($EaValue) & @CRLF) 206 | $EaValueLength = BinaryLen($EaValue) 207 | $tagFILE_FULL_EA_INFORMATION = "ulong NextEntryOffset;byte Flags[1];byte EaNameLength[1];ushort EaValueLength;char EaName["&$EaNameLength&"];byte dummy[1];byte EaValue["&$EaValueLength+1&"]" ; 208 | $EaStruct = DllStructCreate($tagFILE_FULL_EA_INFORMATION) 209 | DllStructSetData($EaStruct,"NextEntryOffset",$NextEntryOffset) 210 | DllStructSetData($EaStruct,"Flags",$EaFlag) 211 | DllStructSetData($EaStruct,"EaNameLength",$EaNameLength) 212 | DllStructSetData($EaStruct,"EaValueLength",$EaValueLength+1) 213 | DllStructSetData($EaStruct,"EaName",$EaName) 214 | DllStructSetData($EaStruct,"EaValue",$EaValue) 215 | $testwrite = _NtSetEaFile($hFile1,$sISB,$EaStruct) 216 | If @error Then 217 | ConsoleWrite("Error in NtSetEaFile; " & $testwrite & @CRLF) 218 | DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile1) 219 | $nBytes = 0 220 | DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile1) 221 | ContinueLoop 222 | Else 223 | ConsoleWrite("Wrote " & $EaValueLength & " bytes into $EA entry named: " & $EaName & @CRLF) 224 | EndIf 225 | DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile1) 226 | $Counter+=1 227 | Until $BytesProcessed+$nBytes >= $FileSize 228 | EndIf 229 | ElseIf $RunMode = 2 Then 230 | If $FileSize <= $MaxEaEntrySize Then 231 | $TargetFile = "\??\" & $TargetContainerPath & "\" & _GenerateMd5String() & ".md5" 232 | $szName = DllStructCreate("wchar[260]") 233 | $sUS = DllStructCreate($tagUNICODESTRING) 234 | $sOA = DllStructCreate($tagOBJECTATTRIBUTES) 235 | $sISB = DllStructCreate($tagIOSTATUSBLOCK) 236 | DllStructSetData($szName, 1, $TargetFile) 237 | ConsoleWrite("Target is: " & StringTrimLeft($TargetFile,4) & @CRLF) 238 | FileSetAttrib(StringTrimLeft($TargetFile,4), "-R") 239 | If StringInStr(FileGetAttrib(StringTrimLeft($TargetFile,4)),"D") Then 240 | $FileMode=$FILE_DIRECTORY_FILE 241 | Else 242 | $FileMode=$FILE_NON_DIRECTORY_FILE 243 | EndIf 244 | $ret = DllCall("ntdll.dll", "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName)) 245 | DllStructSetData($sOA, "Length", DllStructGetSize($sOA)) 246 | DllStructSetData($sOA, "RootDirectory", 0) 247 | DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS)) 248 | DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE) 249 | DllStructSetData($sOA, "SecurityDescriptor", 0) 250 | DllStructSetData($sOA, "SecurityQualityOfService", 0) 251 | $tBuffer = DllStructCreate("byte[" & $FileSize & "]") 252 | $tBuffer2 = DllStructCreate("byte[" & $FileSize & "]") 253 | $read = _WinAPI_ReadFile($hFile0, DllStructGetPtr($tBuffer), $FileSize, $nBytes) 254 | If $read = 0 then 255 | ConsoleWrite("Error ReadFile failed: " & _WinAPI_GetLastErrorMessage() & @CRLF) 256 | _WinAPI_CloseHandle($hFile0) 257 | Exit 258 | EndIf 259 | $NextEntryOffset = 0 260 | $EaName = $TextIdentifier&"1" 261 | $EaNameLength = StringLen($EaName) 262 | $EaValue = DllStructGetData($tBuffer,1) 263 | ; ConsoleWrite(_HexEncode($EaValue) & @CRLF) 264 | $EaValueLength = BinaryLen($EaValue) 265 | $tagFILE_FULL_EA_INFORMATION = "ulong NextEntryOffset;byte Flags[1];byte EaNameLength[1];ushort EaValueLength;char EaName["&$EaNameLength&"];byte dummy[1];byte EaValue["&$EaValueLength+1&"]" ; 266 | $EaStruct = DllStructCreate($tagFILE_FULL_EA_INFORMATION) 267 | DllStructSetData($EaStruct,"NextEntryOffset",$NextEntryOffset) 268 | DllStructSetData($EaStruct,"Flags",$EaFlag) 269 | DllStructSetData($EaStruct,"EaNameLength",$EaNameLength) 270 | DllStructSetData($EaStruct,"EaValueLength",$EaValueLength+1) 271 | DllStructSetData($EaStruct,"EaName",$EaName) 272 | DllStructSetData($EaStruct,"EaValue",$EaValue) 273 | $ret = DllCall("ntdll.dll", "handle", "NtCreateFile", "hwnd*", "", "ulong", $GENERIC_ALL, "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), "int64*", 0, "ulong", $FILE_ATTRIBUTE_NORMAL, "ulong", BitOR($FILE_SHARE_READ,$FILE_SHARE_WRITE), _ 274 | "ulong", $CREATE_ALWAYS, "ulong", $FILE_NON_DIRECTORY_FILE, "ptr", DllStructGetPtr($EaStruct), "ulong", DllStructGetSize($EaStruct)) 275 | If NT_SUCCESS($ret[0]) Then 276 | ; ConsoleWrite("NtCreateFile: Success" & @CRLF) 277 | Else 278 | ConsoleWrite("NtCreateFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 279 | Exit 280 | EndIf 281 | $BytesProcessed=0 282 | $hFile1 = $ret[1] 283 | Else 284 | $Remainder = Mod($FileSize,$MaxEaEntrySize) 285 | $ExpectedLoops = Floor($FileSize/$MaxEaEntrySize) 286 | $BufferSize = $MaxEaEntrySize 287 | $Counter = 0 288 | $nBytes = 0 289 | $BytesProcessed = 0 290 | Do 291 | $TargetFile = $TargetContainerPath & "\" & _GenerateMd5String() & ".md5" 292 | $szName = DllStructCreate("wchar[260]") 293 | $sUS = DllStructCreate($tagUNICODESTRING) 294 | $sOA = DllStructCreate($tagOBJECTATTRIBUTES) 295 | $sISB = DllStructCreate($tagIOSTATUSBLOCK) 296 | DllStructSetData($szName, 1, "\??\"&$TargetFile) 297 | ConsoleWrite("Target is: " & $TargetFile & @CRLF) 298 | $FileMode=$FILE_NON_DIRECTORY_FILE 299 | $ret = DllCall("ntdll.dll", "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName)) 300 | DllStructSetData($sOA, "Length", DllStructGetSize($sOA)) 301 | DllStructSetData($sOA, "RootDirectory", 0) 302 | DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS)) 303 | DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE) 304 | DllStructSetData($sOA, "SecurityDescriptor", 0) 305 | DllStructSetData($sOA, "SecurityQualityOfService", 0) 306 | If $Counter=$ExpectedLoops Then $BufferSize=$Remainder 307 | $tBuffer = DllStructCreate("byte[" & $BufferSize & "]") 308 | $tBuffer2 = DllStructCreate("byte[" & $BufferSize & "]") 309 | $BytesProcessed+=$nBytes 310 | _WinAPI_SetFilePointer($hFile0, $BytesProcessed) 311 | $read = _WinAPI_ReadFile($hFile0, DllStructGetPtr($tBuffer), $BufferSize, $nBytes) 312 | If $read = 0 then 313 | ConsoleWrite("Error ReadFile failed: " & _WinAPI_GetLastErrorMessage() & @CRLF) 314 | _WinAPI_CloseHandle($hFile0) 315 | Exit 316 | EndIf 317 | $NextEntryOffset = 0 318 | $EaName = $TextIdentifier&$Counter 319 | $EaNameLength = StringLen($EaName) 320 | $EaValue = DllStructGetData($tBuffer,1) 321 | ; ConsoleWrite(_HexEncode($EaValue) & @CRLF) 322 | $EaValueLength = BinaryLen($EaValue) 323 | $tagFILE_FULL_EA_INFORMATION = "ulong NextEntryOffset;byte Flags[1];byte EaNameLength[1];ushort EaValueLength;char EaName["&$EaNameLength&"];byte dummy[1];byte EaValue["&$EaValueLength+1&"]" ; 324 | $EaStruct = DllStructCreate($tagFILE_FULL_EA_INFORMATION) 325 | DllStructSetData($EaStruct,"NextEntryOffset",$NextEntryOffset) 326 | DllStructSetData($EaStruct,"Flags",$EaFlag) 327 | DllStructSetData($EaStruct,"EaNameLength",$EaNameLength) 328 | DllStructSetData($EaStruct,"EaValueLength",$EaValueLength+1) 329 | DllStructSetData($EaStruct,"EaName",$EaName) 330 | DllStructSetData($EaStruct,"EaValue",$EaValue) 331 | $ret = DllCall("ntdll.dll", "handle", "NtCreateFile", "hwnd*", "", "ulong", $GENERIC_ALL, "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), "int64*", 0, "ulong", $FILE_ATTRIBUTE_NORMAL, "ulong", BitOR($FILE_SHARE_READ,$FILE_SHARE_WRITE), _ 332 | "ulong", $CREATE_ALWAYS, "ulong", $FILE_NON_DIRECTORY_FILE, "ptr", DllStructGetPtr($EaStruct), "ulong", DllStructGetSize($EaStruct)) 333 | If NT_SUCCESS($ret[0]) Then 334 | ; ConsoleWrite("NtCreateFile: Success" & @CRLF) 335 | Else 336 | ConsoleWrite("NtCreateFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 337 | Exit 338 | EndIf 339 | $hFile1 = $ret[1] 340 | DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile1) 341 | ; If $Counter > $ExpectedLoops Then ExitLoop 342 | $Counter+=1 343 | Until $BytesProcessed+$nBytes >= $FileSize 344 | EndIf 345 | EndIf 346 | DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile1) 347 | _WinAPI_CloseHandle($hFile0) 348 | ConsoleWrite("Success hiding " & $BytesProcessed+$nBytes & " bytes" & @CRLF) 349 | Exit 350 | 351 | 352 | Func _NtSetEaFile($handle,$statusblock,$struct) 353 | $ret = DllCall("ntdll.dll", "handle", "NtSetEaFile", "handle", $handle, "ptr", DllStructGetPtr($statusblock), "ptr", DllStructGetPtr($struct), "ulong", DllStructGetSize($struct)) 354 | If Not NT_SUCCESS($ret[0]) Then 355 | Return SetError(1,0,_TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8)))) 356 | Else 357 | Return True 358 | EndIf 359 | EndFunc 360 | 361 | Func _HexEncode($bInput) 362 | Local $tInput = DllStructCreate("byte[" & BinaryLen($bInput) & "]") 363 | DllStructSetData($tInput, 1, $bInput) 364 | Local $a_iCall = DllCall("crypt32.dll", "int", "CryptBinaryToString", _ 365 | "ptr", DllStructGetPtr($tInput), _ 366 | "dword", DllStructGetSize($tInput), _ 367 | "dword", 11, _ 368 | "ptr", 0, _ 369 | "dword*", 0) 370 | 371 | If @error Or Not $a_iCall[0] Then 372 | Return SetError(1, 0, "") 373 | EndIf 374 | 375 | Local $iSize = $a_iCall[5] 376 | Local $tOut = DllStructCreate("char[" & $iSize & "]") 377 | 378 | $a_iCall = DllCall("crypt32.dll", "int", "CryptBinaryToString", _ 379 | "ptr", DllStructGetPtr($tInput), _ 380 | "dword", DllStructGetSize($tInput), _ 381 | "dword", 11, _ 382 | "ptr", DllStructGetPtr($tOut), _ 383 | "dword*", $iSize) 384 | 385 | If @error Or Not $a_iCall[0] Then 386 | Return SetError(2, 0, "") 387 | EndIf 388 | 389 | Return SetError(0, 0, DllStructGetData($tOut, 1)) 390 | 391 | EndFunc ;==>_HexEncode 392 | 393 | Func NT_SUCCESS($status) 394 | If 0 <= $status And $status <= 0x7FFFFFFF Then 395 | Return True 396 | Else 397 | Return False 398 | EndIf 399 | EndFunc 400 | 401 | Func _RtlNtStatusToDosError($Status) 402 | Local $aCall = DllCall("ntdll.dll", "ulong", "RtlNtStatusToDosError", "dword", $Status) 403 | If Not NT_SUCCESS($aCall[0]) Then 404 | ConsoleWrite("Error in RtlNtStatusToDosError: " & Hex($aCall[0], 8) & @CRLF) 405 | Return SetError(1, 0, $aCall[0]) 406 | Else 407 | Return $aCall[0] 408 | EndIf 409 | EndFunc 410 | 411 | Func _TranslateErrorCode($ErrCode) 412 | Local $tBufferPtr = DllStructCreate("ptr") 413 | 414 | Local $nCount = _FormatMessage(BitOR($__WINAPICONSTANT_FORMAT_MESSAGE_ALLOCATE_BUFFER, $__WINAPICONSTANT_FORMAT_MESSAGE_FROM_SYSTEM), _ 415 | 0, $ErrCode, 0, $tBufferPtr, 0, 0) 416 | If @error Then Return SetError(@error, 0, "") 417 | 418 | Local $sText = "" 419 | Local $pBuffer = DllStructGetData($tBufferPtr, 1) 420 | If $pBuffer Then 421 | If $nCount > 0 Then 422 | Local $tBuffer = DllStructCreate("wchar[" & ($nCount + 1) & "]", $pBuffer) 423 | $sText = DllStructGetData($tBuffer, 1) 424 | EndIf 425 | _LocalFree($pBuffer) 426 | EndIf 427 | 428 | Return $sText 429 | EndFunc 430 | 431 | Func _FormatMessage($iFlags, $pSource, $iMessageID, $iLanguageID, ByRef $pBuffer, $iSize, $vArguments) 432 | Local $sBufferType = "struct*" 433 | If IsString($pBuffer) Then $sBufferType = "wstr" 434 | Local $aResult = DllCall("Kernel32.dll", "dword", "FormatMessageW", "dword", $iFlags, "ptr", $pSource, "dword", $iMessageID, "dword", $iLanguageID, _ 435 | $sBufferType, $pBuffer, "dword", $iSize, "ptr", $vArguments) 436 | If @error Then Return SetError(@error, @extended, 0) 437 | If $sBufferType = "wstr" Then $pBuffer = $aResult[5] 438 | Return $aResult[0] 439 | EndFunc 440 | 441 | Func _LocalFree($hMem) 442 | Local $aResult = DllCall("kernel32.dll", "handle", "LocalFree", "handle", $hMem) 443 | If @error Then Return SetError(@error, @extended, False) 444 | Return $aResult[0] 445 | EndFunc 446 | 447 | Func _GenerateMd5String() 448 | Local $MD5="" 449 | For $i = 1 To 16 450 | $a = Hex(Random(0,15,1),1) 451 | $MD5&=$a 452 | Next 453 | Return $MD5 454 | EndFunc 455 | 456 | Func _ValidateInput() 457 | Local $TargetAttributes 458 | Global $TargetPayload, $RunMode, $TextIdentifier, $EaFlag, $TargetIsDirectory, $TargetContainerPath, $SearchFilter, $RecursiveMode 459 | If $cmdline[0] < 4 Then 460 | ConsoleWrite("Error: Wrong number of parameters" & @CRLF) 461 | ConsoleWrite("Syntax is:" & @CRLF) 462 | ConsoleWrite("EaInject.exe /Payload:TargetPayload /Container:TargetContainer /Mode:{0|1|2} /Identifier:SomeText /Filter:Text /Recurse:boolean" & @CRLF) 463 | ConsoleWrite(" /Payload is the file with the data to hide" & @CRLF) 464 | ConsoleWrite(" /Container is the file or path to hide the payload in" & @CRLF) 465 | ConsoleWrite(" /Mode 0 uses 1 existing file. Mode 1 will search existing files. Mode 2 will create new files in path specified in Container" & @CRLF) 466 | ConsoleWrite(" /Identifier is some text to use for EA names." & @CRLF) 467 | ConsoleWrite(" /EaFlag is boolean 0 or 1. Default is 0. A value of 1 triggers setting FILE_NEED_EA flag (0x80) which means target file cannot be interpreted without understanding the associated extended attributes. Default is zero which means ignore." & @CRLF) 468 | ConsoleWrite(" /Filter is for included results in search. Multiple filters separatet by ';'. Default is '*'." & @CRLF) 469 | ConsoleWrite(" /Recurse is a boolean value 0 or 1 for acivating/deactivating recursive mode." & @CRLF) 470 | Exit 471 | EndIf 472 | For $i = 1 To $cmdline[0] 473 | If StringLeft($cmdline[$i],9) = "/Payload:" Then $TargetPayload = StringMid($cmdline[$i],10) 474 | If StringLeft($cmdline[$i],11) = "/Container:" Then $TargetContainerPath = StringMid($cmdline[$i],12) 475 | If StringLeft($cmdline[$i],6) = "/Mode:" Then $RunMode = StringMid($cmdline[$i],7) 476 | If StringLeft($cmdline[$i],12) = "/Identifier:" Then $TextIdentifier = StringMid($cmdline[$i],13) 477 | If StringLeft($cmdline[$i],8) = "/EaFlag:" Then $EaFlag = StringMid($cmdline[$i],9) 478 | If StringLeft($cmdline[$i],8) = "/Filter:" Then $SearchFilter = StringMid($cmdline[$i],9) 479 | If StringLeft($cmdline[$i],9) = "/Recurse:" Then $RecursiveMode = StringMid($cmdline[$i],10) 480 | Next 481 | If $RunMode <> 0 And $RunMode <> 1 And $RunMode <> 2 Or Not StringIsDigit($RunMode) Then 482 | ConsoleWrite("Error: Mode not set correctly: " & $RunMode & @CRLF) 483 | Exit 484 | Else 485 | $RunMode=Int($RunMode) 486 | EndIf 487 | If FileExists($TargetPayload) = 0 Or StringInStr(FileGetAttrib($TargetPayload),"D") Then 488 | ConsoleWrite("Error: Target payoad not valid: " & $TargetPayload & @CRLF) 489 | Exit 490 | EndIf 491 | If FileExists($TargetContainerPath) = 0 Then 492 | ConsoleWrite("Error: Target container/path does not exist: " & $TargetContainerPath & @CRLF) 493 | Exit 494 | EndIf 495 | $TargetAttributes = FileGetAttrib($TargetContainerPath) 496 | If @error Then 497 | ConsoleWrite("Error: Could not evaluate attributes of: " & $TargetContainerPath & @CRLF) 498 | Exit 499 | EndIf 500 | If StringInStr($TargetAttributes,"D") Then 501 | $TargetIsDirectory = 1 502 | If StringRight($TargetContainerPath,1)="\" Then $TargetContainerPath = StringTrimRight($TargetContainerPath,1) 503 | If $RunMode = 1 Then $TargetContainerParentPath = StringMid($TargetContainerPath,1,StringInStr($TargetContainerPath,"\",0,-1)-1) 504 | Else 505 | If $RunMode = 1 Or $RunMode = 2 Then 506 | ConsoleWrite("Error: Container must be a directory when using mode 1 or 2" & @CRLF) 507 | Exit 508 | EndIf 509 | $TargetIsDirectory = 0 510 | EndIf 511 | If $TextIdentifier = "" Then 512 | ConsoleWrite("Error: EA name can not be empty" & @CRLF) 513 | Exit 514 | EndIf 515 | If $RecursiveMode <> 0 And $RecursiveMode <> 1 And $RecursiveMode <> "False" And $RecursiveMode <> "True" Then 516 | ConsoleWrite("Error: Recursive was not boolean" & @CRLF) 517 | Exit 518 | ElseIf $RecursiveMode = 0 Or $RecursiveMode = "False" Then 519 | $RecursiveMode = 0 520 | ElseIf $RecursiveMode = 1 Or $RecursiveMode = "True" Then 521 | $RecursiveMode = 1 522 | ElseIf $RecursiveMode = "" Then 523 | $RecursiveMode = 0 524 | EndIf 525 | If $SearchFilter = "" Then $SearchFilter = "*" 526 | If $EaFlag = "" Then 527 | $EaFlag = 0 528 | Else 529 | If $EaFlag <> 0 And $EaFlag <> 1 Then 530 | ConsoleWrite("Error: EaFlag is boolean and can only be 0 or 1." & @CRLF) 531 | Exit 532 | EndIf 533 | If $EaFlag = 1 Then 534 | $EaFlag = $FILE_NEED_EA 535 | EndIf 536 | EndIf 537 | EndFunc 538 | 539 | Func _GrantFileAccess($exe) 540 | If @OSBuild >= 6000 Then 541 | RunWait(@ComSpec & " /c " & @WindowsDir & '\system32\takeown.exe /f ' & $exe, "", @SW_HIDE) 542 | RunWait(@ComSpec & " /c " & @WindowsDir & '\system32\icacls.exe ' & $exe & ' /grant *S-1-5-32-544:F', "", @SW_HIDE) 543 | Return 544 | EndIf 545 | EndFunc -------------------------------------------------------------------------------- /EaInject.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jschicht/EaTools/25deec1e211e1b926e8ba0d7bcc87bee9a1047d4/EaInject.exe -------------------------------------------------------------------------------- /EaInject64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jschicht/EaTools/25deec1e211e1b926e8ba0d7bcc87bee9a1047d4/EaInject64.exe -------------------------------------------------------------------------------- /EaQuery.au3: -------------------------------------------------------------------------------- 1 | #Region ;**** Directives created by AutoIt3Wrapper_GUI **** 2 | #AutoIt3Wrapper_UseUpx=y 3 | #AutoIt3Wrapper_Change2CUI=y 4 | #AutoIt3Wrapper_Res_Comment=Analyze extended attributes ($EA) on files on NTFS 5 | #AutoIt3Wrapper_Res_Description=Analyze extended attributes ($EA) on files on NTFS 6 | #AutoIt3Wrapper_Res_Fileversion=1.0.0.1 7 | #AutoIt3Wrapper_Res_LegalCopyright=Joakim Schicht 8 | #AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker 9 | #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** 10 | #include 11 | #include <_RecFileListToArray.au3> 12 | Global Const $OBJ_CASE_INSENSITIVE = 0x00000040 13 | Global Const $FILE_RANDOM_ACCESS = 0x00000800 14 | Global Const $FILE_DIRECTORY_FILE = 0x00000002 15 | Global Const $FILE_NON_DIRECTORY_FILE = 0x00000040 16 | Global Const $tagOBJECTATTRIBUTES = "ulong Length;handle RootDirectory;ptr ObjectName;ulong Attributes;ptr SecurityDescriptor;ptr SecurityQualityOfService" 17 | Global Const $tagUNICODESTRING = "ushort Length;ushort MaximumLength;ptr Buffer" 18 | Global Const $tagFILE_EA_INFORMATION = "ulong EaSize" 19 | Global Const $FILE_READ_EA = 8 20 | Global Const $FileEaInformation = 7 21 | Global Const $tagFILE_FULL_EA_INFORMATION1 = "ulong NextEntryOffset;byte Flags[1];byte EaNameLength[1];ushort EaValueLength" 22 | Global Const $tagIOSTATUSBLOCK = "ptr Status;ptr Information" 23 | Global $TargetPath, $Verbosity, $DoExtract, $TextIdentifier, $TargetIsDirectory, $SearchFilter, $RecursiveMode 24 | 25 | ConsoleWrite("EaQuery v1.0.0.1" & @CRLF & @CRLF) 26 | _ValidateInput() 27 | If $TargetIsDirectory Then 28 | $TargetFile = _RecFileListToArray($TargetPath,$SearchFilter,0,$RecursiveMode) 29 | If @error Then 30 | ConsoleWrite("Error: Searching failed" & @CRLF) 31 | Exit 32 | EndIf 33 | Else 34 | $TargetFile = StringSplit($TargetPath,";") ;Just choose something not valid inside a filename 35 | EndIf 36 | 37 | For $i = 1 To $TargetFile[0] 38 | If $TargetIsDirectory Then 39 | $TargetFileAndPath = $TargetPath&"\"&$TargetFile[$i] 40 | Else 41 | $TargetFileAndPath = $TargetFile[$i] 42 | EndIf 43 | $EaSize = _GetEaInformation($TargetFileAndPath) 44 | If $EaSize > 0 Then 45 | _ProcessEa($TargetFileAndPath,$TextIdentifier,Int($DoExtract),Int($Verbosity)) 46 | Else 47 | ; ConsoleWrite("No Ea found in: " & $TargetFileAndPath & @CRLF) 48 | ContinueLoop 49 | EndIf 50 | Next 51 | 52 | 53 | Func _ProcessEa($TargetFile,$NameIdentifier,$ExtractionMode,$VerboseLevel) 54 | Local $ReturnSingleEntry = 0, $RestartScan = 0, $NextEntryOffset = 0, $nBytes 55 | ConsoleWrite(@CRLF) 56 | $szName = DllStructCreate("wchar[260]") 57 | $sUS = DllStructCreate($tagUNICODESTRING) 58 | $sOA = DllStructCreate($tagOBJECTATTRIBUTES) 59 | $sISB = DllStructCreate($tagIOSTATUSBLOCK) 60 | ; $buffer = DllStructCreate("byte["&$EaSize+16&"]") 61 | $buffer = DllStructCreate("byte["&65535&"]") ;Just oversize it to max possible Ea size 62 | DllStructSetData($szName, 1, "\??\"&$TargetFile) 63 | ; If $VerboseLevel Then ConsoleWrite("TargetFile: " & $TargetFile & @CRLF) 64 | ConsoleWrite("TargetFile: " & $TargetFile & @CRLF) 65 | $ret = DllCall("ntdll.dll", "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName)) 66 | DllStructSetData($sOA, "Length", DllStructGetSize($sOA)) 67 | DllStructSetData($sOA, "RootDirectory", 0) 68 | DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS)) 69 | DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE) 70 | DllStructSetData($sOA, "SecurityDescriptor", 0) 71 | DllStructSetData($sOA, "SecurityQualityOfService", 0) 72 | If StringInStr(FileGetAttrib($TargetFile),"D") Then 73 | $FileMode=$FILE_DIRECTORY_FILE 74 | Else 75 | $FileMode=$FILE_NON_DIRECTORY_FILE 76 | EndIf 77 | $ret = DllCall("ntdll.dll", "int", "NtOpenFile", "hwnd*", "", "dword", $GENERIC_READ, "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), "ulong", $FILE_SHARE_READ, "ulong", BitOR($FileMode,$FILE_READ_EA,$FILE_RANDOM_ACCESS)) 78 | If NT_SUCCESS($ret[0]) Then 79 | ; ConsoleWrite("NtOpenFile: Success" & @CRLF) 80 | Else 81 | ConsoleWrite("TargetFile: " & $TargetFile & @CRLF) 82 | ConsoleWrite("NtOpenFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 83 | Return 84 | EndIf 85 | $hFile = $ret[1] 86 | $ret = DllCall("ntdll.dll", "handle", "NtQueryEaFile", "handle", $hFile, "ptr", DllStructGetPtr($sISB), "ptr", DllStructGetPtr($buffer), "ulong", DllStructGetSize($buffer), "bool", $ReturnSingleEntry, "ptr", 0, "ulong", 0, "ptr", 0, "bool", $RestartScan) 87 | If Not NT_SUCCESS($ret[0]) Then 88 | ConsoleWrite("TargetFile: " & $TargetFile & @CRLF) 89 | ConsoleWrite("NtQueryEaFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 90 | Return 91 | EndIf 92 | 93 | $pPointer = DllStructGetPtr($buffer) 94 | Do 95 | $sEaStruct = DllStructCreate($tagFILE_FULL_EA_INFORMATION1, $pPointer) 96 | $NextEntryOffset = DllStructGetData($sEaStruct, "NextEntryOffset") 97 | $Flags = DllStructGetData($sEaStruct, "Flags") 98 | $EaNameLength = DllStructGetData($sEaStruct, "EaNameLength") 99 | $EaNameLength = Dec(StringTrimLeft($EaNameLength,2)) 100 | $EaValueLength = DllStructGetData($sEaStruct, "EaValueLength") 101 | $pPointer+=8 102 | $sEaStruct = DllStructCreate("char EaName["&$EaNameLength&"]", $pPointer) 103 | $EaName = DllStructGetData($sEaStruct, "EaName") 104 | $pPointer+=$EaNameLength+1 105 | $sEaStruct = DllStructCreate("byte EaValue["&$EaValueLength&"]", $pPointer) 106 | $EaValue = DllStructGetData($sEaStruct, "EaValue") 107 | If StringInStr($EaName,$NameIdentifier) Or $NameIdentifier = "*" Then 108 | If $VerboseLevel > 0 Then 109 | ConsoleWrite("NextEntryOffset: " & $NextEntryOffset & @CRLF) 110 | ConsoleWrite("Flags: " & $Flags & @CRLF) 111 | ConsoleWrite("EaNameLength: " & $EaNameLength & @CRLF) 112 | ConsoleWrite("EaName: " & $EaName & @CRLF) 113 | ConsoleWrite("EaValueLength: " & $EaValueLength & @CRLF) 114 | If $VerboseLevel = 2 Then 115 | ConsoleWrite("EaValue:" & @CRLF) 116 | ConsoleWrite(_HexEncode(StringMid($EaValue,1,$EaValueLength*2)) & @CRLF) 117 | EndIf 118 | ConsoleWrite(@CRLF) 119 | EndIf 120 | If $ExtractionMode Then 121 | If $VerboseLevel Then ConsoleWrite("Found " & $EaValueLength & " bytes in EA with matching name: " & $EaName & " in file: " & $TargetFile & @CRLF) 122 | $hFile2 = _WinAPI_CreateFile("\\.\" & @ScriptDir&"\EA_"&$EaName,1,6,7) 123 | If $hFile2=0 then 124 | ConsoleWrite("Error CreateFile returned: " & _WinAPI_GetLastErrorMessage() & @CRLF) 125 | Exit 126 | EndIf 127 | $tBuffer = DllStructCreate("byte[" & $EaValueLength & "]") 128 | DllStructSetData($tBuffer,1,$EaValue) 129 | $write = _WinAPI_WriteFile($hFile2, DllStructGetPtr($tBuffer), $EaValueLength-1, $nBytes) 130 | If $write = 0 then 131 | ConsoleWrite("Error WriteFile returned: " & _WinAPI_GetLastErrorMessage() & @CRLF) 132 | Exit 133 | Else 134 | ConsoleWrite("Successfully wrote " & $nBytes & " bytes to " & @ScriptDir&"\EA_"&$EaName & @CRLF) 135 | EndIf 136 | ConsoleWrite(@CRLF) 137 | $tBuffer=0 138 | _WinAPI_CloseHandle($hFile2) 139 | EndIf 140 | EndIf 141 | $pPointer+=$NextEntryOffset-8-$EaNameLength-1 142 | Until $NextEntryOffset=0 143 | DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile) 144 | EndFunc 145 | 146 | Func NT_SUCCESS($status) 147 | If 0 <= $status And $status <= 0x7FFFFFFF Then 148 | Return True 149 | Else 150 | Return False 151 | EndIf 152 | EndFunc 153 | 154 | Func _RtlNtStatusToDosError($Status) 155 | Local $aCall = DllCall("ntdll.dll", "ulong", "RtlNtStatusToDosError", "dword", $Status) 156 | If Not NT_SUCCESS($aCall[0]) Then 157 | ConsoleWrite("Error in RtlNtStatusToDosError: " & Hex($aCall[0], 8) & @CRLF) 158 | Return SetError(1, 0, $aCall[0]) 159 | Else 160 | Return $aCall[0] 161 | EndIf 162 | EndFunc 163 | 164 | Func _TranslateErrorCode($ErrCode) 165 | Local $tBufferPtr = DllStructCreate("ptr") 166 | 167 | Local $nCount = _FormatMessage(BitOR($__WINAPICONSTANT_FORMAT_MESSAGE_ALLOCATE_BUFFER, $__WINAPICONSTANT_FORMAT_MESSAGE_FROM_SYSTEM), _ 168 | 0, $ErrCode, 0, $tBufferPtr, 0, 0) 169 | If @error Then Return SetError(@error, 0, "") 170 | 171 | Local $sText = "" 172 | Local $pBuffer = DllStructGetData($tBufferPtr, 1) 173 | If $pBuffer Then 174 | If $nCount > 0 Then 175 | Local $tBuffer = DllStructCreate("wchar[" & ($nCount + 1) & "]", $pBuffer) 176 | $sText = DllStructGetData($tBuffer, 1) 177 | EndIf 178 | _LocalFree($pBuffer) 179 | EndIf 180 | 181 | Return $sText 182 | EndFunc 183 | 184 | Func _FormatMessage($iFlags, $pSource, $iMessageID, $iLanguageID, ByRef $pBuffer, $iSize, $vArguments) 185 | Local $sBufferType = "struct*" 186 | If IsString($pBuffer) Then $sBufferType = "wstr" 187 | Local $aResult = DllCall("Kernel32.dll", "dword", "FormatMessageW", "dword", $iFlags, "ptr", $pSource, "dword", $iMessageID, "dword", $iLanguageID, _ 188 | $sBufferType, $pBuffer, "dword", $iSize, "ptr", $vArguments) 189 | If @error Then Return SetError(@error, @extended, 0) 190 | If $sBufferType = "wstr" Then $pBuffer = $aResult[5] 191 | Return $aResult[0] 192 | EndFunc 193 | 194 | Func _LocalFree($hMem) 195 | Local $aResult = DllCall("kernel32.dll", "handle", "LocalFree", "handle", $hMem) 196 | If @error Then Return SetError(@error, @extended, False) 197 | Return $aResult[0] 198 | EndFunc 199 | 200 | Func _HexEncode($bInput) 201 | Local $tInput = DllStructCreate("byte[" & BinaryLen($bInput) & "]") 202 | DllStructSetData($tInput, 1, $bInput) 203 | Local $a_iCall = DllCall("crypt32.dll", "int", "CryptBinaryToString", _ 204 | "ptr", DllStructGetPtr($tInput), _ 205 | "dword", DllStructGetSize($tInput), _ 206 | "dword", 11, _ 207 | "ptr", 0, _ 208 | "dword*", 0) 209 | 210 | If @error Or Not $a_iCall[0] Then 211 | Return SetError(1, 0, "") 212 | EndIf 213 | 214 | Local $iSize = $a_iCall[5] 215 | Local $tOut = DllStructCreate("char[" & $iSize & "]") 216 | 217 | $a_iCall = DllCall("crypt32.dll", "int", "CryptBinaryToString", _ 218 | "ptr", DllStructGetPtr($tInput), _ 219 | "dword", DllStructGetSize($tInput), _ 220 | "dword", 11, _ 221 | "ptr", DllStructGetPtr($tOut), _ 222 | "dword*", $iSize) 223 | 224 | If @error Or Not $a_iCall[0] Then 225 | Return SetError(2, 0, "") 226 | EndIf 227 | 228 | Return SetError(0, 0, DllStructGetData($tOut, 1)) 229 | 230 | EndFunc ;==>_HexEncode 231 | 232 | Func _GetEaInformation($file) 233 | Local $szName = DllStructCreate("wchar[260]") 234 | Local $sUS = DllStructCreate($tagUNICODESTRING) 235 | Local $sOA = DllStructCreate($tagOBJECTATTRIBUTES) 236 | Local $sISB = DllStructCreate($tagIOSTATUSBLOCK) 237 | Local $buffer = DllStructCreate("byte[16384]") 238 | If StringInStr(FileGetAttrib($file),"D") Then 239 | $FileMode=$FILE_DIRECTORY_FILE 240 | Else 241 | $FileMode=$FILE_NON_DIRECTORY_FILE 242 | EndIf 243 | DllStructSetData($szName, 1, "\??\"&$file) 244 | $ret = DllCall("ntdll.dll", "none", "RtlInitUnicodeString", "ptr", DllStructGetPtr($sUS), "ptr", DllStructGetPtr($szName)) 245 | DllStructSetData($sOA, "Length", DllStructGetSize($sOA)) 246 | DllStructSetData($sOA, "RootDirectory", 0) 247 | DllStructSetData($sOA, "ObjectName", DllStructGetPtr($sUS)) 248 | DllStructSetData($sOA, "Attributes", $OBJ_CASE_INSENSITIVE) 249 | DllStructSetData($sOA, "SecurityDescriptor", 0) 250 | DllStructSetData($sOA, "SecurityQualityOfService", 0) 251 | $ret = DllCall("ntdll.dll", "int", "NtOpenFile", "hwnd*", "", "dword", $GENERIC_READ, "ptr", DllStructGetPtr($sOA), "ptr", DllStructGetPtr($sISB), "ulong", $FILE_SHARE_READ, "ulong", BitOR($FileMode, $FILE_RANDOM_ACCESS)) 252 | If NT_SUCCESS($ret[0]) Then 253 | ; ConsoleWrite("NtOpenFile: Success" & @CRLF) 254 | Else 255 | ConsoleWrite("TargetFile: " & $file & @CRLF) 256 | ConsoleWrite("NtOpenFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 257 | Return False 258 | EndIf 259 | Local $hFile = $ret[1] 260 | $ret = DllCall("ntdll.dll", "int", "NtQueryInformationFile", "ptr", $hFile, "ptr", DllStructGetPtr($sISB), "ptr", DllStructGetPtr($buffer), _ 261 | "int", 16384, "ptr", $FileEaInformation) 262 | 263 | If NT_SUCCESS($ret[0]) Then 264 | Local $pFSO = DllStructGetPtr($buffer) 265 | Local $sFSO = DllStructCreate($tagFILE_EA_INFORMATION, $pFSO) 266 | Local $EaSize = DllStructGetData($sFSO, "EaSize") 267 | Else 268 | ConsoleWrite("TargetFile: " & $file & @CRLF) 269 | ConsoleWrite("NtQueryInformationFile : 0x"&Hex($ret[0],8) &" "& _TranslateErrorCode(_RtlNtStatusToDosError("0x"&Hex($ret[0],8))) & @CRLF) 270 | Return False 271 | EndIf 272 | $ret = DllCall("ntdll.dll", "int", "NtClose", "hwnd", $hFile) 273 | Return $EaSize 274 | EndFunc 275 | 276 | Func _SwapEndian($iHex) 277 | Return StringMid(Binary(Dec($iHex,2)),3, StringLen($iHex)) 278 | EndFunc 279 | 280 | Func _ValidateInput() 281 | Local $TargetAttributes 282 | Global $TargetPath, $Verbosity, $DoExtract, $TextIdentifier, $TargetIsDirectory, $SearchFilter, $RecursiveMode 283 | If $cmdline[0] < 3 Then 284 | ConsoleWrite("Error: Wrong number of parameters" & @CRLF) 285 | ConsoleWrite("Syntax is:" & @CRLF) 286 | ConsoleWrite("EaQuery.exe /Target:TargetPath /Mode:{0|1} /Verbose:{0|1|2} /Identifier:{*|SomeText} /Filter:Text /Recurse:boolean" & @CRLF) 287 | ConsoleWrite(" /Target can be file or directory" & @CRLF) 288 | ConsoleWrite(" /Mode 0 is just displaying result on console. Mode 1 is also extracting the data." & @CRLF) 289 | ConsoleWrite(" /Verbose level 0 show only filenames containing $EA. Level 1 also show some $EA details. Level 2 also dumps the data to console." & @CRLF) 290 | ConsoleWrite(" /Identifier is a filter for what EA names to parse. Default is '*'." & @CRLF) 291 | ConsoleWrite(" /Filter is for included results. Multiple filters separatet by ';'. Default is '*'." & @CRLF) 292 | ConsoleWrite(" /Recurse is a boolean value 0 or 1 for acivating/deactivating recursive mode. Default is off." & @CRLF) 293 | Exit 294 | EndIf 295 | For $i = 1 To $cmdline[0] 296 | If StringLeft($cmdline[$i],8) = "/Target:" Then $TargetPath = StringMid($cmdline[$i],9) 297 | If StringLeft($cmdline[$i],9) = "/Verbose:" Then $Verbosity = StringMid($cmdline[$i],10) 298 | If StringLeft($cmdline[$i],6) = "/Mode:" Then $DoExtract = StringMid($cmdline[$i],7) 299 | If StringLeft($cmdline[$i],12) = "/Identifier:" Then $TextIdentifier = StringMid($cmdline[$i],13) 300 | If StringLeft($cmdline[$i],8) = "/Filter:" Then $SearchFilter = StringMid($cmdline[$i],9) 301 | If StringLeft($cmdline[$i],9) = "/Recurse:" Then $RecursiveMode = StringMid($cmdline[$i],10) 302 | Next 303 | If $Verbosity <> 0 And $Verbosity <> 1 And $Verbosity <> 2 Or Not StringIsDigit($Verbosity) Then 304 | ConsoleWrite("Error: Verbosity not set correctly: " & $Verbosity & @CRLF) 305 | Exit 306 | EndIf 307 | If $DoExtract <> 0 And $DoExtract <> 1 Or Not StringIsDigit($DoExtract) Then 308 | ConsoleWrite("Error: Mode not set correctly: " & $DoExtract & @CRLF) 309 | Exit 310 | EndIf 311 | If FileExists($TargetPath) = 0 Then 312 | ConsoleWrite("Error: Target path does not exist: " & $TargetPath & @CRLF) 313 | Exit 314 | Else 315 | If StringRight($TargetPath,1)="\" Then $TargetPath = StringTrimRight($TargetPath,1) 316 | EndIf 317 | $TargetAttributes = FileGetAttrib($TargetPath) 318 | If @error Then 319 | ConsoleWrite("Error: Could not evaluate attributes of: " & $TargetPath & @CRLF) 320 | Exit 321 | EndIf 322 | If StringInStr($TargetAttributes,"D") Then 323 | $TargetIsDirectory = 1 324 | Else 325 | $TargetIsDirectory = 0 326 | EndIf 327 | If $TextIdentifier = "" Then $TextIdentifier = "*" 328 | If $RecursiveMode <> 0 And $RecursiveMode <> 1 And $RecursiveMode <> "False" And $RecursiveMode <> "True" Then 329 | ConsoleWrite("Error: Recursive was not boolean" & @CRLF) 330 | Exit 331 | ElseIf $RecursiveMode = 0 Or $RecursiveMode = "False" Then 332 | $RecursiveMode = 0 333 | ElseIf $RecursiveMode = 1 Or $RecursiveMode = "True" Then 334 | $RecursiveMode = 1 335 | ElseIf $RecursiveMode = "" Then 336 | $RecursiveMode = 0 337 | EndIf 338 | If $SearchFilter = "" Then $SearchFilter = "*" 339 | EndFunc -------------------------------------------------------------------------------- /EaQuery.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jschicht/EaTools/25deec1e211e1b926e8ba0d7bcc87bee9a1047d4/EaQuery.exe -------------------------------------------------------------------------------- /EaQuery64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jschicht/EaTools/25deec1e211e1b926e8ba0d7bcc87bee9a1047d4/EaQuery64.exe -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | License 2 | 3 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. 4 | 5 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 6 | 7 | 1. Definitions 8 | a."Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. 9 | b."Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. 10 | c."Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. 11 | d."Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. 12 | e."Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. 13 | f."Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. 14 | g."You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. 15 | h."Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. 16 | i."Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. 17 | 18 | 2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. 19 | 20 | 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: 21 | a.to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; 22 | b.to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; 23 | c.to Distribute and Publicly Perform the Work including as incorporated in Collections; and, 24 | d.to Distribute and Publicly Perform Adaptations. 25 | 26 | e.For the avoidance of doubt: 27 | i.Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; 28 | ii.Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, 29 | iii.Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License. 30 | 31 | 32 | The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved. 33 | 34 | 4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: 35 | a.You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(b), as requested. 36 | b.If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and (iv) , consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4 (b) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. 37 | c.Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. 38 | 39 | 5. Representations, Warranties and Disclaimer 40 | 41 | UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 42 | 43 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 44 | 45 | 7. Termination 46 | a.This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. 47 | b.Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 48 | 49 | 8. Miscellaneous 50 | a.Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. 51 | b.Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. 52 | c.If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. 53 | d.No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. 54 | e.This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. 55 | f.The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. 56 | -------------------------------------------------------------------------------- /_RecFileListToArray.au3: -------------------------------------------------------------------------------- 1 | #include-once 2 | 3 | ;#AutoIt3Wrapper_au3check_parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 4 | 5 | ; #INDEX# ======================================================================================================================= 6 | ; Title .........: _RecFileListToArray 7 | ; AutoIt Version : v3.3.1.1 or higher 8 | ; Language ......: English 9 | ; Description ...: Lists files and\or folders in specified path with optional recursion to defined level and result sorting 10 | ; Note ..........: 11 | ; Author(s) .....: Melba23 12 | ; Remarks .......: - Modified Array.au3 functions - credit: Jos van der Zande, LazyCoder, Tylo, Ultima, SolidSnake and gcriaco 13 | ; - SRE patterns - credit: various forum members and Spiff59 in particular 14 | ; - Despite the name, this UDF is iterative, not recursive 15 | ; =============================================================================================================================== 16 | 17 | ; #CURRENT# ===================================================================================================================== 18 | ; _RecFileListToArray: Lists files and\or folders in a specified path with optional recursion to defined level and result sorting 19 | ; =============================================================================================================================== 20 | 21 | ; #INTERNAL_USE_ONLY#============================================================================================================ 22 | ; _RFLTA_ListToMask ......; Convert include/exclude lists to SRE format 23 | ; _RFLTA_AddToList .......; Add element to list which is resized if necessary 24 | ; _RFLTA_AddFileLists ....; Add internal lists after resizing and optional sorting 25 | ; _RFLTA_FileListSearch ..; Search file match list for files associated with a folder 26 | ; _RFLTA_ArraySort .......; Wrapper for QuickSort function 27 | ; _RFLTA_QuickSort .......: Recursive array sort 28 | ; _RFLTA_ArrayConcatenate : Join 2 arrays 29 | ; =============================================================================================================================== 30 | 31 | ; #FUNCTION# ==================================================================================================================== 32 | ; Name...........: _RecFileListToArray 33 | ; Description ...: Lists files and\or folders in a specified path with optional recursion to defined level and result sorting 34 | ; Syntax.........: _RecFileListToArray($sPath[, $sInclude_List = "*"[, $iReturn = 0[, $iRecur = 0[, $iSort = 0[, $iReturnPath = 1[, $sExclude_List = ""[, $sExclude_List_Folder]]]]]]]) 35 | ; Parameters ....: $sPath - Initial path used to generate filelist. If path ends in \ then folders will be returned with an ending \ 36 | ; $sInclude_List - Optional: filter for included results (default "*"). Multiple filters must be separated by ";" 37 | ; $iReturn - Optional: specifies whether to return files, folders or both 38 | ; |$iReturn = 0 - Return both files and folders (Default) 39 | ; If non-recursive Include/Exclude_List applies to files and folders 40 | ; If recursive Include/Exclude_List applies to files only, all folders are searched unless excluded using $sExclude_List_Folder 41 | ; |$iReturn = 1 - Return files only - Include/Exclude_List applies to files only, all folders searched if recursive 42 | ; |$iReturn = 2 - Return folders only - Include/Exclude_List applies to folders only for searching and return 43 | ; $iRecur - Optional: specifies whether to search recursively in subfolders and to what level 44 | ; |$iRecur = 1 - Search in all subfolders (unlimited recursion) 45 | ; |$iRecur = 0 - Do not search in subfolders (Default) 46 | ; |$iRecur = Negative integer - Search in subfolders to specified depth 47 | ; $iSort - Optional: sort ordered in alphabetical and depth order 48 | ; |$iSort = 0 - Not sorted (Default) 49 | ; |$iSort = 1 - Sorted 50 | ; |$iSort = 2 - Sorted with faster algorithm (assumes files sorted within each folder - requires NTFS drive) 51 | ; $iReturnPath - Optional: specifies displayed path of results 52 | ; |$iReturnPath = 0 - File/folder name only 53 | ; |$iReturnPath = 1 - Relative to initial path (Default) 54 | ; |$iReturnPath = 2 - Full path included 55 | ; $sExclude_List - Optional: filter for excluded results (default ""). Multiple filters must be separated by ";" 56 | ; $sExclude_List_Folder - Optional: only used if $iReturn = 0 AND $iRecur = 1 to exclude folders matching the filter 57 | ; Requirement(s).: v3.3.1.1 or higher 58 | ; Return values .: Success: One-dimensional array made up as follows: 59 | ; |$array[0] = Number of Files\Folders returned 60 | ; |$array[1] = 1st File\Folder 61 | ; |$array[2] = 2nd File\Folder 62 | ; |... 63 | ; |$array[n] = nth File\Folder 64 | ; Failure: Null string and @error = 1 with @extended set as follows: 65 | ; |1 = Path not found or invalid 66 | ; |2 = Invalid $sInclude_List 67 | ; |3 = Invalid $iReturn 68 | ; |4 = Invalid $iRecur 69 | ; |5 = Invalid $iSort 70 | ; |6 = Invalid $iReturnPath 71 | ; |7 = Invalid $sExclude_List 72 | ; |8 = Invalid $sExclude_List_Folder 73 | ; |9 = No files/folders found 74 | ; Author ........: Melba23 75 | ; Remarks .......: Compatible with existing _FileListToArray syntax 76 | ; Related .......: 77 | ; Link ..........; 78 | ; Example .......; Yes 79 | ; =============================================================================================================================== 80 | Func _RecFileListToArray($sInitialPath, $sInclude_List = "*", $iReturn = 0, $iRecur = 0, $iSort = 0, $iReturnPath = 1, $sExclude_List = "", $sExclude_List_Folder = "") 81 | 82 | Local $asReturnList[100] = [0], $asFileMatchList[100] = [0], $asRootFileMatchList[100] = [0], $asFolderMatchList[100] = [0], $asFolderSearchList[100] = [1] 83 | Local $sFolderSlash = "", $iMaxLevel, $sInclude_File_Mask, $sExclude_File_Mask, $sInclude_Folder_Mask = ".+", $sExclude_Folder_Mask = ":" 84 | Local $hSearch, $fFolder, $sRetPath = "", $sCurrentPath, $sName 85 | Local $asFolderFileSectionList[100][2] = [[0, 0]], $sFolderToFind, $iFileSectionStartIndex, $iFileSectionEndIndex 86 | 87 | ; Check for valid path 88 | If Not FileExists($sInitialPath) Then Return SetError(1, 1, "") 89 | ; Check if folders should have trailing \ and ensure that initial path does have one 90 | If StringRight($sInitialPath, 1) = "\" Then 91 | $sFolderSlash = "\" 92 | Else 93 | $sInitialPath = $sInitialPath & "\" 94 | EndIf 95 | ; Add path to folder search list 96 | $asFolderSearchList[1] = $sInitialPath 97 | 98 | ; Check for valid recur value 99 | If $iRecur > 1 Or Not IsInt($iRecur) Then Return SetError(1, 4, "") 100 | ; If required, determine \ count for max recursive level setting 101 | If $iRecur < 0 Then 102 | StringReplace($sInitialPath, "\", "", 2) 103 | $iMaxLevel = @extended - $iRecur 104 | EndIf 105 | 106 | ; Create Include mask for files 107 | If $sInclude_List = "*" Then 108 | $sInclude_File_Mask = ".+" 109 | Else 110 | If Not _RFLTA_ListToMask($sInclude_File_Mask, $sInclude_List) Then Return SetError(1, 2, "") 111 | EndIf 112 | ; Set Include mask for folders 113 | Switch $iReturn 114 | Case 0 115 | ; Folders affected by mask if not recursive 116 | Switch $iRecur 117 | Case 0 118 | ; Folders match mask for compatibility 119 | $sInclude_Folder_Mask = $sInclude_File_Mask 120 | ;Case Else 121 | ; All folders match 122 | EndSwitch 123 | ;Case 1 124 | ; All folders match 125 | Case 2 126 | ; Folders affected by mask 127 | $sInclude_Folder_Mask = $sInclude_File_Mask 128 | EndSwitch 129 | 130 | ; Create Exclude List mask for files 131 | If $sExclude_List = "" Then 132 | $sExclude_File_Mask = ":" ; Set unmatchable mask 133 | Else 134 | If Not _RFLTA_ListToMask($sExclude_File_Mask, $sExclude_List) Then Return SetError(1, 7, "") 135 | EndIf 136 | ; Set Exclude mask for folders 137 | Switch $iReturn 138 | Case 0 139 | ; Folders affected by mask if not recursive 140 | Switch $iRecur 141 | Case 0 142 | ; Folders match mask for compatibility 143 | $sExclude_Folder_Mask = $sExclude_File_Mask 144 | Case Else 145 | ; Exclude defined folders as set in extended 146 | If $sExclude_List_Folder <> "" Then 147 | If Not _RFLTA_ListToMask($sExclude_Folder_Mask, $sExclude_List_Folder) Then Return SetError(1, 8, "") 148 | EndIf 149 | EndSwitch 150 | ;Case 1 151 | ; All folders match 152 | Case 2 153 | ; Folders affected by normal mask 154 | $sExclude_Folder_Mask = $sExclude_File_Mask 155 | EndSwitch 156 | 157 | ; Verify other parameters 158 | If Not ($iReturn = 0 Or $iReturn = 1 Or $iReturn = 2) Then Return SetError(1, 3, "") 159 | If Not ($iSort = 0 Or $iSort = 1 Or $iSort = 2) Then Return SetError(1, 5, "") 160 | If Not ($iReturnPath = 0 Or $iReturnPath = 1 Or $iReturnPath = 2) Then Return SetError(1, 6, "") 161 | 162 | ; Search within listed folders 163 | While $asFolderSearchList[0] > 0 164 | 165 | ; Set path to search 166 | $sCurrentPath = $asFolderSearchList[$asFolderSearchList[0]] 167 | 168 | ; Reduce folder search list count 169 | $asFolderSearchList[0] -= 1 170 | 171 | ; Determine return path to add to file/folder name 172 | Switch $iReturnPath 173 | ; Case 0 ; Name only 174 | ; Leave as "" 175 | Case 1 ;Relative to initial path 176 | $sRetPath = StringReplace($sCurrentPath, $sInitialPath, "") 177 | Case 2 ; Full path 178 | $sRetPath = $sCurrentPath 179 | EndSwitch 180 | 181 | ; Get search handle 182 | $hSearch = FileFindFirstFile($sCurrentPath & "*") 183 | ; If sorting files and folders with paths then store folder name and position of associated files in list 184 | If $iReturn = 0 And $iSort And $iReturnPath Then 185 | _RFLTA_AddToList($asFolderFileSectionList, $sRetPath, $asFileMatchList[0] + 1) 186 | EndIf 187 | ; If folder empty move to next in list 188 | If $hSearch = -1 Then 189 | ContinueLoop 190 | EndIf 191 | 192 | ; Search folder 193 | While 1 194 | $sName = FileFindNextFile($hSearch) 195 | ; Check for end of folder 196 | If @error Then 197 | ExitLoop 198 | EndIf 199 | ; Set subfolder flag - @extended set in 3.3.1.1 + 200 | $fFolder = @extended 201 | 202 | ; If folder then check whether to add to search list 203 | If $fFolder Then 204 | Select 205 | Case $iRecur < 0 ; Check recur depth 206 | StringReplace($sCurrentPath, "\", "", 0, 2) 207 | If @extended < $iMaxLevel Then 208 | ContinueCase ; Check if matched to masks 209 | EndIf 210 | Case $iRecur = 1 ; Full recur 211 | If Not StringRegExp($sName, $sExclude_Folder_Mask) Then ; Add folder unless excluded 212 | _RFLTA_AddToList($asFolderSearchList, $sCurrentPath & $sName & "\") 213 | EndIf 214 | ; Case $iRecur = 0 ; Never add 215 | ; Do nothing 216 | EndSelect 217 | EndIf 218 | 219 | If $iSort Then ; Save in relevant folders for later sorting 220 | 221 | If $fFolder Then 222 | If StringRegExp($sName, $sInclude_Folder_Mask) And Not StringRegExp($sName, $sExclude_Folder_Mask) Then 223 | _RFLTA_AddToList($asFolderMatchList, $sRetPath & $sName & $sFolderSlash) 224 | EndIf 225 | Else 226 | If StringRegExp($sName, $sInclude_File_Mask) And Not StringRegExp($sName, $sExclude_File_Mask) Then 227 | ; Select required list for files 228 | If $sCurrentPath = $sInitialPath Then 229 | _RFLTA_AddToList($asRootFileMatchList, $sRetPath & $sName) 230 | Else 231 | _RFLTA_AddToList($asFileMatchList, $sRetPath & $sName) 232 | EndIf 233 | EndIf 234 | EndIf 235 | 236 | Else ; Save directly in return list 237 | If $fFolder Then 238 | If $iReturn <> 1 And StringRegExp($sName, $sInclude_Folder_Mask) And Not StringRegExp($sName, $sExclude_Folder_Mask) Then 239 | _RFLTA_AddToList($asReturnList, $sRetPath & $sName & $sFolderSlash) 240 | EndIf 241 | Else 242 | If $iReturn <> 2 And StringRegExp($sName, $sInclude_File_Mask) And Not StringRegExp($sName, $sExclude_File_Mask) Then 243 | _RFLTA_AddToList($asReturnList, $sRetPath & $sName) 244 | EndIf 245 | EndIf 246 | EndIf 247 | 248 | WEnd 249 | 250 | ; Close current search 251 | FileClose($hSearch) 252 | 253 | WEnd 254 | 255 | If $iSort Then 256 | 257 | ; Check if any file/folders have been added depending on required return 258 | Switch $iReturn 259 | Case 0 ; If no folders then number of files is immaterial 260 | If $asRootFileMatchList[0] = 0 And $asFolderMatchList[0] = 0 Then Return SetError(1, 9, "") 261 | Case 1 262 | If $asRootFileMatchList[0] = 0 And $asFileMatchList[0] = 0 Then Return SetError(1, 9, "") 263 | Case 2 264 | If $asFolderMatchList[0] = 0 Then Return SetError(1, 9, "") 265 | EndSwitch 266 | 267 | Switch $iReturn 268 | Case 2 ; Folders only 269 | ; Correctly size folder match list 270 | ReDim $asFolderMatchList[$asFolderMatchList[0] + 1] 271 | ; Copy size folder match array 272 | $asReturnList = $asFolderMatchList 273 | ; Simple sort list 274 | _RFLTA_ArraySort($asReturnList) 275 | Case 1 ; Files only 276 | If $iReturnPath = 0 Then ; names only so simple sort suffices 277 | ; Combine file match lists 278 | _RFLTA_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList) 279 | ; Simple sort combined file list 280 | _RFLTA_ArraySort($asReturnList) 281 | Else 282 | ; Combine sorted file match lists 283 | _RFLTA_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList, 1) 284 | EndIf 285 | Case 0 ; Both files and folders 286 | If $iReturnPath = 0 Then ; names only so simple sort suffices 287 | ; Combine file match lists 288 | _RFLTA_AddFileLists($asReturnList, $asRootFileMatchList, $asFileMatchList) 289 | ; Set correct count for folder add 290 | $asReturnList[0] += $asFolderMatchList[0] 291 | ; Resize and add file match array 292 | ReDim $asFolderMatchList[$asFolderMatchList[0] + 1] 293 | _RFLTA_ArrayConcatenate($asReturnList, $asFolderMatchList) 294 | ; Simple sort final list 295 | _RFLTA_ArraySort($asReturnList) 296 | Else 297 | ; Size return list 298 | Local $asReturnList[$asFileMatchList[0] + $asRootFileMatchList[0] + $asFolderMatchList[0] + 1] 299 | $asReturnList[0] = $asFileMatchList[0] + $asRootFileMatchList[0] + $asFolderMatchList[0] 300 | ; Sort root file list 301 | _RFLTA_ArraySort($asRootFileMatchList, 1, $asRootFileMatchList[0]) 302 | ; Add the sorted root files at the top 303 | For $i = 1 To $asRootFileMatchList[0] 304 | $asReturnList[$i] = $asRootFileMatchList[$i] 305 | Next 306 | ; Set next insertion index 307 | Local $iNextInsertionIndex = $asRootFileMatchList[0] + 1 308 | ; Sort folder list 309 | _RFLTA_ArraySort($asFolderMatchList, 1, $asFolderMatchList[0]) 310 | ; Work through folder list 311 | For $i = 1 To $asFolderMatchList[0] 312 | ; Format folder name for search 313 | If $sFolderSlash Then 314 | $sFolderToFind = $asFolderMatchList[$i] 315 | Else 316 | $sFolderToFind = $asFolderMatchList[$i] & "\" 317 | EndIf 318 | ; Find folder in FolderFileSectionList 319 | For $j = 1 To $asFolderFileSectionList[0][0] 320 | If $sFolderToFind = $asFolderFileSectionList[$j][0] Then ExitLoop 321 | Next 322 | ; Set file list indexes 323 | $iFileSectionStartIndex = $asFolderFileSectionList[$j][1] 324 | If $j = $asFolderFileSectionList[0][0] Then 325 | $iFileSectionEndIndex = $asFileMatchList[0] 326 | Else 327 | $iFileSectionEndIndex = $asFolderFileSectionList[$j + 1][1] - 1 328 | EndIf 329 | ; Sort files if required 330 | If $iSort = 1 Then 331 | _RFLTA_ArraySort($asFileMatchList, $iFileSectionStartIndex, $iFileSectionEndIndex) 332 | EndIf 333 | ; Add folder to return list 334 | $asReturnList[$iNextInsertionIndex] = $asFolderMatchList[$i] 335 | $iNextInsertionIndex += 1 336 | ; Add files to return list 337 | For $j = $iFileSectionStartIndex To $iFileSectionEndIndex 338 | $asReturnList[$iNextInsertionIndex] = $asFileMatchList[$j] 339 | $iNextInsertionIndex += 1 340 | Next 341 | Next 342 | EndIf 343 | EndSwitch 344 | 345 | Else ; No sort 346 | 347 | ; Check if any file/folders have been added 348 | If $asReturnList[0] = 0 Then Return SetError(1, 9, "") 349 | 350 | ; Remove any unused return list elements from last ReDim 351 | ReDim $asReturnList[$asReturnList[0] + 1] 352 | 353 | EndIf 354 | 355 | Return $asReturnList 356 | 357 | 358 | EndFunc ;==>_RecFileListToArray 359 | 360 | ; #INTERNAL_USE_ONLY#============================================================================================================ 361 | ; Name...........: _RFLTA_ListToMask 362 | ; Description ...: Convert include/exclude lists to SRE format 363 | ; Syntax ........: _RFLTA_ListToMask(ByRef $sMask, $sList) 364 | ; Parameters ....: $asMask - Include/Exclude mask to create 365 | ; $asList - Include/Exclude list to convert 366 | ; Return values .: Success: 1 367 | ; Failure: 0 368 | ; Author ........: SRE patterns developed from those posted by various forum members and Spiff59 in particular 369 | ; Remarks .......: This function is used internally by _RecFileListToArray 370 | ; =============================================================================================================================== 371 | Func _RFLTA_ListToMask(ByRef $sMask, $sList) 372 | 373 | ; Check for invalid characters within list 374 | If StringRegExp($sList, "\\|/|:|\<|\>|\|") Then Return 0 375 | ; Strip WS and insert | for ; 376 | $sList = StringReplace(StringStripWS(StringRegExpReplace($sList, "\s*;\s*", ";"), 3), ";", "|") 377 | ; Convert to SRE pattern 378 | $sList = StringReplace(StringReplace(StringRegExpReplace($sList, "[][$^.{}()+\-]", "\\$0"), "?", "."), "*", ".*?") 379 | ; Add prefix and suffix 380 | $sMask = "(?i)^(" & $sList & ")\z" 381 | Return 1 382 | 383 | EndFunc ;==>_RFLTA_ListToMask 384 | 385 | ; #INTERNAL_USE_ONLY#============================================================================================================ 386 | ; Name...........: _RFLTA_AddToList 387 | ; Description ...: Add element to [?] or [?][2] list which is resized if necessary 388 | ; Syntax ........: _RFLTA_AddToList(ByRef $asList, $vValue_0, [$vValue_1]) 389 | ; Parameters ....: $aList - List to be added to 390 | ; $vValue_0 - Value to add (to [0] element in [?][2] array if $vValue_1 exists) 391 | ; $vValue_1 - Value to add to [1] element in [?][2] array (optional) 392 | ; Return values .: None - array modified ByRef 393 | ; Author ........: Melba23 394 | ; Remarks .......: This function is used internally by _RecFileListToArray 395 | ; =============================================================================================================================== 396 | Func _RFLTA_AddToList(ByRef $aList, $vValue_0, $vValue_1 = -1) 397 | 398 | If $vValue_1 = -1 Then ; [?] array 399 | ; Increase list count 400 | $aList[0] += 1 401 | ; Double list size if too small (fewer ReDim needed) 402 | If UBound($aList) <= $aList[0] Then ReDim $aList[UBound($aList) * 2] 403 | ; Add value 404 | $aList[$aList[0]] = $vValue_0 405 | Else ; [?][2] array 406 | $aList[0][0] += 1 407 | If UBound($aList) <= $aList[0][0] Then ReDim $aList[UBound($aList) * 2][2] 408 | $aList[$aList[0][0]][0] = $vValue_0 409 | $aList[$aList[0][0]][1] = $vValue_1 410 | EndIf 411 | 412 | EndFunc ;==>_RFLTA_AddToList 413 | 414 | ; #INTERNAL_USE_ONLY#============================================================================================================ 415 | ; Name...........: _RFLTA_AddFileLists 416 | ; Description ...: Add internal lists after resizing and optional sorting 417 | ; Syntax ........: _RFLTA_AddFileLists(ByRef $asTarget, $asSource_1, $asSource_2[, $iSort = 0]) 418 | ; Parameters ....: $asReturnList - Base list 419 | ; $asRootFileMatchList - First list to add 420 | ; $asFileMatchList - Second list to add 421 | ; $iSort - (Optional) Whether to sort lists before adding 422 | ; |$iSort = 0 (Default) No sort 423 | ; |$iSort = 1 Sort in descending alphabetical order 424 | ; Return values .: None - array modified ByRef 425 | ; Author ........: Melba23 426 | ; Remarks .......: This function is used internally by _RecFileListToArray 427 | ; =============================================================================================================================== 428 | Func _RFLTA_AddFileLists(ByRef $asTarget, $asSource_1, $asSource_2, $iSort = 0) 429 | 430 | ; Correctly size root file match array 431 | ReDim $asSource_1[$asSource_1[0] + 1] 432 | ; Simple sort root file match array if required 433 | If $iSort = 1 Then _RFLTA_ArraySort($asSource_1) 434 | ; Copy root file match array 435 | $asTarget = $asSource_1 436 | ; Add file match count 437 | $asTarget[0] += $asSource_2[0] 438 | ; Correctly size file match array 439 | ReDim $asSource_2[$asSource_2[0] + 1] 440 | ; Simple sort file match array if required 441 | If $iSort = 1 Then _RFLTA_ArraySort($asSource_2) 442 | ; Add file match array 443 | _RFLTA_ArrayConcatenate($asTarget, $asSource_2) 444 | 445 | EndFunc ;==>_RFLTA_AddFileLists 446 | 447 | ; #INTERNAL_USE_ONLY#============================================================================================================ 448 | ; Name...........: _RFLTA_FileListSearch 449 | ; Description ...: Search file array for beginning and end indices of folder associated files 450 | ; Syntax ........: _RFLTA_FileListSearch(Const ByRef $avArray, $vValue) 451 | ; Parameters ....: $avArray - Array to search ($asFileMatchList) 452 | ; $vValue - Value to search for (Folder name from $asFolderMatchList) 453 | ; $iIndex - Index to begin search (search down from here - and then from here to top if not found) 454 | ; $sSlash - \ if folder names end in \ - else empty string 455 | ; Return values .: Success: Array holding top and bottom indices of folder associated files 456 | ; Failure: Returns -1 457 | ; Author ........: Melba23 458 | ; Modified.......: 459 | ; Remarks .......: This function is used internally by _RecFileListToArray 460 | ; =============================================================================================================================== 461 | Func _RFLTA_FileListSearch(Const ByRef $avArray, $vValue, $iIndex, $sSlash) 462 | 463 | Local $aRet[2] 464 | 465 | ; Add final \ if required 466 | If Not $sSlash Then $vValue &= "\" 467 | ; Start by getting top match - search down from start index 468 | For $i = $iIndex To $avArray[0] 469 | ; SRE gives path less filename 470 | If StringRegExpReplace($avArray[$i], "(^.*\\)(.*)", "\1") = $vValue Then ExitLoop 471 | Next 472 | If $i > $avArray[0] Then 473 | ; No match found so look from start index upwards 474 | If $iIndex = $avArray[0] Then $iIndex -= 1 475 | For $i = $iIndex + 1 To 1 Step -1 476 | If StringRegExpReplace($avArray[$i], "(^.*\\)(.*)", "\1") = $vValue Then ExitLoop 477 | Next 478 | ; If still no match - return " nothing found" for empty folder 479 | If $i = 0 Then Return SetError(1, 0, "") 480 | ; Set index of bottom file 481 | $aRet[1] = $i 482 | ; Now look for top match 483 | For $i = $aRet[1] To 1 Step -1 484 | If StringRegExpReplace($avArray[$i], "(^.*\\)(.*)", "\1") <> $vValue Then ExitLoop 485 | Next 486 | ; Set top match 487 | $aRet[0] = $i + 1 488 | Else 489 | ; Set index of top associated file 490 | $aRet[0] = $i 491 | ; Now look for bottom match - find first file which does not match 492 | For $i = $aRet[0] To $avArray[0] 493 | If StringRegExpReplace($avArray[$i], "(^.*\\)(.*)", "\1") <> $vValue Then ExitLoop 494 | Next 495 | ; Set bottom match 496 | $aRet[1] = $i - 1 497 | EndIf 498 | 499 | Return $aRet 500 | 501 | EndFunc ;==>_RFLTA_FileListSearch 502 | 503 | ; #INTERNAL_USE_ONLY#============================================================================================================ 504 | ; Name...........: _RFLTA_ArraySort 505 | ; Description ...: Wrapper for QuickSort function 506 | ; Syntax ........: _RFLTA_ArraySort(ByRef $avArray) 507 | ; Parameters ....: $avArray - Array to sort 508 | ; $iStart - Index to start sort 509 | ; $iEnd - Index to end sort 510 | ; Return values .: None - array modified ByRef 511 | ; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima 512 | ; Modified.......: Melba23 513 | ; Remarks .......: This function is used internally by _RecFileListToArray 514 | ; =============================================================================================================================== 515 | Func _RFLTA_ArraySort(ByRef $avArray, $iStart = 1, $iEnd = -99) 516 | 517 | If $iEnd = -99 Then $iEnd = UBound($avArray) - 1 518 | 519 | _RFLTA_QuickSort($avArray, $iStart, $iEnd) 520 | 521 | EndFunc ;==>_RFLTA_ArraySort 522 | 523 | ; #INTERNAL_USE_ONLY#============================================================================================================ 524 | ; Name...........: _RFLTA_QuickSort 525 | ; Description ...: Recursive array sort 526 | ; Syntax ........: _RFLTA_QuickSort(ByRef $avArray, ByRef $iStart, ByRef $iEnd) 527 | ; Parameters ....: $avArray - Array to sort in descending alphabetical order 528 | ; $iStart - Start index 529 | ; $iEnd - End index 530 | ; Return values .: None - array modified ByRef 531 | ; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima 532 | ; Modified.......: Melba23 533 | ; Remarks .......: This function is used internally by _RFLTA_ArraySort 534 | ; =============================================================================================================================== 535 | Func _RFLTA_QuickSort(ByRef $avArray, ByRef $iStart, ByRef $iEnd) 536 | 537 | Local $vTmp 538 | If ($iEnd - $iStart) < 15 Then 539 | Local $i, $j, $vCur 540 | For $i = $iStart + 1 To $iEnd 541 | $vTmp = $avArray[$i] 542 | If IsNumber($vTmp) Then 543 | For $j = $i - 1 To $iStart Step -1 544 | $vCur = $avArray[$j] 545 | If ($vTmp >= $vCur And IsNumber($vCur)) Or (Not IsNumber($vCur) And StringCompare($vTmp, $vCur) >= 0) Then ExitLoop 546 | $avArray[$j + 1] = $vCur 547 | Next 548 | Else 549 | For $j = $i - 1 To $iStart Step -1 550 | If (StringCompare($vTmp, $avArray[$j]) >= 0) Then ExitLoop 551 | $avArray[$j + 1] = $avArray[$j] 552 | Next 553 | EndIf 554 | $avArray[$j + 1] = $vTmp 555 | Next 556 | Return 557 | EndIf 558 | Local $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)], $fNum = IsNumber($vPivot) 559 | Do 560 | If $fNum Then 561 | While ($avArray[$L] < $vPivot And IsNumber($avArray[$L])) Or (Not IsNumber($avArray[$L]) And StringCompare($avArray[$L], $vPivot) < 0) 562 | $L += 1 563 | WEnd 564 | While ($avArray[$R] > $vPivot And IsNumber($avArray[$R])) Or (Not IsNumber($avArray[$R]) And StringCompare($avArray[$R], $vPivot) > 0) 565 | $R -= 1 566 | WEnd 567 | Else 568 | While (StringCompare($avArray[$L], $vPivot) < 0) 569 | $L += 1 570 | WEnd 571 | While (StringCompare($avArray[$R], $vPivot) > 0) 572 | $R -= 1 573 | WEnd 574 | EndIf 575 | If $L <= $R Then 576 | $vTmp = $avArray[$L] 577 | $avArray[$L] = $avArray[$R] 578 | $avArray[$R] = $vTmp 579 | $L += 1 580 | $R -= 1 581 | EndIf 582 | Until $L > $R 583 | _RFLTA_QuickSort($avArray, $iStart, $R) 584 | _RFLTA_QuickSort($avArray, $L, $iEnd) 585 | 586 | EndFunc ;==>_RFLTA_QuickSort 587 | 588 | ; #INTERNAL_USE_ONLY#============================================================================================================ 589 | ; Name...........: _RFLTA_ArrayConcatenate 590 | ; Description ...: Joins 2 arrays 591 | ; Syntax ........: _RFLTA_ArrayConcatenate(ByRef $avArrayTarget, Const ByRef $avArraySource) 592 | ; Parameters ....: $avArrayTarget - Base array 593 | ; $avArraySource - Array to add from element 1 onwards 594 | ; Return values .: None - array modified ByRef 595 | ; Author ........: Ultima 596 | ; Modified.......: Melba23 597 | ; Remarks .......: This function is used internally by _RecFileListToArray 598 | ; =============================================================================================================================== 599 | Func _RFLTA_ArrayConcatenate(ByRef $avArrayTarget, Const ByRef $avArraySource) 600 | 601 | Local $iUBoundTarget = UBound($avArrayTarget) - 1, $iUBoundSource = UBound($avArraySource) 602 | ReDim $avArrayTarget[$iUBoundTarget + $iUBoundSource] 603 | For $i = 1 To $iUBoundSource - 1 604 | $avArrayTarget[$iUBoundTarget + $i] = $avArraySource[$i] 605 | Next 606 | 607 | EndFunc ;==>_RFLTA_ArrayConcatenate -------------------------------------------------------------------------------- /changelog.txt: -------------------------------------------------------------------------------- 1 | 2 | v1.0.0.1 3 | Added option to specify Flags param to fill in FILE_FULL_EA_INFORMATION struct in EaInject. 4 | Removed the appended "1" on the name for single file/entry injection. 5 | Fixed bug in EaQuery that caused all extracted data to have a null byte prepended. 6 | Fixed errors in syntax help of both programs. 7 | 8 | v1.0.0.0 9 | Initial version. -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | These tools are made to handle extended attributes on NTFS. 2 | 3 | What is extended attribute? 4 | It is an attribute called $EA, and it is thought to be there for compatibility with OS/2. It is constructed as a pair of name/value, where name is restricted as normal filenames on Windows, and the value part is anything binary. It can reside in both files and directories. It is restricted in size to 0xFFFF bytes per file/directory. There can be any number of pairs per object, but restricted by the total bytes of the attribute. The presence of $EA only has 1 effect worth noting. Apparently $EA and $REPARSE_POINT don't work together, so a file/directory can supposedly only have one or the other. This behavior has not been verified. Also it may worth noting that Windows does not contain any api that can be used to removed extended attributes. That means if we want to remove $EA from a file, we can: 5 | * Delete the file altogether. 6 | * Move the file to a non-NTFS volume and back again. 7 | * Archive the file to a zip (for instance), delete the original file, and then unpack the zip back to the original location. 8 | * Modify $MFT directly. This may work in certain circumstances. 9 | 10 | Apparently, Symantec (and possibly others too) are struggling with $EA in their backup solutions; http://www.symantec.com/business/support/index?page=content&id=TECH167806 (ref reparse points mentioned above) 11 | 12 | Some malware, like ZeroAccess, has got some attention lately due to data hiding in $EA; http://journeyintoir.blogspot.no/2012/12/extracting-zeroaccess-from-ntfs.html and http://www.symantec.com/connect/blogs/trojanzeroaccessc-hidden-ntfs-ea 13 | 14 | Technical details 15 | ZwCreateFile routine: http://msdn.microsoft.com/en-us/library/windows/hardware/ff566424(v=vs.85).aspx 16 | ZwSetEaFile routine: http://msdn.microsoft.com/en-us/library/windows/hardware/ff961908(v=vs.85).aspx 17 | ZwQueryEaFile routine: http://msdn.microsoft.com/en-us/library/windows/hardware/ff625894(v=vs.85).aspx 18 | FILE_FULL_EA_INFORMATION structure: http://msdn.microsoft.com/en-us/library/windows/hardware/ff545793(v=vs.85).aspx 19 | ZwQueryInformationFile routine: http://msdn.microsoft.com/en-us/library/windows/hardware/ff567052(v=vs.85).aspx 20 | FILE_EA_INFORMATION structure: http://msdn.microsoft.com/en-us/library/windows/hardware/ff545773(v=vs.85).aspx 21 | 22 | As source code reveils, there are 2 ways of writing $EA: 23 | 1. NtCreateFile and simpel as that. 24 | 2. NtOpenFile and subsequent NtSetEaFile 25 | 26 | The FILE_FULL_EA_INFORMATION structure holds the relevant data. 27 | 28 | The Flag member of FILE_FULL_EA_INFORMATION structure is configurable and can be zero or set with FILE_NEED_EA (0x80). 29 | 30 | 31 | Usage examples EaInject: 32 | 33 | Hiding a small file (10 kB) inside an existing file, and naming the EA "TEST", and no FILE_NEED_EA flag set: 34 | EaInject.exe /Payload:C:\program.exe /Container:C:\tmp\file.txt /Mode:0 /Identifier:TEST 35 | 36 | Hiding a bigger file above 65 kB and spreading the output across existing files inside the directory "C:\temp", naming the EA "something", searching in non-recursive mode, and setting FILE_NEED_EA flag: 37 | EaInject.exe /Payload:C:\bigfile.bin /Container:C:\temp /Mode:1 /Identifier:something /EaFlag:1 /Filter:* /Recurse:0 38 | 39 | Hiding a bigger file above 65 kB and spreading the out across existing txt files in the directory "C:\temp", naming the EA "testname", and searching in recursive mode, and setting FILE_NEED_EA flag: 40 | EaInject.exe /Payload:C:\bigfile.bin /Container:C:\temp /Mode:1 /Identifier:testname /EaFlag:1 /Filter:*.txt /Recurse:1 41 | 42 | Hiding a bigger file above 65 kB and spreading the output into newly created files with random md5 names in the output directory C:\tmp, giving the EA name of "joke, and no FILE_NEED_EA flag set" 43 | EaInject.exe /Payload:C:\bigfile.bin /Container:C:\tmp /Mode:2 /Identifier:joke 44 | 45 | 46 | Usage examples EaQuery: 47 | 48 | Scanning the current directory for $EA of any name in non-recursive mode in files by any extension, and verbose output on: 49 | EaQuery.exe /Target:"%CD%" /Mode:0 /Verbose:1 /Identifier:* /Filter:* /Recurse:0 50 | 51 | Scanning the directory "C:\Program Files" recursively for files by extension .exe and .dll, searching any EA name and displaying result to console in super verbose mode: 52 | EaQuery.exe /Target:"C:\Program Files" /Mode:0 /Verbose:2 /Identifier:* /Filter:*.exe;*.dll /Recurse:1 53 | 54 | Scanning the directory C:\WINDOWS\System32 recursively any file extension, extracting EA's detected to current directory, show no verbose output, and filter EA by name "something": 55 | EaQuery.exe /Target:C:\WINDOWS\System32 /Mode:1 /Verbose:0 /Identifier:something /Filter:* /Recurse:1 56 | 57 | Scan 1 file, C:\testfile.txt, extract any found EA and display super verbose output, including the EA data content in console: 58 | EaQuery.exe /Target:C:\testfile.txt /Mode:2 /Verbose:2 /Identifier:* /Filter:* /Recurse:0 59 | --------------------------------------------------------------------------------