Search code examples
pythoncdecompilingida

How to use decompiled C function from IDA in Python code?


I took this C function from the decompiling (F5) option on IDA.

I want to use it in my Python program, how can I do this in the easiest way?

__int64 __fastcall manipulateBeforSend(__int64 a1, int a2)
{
  int v2; // w0
  __int64 result; // x0
  int i; // [xsp+1Ch] [xbp-4h]

  for ( i = 0; i < a2 - 3; i += 4 )
    *(_DWORD *)(a1 + 4LL * (i / 4)) ^= 0xDEAD1337;// leet? XOR 
  while ( 1 )
  {
    result = (unsigned int)a2;
    if ( i >= a2 )
      break;
    LOBYTE(v2) = i & 3;
    if ( i <= 0 )
      v2 = -(-i & 3);
    *(_BYTE *)(a1 + i++) ^= 0xDEAD1337 >> 8 * v2;
  }
  return result;
}

@Marco Bonelli, you help me a lot, Thanks! But I keep get those errors:

manipulate.c:1:0: warning: -fPIC ignored for target (all code is position independent)
 #include <stdint.h>
 ^
In file included from C:/TDM-GCC-64/x86_64-w64-mingw32/include/crtdefs.h:10:0,
                 from C:/TDM-GCC-64/x86_64-w64-mingw32/include/stdint.h:28,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/stdint.h:9,
                 from manipulate.c:1:
manipulate.c:4:17: error: two or more data types in declaration specifiers
 typedef int64_t __int64;
                 ^
manipulate.c:4:17: error: two or more data types in declaration specifiers
 typedef int64_t __int64;
                 ^
manipulate.c:4:1: warning: useless type name in empty declaration
 typedef int64_t __int64;
 ^

Solution

  • This is a "quick" solution:

    1. First, use typedef to define the types used by IDA:

      #include <stdint.h>
      
      typedef uint8_t _BYTE;
      typedef int64_t __int64;
      typedef uint32_t _DWORD;
      

      You could also do this from IDA through "File"->"Produce file"->"Create C header file", but since there types are just a few it's simpler to do it by hand in this case.

    2. Then replace unneeded macros/values with working code:

      __int64 __fastcall manipulateBeforSend(__int64 a1, int a2)
      // remove __fastcall:
      __int64 manipulateBeforSend(__int64 a1, int a2)
      
      
      LOBYTE(v2) = i & 3;
      // convert using a bit mask:
      v2 = (v2 & 0xffffff00) | (i & 3);
      
    3. There is a problem now: as @Ctx makes us notice, your C code is dereferencing the first argument, most likely because it is a uint32_t* pointer, and not just an int64:

      *(_DWORD *)(a1 + 4LL * (i / 4))
      // and also 
      *(_BYTE *)(a1 + i++) ^= 0xDEAD1337 >> 8 * v2;
      

      You should probably spend more time reverse-engineering what that pointer is used for first. To get around this issue, you could create a fake array and add it to your C code in order to make it work, like this:

      static uint32_t fakearr[1024 * 1024] = {0};
      
      __int64 manipulateBeforSend(int a2)
      {
        uint32_t *a1 = fakearr;
        // ...
      

      Of course, in general you would probably want to use a real array, you can take a look at this answer for that.

    4. Then put all the (working) code inside a .c file:

      #include <stdint.h>
      
      typedef uint8_t _BYTE;
      typedef int64_t __int64;
      typedef uint32_t _DWORD;
      
      uint32_t fakearr[1024 * 1024] = {0};
      
      __int64 manipulateBeforSend(int a2)
      {
        uint32_t *a1 = fakearr;
      
        int v2; // w0
        __int64 result; // x0
        int i; // [xsp+1Ch] [xbp-4h]
      
        for ( i = 0; i < a2 - 3; i += 4 )
          *(_DWORD *)(a1 + 4LL * (i / 4)) ^= 0xDEAD1337;// leet? XOR
        while ( 1 )
        {
          result = (unsigned int)a2;
          if ( i >= a2 )
            break;
          v2 = (v2 & 0xffffff00) | (i & 3);
          if ( i <= 0 )
            v2 = -(-i & 3);
          *(_BYTE *)(a1 + i++) ^= 0xDEAD1337 >> 8 * v2;
        }
        return result;
      }
      
    5. Compile the code as a shared library:

      gcc -fPIC -shared -o mylib.so mylib.c
      
    6. Now you can load it from Python using the ctypes module:

      >>> from ctypes import cdll, c_int32
      >>> mylib = cdll.LoadLibrary('./mylib.so')
      >>> mylib.manipulateBeforSend(c_int32(1))
      1