1

I'm working with a function thats similar to Memory Resize like realloc / redim in VB.

The first 3 lines decompiled look like

char *__cdecl ExpandMemory(void *lpAddress, signed int StartPos, signed int MaxSize)
{
    int NewSize; // edi@3

    if ( StartPos > 0x80000 )
        MaxSize = 16 * MaxSize;
    NewSize = MaxSize * (MaxSize + StartPos - 1) / MaxSize;
    //Lots of stuff goes here
}

Can someone tell me what this line is suppose to do

NewSize = MaxSize * (MaxSize + StartPos - 1) / MaxSize;

I have a very strong feeling its a Math.MIN() function without ?:

Since MIN function is declared like this

#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))

I don't understand how that math could resemble it, could someone explain what it's suppose to do.

As far as I know it doesn't even work properly keeps creating a NewSize which is far greater then the MaxSize, if it could work can someone explain how it could actually work? In most spots the MaxSize parameter is usually 1 which indicates no limit and uses StartPos only, where MaxSize is used it usually is 65536 or 2048 some binary values. But it doesn't have anything to do with binary what so ever.

In ASM the code looks like this

.text:004083BC                 lea     eax, [ecx+eax-1]
.text:004083C0                 cdq
.text:004083C1                 idiv    ecx
.text:004083C3                 mov     edi, eax
.text:004083C5                 imul    edi, ecx
.text:004083C8                 mov     ecx, [esp+114h+arg_0]

Full decompiled source:

char *__cdecl ExpandMemory(void *a1, signed int NewSize, signed int MaxSize)
{
  signed int HowMuchBiggerr; // ecx@1
  int NewSizee; // edi@3
  char *v5; // eax@5
  char *v6; // esi@8
  char *result; // eax@13
  void *v8; // eax@15
  signed int v9; // esi@18
  int v10; // edi@18
  char *v11; // eax@22
  char *v12; // eax@27
  char *v13; // ebp@30
  unsigned int v14; // ecx@35
  void *Memory; // [sp+10h] [bp-104h]@18
  char Text[256]; // [sp+14h] [bp-100h]@11

  HowMuchBiggerr = MaxSize;
  if ( NewSize > (signed int)0x80000u )
    HowMuchBiggerr = 16 * MaxSize;
  NewSizee = HowMuchBiggerr * (HowMuchBiggerr + NewSize - 1) / HowMuchBiggerr;
  if ( a1 )
  {
    if ( NewSizee )
    {
      v9 = *((_DWORD *)a1 - 1);                 // Okay minus 4 bytes from beginning of pointed data is size? (must be a special structure of some kind)
      v10 = NewSizee + 4;
      Memory = (char *)a1 - 4;
      if ( v10 == v9 )                          // Check if special attribute (Size?) exists and equals the New Size so it can ignore it.
      {
        result = (char *)a1;
      }
      else
      {
        if ( v9 > (signed int)0x80000u || v10 > (signed int)0x80000u )
        {
          if ( v10 <= (signed int)0x80000u )
            v12 = (char *)malloc(v10);
          else
            v12 = (char *)VirtualAlloc(0, v10, 0x1000u, 4u);
          if ( v12 )
          {
            *(_DWORD *)v12 = v10;
            v13 = v12 + 4;
          }
          else
          {
            v13 = 0;
          }
          if ( !v13 )
          {
            sprintf(Text, "Out of memory (Alloc:%d)", v10 - 4);
            MessageBoxA(0, Text, "Error", 0x30u);
            exit(1);
          }
          v14 = v9 - 4;
          if ( v9 - 4 >= v10 - 4 )
            v14 = v10 - 4;
          memcpy(v13, a1, v14);
          if ( *(_DWORD *)Memory <= (signed int)0x80000u )
          {
            free(Memory);
            result = v13;
          }
          else
          {
            VirtualFree(Memory, 0, 0x8000u);
            result = v13;
          }
        }
        else
        {
          v11 = (char *)realloc((char *)a1 - 4, v10);
          if ( !v11 )
          {
            MessageBoxA(0, "Out of memory (Resize)", "Error", 0x30u);
            exit(1);
          }
          *(_DWORD *)v11 = v10;
          result = v11 + 4;
        }
      }
    }
    else
    {
      v8 = (char *)a1 - 4;
      if ( *((_DWORD *)a1 - 1) <= (signed int)0x80000u )
      {
        free(v8);
        result = 0;
      }
      else
      {
        VirtualFree(v8, 0, 0x8000u);
        result = 0;
      }
    }
  }
  else
  {
    if ( NewSizee + 4 <= (signed int)0x80000u )
      v5 = (char *)malloc(NewSizee + 4);
    else
      v5 = (char *)VirtualAlloc(0, NewSizee + 4, 0x1000u, 4u);
    if ( v5 )
    {
      *(_DWORD *)v5 = NewSizee + 4;
      v6 = v5 + 4;
    }
    else
    {
      v6 = 0;
    }
    if ( !v6 )
    {
      sprintf(Text, "Out of memory (Alloc:%d)", NewSizee);
      MessageBoxA(0, Text, "Error", 0x30u);
      exit(1);
    }
    result = v6;
  }
  return result;
}
  • MaxSize should be more properly called alignment or granularity. And StartPos is probably the size of requested memory (not aligned). – Igor Skochinsky Nov 24 '14 at 0:28
  • I don't know anything about alignment but yeah StartPos isn't a good name I've changed it to Bytes but MaxSize does seem to be a limiter so it doesn't allocate too much memory. I've updated the question with the whole source code. I know you probably wouldn't want to help me as I am using your pirated software. But all I can say is it does a pretty damn good job. I've found one problem where it did parenthesis incorrectly in logic which resulted in wrong answer, but that's about it. – SSpoke Nov 24 '14 at 0:48
3

Looks like a common pattern for ceiling to me.

In other words NewSize = ceil(StartPos/MaxSize) * MaxSize, which is rounding it to the nearest multiple of MaxSize that is larger than StartPos.

| improve this answer | |
  • Yeah it does looks pretty close to a ceil pattern without the multiply though. – SSpoke Nov 24 '14 at 5:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.