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.