1

When you store a file in OneDrive, an :ms-properties alternate data stream is added. I opened an example stream using FlexHex (as shown in the image), but I can't tell what type of structure those bytes might represent. Does anyone know?

enter image description here

Actually, based on the 1SPS sequence, I think it might be a prop store or a shell bag or something. For reference. And this. But I'm not sure if that's right.

2 Answers2

0

1SPS is the signature for a serialized property store, which is essentially a key value pair type system. its a standard structure, so its easy to parse, although the data types can make it a bit of a challenge.

It looks like there are some GUIDs in there among the 4 or so. it would be easy enough to parse out those structures as similar things are used in shellbags. it certainly just looks like a series of 1sps blocks which makes it easy.

you already know my email, so if you can extract out a few of these ADS examples, zip them, and send, i can take a closer look. if its warranted, ill even write a new forensic tool to parse them

Eric
  • 74
  • 4
0

They are just serialized Windows properties. You can write and read these files (as streams) using builtin Windows implementation of IPropertyStore, for example using the PSCreateMemoryPropertyStore function

Here is a small sample console app that creates a test.props file with one property of string type:

#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <propsys.h>
#include <propkey.h>
#include <propvarutil.h>

// some COM error handling useful macros
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define SBTRACE wprintf
#define CHECKHR(expr) {hr=(expr);if(FAILED(hr)){ SBTRACE(L"HR FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define HR HRESULT hr=S_OK;

int main()
{
  HR;
  PROPVARIANT pv;
  PropVariantInit(&pv);
  CoInitialize(NULL);
  {
    CComPtr<IPropertyStore> ps;
    CComPtr<IPersistStream> pstream;
    CComPtr<IStream> stream;

    // create the in-memory store
    CHECKHR(PSCreateMemoryPropertyStore(IID_PPV_ARGS(&ps)));

    // define some PROPVARIANT value (here it's a string)
    CHECKHR(InitPropVariantFromString(L"hello world", &pv));

    // any property key would work
    CHECKHR(ps->SetValue(PKEY_ItemNameDisplay, pv));

    // get IPersistStream to be able to load or write
    CHECKHR(ps->QueryInterface(&pstream));

    // create a file stream
    CHECKHR(SHCreateStreamOnFileEx(L"test.props", STGM_WRITE | STGM_CREATE, 0, TRUE, nullptr, &stream));

    // this sample only saves, but you can load from an existing stream
    CHECKHR(pstream->Save(stream, TRUE));
  }

cleanup:
  PropVariantClear(&pv);
  CoUninitialize();
  return 0;
}

Here is the result:

enter image description here

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • Thanks a lot. Can I also ask which interfaces/methods you use to deserialize? I had been using IPersistSerializedPropStorage, but your methods look easier. –  Mar 17 '20 at 18:10
  • @loop123123 - IPersistStream::Save to save, IPersistStream::Load to load – Simon Mourier Mar 17 '20 at 18:11