how to convert this ASM to C

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. • void *this is the way C++ non-static member functions receive the this pointer. 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? Jun 14, 2013 at 16:21 • 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 • My question is clear: whats the c equivalent of that asm code. Jun 15, 2013 at 7:07 • 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. Jun 15, 2013 at 8:36 1 Answer 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.

• 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