Extending the IDA Script Language
A First Stab
+ourtools
Our tools
27 January 1997
by Quine
+cracker
Courtesy of Fravia's page of reverse engineering
 
This present essay by Quine is -once more- the kind of work anyone is expecting from us: ameliorating and exstending the functionalities of our targets... just reversing protected proggies is getting dull, if we don't add anything.
Life is development, and development is progress (based on history and sound knowledge of the past... else it would be frills instead of progress :-) and progress is building for free on each others shoulders, out of the commercial dead ends where "they" want to push us.
You'll find here an ADDITION to the already incredible IDA disassembler (and if you are still just cracking with wdasm -believe me- you don't know what you are loosing) addition that will work immediatly if you have IDA's 'Quined' version, will require some fumbling if you -instead- have stolen the full regged one from the Web. Which suites us, since we want you to reverse engineer targets, not to steal them... man, it should be obvious!

So, let's hope you
1)have cracked ('quined') IDA demo
2) Have used it and got a little 'feeling'
3) Know how its 'internal' language works, at least a little.
Else leave this stuff and go play elsewhere.

Hope Pierre and his Russian Genius notice that we don't only take, we give too... Pierre, if you commercialize this, the minimum you can do is send a copy of your new IDA to Quine :-)
Also in:

+advanced
Advanced

crippled
Crippled

Related:

+progcor
Programmers

There is a crack, a crack in everything That's how the light gets in
Rating
( )Beginner ( )Intermediate (x)Advanced ( )Expert
NO beginners

A short tutorial on extending the IDC scripting language used by IDA.
Extending the IDA Script Language
A First Stab
Written by Quine
wvo_quine@hotmail.com

Introduction

Well, quite a long time ago I promised that I would write some extensions to IDA. Well, here's the first. mammon, who, by the way, knows a lot about IDA and has some great info on his web page, mentioned to me that he was looking for a way to display bitmap resources and the like from within IDA. This was in connection with his resource parser (written in IDC) for IDA. This, in turn, reminded me of an IDC extension I had wanted to do. The goal, then, is to add a command to IDC which lets you run another program. This would solve mammon's problem because IDC gives you the resources to create a bitmap file out of the resource data, but no way to run a viewer app. I want to add a command of the following form:

success Exec (char CommandLine);

This will simply execute the command line as a separate process. Since it's not possible as far as I know to implement this as a straightforward IDC function, we're going to have to hack ida.wll. I am in this essay assuming that you have the demo version with the load and file size cracks I have outlined previously on this site. Cracking the full version would just be a matter of recomputing some offsets. I'll leave that as an exercise to those who have the full version. Ok, here goes.



Tools required

IDA Pro 3.7 Demo
A Hex Editor

Target's URL/FTP

IDA Homepage in Russia

Program History

Please see my first two IDA essays:
quine1.htm
quine_21.htm



Essay

If you look at address 48BDF4 in ida.wll you'll see an array of structures that starts out like this:


dd offset aSegbyname

dd offset sub_40E914

dd offset unk_48CBD8

Let's have a look in the IDA SDK and see if we can find the declaration for this structure (even though it's pretty easy to figure out). You'll find it in expr.h:


typedef struct {		/* Element of functions table */

  const char near *name;	/* Name of function */

  error_t (*fp)(value_t *argv,value_t *res); /* Pointer to the Function */

  const char near *args;	/* Type of arguments. Terminated with 0 */

				/* VT_WILD means a function with arbitrary

				   number of arguments. Actual number of

				   arguments will be passed in res->num */

} extfun_t;

Now we need to find out what value_t is:


typedef struct {	/* Result of expression */

  char vtype;		/* Type			*/

#define  VT_STR		1

#define  VT_LONG	2

#define  VT_FLOAT	3

#define  VT_WILD	4	// used only in function arg type declarations

  union {

    char *str;		/* T_str  	*/

    long num;		/* T_long 	*/

    ushort e[6];	/* T_flt	*/

  };

} value_t;

Ok, so the structure specifies first, a pointer to the IDC command name, second, a pointer to the function that implements the command, and third, a pointer to information about how many what type of arguments the command takes. What we want to do is hijack one of the IDC commands and use it for own purposes. However, doing so would seem to be a problem because any other IDC script that uses the command we hijack will not work. I at first thought that I would just take one that wasn't used that often, but then I had a better idea. We just need to pass Exec one argument, the command line, but what if we take over a command that takes two arguments? For example,


success MakeName        (long ea,char name);

Now, an ea (Effective Address) that will pretty much never be passed to this function is FFFFFFFE (FFFFFFFF probably will be passed by buggy scripts because it is the value of BADADDR). So, for Exec, we'll take over MakeName and pass it FFFFFFFE as the first argument and the command line as the second. To do so, we'll re-route the function pointer in the array of extfun_t's to point to a function we'll add to the end of the code section. Our new function will first check to see if FFFFFFFE is passed as the first argument and if it isn't it'll immediately jump to the real MakeName function. So, now all we have to do is write our new function.

To run another process, the Win32 API provides the CreateProcess function. It takes 9 arguments, two of which are pointers to structures for which the caller has to allocate the memory. This is annoying because it means there's more we have to deal with. I thought about using the Borland run-time library function system, which takes only a command line. Unfortunately, system doesn't return until the new process terminates, so IDA is left hanging while our viewer or whatever is up. Further, when it does return, IDA won't recognize the mouse anymore. Fuck that. CreateProcess it is. I trust that everyone has got some sort of Win32 API reference (you can find them everywhere), so I won't go over CreateProcess, STARTUPINFO, or PROCESS_INFORMATION (these are the two structures we're going to have to create) in detail.

Alright, let's first work out how to get the parameters that are passed to the IDC function. Remember, according to the function definition in extfun_t, each idc function takes two pointers to value_t structures. The first pointer is actually a pointer to an array of value_t structures which has as many elements as there are arguments for the particular command. The second pointer is a pointer to a single value_t struct which will contain the result of the IDC command. Take a look at the real MakeName function.


idc_MakeName    proc near

                push    ebx

                mov     ebx, eax ; eax points to arg. value_t array

                push    esi

                mov     esi, edx ; edx points to result value_t

                mov     edx, [ebx+0Eh] ; the second argument

                mov     eax, [ebx+1] ; the first argument

                call    @set_name$qqrulpxc ; set_name(ulong,char *)

                mov     [esi+1], eax ; the result

                xor     eax, eax

                pop     esi

                pop     ebx

                retn

idc_MakeName    endp

This should be fairly straightforward. The only quirky thing is that every function (just about) in ida.wll uses the fastcall convention (see my first IDA essay) so the first three arguments always come in through registers rather than through the stack. One other thing I should mention is that the length of a value_t object is 13d bytes. One byte for the first member, and then 12d bytes for the union. A union is always as long as its longest member, which in this case is the 6 element array of words used for floating point arguments. That's why the second IDC argument is at offset 0Eh. Ok, the last thing to worry about is the call to CreateProcess. Most of the arguments to it can just be null because we don't want it to do anything fancy. All we're going to do is pass it the command line and two creation flags, CREATE_NEW_PROCESS_GROUP and CREATE_NEW_CONSOLE. The second flag will enable us to run separate console apps. However, we've got to allocate 10h byte for the PROCESS_INFORMATION structure and 44h bytes for the STARTUPINFO struct. This will be done on the stack which is infinitely easier than allocating from the free store. Furthermore, we'll zero out both of them with a call to memset and then all we need to fill in is the length of STARTUPINFO in the first dword of STARTUPINFO. The rest of the members can safely be left at zero. So, here's our code:




; is it a call to Exec or MakeName?

cmp [eax+1], 0fffffffeh ; 81 7c 20 01 fe ff ff ff

je exec                 ; 74 05

jmp MakeName            ; e9 d3 60 f8 ff

exec:

; set up stack and reserve 54h bytes for our structs

push ebp                ; 55

mov ebp, esp            ; 8b ec

sub esp, 54h            ; 81 c4 ac ff ff ff

; save esi and ebx

push esi                ; 56

push ebx                ; 53

; ebx = *res

mov ebx, edx            ; 89 d3

; esi = *CommandLine

mov esi, [eax+0eh]      ; 8b 70 0e

; zero out the structs

push 54h                ; 6a 54

push 0                  ; 6a 00

lea eax, [ebp-54h]      ; 8d 85 ac ff ff ff

push eax                ; 50

call _memset            ; e8 73 34 fa ff

; clean stack after memset

add esp, 0ch            ; 83 c4 0c

; move size of STARTUPINFO into struct

mov [ebp-44h], 44h      ; c7 85 bc ff ff ff 44 00 00 00

; this is where we start pushing the args to CreateProcess

; ptr to PROCESS_INFORMATION

lea eax, [ebp-54h]      ; 8d 85 ac ff ff ff

push eax                ; 50

; ptr to STARTUPINFO

add eax, 10h            ; 83 c0 10

push eax                ; 50

; unused

push 0                  ; 6a 00

push 0                  ; 6a 00

; our creation flags

push 210h               ; 68 10 02 00 00

; unused

push 0                  ; 6a 00

push 0                  ; 6a 00

push 0                  ; 6a 00

; ptr to CommandLine

push esi                ; 56

; unused

push 0                  ; 6a 00

call j_CreateProcess    ; e8 11 fe ff ff

; stick the return value into res.num

mov [ebx+1], eax        ; 89 43 01

; eax = 0 means function was successful

xor eax, eax            ; 33 c0

; clean up stack and that's it

pop ebx                 ; 5b

pop esi                 ; 5e

mov esp, ebp            ; 8b e5

pop ebp                 ; 5d

ret                     ; c3

The relative references are set up assuming that the code starts at VA 488886h, which is file offset 87E86h, which is right after the code I inserted for the load crack. If you want to put it somewhere else or you want to patch the full version, make sure to correct the one relative jump to MakeName and the calls to memset and CreateProcess.

The last thing to do is to patch the extfun_t array. The pointer to the real MakeName function is at 48BE1C, so put 00488886 into that location (in big endian order, of course).

Now, typing MakeName (0xfffffffe, "notepad.exe") each time we want to use Exec in a script is annoying and makes the code less readable. So, let's use a preprocessor define to fix it up:


#define Exec(x) MakeName(0xfffffffe, x)

Put this into idc.idc somewhere and you can use Exec as I originally wanted:


Exec("notepad.exe");

So, let's test it. Create the following IDC script and run it:


#include <idc.idc>

#define Exec(x) MakeName(0xfffffffe, x)



static main () {

Exec("notepad.exe");

}

Look! There's the Notepad. It works. That's it.

One more thing. You can pass whatever you want on the command line, but remember to escape special characters (quotes, backslashes, etc.) with a backslash.

Quine, January 1998
You are deep inside fravia's page of reverse engineering, choose your way out:

+ourtools
Our tools
redhomepage redlinks redanonymity +ORC redstudents' essays redacademy database
redtools redJavascript wars redcocktails redantismut CGI-scripts redsearch_forms redmail_fravia+
redIs reverse engineering legal?