0

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;
 ^
sz555
  • 7
  • 3
  • [Start](https://docs.python.org/3/extending/extending.html) from here? – Abdul Niyas P M Jan 17 '20 at 13:42
  • 2
    @sz555 - What do you mean by _use it in my Python program_ - call it from your program, or translate it to Python and include the translation? – Armali Jan 17 '20 at 13:52
  • This seems to include pointers to memory locations, which are passed as function arguments. I think its hard to convert that to python code or call it from python – Ctx Jan 17 '20 at 13:57
  • Do note that although decompilers generally do a good job of producing source code that corresponds to the binary, they do a crummy job of reproducing the original source code from which the binary was built. It's not really their fault: even with debug information, when available, they don't have nearly enough information. This makes typical decompiler output difficult to read and somewhat obscure. My first step is usually to analyze the code so as to rewrite it to equivalent code with with meaningful variable names, appropriate data types, and good style. – John Bollinger Jan 17 '20 at 14:22
  • @JohnBollinger, that what I trying to do with all the other code, rewrite it in Python. But I find it difficult to do it with this function. You can help? – sz555 Jan 17 '20 at 14:35
  • If rewriting the function in Python is what you're actually after then Marco's response is of little help to you after all, and trying to sort out the compilation errors you observed is a waste of time. Please edit the question to clarify what you are really asking. – John Bollinger Jan 17 '20 at 14:42

1 Answers1

2

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
    
Marco Bonelli
  • 48,251
  • 16
  • 95
  • 101
  • 1
    You present a generic method for calling c code from python, and this is as such useful. But I think, not in this particular case, since the arguments are used as pointers and those are dereferenced, so there is no way to pass sensible arguments from python level. – Ctx Jan 17 '20 at 13:59
  • @Ctx you're right. Let me edit my answer. – Marco Bonelli Jan 17 '20 at 14:01
  • @MarcoBonelli, Thanks a lot! I keep getting error. You can look at my edited post, please? – sz555 Jan 17 '20 at 14:20
  • @sz555 you have some kind of copy-paste error. The code I posted works *as is*. – Marco Bonelli Jan 17 '20 at 14:22
  • I think not, @MarcoBonelli. The OP's error messages suggest that `__int64` is already a type in their implementation. It's probably a built-in one, but it could also be a typedef defined by their implementation's `stdint.h`. Identifiers beginning with two underscores are reserved for implementation use, so C sources should not attempt to `typedef` them. – John Bollinger Jan 17 '20 at 14:26
  • @JohnBollinger hmm, I don't see any meaningful definition of `__int64` in the libc source code. Anyway, yes that's true, double underscore names are reserved. @sz555 you can replace types by hand instead of using `typedef` if that is a problem. – Marco Bonelli Jan 17 '20 at 14:33
  • @MarcoBonelli, I'm just reading the error messages, but I've no idea how you could be reading ***the*** libc source code, since each implementation provides its own. Certainly the identifier `__int64` has a form that some implementations use internally. – John Bollinger Jan 17 '20 at 14:39
  • MarcoBonelli & JohnBollinger, thank you! It compiled now, I will try to use it now in my Python. – sz555 Jan 17 '20 at 14:41
  • @sz555 take note that my question is a general suggestion rather than a definive solution to your problem. It is likely that you will need to do more reverse engineering to solve any further problem. – Marco Bonelli Jan 17 '20 at 14:43