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.
Please see my first two IDA essays:
quine1.htm
quine_21.htm
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