3

I have this function that I know its responsible for making some nice math between a 2D vector to return the highest 3D Y value at the provided 2D coordinate. I also know it takes two parameters, int iX and int iZ. I have the ASM and the pseudo-C generated by Hex-Rays, but I can't make this code cmpile, I'm not so good with the Hex-Rays pseudo-code.

The ASM code:

00464770  /$ 56             PUSH ESI
00464771  |. 8BF1           MOV ESI,ECX
00464773  |. 833E 00        CMP DWORD PTR DS:[ESI],0
00464776  |. 75 06          JNZ SHORT 0046477E
00464778  |. 33C0           XOR EAX,EAX
0046477A  |. 5E             POP ESI
0046477B  |. C2 0800        RETN 8
0046477E  |> 8B4424 0C      MOV EAX,DWORD PTR SS:[ESP+C]
00464782  |. 8B4C24 08      MOV ECX,DWORD PTR SS:[ESP+8]
00464786  |. 50             PUSH EAX
00464787  |. 51             PUSH ECX
00464788  |. C1F8 0E        SAR EAX,0E
0046478B  |. C1F9 0E        SAR ECX,0E
0046478E  |. 50             PUSH EAX
0046478F  |. 51             PUSH ECX
00464790  |. 8BCE           MOV ECX,ESI
00464792  |. E8 59FEFFFF    CALL 004645F0
00464797  |. FF86 14000400  INC DWORD PTR DS:[ESI+40014]
0046479D  |. 5E             POP ESI
0046479E  \. C2 0800        RETN 8

The pseudo-code:

signed int __thiscall sub_464770(void *this, int a2, int a3)
{
  void *v3; // esi@1
  signed int result; // eax@2


  v3 = this;
  if ( *(_DWORD *)this )
  {
    result = sub_4645F0((int)this, a2 >> 14, a3 >> 14, a2, a3);
    ++*((_DWORD *)v3 + 65541);
  }
  else
  {
    result = 0;
  }
  return result;
}
signed int __thiscall sub_4645F0(int this, unsigned __int8 a2, unsigned __int8 a3, int a4, int a5)
{
  int v5; // ebx@1
  int v6; // edi@1
  int v7; // esi@1
  signed int v8; // ebp@2
  int v9; // eax@3
  int v10; // edx@3
  int v11; // eax@3
  int v12; // ecx@3
  int v13; // eax@5
  signed int result; // eax@9
  signed int v15; // [sp+14h] [bp+4h]@1
  int v16; // [sp+18h] [bp+8h]@2


  v7 = this;
  v5 = this + 4 * (a3 + (a2 << 8)) + 4;
  v6 = *(_DWORD *)(this + 262164);
  v15 = -51200;
  if ( *(_DWORD *)v5 && (v8 = 1, v16 = **(_WORD **)v5 + 1, v16 > 1) )
  {
    do
    {
      v10 = *(_DWORD *)(v7 + 262172);
      v11 = 28 * *(_WORD *)(*(_DWORD *)v5 + 2 * v8);
      v12 = *(_DWORD *)(v11 + v10 + 4);
      v9 = v10 + v11;
      if ( v12 != v6 )
      {
        if ( *(_BYTE *)(320 * *(_WORD *)(v9 + 14) + *(_DWORD *)(v7 + 262192) + 168) & 1 )
        {
          *(_DWORD *)(v9 + 4) = v6;
          v13 = sub_464320(v7, v9, a4, a5);
          if ( v13 != -32767 )
          {
            if ( v13 > v15 )
              v15 = v13;
          }
        }
      }
      ++v8;
    }
    while ( v8 < v16 );
    result = v15;
  }
  else
  {
    result = -51200;
  }
  return result;
}
int __thiscall sub_464320(int this, int a2, int a3, int a4)
{
  int v4; // eax@1
  int v5; // ecx@1
  int v6; // ebx@1
  int v7; // esi@1
  int v8; // esi@1
  int v9; // edi@1
  int v10; // edx@1
  signed int v11; // ecx@16
  int v12; // eax@17
  int v13; // edx@22
  int v14; // edi@22
  int v15; // eax@23
  int v16; // ecx@24
  int v17; // eax@31
  int v18; // edx@33
  int v19; // ebx@33
  int v20; // ebp@33
  signed int v21; // ecx@34
  int v22; // ecx@36
  int v23; // eax@37
  int v24; // eax@40
  int v25; // eax@45
  int v26; // edx@45
  int v27; // esi@45
  int v28; // edi@46
  int v29; // eax@49
  int v30; // eax@49
  signed int v31; // ecx@52
  int result; // eax@53
  int v33; // [sp+10h] [bp-24h]@1
  int v34; // [sp+14h] [bp-20h]@1
  signed int v35; // [sp+18h] [bp-1Ch]@25
  signed int v36; // [sp+1Ch] [bp-18h]@28
  signed int v37; // [sp+20h] [bp-14h]@24
  int v38; // [sp+20h] [bp-14h]@37
  signed int v39; // [sp+24h] [bp-10h]@24
  int v40; // [sp+24h] [bp-10h]@40
  int v41; // [sp+28h] [bp-Ch]@1
  int v42; // [sp+2Ch] [bp-8h]@1
  int v43; // [sp+30h] [bp-4h]@1
  int v44; // [sp+38h] [bp+4h]@1
  int v45; // [sp+38h] [bp+4h]@43
  signed int v46; // [sp+40h] [bp+Ch]@24


  v8 = *(_DWORD *)(this + 262168);
  v4 = v8 + 28 * *(_WORD *)(a2 + 10);
  v5 = v8 + 28 * *(_WORD *)(a2 + 8);
  v9 = *(_DWORD *)(v5 + 16);
  v43 = v8 + 28 * *(_WORD *)(a2 + 12);
  v33 = v43;
  v10 = *(_DWORD *)(v4 + 16);
  v7 = v5;
  v6 = v4;
  v41 = v5;
  v42 = v4;
  v34 = v5;
  v44 = v4;
  if ( v10 < v9 )
  {
    v7 = v4;
    v34 = v4;
  }
  if ( *(_DWORD *)(v43 + 16) < *(_DWORD *)(v7 + 16) )
  {
    v7 = v43;
    v34 = v43;
  }
  if ( v7 == v4 )
  {
    v44 = v43;
    v6 = v43;
  }
  if ( *(_DWORD *)(v5 + 16) > *(_DWORD *)(v6 + 16) )
  {
    if ( v7 != v5 )
    {
      v44 = v5;
      v6 = v5;
    }
  }
  if ( *(_DWORD *)(v4 + 16) > *(_DWORD *)(v6 + 16) )
  {
    if ( v7 != v4 )
    {
      v44 = v4;
      v6 = v4;
    }
  }
  if ( *(_DWORD *)(v43 + 16) > *(_DWORD *)(v6 + 16) )
  {
    if ( v7 != v43 )
    {
      v44 = v43;
      v6 = v43;
    }
  }
  v11 = 0;
  while ( 1 )
  {
    v12 = *(&v41 + v11);
    if ( v7 != v12 )
    {
      if ( v6 != v12 )
        break;
    }
    ++v11;
    if ( v11 >= 3 )
      goto LABEL_22;
  }
  v33 = *(&v41 + v11);
LABEL_22:
  v13 = *(_DWORD *)(v7 + 16);
  v14 = a4;
  if ( a4 < v13 )
    goto LABEL_58;
  v15 = *(_DWORD *)(v6 + 16);
  if ( a4 > v15 )
    goto LABEL_58;
  v16 = *(_DWORD *)(v33 + 16);
  v37 = v15 - v13;
  v39 = *(_DWORD *)(v33 + 16) - v13;
  v46 = v15 - v16;
  v35 = v15 == v13 ? 0 : ((*(_DWORD *)(v44 + 8) - *(_DWORD *)(v7 + 8)) << 8) / (v15 - v13);
  v36 = *(_DWORD *)(v33 + 16) == v13 ? 0 : ((*(_DWORD *)(v33 + 8) - *(_DWORD *)(v7 + 8)) << 8)
                                         / (*(_DWORD *)(v33 + 16) - v13);
  v17 = v46 ? ((*(_DWORD *)(v44 + 8) - *(_DWORD *)(v33 + 8)) << 8) / v46 : 0;
  v20 = v14 - *(_DWORD *)(v7 + 16);
  v18 = *(_DWORD *)(v7 + 8);
  v19 = v18 + (v35 * (v14 - *(_DWORD *)(v7 + 16)) >> 8);
  if ( v14 >= v16 )
  {
    v21 = v17 * (v14 - *(_DWORD *)(v33 + 16));
    v18 = *(_DWORD *)(v33 + 8);
  }
  else
  {
    v21 = v36 * v20;
  }
  v22 = v18 + (v21 >> 8);
  if ( v37 )
  {
    v23 = ((*(_DWORD *)(v44 + 12) - *(_DWORD *)(v7 + 12)) << 8) / v37;
    v7 = v34;
    v38 = v23;
  }
  else
  {
    v38 = 0;
  }
  if ( v39 )
  {
    v24 = ((*(_DWORD *)(v33 + 12) - *(_DWORD *)(v7 + 12)) << 8) / v39;
    v7 = v34;
    v40 = v24;
  }
  else
  {
    v40 = 0;
  }
  if ( v46 )
  {
    v7 = v34;
    v45 = ((*(_DWORD *)(v44 + 12) - *(_DWORD *)(v33 + 12)) << 8) / v46;
  }
  else
  {
    v45 = 0;
  }
  v25 = *(_DWORD *)(v7 + 12);
  v26 = *(_DWORD *)(v33 + 16);
  v27 = v25 + (v38 * v20 >> 8);
  v28 = v14 >= v26 ? *(_DWORD *)(v33 + 12) + (v45 * (v14 - v26) >> 8) : v25 + (v40 * v20 >> 8);
  if ( v19 > v22 )
  {
    v29 = v19;
    v19 = v22;
    v22 = v29;
    v30 = v27;
    v27 = v28;
    v28 = v30;
  }
  if ( a3 < v19 || a3 > v22 )
  {
LABEL_58:
    result = -32767;
  }
  else
  {
    v31 = v22 - v19;
    if ( v31 )
      result = v27 + (((v28 - v27) << 8) / v31 * (a3 - v19) >> 8);
    else
      result = v27 + (v27 * (a3 - v19) >> 8);
  }
  return result;
}

I don't know why the functions have void *this as the first parameter though.

9
  • void *this is the way C++ non-static member functions receive the this pointer.
    – DCoder
    Jun 14, 2013 at 13:01
  • Out of curiosity, how many mathematically correct ways are there to compute the result? Or are you interested in the reversing process itself, rather than the specific formula?
    – DCoder
    Jun 14, 2013 at 16:21
  • 3
    This doesn't seem like a real question. The title of the question asks what the code is. You pasted both the code and the Hex-Rays decompilation, thereby answering your own question. Then you said "I can't work around with it, I'm not so good with the Hex-Rays pseudo-code" which does not contain a clear or precise question. Voting to close unless it is edited to ask a well-defined question. Jun 14, 2013 at 21:59
  • 2
    My question is clear: whats the c equivalent of that asm code. Jun 15, 2013 at 7:07
  • 1
    The ASM snippet you provided is only for the first function from your C code block. For me personally, it would be easier to reverse this if you provided the binary itself rather than the pseudo C.
    – DCoder
    Jun 15, 2013 at 8:36

1 Answer 1

1

It is very difficult to give you an ideal C equivalent that will accurately reflect original code in almost all but trivial cases. While I don't immediately see signs of this in your code, you must bear in mind that when a compiler is executed, especially with any optimization options, it can result in logically jumbled code to allow the processor to more efficiently utilize cache and execution pipelines.

That said, rather than trying to go for a line by line decompilation, I find that it's better to start out commenting the assembly directly. From there, try to stand back and identify general function. From there you should be able to generate code.

For example: (by the way, the start of this assembly fragment seems pretty arbitrary)

00464770  /$ 56             PUSH ESI                 ; save ESI
00464771  |. 8BF1           MOV ESI,ECX              ; ECX seems to contain the location of something important.
00464773  |. 833E 00        CMP DWORD PTR DS:[ESI],0 ; Check to see if it's zero.
00464776  |. 75 06          JNZ SHORT 0046477E       ; If it is, do this.
00464778  |. 33C0           XOR EAX,EAX              ; If it isn't, zero out EAX.  Remember that EAX is almost always used to return values, especially in compiled C code.
0046477A  |. 5E             POP ESI                  ; Restore ESI..  Why isn't EBP or anything else being restored?  This makes me suspicious of whether this code was compiled from C code to start with.  There doesn't seem to be a function prolog/epilog.
0046477B  |. C2 0800        RETN 8                   ; Return, unwinding 8 bytes off of the stack.

From there, stand back and try to identify functional blocks. I'd need to have more code to reverse this, though, since there is no hint as to what ECX might be pointing at, for example, or how and why this function was called.

2
  • Looking at this again today it could actually be some type of fastcall or register calling but I would still expect to see ESP and EBP being saved/restored. If you happen to know what compiled this code (if it wasn't written in assembly to start with) I'd be very interested to know it. Jul 13, 2013 at 21:57
  • actually, the source code for this game got leaked, and it was compiled using visual studio 2002 Jan 6, 2016 at 23:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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