News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Buffer alignment

Started by sinsi, December 18, 2024, 03:16:28 PM

Previous topic - Next topic

NoCforMe

Quote from: TimoVJL on March 31, 2025, 08:01:34 PMa that buffer store linked lists, so it isn't BYTE nor WCHAR buffer.
Care to state that in English?
32-bit code and Windows 7 foreva!

TimoVJL

that API function parameter is variable size struct FILE_NOTIFY_INFORMATION or several of them.
struct native align is DWORD (4)
simple, isn't it ?
May the source be with you

guga

#17
This function, is just a call to ReadDirectoryChangesExW (kernelbase.dll) whose last parameter is settled as 1 (always), where 1 = ReadDirectoryNotifyInformation  from _READ_DIRECTORY_NOTIFY_INFORMATION_CLASS . here

In windows 10, the function when used for 32 bits app is created like this:
BOOL __stdcall ReadDirectoryChangesW(
        HANDLE hDirectory,
        LPVOID lpBuffer,
        DWORD nBufferLength,
        BOOL bWatchSubtree,
        DWORD dwNotifyFilter,
        LPDWORD lpBytesReturned,
        LPOVERLAPPED lpOverlapped,
        LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
  return ReadDirectoryChangesExW(
           hDirectory,
           (int)lpBuffer,
           nBufferLength,
           bWatchSubtree,
           dwNotifyFilter,
           (int)lpBytesReturned,
           (int)lpOverlapped,
           (int)lpCompletionRoutine,
           1);
}

Since the function calls to ReadDirectoryChangesExW that uses (as an alternative) the structure  FILE_NOTIFY_EXTENDED_INFORMATION (which is bigger than FILE_NOTIFY_INFORMATION), the better would be fill the buffer with an array of the same size as  FILE_NOTIFY_EXTENDED_INFORMATION. On this way it will hold enough data to store the array of FILE_NOTIFY_INFORMATION structure and probably won´t need to align.

So, the buffer may consists of a pointer to FILE_NOTIFY_EXTENDED_INFORMATION

typedef struct _FILE_NOTIFY_EXTENDED_INFORMATION {
  DWORD         NextEntryOffset;
  DWORD         Action;
  LARGE_INTEGER CreationTime;
  LARGE_INTEGER LastModificationTime;
  LARGE_INTEGER LastChangeTime;
  LARGE_INTEGER LastAccessTime;
  LARGE_INTEGER AllocatedLength;
  LARGE_INTEGER FileSize;
  DWORD         FileAttributes;
  union {
    DWORD ReparsePointTag;
    DWORD EaSize;
  } DUMMYUNIONNAME;
  LARGE_INTEGER FileId;
  LARGE_INTEGER ParentFileId;
  DWORD         FileNameLength;
  WCHAR         FileName[1];
} FILE_NOTIFY_EXTENDED_INFORMATION, *PFILE_NOTIFY_EXTENDED_INFORMATION;

typedef struct _FILE_NOTIFY_INFORMATION {
  DWORD NextEntryOffset;
  DWORD Action;
  DWORD FileNameLength;
  WCHAR FileName[1];
} FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;


On curiosity, the api also uses NtNotifyChangeDirectoryFileEx ZwNotifyChangeDirectoryFileEx. It doesn´t seems to be a huge function, so perhaps it can be rewritten completelly.

If anyone is interested in doing this, here are the C code (untested) that can be used to rebuild it later

BOOL __stdcall ReadDirectoryChangesW(
        HANDLE hDirectory,
        LPVOID lpBuffer,
        DWORD nBufferLength,
        BOOL bWatchSubtree,
        DWORD dwNotifyFilter,
        LPDWORD lpBytesReturned,
        LPOVERLAPPED lpOverlapped,
        LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
  return ReadDirectoryChangesExW(
           hDirectory,
           (int)lpBuffer,
           nBufferLength,
           bWatchSubtree,
           dwNotifyFilter,
           lpBytesReturned,
           lpOverlapped,
           lpCompletionRoutine,
           1);
}

int __stdcall ReadDirectoryChangesExW(
        HANDLE hDirectory,
        int lpBuffer,
        int nBufferLength,
        int bWatchSubtree,
        int dwNotifyFilter,
        _DWORD *lpBytesReturned,
        _DWORD *lpOverlapped,
        _DWORD *lpCompletionRoutine,
        int ReadDirectoryNotifyInformationClass)
{
  int v9; // ebx
  PVOID v10; // edi
  int v12; // eax
  _DWORD *v13; // ecx
  _DWORD *v14; // esi
  NTSTATUS v15; // eax
  int (__stdcall *v16)(int, int, int); // edx
  NTSTATUS v17; // esi
  int v18; // eax
  int v19; // [esp-4h] [ebp-24h]
  _DWORD v20[2]; // [esp+Ch] [ebp-14h] BYREF
  int v21; // [esp+14h] [ebp-Ch]
  int v22; // [esp+18h] [ebp-8h]
  PVOID P; // [esp+1Ch] [ebp-4h] BYREF

  v9 = 1;
  v10 = 0;
  P = 0;
  if ( ReadDirectoryNotifyInformationClass == 1 )
  {
    v12 = 1;
    v22 = 1;
  }
  else
  {
    if ( ReadDirectoryNotifyInformationClass != 2 )
    {
      RtlSetLastWin32Error(0x57u);
      return 0;
    }
    v12 = 2;
    v22 = 2;
  }
  v13 = lpOverlapped;
  if ( !lpOverlapped )
  {
    v18 = NtNotifyChangeDirectoryFileEx(
            hDirectory,
            0,
            0,
            0,
            v20,
            lpBuffer,
            nBufferLength,
            dwNotifyFilter,
            bWatchSubtree,
            v12);
    if ( v18 == 259 )
    {
      v18 = NtWaitForSingleObject(hDirectory, 0, 0);
      if ( v18 < 0 )
        goto LABEL_24;
      v18 = v20[0];
    }
    if ( v18 >= 0 )
    {
      *lpBytesReturned = v20[1];
      return v9;
    }
LABEL_24:
    BaseSetLastNTError(v18);
    return 0;
  }
  v14 = lpCompletionRoutine;
  if ( lpCompletionRoutine )
  {
    v21 = 0;
    v15 = BasepAllocateActivationContextActivationBlock(lpOverlapped, &P);
    if ( v15 < 0 )
    {
      BaseSetLastNTError(v15);
      return 0;
    }
    v10 = P;
    v13 = lpOverlapped;
    if ( P )
    {
      v16 = (int (__stdcall *)(int, int, int))BasepIoCompletion;
      v14 = P;
    }
    else
    {
      v16 = BasepIoCompletionSimple;
    }
  }
  else
  {
    v16 = 0;
    v21 = lpOverlapped[4];
    v14 = (v21 & 1) == 0 ? lpOverlapped : 0;
  }
  v19 = v22;
  *v13 = 259;
  v17 = NtNotifyChangeDirectoryFileEx(
          hDirectory,
          v21,
          v16,
          v14,
          v13,
          lpBuffer,
          nBufferLength,
          dwNotifyFilter,
          bWatchSubtree,
          v19);
  if ( (v17 & 0xC0000000) == 0xC0000000 )
  {
    if ( v10 )
      BasepFreeActivationContextActivationBlock(v10);
    BaseSetLastNTError(v17);
    return 0;
  }
  return v9;
}
ULONG __thiscall BaseSetLastNTError(NTSTATUS Status)
{
  ULONG v1; // esi

  v1 = RtlNtStatusToDosError(Status);
  RtlSetLastWin32Error(v1);
  return v1;
}
int __fastcall BasepAllocateActivationContextActivationBlock(int a1, int a2, int a3, _DWORD *a4)
{
  char v4; // bl
  int v5; // esi
  NTSTATUS v6; // eax
  _DWORD *Heap; // eax
  HANDLE pvBuffer; // [esp+Ch] [ebp-Ch] BYREF
  int v10; // [esp+10h] [ebp-8h]
  int v11; // [esp+14h] [ebp-4h]

  v4 = a1;
  v11 = a2;
  pvBuffer = 0;
  v10 = 0;
  if ( a4 )
    *a4 = 0;
  if ( (a1 & 0xFFFFFFFC) != 0 )
    return 0xC00000EF;
  if ( !a4 )
    return 0xC00000F2;
  v6 = RtlQueryInformationActivationContext(1u, 0, 0, 1u, &pvBuffer, 8u, 0);
  v5 = v6;
  if ( v6 < 0 )
  {
    _DbgPrintEx(
      0x33u,
      0,
      "SXS: %s - Failure getting active activation context; ntstatus %08lx\n",
      "BasepAllocateActivationContextActivationBlock",
      v6);
    goto LABEL_19;
  }
  if ( (v10 & 1) != 0 )
  {
    RtlReleaseActivationContext(pvBuffer);
    pvBuffer = 0;
  }
  if ( (v4 & 2) == 0 || pvBuffer )
  {
    Heap = RtlAllocateHeap(NtCurrentPeb()->ProcessHeap, KernelBaseGlobalData, 0x10u);
    *a4 = Heap;
    if ( !Heap )
    {
      v5 = -1073741801;
      goto LABEL_19;
    }
    *Heap = 0;
    Heap[3] = pvBuffer;
    pvBuffer = 0;
    if ( (v4 & 1) != 0 )
      *Heap |= 1u;
    Heap[1] = v11;
    Heap[2] = a3;
  }
  v5 = 0;
LABEL_19:
  if ( pvBuffer )
    RtlReleaseActivationContext(pvBuffer);
  return v5;
}

void __stdcall BasepIoCompletion(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved)
{
  ULONG v3; // edi
  ULONG_PTR Information; // ebx
  struct _RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED Frame; // [esp+10h] [ebp-44h] BYREF
  void (__thiscall *v6)(_DWORD, ULONG, ULONG_PTR, PIO_STATUS_BLOCK); // [esp+34h] [ebp-20h]
  PVOID Context; // [esp+38h] [ebp-1Ch]
  CPPEH_RECORD ms_exc; // [esp+3Ch] [ebp-18h]

  Frame.Size = 36;
  Frame.Format = 1;
  memset(&Frame.Frame, 0, 0x1Cu);
  if ( (IoStatusBlock->Status & 0xC0000000) == 0xC0000000 )
  {
    v3 = RtlNtStatusToDosError(IoStatusBlock->Status);
    Information = 0;
  }
  else
  {
    v3 = 0;
    Information = IoStatusBlock->Information;
  }
  Context = (PVOID)*((_DWORD *)ApcContext + 3);
  v6 = (void (__thiscall *)(_DWORD, ULONG, ULONG_PTR, PIO_STATUS_BLOCK))*((_DWORD *)ApcContext + 1);
  if ( (*(_BYTE *)ApcContext & 1) == 0 )
    BasepFreeActivationContextActivationBlock((HANDLE *)ApcContext);
  RtlActivateActivationContextUnsafeFast(&Frame, Context);
  ms_exc.registration.TryLevel = 0;
  v6(v6, v3, Information, IoStatusBlock);
  ms_exc.registration.TryLevel = -2;
  RtlDeactivateActivationContextUnsafeFast(&Frame);
}

BOOLEAN __thiscall BasepFreeActivationContextActivationBlock(HANDLE *P)
{
  BOOLEAN result; // al

  if ( P )
  {
    if ( P[3] )
    {
      RtlReleaseActivationContext(P[3]);
      P[3] = 0;
    }
    return RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, P);
  }
  return result;
}

int __stdcall BasepIoCompletionSimple(int (__thiscall *a1)(_DWORD, ULONG, NTSTATUS, NTSTATUS *), NTSTATUS *a2, int a3)
{
  ULONG v3; // eax
  NTSTATUS v4; // ecx

  if ( (*a2 & 0xC0000000) == 0xC0000000 )
  {
    v3 = RtlNtStatusToDosError(*a2);
    v4 = 0;
  }
  else
  {
    v4 = a2[1];
    v3 = 0;
  }
  return a1(a1, v3, v4, a2);
}

BOOLEAN __thiscall BasepFreeActivationContextActivationBlock(HANDLE *P)
{
  BOOLEAN result; // al

  if ( P )
  {
    if ( P[3] )
    {
      RtlReleaseActivationContext(P[3]);
      P[3] = 0;
    }
    return RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, P);
  }
  return result;
}
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

daydreamer

The noticeable speed difference is when I change movsb /stosb to movsd / stosd
when running 16 bit dos
I have treasure box pop up code using xmm regs using 16 char string = 8+8 chars random chooses 8 char material and 8 char object you find in treasure chest together with random amount of coin,capped by which level you are on
Like this "mythril"+" sword"
my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

NoCforMe

"daydreamer": what the hell does this have to do with buffer alignment?
And what's with that blond girl picture? Not you, we know ...
32-bit code and Windows 7 foreva!