Explorando a HSTRING

2023-08-21 computer reversing_tag blog blogging

Estava me enveredando hoje nos bytes usados para montar e demonstar os argumentos de uma interface COM proxy da WinRT quando quis saber qual era o leiaute da nova string do Windows, a HSTRING, usada na WinRT e em todo o ecossistema dos Universal apps.

Bom, para quem sabe assembly básico, não há nada prático que fazer uma sessão simples de debugging chamando as funções da API. Inspirado na primeira sessão do livro reversing, fiz as chamadas básicas para obter o tamanho da string, o raw buffer, etc, e fui adentrando no disassembly de cada uma, obtendo as linhas-chave para montar a struct que representa uma HSTRING. Abaixo o código-fonte:

#include <winstring.h>
#include <string>

using namespace std;

int main()
{
    wstring str = L"my hstring";
    HSTRING hstr = NULL;
    HRESULT hr = WindowsCreateString(str.c_str(), (UINT32) str.size(), &hstr);

    if( SUCCEEDED( hr ) )
    {
        UINT32 hstrLen = WindowsGetStringLen(hstr);
        hstrLen = 0;
        PCWSTR rawHstr = WindowsGetStringRawBuffer(hstr, &hstrLen);
        BOOL isEmpty = WindowsIsStringEmpty(hstr);
        HSTRING hstr2 = NULL;
        hr = WindowsDuplicateString(hstr, &hstr2);
        if( SUCCEEDED(hr) )
        {
            hr = WindowsDeleteString(hstr2);
        }
        hr = WindowsDeleteString(hstr);
    }

    HSTRING_HEADER hstrHeader = {};
    HSTRING hstr3 = NULL;
    hr = WindowsCreateStringReference(str.c_str(), (UINT32) str.size(), &hstrHeader, &hstr3);

    if( SUCCEEDED( hr ) )
    {
        hr = WindowsDeleteString(hstr3);
    }

    return hr;
}

Com isso fui fazendo as calls e encontrando os offsets pelas instruções referentes ao rcx, primeiro parâmetro passado em x64:

UINT32 hstrLen = WindowsGetStringLen(hstr);
00007FFC84D8BBE7  mov         eax,dword ptr [rcx+4]

PCWSTR rawHstr = WindowsGetStringRawBuffer(hstr, &hstrLen);
00007FFC84D22345  mov         rax,qword ptr [rcx+10h]

BOOL isEmpty = WindowsIsStringEmpty(hstr);
00007FFC84D23019  mov         edx,dword ptr [rcx+4]
00007FFC84D2301C  test        edx,edx
00007FFC84D2301E  sete        al

hr = WindowsDuplicateString(hstr, &hstr2);
00007FFC84D1789A  lock inc    dword ptr [rcx+18h]

hr = WindowsDeleteString(hstr2);
00007FFC84D176A8  lock xadd   dword ptr [rcx+18h],eax

hr = WindowsCreateStringReference(...
layout:
0x0000009C0230F848  00000001

E eis o resultado que cheguei:

struct HSTRING {
  BOOL Reference;     // +0x00
  UINT32 Length;      // +0x04
  UINT64 Unused2;
  PCWSTR RawString;   // +0x10
  UINT32 RefCounter;  // +0x18
};

Para mais detalhes do uso dessa string dê uma olhada no ótimo artigo de Raymond Chen.

[comment] [TRAFFIC]