-1

I've be on with the application for a while now and have pinpointed some interested functions, I would like to be able to implement them in to another application but I'm not sure how to get them "out" of IDA.

I was going to try and copy the ASM code and use that, then I found how to decompile it into some Pseudo readable Code, but I can't get it to compile again as I don't have enough experience with C.

Here is the code it generated:

int __usercall sub_10001000@<eax>(unsigned int a1@<eax>, int a2@<ecx>)
    {
      unsigned __int16 v2; // dx@1
      unsigned int v3; // eax@1

      v2 = (unsigned __int8)a1;
      v3 = a1 >> 8;

      return *(_DWORD *)(a2 + 4 * v2 + 3144)
      + (*(_DWORD *)(a2 + 4 * (unsigned __int8)v3 + 2120) ^ (*(_DWORD *)(a2 
      + 4 * BYTE1(v3) + 1096) + *(_DWORD *)(a2 + 4 * ((unsigned __int16)(v3 
      >> 8) >> 8) + 72)));
    }

I'd like to understand what this code does and to hopefully recreate it.

Would anyone be so kind as to write out a function what performs the same task ?

  • Ok i misundertood do you need to compile a disassembled function in a new application ? i don't think it's feasible because the anatomic nature of asm code don't fit to be recompiled again, there is an example of boomrang that tries to recompiles a recovered code from ASM but it often fails. – Abr001am Mar 5 '18 at 20:42
  • the function takes a dword from one of each equally spaced table does some magic with it and returns a dword you can see let a1 = 0x10000000 let a2 = 0x20000000 so v2 = 0x0000 so v3 = 0x00100000 (0x20000000 + (4 * 0) + 3144) = dword[0x20000c48] + (0x20000000 + (4 * 0) + 2120) = dword[0x20000848] ^ (0x20000000 + (4 * 0) + 1096) = dword[0x20000448] + (0x20000000 + (4 * 0) + 0072) = dword[0x20000048] – blabb Mar 6 '18 at 10:06
  • @blabb Thanks, I've had a go at creating a function but can't get it compiled, I'm not too clever with C/C++. Could you write out a function please ? – henda79 Mar 6 '18 at 10:48
  • 2
    since this question is closed you may have to start anew start by showing both the pseudo code and disassembly along with what you tried and where you are stuck no one may be writing you a replacement function but may provide you advice on how to write one yourself – blabb Mar 6 '18 at 16:00
4

The thing about "decompiled" code is, it doesn't really say much about what the author was trying to do. It is simply the compiler's view on what the code meant, and the compiler will optimize away most of the readability. :P

Take that "decompiled" function, and first off, let's turn it into compilable C. For the most part, that just means stripping off the @<register> stuff from the function and parameter names. We don't care about registers any more. That's the compiler's job. :P

int sub_10001000(unsigned int a1, int a2)
{
  unsigned __int16 v2;
  unsigned int v3;

  v2 = (unsigned __int8)a1;
  v3 = a1 >> 8;

  return *(_DWORD *)(a2 + 4 * v2 + 3144)
  + (*(_DWORD *)(a2 + 4 * (unsigned __int8)v3 + 2120) ^ (*(_DWORD *)(a2 
  + 4 * BYTE1(v3) + 1096) + *(_DWORD *)(a2 + 4 * ((unsigned __int16)(v3 
  >> 8) >> 8) + 72)));
}

Now...see all that *(_DWORD *) stuff? It happens every time we use a2. That hints that a2 should be a _DWORD *. Note that when we do that, C will change what a2 + (whatever) means. (It'll add (whatever) * the size of a _DWORD, which is almost certainly 4.) We also have to adjust the stuff inside so that instead of adding 4 * X, we simply add X.

int sub_10001000(unsigned int a1, _DWORD * a2)
{
  unsigned __int16 v2;
  unsigned int v3;

  v2 = (unsigned __int8)a1;
  v3 = a1 >> 8;

  // 786 = 3144/4, 530 = 2120/4, 274 = 1096/4, 18 = 72/4
  return *(a2 + v2 + 786) 
  + (*(a2 + (unsigned __int8)v3 + 530) ^ (*(a2
  + BYTE1(v3) + 274) + *(a2 + ((unsigned __int16)(v3
  >> 8) >> 8) + 18)));
}

Now, look at the things we're doing with v2 and v3. Converting them to 8-bit unsigned integers, shifting them by 8...taking "byte 1"...etc. And it's all based on a1. Basically, this code is treating a1 not as one 32-bit integer, but as four 8-bit integers.

  • v2 is a1 converted to an unsigned byte. The effect that v2 is the least significant, ie: first, byte of a1. v3 is the remaining three bytes.
  • (unsigned __int8)v3 is the first byte of v3, making it the second byte of a1.
  • BYTE1(v3) uses a function/macro/whatever that is apparently built into IDA. It represents the second byte of v3, and the third byte of a1.
  • ((unsigned __int16)(v3 >> 8) >> 8) contains an unnecessary cast, a side effect of decompilation. (v3 is a 24-bit quantity in a 32-bit package, but the decompiler wasn't smart enough to remember that. So it added the cast in order to lop off the high byte, which is already provably zero.) It is equal to v3 >> 16, which is equivalent to a1 >> 24, and thus to the fourth byte of a1.

Let's add that observation to the code.

int sub_10001000(unsigned int a1, _DWORD * a2)
{
  unsigned __int16 v2;
  unsigned int v3;
  unsigned __int8 b0, b1, b2, b3;

  v2 = (unsigned __int8)a1;
  v3 = a1 >> 8;

  b0 = v2;
  b1 = (unsigned __int8) v3;
  b2 = (unsigned __int8) (a1 >> 16);
  b3 = (unsigned __int8) (a1 >> 24);

  return *(a2 + b0 + 786) + (*(a2 + b1 + 530) ^ (*(a2 + b2 + 274) + *(a2 + b3 + 18)));
}

C says that *(pointer + offset) and pointer[offset] are equivalent. Let's see if this increases readability any.

int sub_10001000(unsigned int a1, _DWORD * a2)
{
  unsigned __int16 v2;
  unsigned int v3;
  unsigned __int8 b0, b1, b2, b3;

  v2 = (unsigned __int8)a1;
  v3 = a1 >> 8;

  b0 = v2;
  b1 = (unsigned __int8) v3;
  b2 = (unsigned __int8) (a1 >> 16);
  b3 = (unsigned __int8) (a1 >> 24);

  return a2[b0 + 786] + (a2[b1 + 530] ^ (a2[b2 + 274] + a2[b3 + 18]));
}

So the formula even fits on one line now.

Now, since we no longer use v2 and v3 in the function (aside from calculating the byte values, and we can do that ourselves), we can get rid of them.

int sub_10001000(unsigned int a1, _DWORD * a2)
{
  unsigned __int8 b0, b1, b2, b3;

  b0 = a1;
  b1 = a1 >> 8;
  b2 = a1 >> 16;
  b3 = a1 >> 24;

  return a2[b0 + 786] + (a2[b1 + 530] ^ (a2[b2 + 274] + a2[b3 + 18]));
}

C has an 8-bit-integer type: uint8_t. And every modern C compiler knows about it. So we can get rid of these compiler-specific names.

Also, since C99, we can declare a variable where it's first initialized.

#include <stdint.h>

int sub_10001000(unsigned int a1, _DWORD * a2)
{
  uint8_t b0 = a1;
  uint8_t b1 = a1 >> 8;
  uint8_t b2 = a1 >> 16;
  uint8_t b3 = a1 >> 24;

  return a2[b0 + 786] + (a2[b1 + 530] ^ (a2[b2 + 274] + a2[b3 + 18]));
}

Notice now, also...when you put the numbers in order, any two adjacent numbers will have the same difference between them (256). And the first value is not at 0, but at 18. Looks like a2 is actually being treated as a pointer to a struct that looks somewhat like this (as far as we can see)...

struct example {
    DWORD unknown[18];
    DWORD w[256];
    DWORD x[256];
    DWORD y[256];
    DWORD z[256];
};

which would be used like...

#include <stdint.h>

int sub_10001000(unsigned int a1, struct example *ex)
{
    uint8_t b0 = a1;
    uint8_t b1 = a1 >> 8;
    uint8_t b2 = a1 >> 16;
    uint8_t b3 = a1 >> 24;

    return ex->z[b0] + (ex->y[b1] ^ (ex->x[b2] + ex->w[b3]));
}

But we can't know much more from this code alone -- including what the function is supposed to do -- so it's impossible to come up with much more meaningful names. The rest of the code should help with that.

  • Very interesting effort, cheers! – Abr001am Mar 8 '18 at 18:56
  • Do not forget that most optimizers deal with integer division by 2 directly by shifting to right, see here. – Abr001am Mar 8 '18 at 23:08
  • Thanks cHao for your lengthy explanation. It really helped me out and is much appreciated ! – henda79 Mar 9 '18 at 11:09
  • errrmm, how do I accept the answer ? There doesn't seem to be an option. – henda79 Mar 9 '18 at 11:10
  • 1
    Click the check mark next to an answer (near the vote buttons) to accept it. – cHao Mar 9 '18 at 12:25

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.