Alternate Data Stream Gibberish Topic is solved
Re: Alternate Data Stream Gibberish
I have updated the code above, try again.
Re: Alternate Data Stream Gibberish
No, same error again. Propvariant seems difficult.
---------------------------
proptest.ahk
---------------------------
Error: Memory limit reached (see #MaxMem in the help file).
Line#
040: NumPut(1, &PROPSPEC, "UInt")
041: NumPut(propid, &PROPSPEC+A_PtrSize, "UInt")
043: VarSetCapacity(PROPVARIANT, A_PtrSize == 4 ? 16 : 24)
046: DllCall(NumGet(NumGet(IPropertyStorage+0)+3*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UPtr", &PROPSPEC, "UPtr", &PROPVARIANT, "UInt")
047: if (NumGet(&PROPVARIANT+0, "UShort") == 31)
048: List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), "UTF-16") . "
--------------------
"
049: Else
---> 050: List .= "PROPVARIANT.vt=" . NumGet(&PROPVARIANT+0, "UShort") . "
--------------------
"
051: DllCall("Ole32.dll\PropVariantClear", "UPtr", &PROPVARIANT)
052: }
054: MsgBox,Str . "
" . List
055: }
056: Exit
057: Exit
057: Exit
The current thread will exit.
---------------------------
OK
---------------------------
Re: Alternate Data Stream Gibberish
Replace List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), "UTF-16") . "`n--------------------`n" with List .= StrLen(StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), "UTF-16")) . "`n--------------------`n". test with AHKU32. Tell me what you see in the messages.
Edit: try #MaxMem 500. Although I do not think this is a good idea.
Edit2: Replace List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), "UTF-16") . "`n--------------------`n" with List .= SubStr(StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), "UTF-16"), 1, 100) . "`n--------------------`n" or List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), 100, "UTF-16") . "`n--------------------`n"
Edit: try #MaxMem 500. Although I do not think this is a good idea.
Edit2: Replace List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), "UTF-16") . "`n--------------------`n" with List .= SubStr(StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), "UTF-16"), 1, 100) . "`n--------------------`n" or List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), 100, "UTF-16") . "`n--------------------`n"
PROPVARIANT is not difficult to understand, in fact, my only problem is to try to understand the correct steps to follow to recover the OLE Streams.zcooler wrote:Propvariant seems difficult
Re: Alternate Data Stream Gibberish
It's a no go. Same Memory limit reached message. Testing with #MaxMem 500 the errormsg doesnt show up but stalls the script and it's infinity waiting for the msgbox. Does this work for u? I do use aHK_H U32 and have kept thos english inclied doublequotes, which I see you removed in the testfile.
Re: Alternate Data Stream Gibberish
Find and select the .ts file in the dialog.
Code: Select all
fileselectfile File
VarSetCapacity(GUID, 16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{0000013A-0000-0000-C000-000000000046}", "UPtr", &GUID)
IPropertySetStorage := 0
DllCall("Ole32.dll\StgOpenStorageEx", "UPtr", &File, "UInt", 0x10, "Int", 4, "UInt", 0, "UPtr", 0, "UPtr", 0, "UPtr", &GUID, "UPtrP", IPropertySetStorage, "UInt")
IEnumSTATPROPSETSTG := 0
DllCall(NumGet(NumGet(IPropertySetStorage+0)+6*A_PtrSize), "UPtr", IPropertySetStorage, "UPtrP", IEnumSTATPROPSETSTG, "UInt")
Buffer := 0
VarSetCapacity(STATPROPSETSTG, 64)
Fetched := 0
While !DllCall(NumGet(NumGet(IEnumSTATPROPSETSTG+0)+3*A_PtrSize), "UPtr", IEnumSTATPROPSETSTG, "UInt", 1, "UPtr", &STATPROPSETSTG, "UIntP", Fetched, "UInt") ;enum
{
; Predefined Property Set Format Identifiers : https://msdn.microsoft.com/en-us/library/windows/desktop/aa380060(v=vs.85).aspx
; FMTID_SummaryInformation = {F29F85E0-4FF9-1068-AB91-08002B27B3D9}
; FMTID_DocSummaryInformation = {D5CDD502-2E9C-101B-9397-08002B2CF9AE}
; FMTID_UserDefinedProperties = {D5CDD505-2E9C-101B-9397-08002B2CF9AE}
DllCall("Ole32.dll\StringFromCLSID", "UPtr", &STATPROPSETSTG, "UPtrP", Buffer)
Str := StrGet(Buffer, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", Buffer) ; stream name
IPropertyStorage := 0
DllCall(NumGet(NumGet(IPropertySetStorage+0)+4*A_PtrSize), "UPtr", IPropertySetStorage, "UPtr", &STATPROPSETSTG, "UInt", 0x10, "UPtrP", IPropertyStorage, "UInt")
IEnumSTATPROPSTG := 0
; IPropertyStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379973(v=vs.85).aspx
DllCall(NumGet(NumGet(IPropertyStorage+0)+11*A_PtrSize), "UPtr", IPropertyStorage, "UPtrP", IEnumSTATPROPSTG, "UInt")
List := ""
VarSetCapacity(STATPROPSTG, A_PtrSize + 4 + 4)
While !DllCall(NumGet(NumGet(IEnumSTATPROPSTG+0)+3*A_PtrSize), "UPtr", IEnumSTATPROPSTG, "UInt", 1, "UPtr", &STATPROPSTG, "UIntP", Fetched, "UInt") ;enum
{
propid := NumGet(&STATPROPSTG + A_PtrSize, "UInt")
VarSetCapacity(PROPSPEC, 2*A_PtrSize)
NumPut(1, &PROPSPEC, "UInt")
NumPut(propid, &PROPSPEC+A_PtrSize, "UInt")
VarSetCapacity(PROPVARIANT, A_PtrSize == 4 ? 16 : 24)
; IPropertyStorage::ReadMultiple method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379975(v=vs.85).aspx
DllCall(NumGet(NumGet(IPropertyStorage+0)+3*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UPtr", &PROPSPEC, "UPtr", &PROPVARIANT, "UInt")
If (NumGet(&PROPVARIANT+0, "UShort") == 31) ; VT_LPWSTR
List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), 1000, "UTF-16") . "`n--------------------`n"
Else
List .= "PROPVARIANT.vt=" . NumGet(&PROPVARIANT+0, "UShort") . "`n--------------------`n"
DllCall("Ole32.dll\PropVariantClear", "UPtr", &PROPVARIANT)
}
MsgBox % Str . "`n`n" . List
}
;ObjRelease * ...
Re: Alternate Data Stream Gibberish
Oh my, it was my mistake all along Had to use UTF-8-BOM encoding and then it works
Re: Alternate Data Stream Gibberish
Flipeador..nicely done
I wonder if it might be possible to convert the GUIDs to display the actual stream names?
I mean these names:
Stream : DocumentSummaryInformation
Stream : SebiesnrMkudrfcoIaamtykdDa
Stream : SummaryInformation
I wonder if it might be possible to convert the GUIDs to display the actual stream names?
I mean these names:
Stream : DocumentSummaryInformation
Stream : SebiesnrMkudrfcoIaamtykdDa
Stream : SummaryInformation
Last edited by zcooler on 24 Jun 2018, 12:08, edited 1 time in total.
Re: Alternate Data Stream Gibberish
I always recommend using UTF-8 with BOM.Had to use UTF-8-BOM encoding and then it works
Read Predefined Property Set Format Identifiers. That's the least of it, just use If.I wonder if it might be possible to convert the GUIDs to display the actual stream names?
Edit: As I said, I'm not sure what this data represents, I think the name of the Stream is the GUIDs.
I will continue investigating, I am not sure what kind of data the PROPVARIANT structure is recovering (if it's about the Stream data or what). Then we'll have to turn all this ugly code into a nice function .
Yes, I know, I have no idea where it get those names, maybe ADS Manager do some conversion and are not the real names, you should try another program. is weird, maybe it's a BOM. Several unknownszcooler wrote:I mean these names:
Stream : DocumentSummaryInformation
Stream : SebiesnrMkudrfcoIaamtykdDa
Stream : SummaryInformation
Re: Alternate Data Stream Gibberish
I just tested my previous function and enumerates the Streams correctly.
Edit: This is very rare, if I try to modify the Stream data with ADS Manager (load data from a file), PROPVARIANT.vt is set to zero (VT_EMPTY). It seems that ADS Manager uses only FindFirstStream (does not use any interface, so it breaks the OLE Streams, and converts it into normal Streams, or maybe what I'm saying does not make any sense).
Code: Select all
fileselectfile file
List := ""
For Each, Stream in EnumStreams(File)
List .= "[" . Stream.Size . "] " . Stream.Name . "`n"
MsgBox % List
EnumStreams(File)
{
Local Streams := []
, WIN32_FIND_STREAM_DATA := ""
VarSetCapacity(WIN32_FIND_STREAM_DATA, 8 + (260 + 36) * 2)
Local Handle := DllCall("Kernel32.dll\FindFirstStreamW", "UPtr", &File, "UInt", 0, "UPtr", &WIN32_FIND_STREAM_DATA, "UInt", 0, "Ptr")
If (!Handle)
Return FALSE
ObjPush(Streams, {Size: NumGet(&WIN32_FIND_STREAM_DATA, "Int64"), Name: RTrim(StrGet(&WIN32_FIND_STREAM_DATA + 8, "UTF-16"), ":$DATA")})
While (DllCall("Kernel32.dll\FindNextStreamW", "Ptr", Handle, "UPtr", &WIN32_FIND_STREAM_DATA, "Ptr"))
ObjPush(Streams, {Size: NumGet(&WIN32_FIND_STREAM_DATA, "Int64"), Name: RTrim(StrGet(&WIN32_FIND_STREAM_DATA + 8, "UTF-16"), ":$DATA")})
Return Streams
} ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa365741(v=vs.85).aspx
Re: Alternate Data Stream Gibberish
Oh wow, that would be amazingFlipeador wrote:I will continue investigating, I am not sure what kind of data the PROPVARIANT structure is recovering (if it's about the Stream data or what). Then we'll have to turn all this ugly code into a nice function .
Heck yes, this is so far above my head...you are impressing thoughFlipeador wrote:Yes, I know, I have no idea where it get those names, maybe ADS Manager do some conversion and are not the real names, you should try another program. is weird, maybe it's a BOM. Several unknownszcooler wrote:I mean these names:
Stream : DocumentSummaryInformation
Stream : SebiesnrMkudrfcoIaamtykdDa
Stream : SummaryInformation
Re: Alternate Data Stream Gibberish
That is correctly observed...it's my experience with aDSmanager as well in text preview. The hex preview works better.Flipeador wrote:Edit: This is very rare, if I try to modify the Stream data with ADS Manager (load data from a file), PROPVARIANT.vt is set to zero (VT_EMPTY). It seems that ADS Manager uses only FindFirstStream (does not use any interface, so it breaks the OLE Streams, and converts it into normal Streams, or maybe what I'm saying does not make any sense).
Re: Alternate Data Stream Gibberish
Does FindFirstStream work for you too?.That is correctly observed...it's my experience with aDSmanager as well in text preview.
That's because it's probably binary data, and not a string. Or who knows what strange things do ADS Manager.The hex preview works better
Re: Alternate Data Stream Gibberish
Hmm..that is strange. Your code doesnt seem to find the content of DocumentSummaryInformation, while the other two SebiesnrMkudrfcoIaamtykdDa and SummaryInformation seem to be no problem.Flipeador wrote:Does FindFirstStream work for you too?.
Re: Alternate Data Stream Gibberish
What do you mean? using FileOpen?, What code are you using.
Re: Alternate Data Stream Gibberish
With this code:
If using your enumeration function these streams are found:
Code: Select all
; put the file path here
File := "F:\Ny mapp\20180116_20-59-02_Discovery Channel_Gold Rush Alaska - S08E03 - “Busted And Bushfixed”.ts"
;File := "F:\Ny mapp\20180102_02-19-01_Sjuan_Clueless - ★★★★★★★☆☆☆.ts"
VarSetCapacity(GUID, 16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{0000013A-0000-0000-C000-000000000046}", "UPtr", &GUID)
IPropertySetStorage := 0
DllCall("Ole32.dll\StgOpenStorageEx", "UPtr", &File, "UInt", 0x10, "Int", 4, "UInt", 0, "UPtr", 0, "UPtr", 0, "UPtr", &GUID, "UPtrP", IPropertySetStorage, "UInt")
IEnumSTATPROPSETSTG := 0
DllCall(NumGet(NumGet(IPropertySetStorage+0)+6*A_PtrSize), "UPtr", IPropertySetStorage, "UPtrP", IEnumSTATPROPSETSTG, "UInt")
Buffer := 0
VarSetCapacity(STATPROPSETSTG, 64)
Fetched := 0
While !DllCall(NumGet(NumGet(IEnumSTATPROPSETSTG+0)+3*A_PtrSize), "UPtr", IEnumSTATPROPSETSTG, "UInt", 1, "UPtr", &STATPROPSETSTG, "UIntP", Fetched, "UInt") ;enum
{
; Predefined Property Set Format Identifiers : https://msdn.microsoft.com/en-us/library/windows/desktop/aa380060(v=vs.85).aspx
; FMTID_SummaryInformation = {F29F85E0-4FF9-1068-AB91-08002B27B3D9}
; FMTID_DocSummaryInformation = {D5CDD502-2E9C-101B-9397-08002B2CF9AE}
; FMTID_UserDefinedProperties = {D5CDD505-2E9C-101B-9397-08002B2CF9AE}
DllCall("Ole32.dll\StringFromCLSID", "UPtr", &STATPROPSETSTG, "UPtrP", Buffer)
Str := StrGet(Buffer, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", Buffer) ; stream name
IPropertyStorage := 0
DllCall(NumGet(NumGet(IPropertySetStorage+0)+4*A_PtrSize), "UPtr", IPropertySetStorage, "UPtr", &STATPROPSETSTG, "UInt", 0x10, "UPtrP", IPropertyStorage, "UInt")
IEnumSTATPROPSTG := 0
; IPropertyStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379973(v=vs.85).aspx
DllCall(NumGet(NumGet(IPropertyStorage+0)+11*A_PtrSize), "UPtr", IPropertyStorage, "UPtrP", IEnumSTATPROPSTG, "UInt")
List := ""
VarSetCapacity(STATPROPSTG, A_PtrSize + 4 + 4)
While !DllCall(NumGet(NumGet(IEnumSTATPROPSTG+0)+3*A_PtrSize), "UPtr", IEnumSTATPROPSTG, "UInt", 1, "UPtr", &STATPROPSTG, "UIntP", Fetched, "UInt") ;enum
{
propid := NumGet(&STATPROPSTG + A_PtrSize, "UInt")
VarSetCapacity(PROPSPEC, 2*A_PtrSize)
NumPut(1, &PROPSPEC, "UInt")
NumPut(propid, &PROPSPEC+A_PtrSize, "UInt")
VarSetCapacity(PROPVARIANT, A_PtrSize == 4 ? 16 : 24)
; IPropertyStorage::ReadMultiple method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379975(v=vs.85).aspx
DllCall(NumGet(NumGet(IPropertyStorage+0)+3*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UPtr", &PROPSPEC, "UPtr", &PROPVARIANT, "UInt")
If (NumGet(&PROPVARIANT+0, "UShort") == 31) ; VT_LPWSTR
List .= StrGet(NumGet(&PROPVARIANT + 8, "UPtr"), 1000, "UTF-16") . "`n--------------------`n"
Else
List .= "PROPVARIANT.vt=" . NumGet(&PROPVARIANT+0, "UShort") . "`n--------------------`n"
DllCall("Ole32.dll\PropVariantClear", "UPtr", &PROPVARIANT)
}
MsgBox % Str . "`n`n" . List
}
;ObjRelease * ...
Spoiler
Re: Alternate Data Stream Gibberish
I have cleaned the code but I do not know why it does not show the content of DocumentSummaryInformation. Also i do not know why it does not retrieve {4c8cc155-6c1e-11d1-8e41-00c04fb9386d}.
If you want to see the code (AHKv2) (do not be intimidated by the amount of code, it's just for greater readability):
I will continue investigating!
Edit: It seems that there is a misunderstanding (or at least on my part). Read: Structured Storage | About Structured Storage | Storages and Streams.
It seems that ADS Manager uses the equivalent to FileOpen of AHK, it is exactly the same. When you use FileOpen the data is not displayed correctly because it is binary data, and not a string. This binary data represents a Storage Object, and can only be read through the IPropertySetStorage interface.
If you want to see the code (AHKv2) (do not be intimidated by the amount of code, it's just for greater readability):
Code: Select all
Filename := FileSelect()
; opens an existing root storage object in the file system
IPropertySetStorage := GetPropSetStorage(Filename)
If (!IPropertySetStorage)
{
MsgBox "IPropertySetStorage ERROR " . Format("0x{:08X}", ErrorLevel)
ExitApp
}
Info := ""
; retrieves the property sets stored in this property set storage
PropertySets := EnumPropSetStorage(IPropertySetStorage)
For Each, STATPROPSETSTG in PropertySets
{
Info .= "STATPROPSETSTG.fmtid " . StringFromCLSID(STATPROPSETSTG.fmtid) . "`n" ; format identifier (FMTID) of the property set
Info .= "STATPROPSETSTG.clsid " . StringFromCLSID(STATPROPSETSTG.clsid) . "`n"
Info .= "STATPROPSETSTG.grfFlags " . STATPROPSETSTG.grfFlags . "`n`n"
; opens a property set contained in the property set storage object
IPropertyStorage := PropSetStorage_Open(IPropertySetStorage, STATPROPSETSTG.fmtid)
If (IPropertyStorage)
{
; get statistical data in the property set
StatisticalData := EnumPropStorage(IPropertyStorage)
If (!ObjLength(StatisticalData))
Info .= "> no statistical data <`n"
For Each, STATPROPSTG in StatisticalData
{
Info .= "STATPROPSTG.lpwstrName " . STATPROPSTG.lpwstrName . "`n"
Info .= "STATPROPSTG.propid " . STATPROPSTG.propid . "`n"
Info .= "STATPROPSTG.vt " . STATPROPSTG.vt . "`n"
; retrieves any existing string name for the specified property ID
Info .= "PropertyName " . PropStorage_ReadPropertyName(IPropertyStorage, STATPROPSTG.propid) . " (" . ErrorLevel . ")`n"
; reads the property value
PROPVARIANT := PropStorage_Read(IPropertyStorage, STATPROPSTG.propid)
If (PROPVARIANT)
{
Info .= "PROPVARIANT.vt " . PROPVARIANT.vt . "`n"
If (PROPVARIANT.vt == 30 || PROPVARIANT.vt == 31) ; VT_LPSTR = 30 | VT_LPWSTR = 31
Info .= "`n" . StrGet(PROPVARIANT.ptr, PROPVARIANT.vt == 30 ? "UTF-8" : "UTF-16") . "`n`n"
Else
Info .= "`n< no string >`n`n"
PropVariantClear(PROPVARIANT)
}
}
ObjRelease(IPropertyStorage)
}
Info .= "`n`n`n----------------------`n`n`n`n"
}
; special-case handling for the UserDefined property set
CLSID := ""
IPropertyStorage := PropSetStorage_Open(IPropertySetStorage, CLSIDFromString("{D5CDD505-2E9C-101B-9397-08002B2CF9AE}", CLSID))
If (IPropertyStorage)
{
Info .= "STATPROPSETSTG.fmtid " . StringFromCLSID(&CLSID) . "`n`n" ; format identifier (FMTID) of the property set
StatisticalData := EnumPropStorage(IPropertyStorage)
If (!ObjLength(StatisticalData))
Info .= "> no statistical data <`n"
For Each, STATPROPSTG in StatisticalData
{
Info .= "STATPROPSTG.lpwstrName " . STATPROPSTG.lpwstrName . "`n"
Info .= "STATPROPSTG.propid " . STATPROPSTG.propid . "`n"
Info .= "STATPROPSTG.vt " . STATPROPSTG.vt . "`n"
Info .= "PropertyName " . PropStorage_ReadPropertyName(IPropertyStorage, STATPROPSTG.propid) . " (" . ErrorLevel . ")`n"
PROPVARIANT := PropStorage_Read(IPropertyStorage, STATPROPSTG.propid)
If (PROPVARIANT)
{
Info .= "PROPVARIANT.vt " . PROPVARIANT.vt . "`n"
If (PROPVARIANT.vt == 30 || PROPVARIANT.vt == 31) ; VT_LPSTR = 30 | VT_LPWSTR = 31
Info .= "`n" . StrGet(PROPVARIANT.ptr, PROPVARIANT.vt == 30 ? "UTF-8" : "UTF-16") . "`n`n"
Else
Info .= "`n< no string >`n`n"
PropVariantClear(PROPVARIANT)
}
}
ObjRelease(IPropertyStorage)
}
ObjRelease(IPropertySetStorage)
FileOpen(A_Desktop . "\~tmp.txt", "w", "UTF-16").Write(Info)
Run(A_Desktop . "\~tmp.txt")
ExitApp
GetPropSetStorage(Filename, AccessMode := 0x10)
{
Local GUID := "", IPropertySetStorage := 0
VarSetCapacity(GUID, 16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{0000013A-0000-0000-C000-000000000046}", "UPtr", &GUID, "UInt")
; StgOpenStorageEx function
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380342(v=vs.85).aspx
; STGFMT_ANY = 4
ErrorLevel := DllCall("Ole32.dll\StgOpenStorageEx", "UPtr", &Filename, "UInt", AccessMode, "Int", 4, "UInt", 0, "UPtr", 0, "UPtr", 0, "UPtr", &GUID, "UPtrP", IPropertySetStorage, "UInt")
Return IPropertySetStorage
}
EnumPropSetStorage(IPropertySetStorage)
{
; IPropertySetStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379960(v=vs.85).aspx
Local IEnumSTATPROPSETSTG := 0
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertySetStorage)+6*A_PtrSize), "UPtr", IPropertySetStorage, "UPtrP", IEnumSTATPROPSETSTG, "UInt"))
Return FALSE
; STATPROPSETSTG structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380317(v=vs.85).aspx
Local PropertySets := [ {Buffer: ""} ], i := 1, Address := 0
ObjSetCapacity(PropertySets[i], "Buffer", 64) ; sizeof STATPROPSETSTG = 64 | PropertySets.Buffer = struct STATPROPSETSTG
; IEnumSTATPROPSETSTG::Next method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379202(v=vs.85).aspx
While (!DllCall(NumGet(NumGet(IEnumSTATPROPSETSTG)+3*A_PtrSize), "UPtr", IEnumSTATPROPSETSTG, "UInt", 1, "UPtr", Address:=ObjGetAddress(PropertySets[i], "Buffer"), "UPtr", 0, "UInt"))
{
ObjRawSet(PropertySets[i], "fmtid", Address) ; FMTID STATPROPSETSTG.fmtid (FMTID of the current property set when created)
ObjRawSet(PropertySets[i], "clsid", Address+16) ; CLSID STATPROPSETSTG.clsid (CLSID associated with this property set when created or modified)
ObjRawSet(PropertySets[i], "grfFlags", NumGet(Address+32, "UInt")) ; DWORD STATPROPSETSTG.grfFlags (https://msdn.microsoft.com/en-us/library/windows/desktop/aa380069(v=vs.85).aspx)
ObjRawSet(PropertySets[i], "mtime", Address+40) ; FILETIME STATPROPSETSTG.mtime (time in Universal Coordinated Time (UTC) when the property set was last modified)
ObjRawSet(PropertySets[i], "ctime", Address+48) ; FILETIME STATPROPSETSTG.ctime (time in UTC when this property set was created)
ObjRawSet(PropertySets[i], "atime", Address+56) ; FILETIME STATPROPSETSTG.atime (Time in UTC when this property set was last accessed)
ObjSetCapacity(PropertySets[i:=ObjPush(PropertySets, {Buffer: ""})], "Buffer", 64) ; new struct STATPROPSETSTG
}
ObjPop(PropertySets) ; remove the last STATPROPSETSTG structure
ObjRelease(IEnumSTATPROPSETSTG)
Return PropertySets
}
PropSetStorage_Open(IPropertySetStorage, FMTID, AccessMode := 0x10)
{
; IPropertySetStorage::Open method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379965(v=vs.85).aspx
Local IPropertyStorage := 0
ErrorLevel := DllCall(NumGet(NumGet(IPropertySetStorage)+4*A_PtrSize), "UPtr", IPropertySetStorage, "UPtr", FMTID, "UInt", AccessMode, "UPtrP", IPropertyStorage, "UInt")
Return IPropertyStorage
}
EnumPropStorage(IPropertyStorage)
{
; IPropertyStorage::Enum method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379973(v=vs.85).aspx
Local IEnumSTATPROPSTG := 0
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage)+11*A_PtrSize), "UPtr", IPropertyStorage, "UPtrP", IEnumSTATPROPSTG, "UInt"))
Return FALSE
; STATPROPSTG structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380318(v=vs.85).aspx
Local StatisticalData := [ {Buffer: ""} ], i := 1, Address := 0
ObjSetCapacity(StatisticalData[i], "Buffer", A_PtrSize+8) ; sizeof STATPROPSTG = A_PtrSize+8 | StatisticalData.Buffer = struct STATPROPSTG
; IEnumSTATPROPSTG::Next method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379213(v=vs.85).aspx
While (!DllCall(NumGet(NumGet(IEnumSTATPROPSTG)+3*A_PtrSize), "UPtr", IEnumSTATPROPSTG, "UInt", 1, "UPtr", Address:=ObjGetAddress(StatisticalData[i], "Buffer"), "UPtr", 0, "UInt"))
{
If (NumGet(Address))
ObjRawSet(StatisticalData[i], "lpwstrName", StrGet(NumGet(Address), "UTF-16")) ; LPWSTR STATPROPSTG.lpwstrName (optional string name associated with the property)
, DllCall("Ole32.dll\CoTaskMemFree", "UPtr", NumGet(Address)) ; must be freed using CoTaskMemFree
, NumPut(ObjGetAddress(StatisticalData[i], "lpwstrName"), Address) ; update STATPROPSTG.lpwstrName with the new pointer because we released the previous one
ObjRawSet(StatisticalData[i], "propid", NumGet(Address+A_PtrSize, "UInt")) ; PROPID STATPROPSTG.propid (32-bit identifier that uniquely identifies the property)
ObjRawSet(StatisticalData[i], "vt", NumGet(Address+A_PtrSize+4, "UShort")) ; VARTYPE STATPROPSTG.vt (property type)
ObjSetCapacity(StatisticalData[i:=ObjPush(StatisticalData, {Buffer: ""})], "Buffer", A_PtrSize+8) ; new struct STATPROPSTG
}
ObjPop(StatisticalData) ; remove the last STATPROPSTG structure
ObjRelease(IEnumSTATPROPSTG)
Return StatisticalData
}
PropStorage_Read(IPropertyStorage, PropID)
{
; PROPSPEC structure
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa380070(v=vs.85).aspx
Local PROPSPEC := ""
VarSetCapacity(PROPSPEC, 2*A_PtrSize)
NumPut(1, &PROPSPEC, "UInt") ; ULONG PROPSPEC.ulKind
NumPut(PropID, &PROPSPEC + A_PtrSize, "UInt") ; PROPID PROPSPEC.propid
; PROPVARIANT structure
; https://docs.microsoft.com/es-es/windows/desktop/api/propidl/ns-propidl-tagpropvariant
Local PROPVARIANT := {Buffer: ""}
ObjSetCapacity(PROPVARIANT, "Buffer", A_PtrSize == 4 ? 16 : 24)
Local Address := ObjGetAddress(PROPVARIANT, "Buffer")
; IPropertyStorage::ReadMultiple method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379975(v=vs.85).aspx
; S_FALSE = 1 (valid syntax, but no properties were retrieved)
If (ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage)+3*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UPtr", &PROPSPEC, "UPtr", Address, "UInt"))
Return FALSE
ObjRawSet(PROPVARIANT, "vt", NumGet(Address, "UInt"))
ObjRawSet(PROPVARIANT, "ptr", NumGet(Address+8, "UPtr"))
Return PROPVARIANT
}
PropStorage_ReadPropertyName(IPropertyStorage, PropID)
{
; IPropertyStorage::ReadPropertyNames method
; https://msdn.microsoft.com/en-us/library/windows/desktop/aa379976(v=vs.85).aspx
Local Buffer := 0
ErrorLevel := DllCall(NumGet(NumGet(IPropertyStorage)+6*A_PtrSize), "UPtr", IPropertyStorage, "UInt", 1, "UIntP", PropID, "UPtrP", Buffer, "UInt")
Local R := ""
If (!ErrorLevel) ; S_OK
R := StrGet(Buffer, "UTF-16"), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", Buffer)
Return R
}
StringFromCLSID(Address)
{
; StringFromGUID2 function
; https://msdn.microsoft.com/en-us/library/windows/desktop/ms683893(v=vs.85).aspx
Local Buffer := ""
VarSetCapacity(Buffer, (38 + 1) * 2)
DllCall("Ole32.dll\StringFromGUID2", "UPtr", Address, "Str", Buffer, "Int", 38 + 1)
Return Buffer
}
CLSIDFromString(String, ByRef CLSID)
{
; CLSIDFromString function
; https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-clsidfromstring
VarSetCapacity(CLSID, 16)
Return DllCall("Ole32.dll\CLSIDFromString", "Str", String, "UPtr", &CLSID, "UInt") ? 0 : &CLSID
}
PropVariantClear(Address)
{
Return DllCall("Ole32.dll\PropVariantClear", "UPtr", IsObject(Address) ? ObjGetAddress(Address, "Buffer") : Address)
}
Edit: It seems that there is a misunderstanding (or at least on my part). Read: Structured Storage | About Structured Storage | Storages and Streams.
It seems that ADS Manager uses the equivalent to FileOpen of AHK, it is exactly the same. When you use FileOpen the data is not displayed correctly because it is binary data, and not a string. This binary data represents a Storage Object, and can only be read through the IPropertySetStorage interface.
Re: Alternate Data Stream Gibberish
The correct way to do this is to retrieve the binary data from the Stream using FileOpen, and then call StgOpenStorageOnILockBytes to retrieve the IPropertySetStorage interface to read the data correctly.
- For a file, ::$DATA is always the default Stream type (however, there does not seem to be another type)
- To list all Streams in a file we must call FindFirstStreamW.
- To read or write to a Stream we must use FileOpen.
- To delete a Stream we must use FileDelete.
- So... what is IPropertySetStorage for?. It is just an interface to organize the streams data in a better way, as if it were a directory/folder. You must use this interface to correctly interpret the binary data in the stream.
- In a Stream whose content is a Stream Object, its name must start with the U+2663 character. Read: Document Properties Stream Name.
- If the file contains Streams Objects, you must add a Stream with the name {4c8cc155-6c1e-11d1-8e41-00c04fb9386d}. Read: Control Stream.
Re: Alternate Data Stream Gibberish
It might not retrieve it cuz it seem to be a control stream and no iproperty stream.Flipeador wrote:Also i do not know why it does not retrieve {4c8cc155-6c1e-11d1-8e41-00c04fb9386d}.
Re: Alternate Data Stream Gibberish
Yes but no.zcooler wrote:It might not retrieve it cuz it seem to be a control stream and no iproperty stream.
This Stream complies with the name, but not with the content, since it is zero bytes sized, and this is not correct. We could say that it is an "incomplete" or "erroneous" Control Stream.2.24.3 Control Stream wrote:A file that has one or more property sets associated with it through the alternate stream binding MUST have a control stream, which is an alternate stream with the name "{4c8cc155-6c1e-11d1-8e41-00c04fb9386d}". This stream MUST contain the following packet. [...]
https://msdn.microsoft.com/en-us/library/dd942541.aspx
Edit: Although maybe if it is valid if all the data is zero.
A Control Stream is just a Stream with the name {4c8cc155-6c1e-11d1-8e41-00c04fb9386d} and whose content is the following: Reserved1 (2 bytes) + Reserved2 (2 bytes) + ApplicationState (4 bytes) + CLSID (16 bytes).
In a hexadecimal viewer, each pair of numbers represents a byte, so we would have something like this:
Example of how to create a Control Stream in AHK:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Code: Select all
FileOpen(A_Desktop . "\~tmp.txt", "w", "UTF-8-RAW").Write("I have a Control Stream inside of me")
cs := FileOpen(A_Desktop . "\~tmp.txt:{4c8cc155-6c1e-11d1-8e41-00c04fb9386d}", "w")
cs.Length := 2 + 2 + 4 + 16
cs.Seek(0)
; Reserved1 (2 bytes): MUST be set to zero, and nonzero values MUST be rejected.
cs.WriteUShort(0x0000)
; Reserved2 (2 bytes): MUST be set to zero, and MUST be ignored.
cs.WriteUShort(0x0000)
; ApplicationState (4 bytes): An application-provided value that MUST NOT be interpreted by the OLEPS implementation. If the application did not provide a value, it SHOULD be set to zero.
cs.WriteUInt(0x00000000)
; CLSID (16 bytes): An application-provided value that MUST NOT be interpreted by the OLEPS implementation. If the application did not provide a value, it SHOULD be absent.
CLSID := ""
VarSetCapacity(CLSID, 16)
DllCall("Ole32.dll\CLSIDFromString", "Str", "{00000000-0000-0000-0000-000000000000}", "UPtr", &CLSID, "UInt")
cs.RawWrite(&CLSID+0, 16)
cs.Close()
ExitApp
Data Type Ranges: https://msdn.microsoft.com/en-us/library/s3f49ktz.aspx.
A CLSID/GUID is defined as:
Edit2: 5.6.3 Document Properties Stream Name. That strange character at the beginning of the Streams names is for distinguish "IProperty Streams" from other Streams (note that we always refer to the content of the Stream and not the Stream itself).C:\Program Files (x86)\Windows Kits\10\Include\10.0.16299.0\shared\guiddef.h wrote:typedef struct _GUID {
⠀⠀unsigned long Data1;⠀⠀⠀⠀⠀⠀// 4 bytes | 4⠀| 00000000
⠀⠀unsigned short Data2;⠀⠀⠀⠀ ⠀// 2 bytes | 6⠀| 0000
⠀⠀unsigned short Data3;⠀⠀⠀⠀ ⠀// 2 bytes | 8⠀| 0000
⠀⠀unsigned char Data4[ 8 ];⠀⠀⠀// 8 bytes | 16 | 0000-000000000000
} GUID;
Re: Alternate Data Stream Gibberish
See this example (AHKv2):
Code: Select all
Global Gui, Tab, Txt, Hex, Btn, LV, File
Gui := GuiCreate("-DPIScale", "Alternate Streams Viewer")
Gui.SetFont("s10", "Segoe UI")
Tab := Gui.AddTab3("x0 y0 w512 h310", "String view|Hexadecimal view")
Tab.UseTab(1)
Txt := Gui.AddEdit("x5 y30 w500 h272 +ReadOnly -Wrap")
Tab.UseTab(2)
Hex := Gui.AddEdit("x5 y30 w500 h272 +ReadOnly -Wrap")
Hex.SetFont("s9", "Monospac821 BT")
Tab.UseTab()
LV := Gui.AddListView("x0 y310 w510 h200 -Multi", "Name|Size|Stream Object")
LV.OnEvent("ItemSelect", "LVEvent")
Btn := Gui.AddButton("x0 y510 w510 h25", "Select file")
Btn.OnEvent("Click", "SelectFile")
Gui.Show("w510 h535")
Gui.OnEvent("Close", () => ExitApp())
Return
LVEvent(GuiCtrlObj, Item, Selected)
{
Txt.Text := "", Hex.Text := ""
Sleep(50)
Local Stream := LV.GetText(Item)
, f := FileOpen(File . (Stream == "<unnamed>" ? "" : ":" . Stream), "r")
If (!f)
{
MsgBox "The file couldn't be opened"
Return
}
Txt.Text := f.Read(10000)
f.Seek(0)
Local HexTxt := "0001 ", Arr := [], i := 0
While (!f.AtEOF)
{
HexTxt .= Format("{:02X} ", Arr[ObjPush(Arr, f.ReadUChar())])
If (!Mod(i:=A_Index, 16))
{
HexTxt .= " "
For k, v in Arr
HexTxt .= !v || v == 10 || v == 13 ? "." : Chr(v)
HexTxt .= "`r`n" . Format("{:04X} ", A_Index//16+1)
Arr := []
}
If (A_Index//16 > 10000)
{
HexTxt .= "`r`n ..."
Break
}
}
If (i:=Mod(i, 16))
{
HexTxt .= " "
Loop 16-i
HexTxt .= " "
For k, v in Arr
HexTxt .= !v || v == 10 || v == 13 ? "." : Chr(v)
}
Hex.Text := HexTxt
}
SelectFile()
{
File := FileSelect(3)
If (ErrorLevel)
Return
Txt.Text := "", Hex.Text := ""
LV.Delete()
Local Each := "", Stream := ""
For Each, Stream in EnumStreams(File)
LV.Add(, Stream.Name == "" ? "<unnamed>" : Stream.Name, StrFormatByteSize(Stream.Size), Stream.Name ~= "^\x5" ? "TRUE" : "FALSE")
LV.ModifyCol(1, "AutoHdr")
LV.ModifyCol(2, "AutoHdr")
}
EnumStreams(File)
{
Local Streams := []
, WIN32_FIND_STREAM_DATA := ""
VarSetCapacity(WIN32_FIND_STREAM_DATA, 8 + (260 + 36) * 2)
Local Handle := DllCall("Kernel32.dll\FindFirstStreamW", "UPtr", &File, "UInt", 0, "UPtr", &WIN32_FIND_STREAM_DATA, "UInt", 0, "Ptr")
If (!Handle)
Return FALSE
ObjPush(Streams, {Size: NumGet(&WIN32_FIND_STREAM_DATA, "Int64"), Name: SubStr(StrGet(&WIN32_FIND_STREAM_DATA + 8, "UTF-16"), 2, -6)})
While (DllCall("Kernel32.dll\FindNextStreamW", "Ptr", Handle, "UPtr", &WIN32_FIND_STREAM_DATA, "Ptr"))
ObjPush(Streams, {Size: NumGet(&WIN32_FIND_STREAM_DATA, "Int64"), Name: SubStr(StrGet(&WIN32_FIND_STREAM_DATA + 8, "UTF-16"), 2, -6)})
Return Streams
} ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa365741(v=vs.85).aspx
StrFormatByteSize(Number, Flags := 1)
{
Local Buffer := ""
VarSetCapacity(Buffer, 30 * 2, 0)
Local R := DllCall("Shlwapi.dll\StrFormatByteSizeEx", "Int64", Number, "UInt", Flags, "UPtr", &Buffer, "UInt", 30)
Return R == 0 ? StrGet(&Buffer, "UTF-16") : ""
} ;https://msdn.microsoft.com/en-us/library/windows/desktop/bb892884(v=vs.85).aspx
Who is online
Users browsing this forum: Google [Bot] and 344 guests