mb3d icon indicating copy to clipboard operation
mb3d copied to clipboard

Is there anyway to get the source code of a certain formula?

Open JamesHuJC opened this issue 1 year ago • 6 comments

I'm trying to port a formula to ue5. SierpHilbert specifically, when I press the info button it doesn't show the source code, unlike some others do. SierpHilbert.m3f has a [code] section but I'm not sure what to do with it.

JamesHuJC avatar Aug 12 '24 00:08 JamesHuJC

The [code] section contains assembly code, difficult to reverse-engineer. I suggest looking up the formula at other places. For example I believe mandelbulber2 has this formula and implemented in c++ 👍

bezo97 avatar Aug 13 '24 21:08 bezo97

It would be interesting if some of the modern code-LLM's (for example, code-llama-3) can "back-translate" it in a higher language like C, but I did not try this yet

thargor6 avatar Aug 14 '24 22:08 thargor6

It would be interesting if some of the modern code-LLM's (for example, code-llama-3) can "back-translate" it in a higher language like C, but I did not try this yet

I actually tried this. There are certain websites that do this. But the results aren't that good. www.disasm.pro [code]-> assembly www.codeconvert.ai/free-converter assembly -> to cpp python java etc. (btw java seems to get better results) this website is based on llms

JamesHuJC avatar Aug 15 '24 00:08 JamesHuJC

@thargor6 Hi, do you still remember how SierpHilbert works? I can't find any other implementation of it anywhere else, and I like the fractals it generates. Thanks

JamesHuJC avatar Aug 16 '24 05:08 JamesHuJC

The [code] section contains assembly code, difficult to reverse-engineer. I suggest looking up the formula at other places. For example I believe mandelbulber2 has this formula and implemented in c++ 👍

I can't find it in mandelbulber2, is it a different name?(not SierpHilbert)

JamesHuJC avatar Aug 16 '24 08:08 JamesHuJC

Sorry, I couldn't find/remember any valuable information about this one. Maybe you could ask one of the developers of Mandelbulber if they know something about it.

thargor6 avatar Aug 16 '24 13:08 thargor6

Here's one of the ways how the code can be reverse engineered with the use of IDA (version 9.0.240925). In this case I'll do it on linux and for SierpHilbert.m3f

Full guide

Let's convert hex text into the binary file

printf "558BEC535689C38B75088B7630DD01DD02DD03D9C0D84EBCD9C2D84EB8DEC1D9
C3D84EB4DEC1D9C1D84ED4D9C3D84ED0DEC1D9C4D84ECCDEC1D9CAD84EC8D9CB
D84EC4DEC3D9CBD84EC0DEC2D9E0D8D1DFE0D0EC7202D9C9D8D2DFE0D0EC7202
D9CAD9E0D9C9D9E0D8D2DFE0D0EC7202D9CAD9E0D9C99090DD4688D9EED8D9DF
E0D0EC730BD8E2D9E1D9E0DC4688D9CADDD89090DD4680D9EED8D9DFE0D0EC73
0BD8E1D9E1D9E0DC4680D9C9DDD89090D9D0D9C0D84E98D9C2D84E94DEC1D9C3
D84E90DEC1D9C1D84EB0D9C3D84EACDEC1D9C4D84EA8DEC1D9CAD84EA4D9CBD8
4EA0DEC3D9CBD84E9CDEC2DD46F0DD4108D8C9DD5908DCCBDCCADCC9D9E8DEE9
D9C0DC4ED8DEECD9C0DC4EE0DEEBDC4EE8DEE9DD1BDD1ADD1989D85E5B5DC208
00" | tr -d '\n' | xxd -r -p - SierpHilbert.bin

Open it in IDA with Intel 8086 processor in 32-bit mode

image

Select GCC as the compiler

image

Create function at the zero (0x00000000) address

image

Press tab (or Jump > Jump to pseudocode) to go to pseudocode

image

The first 3 arguments to a function are pointers to x, y, z. Let's rename them

image

The 4th argument is a pointer to a struct called TIteration3Dext, here's its documentation, let's define it in IDA

image image

Then let's create inputs and constants struct that is located at PVar address, these are unique to .m3f file and they go in reverse (because negative offsets), also we need to be careful with types, for example 3SingleAngles is actually passed to our function as a rotation matrix (9 floats).

image image image image

Now let's modify TIteration3Dext struct to point to our InputsConstants struct, we need to shift it, because it points to our first constant (we don't have any, but it's easier to add it anyway)

image

Then we change 4th argument type to reanalyze it, and we can change the name as well

image

Now here we have a pointer to first_constant field, but IDA just saved it like double* type, let's change that

image image

Now we have almost readable code, except we could also rename intermediate variables by guessing what they mean (depends on optimizations), or collapse some variables that just copy other values.

image

Function code (could be cleaned up manually as the next step)
double *__userpurge sub_0@<eax>(
        double *xptr@<eax>,
        double *yptr@<edx>,
        double *zptr@<ecx>,
        double *__shifted(TIteration3Dext,0x38) inputsconstants,
        int a5)
{
  double *__shifted(InputsConstants,0x80) p_first_constant; // esi
  double v6; // st7
  double v7; // st6
  double v8; // st5
  double v9; // st4
  double v10; // st3
  double v11; // st5
  double v12; // rt2
  double v13; // st4
  double v14; // st7
  double v15; // st6
  double v16; // st5
  double v17; // rtt
  double v18; // rt0
  long double v19; // rt1
  double v20; // st5
  long double v21; // st6
  double v22; // st5
  double v23; // rt2
  long double v24; // rtt
  long double v25; // st5
  long double v26; // st6
  double v27; // st4
  double v28; // st4
  long double v29; // st4
  long double v30; // st3
  long double v31; // st5
  long double v32; // rt0
  long double v33; // st6
  double v34; // st4
  long double v35; // st7
  long double v36; // st6
  long double v37; // st5
  double v38; // st4
  double v39; // st7
  double v40; // st6

  p_first_constant = &ADJ(ADJ(inputsconstants)->PVar)->first_constant;
  v6 = *zptr;
  v7 = *yptr;
  v8 = *xptr;
  v9 = v8 * ADJ(p_first_constant)->rotation1[0][2]
     + v7 * ADJ(p_first_constant)->rotation1[0][1]
     + v6 * ADJ(p_first_constant)->rotation1[0][0];
  v10 = v8;
  v11 = v8 * ADJ(p_first_constant)->rotation1[2][2]
      + v7 * ADJ(p_first_constant)->rotation1[2][1]
      + v6 * ADJ(p_first_constant)->rotation1[2][0];
  v12 = v9;
  v13 = v6;
  v14 = v12;
  v15 = v10 * ADJ(p_first_constant)->rotation1[1][2]
      + v7 * ADJ(p_first_constant)->rotation1[1][1]
      + v13 * ADJ(p_first_constant)->rotation1[1][0];
  v16 = -v11;
  if ( v16 >= v15 )
  {
    v17 = v16;
    v16 = v15;
    v15 = v17;
  }
  if ( v16 >= v14 )
  {
    v18 = v16;
    v16 = v14;
    v14 = v18;
  }
  v19 = -v16;
  v20 = v15;
  v21 = v19;
  v22 = -v20;
  if ( v22 >= v14 )
  {
    v23 = v22;
    v22 = v14;
    v14 = v23;
  }
  v24 = -v22;
  v25 = v21;
  v26 = v24;
  v27 = ADJ(p_first_constant)->edge1;
  if ( v27 > 0.0 )
    v26 = ADJ(p_first_constant)->edge1 - fabs(v27 - v26);
  v28 = ADJ(p_first_constant)->edge2;
  if ( v28 > 0.0 )
    v25 = ADJ(p_first_constant)->edge2 - fabs(v28 - v25);
  v29 = v25 * ADJ(p_first_constant)->rotation2[0][2]
      + v26 * ADJ(p_first_constant)->rotation2[0][1]
      + v14 * ADJ(p_first_constant)->rotation2[0][0];
  v30 = v25;
  v31 = v25 * ADJ(p_first_constant)->rotation2[2][2]
      + v26 * ADJ(p_first_constant)->rotation2[2][1]
      + v14 * ADJ(p_first_constant)->rotation2[2][0];
  v32 = v29;
  v33 = v30 * ADJ(p_first_constant)->rotation2[1][2]
      + v26 * ADJ(p_first_constant)->rotation2[1][1]
      + v14 * ADJ(p_first_constant)->rotation2[1][0];
  v34 = ADJ(p_first_constant)->scale;
  zptr[1] = zptr[1] * v34;
  v35 = v32 * v34;
  v36 = v33 * v34;
  v37 = v31 * v34;
  v38 = v34 - 1.0;
  v39 = v35 - v38 * ADJ(p_first_constant)->cscale_z;
  v40 = v36 - v38 * ADJ(p_first_constant)->cscale_y;
  *xptr = v37 - v38 * ADJ(p_first_constant)->cscale_x;
  *yptr = v40;
  *zptr = v39;
  return xptr;
}

I think zptr[1] which can be viewed as *(zptr + 1) is w because it comes right after z in TIteration3Dext struct.

temhelk avatar Dec 08 '24 19:12 temhelk