├── .github └── CODEOWNERS ├── LICENSE ├── README.md ├── buffer.cpp ├── buffer.h ├── display.cpp ├── display.h ├── mIDA.sln ├── mIDA.vcproj ├── mida.cpp ├── mida_res.rc ├── midl.cpp ├── midl.h ├── midl_decompile.cpp ├── midl_decompile.h ├── midl_scan.cpp ├── midl_scan.h ├── nessus_logo_16x16.ico ├── parser.cpp ├── parser.h ├── resource.h ├── tracer.cpp ├── tracer.h ├── window.cpp └── window.h /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @tenable/infosec 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2018 Tenable Network Security. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Tenable Network Security nor the names of its contributors 13 | may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL TENABLE NETWORK SECURITY BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 22 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 24 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 25 | OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------ 2 | mIDA v1.0.10 - MIDL Decompiler for IDA 3 | 4 | (C) 2008 Nicolas Pouvesle / Tenable Network Security 5 | ------------------------------------------------------------------------------------ 6 | 7 | 8 | WHAT IS mIDA? 9 | 10 | mIDA is an IDA plugin which extracts RPC interfaces and recreates 11 | the associated IDL file. 12 | mIDA supports inline, interpreted and fully interpreted server stubs. 13 | 14 | 15 | INSTALLATION 16 | 17 | Just copy mida.plw to your IDA plugin directory. 18 | 19 | 20 | HOW TO USE IT? 21 | 22 | mIDA only works with the Windows GUI version of IDA (5.2 or later). 23 | The plugin can be launched via the plugin menu or by using the shortcut 24 | CTRL+7. 25 | 26 | mIDA displays each interface inside a separate list dialog box. 27 | Each function can be edited or decompiled (right click). 28 | Format string addresses must only be changed if you suspect that 29 | mIDA does not use the correct entry. 30 | 31 | 32 | NOTE: mIDA can save the output to a file instead of using windows 33 | when the 'ofile' option is given. 34 | 35 | 36 | CHANGELOG 37 | 38 | v1.0.10 39 | ------ 40 | 41 | - Adds support for NDR version 0x50004 42 | 43 | v1.0.9 44 | ------ 45 | 46 | - Really fix FC_XSTRUCT with FC_ALIGNMX element (Thanks to Cody Pierce) 47 | - Add debug statements if the key "HKLM\SOFTWARE\Tenable\mIDA - Debug" is set to 1 48 | 49 | v1.0.8 50 | ------ 51 | 52 | - Display [ref] if set 53 | - Fix FC_XSTRUCT with FC_ALIGNMX element (Thanks to Cody Pierce) 54 | 55 | v1.0.7 56 | ------ 57 | 58 | - Add support for FC_CVSTRUCT 59 | - Ndr version 0x10001 can be an interpreted stub too 60 | - Fix encapsulated union display to work with midl.exe 61 | 62 | v1.0.6 63 | ------ 64 | 65 | - Fix an access violation error if the NDR version is not supported (Thanks to Alexander Sotirov) 66 | - Fix Union if multiple cases refer to the same element 67 | - Fix field reference if the structure contains an encapsulated union 68 | - Add support for FC_USER_MARSHAL attribute (just display the size to send) 69 | - Add support for NDR version 0x60001 used in Vista: 70 | * Add support for FC_SUPPLEMENT 71 | * Add support for FC_FORCED_BOGUS_STRUCT 72 | * Add support for FC_EXPR (complex size_is/length_is are now encoded using a Reverse Polish Notation) 73 | * Add support for new range type 74 | 75 | 76 | v1.0.5 77 | ------ 78 | 79 | - Bugfix for special return values for inline stubs 80 | 81 | v1.0.4 82 | ------ 83 | 84 | - Display FC_CALLBACK address instead of '?' 85 | - Generated IDL code can now be compiled with a midl compiler 86 | - FC_ENUM16 is now displayed as a short 87 | - Add support for obsolete keywords FC_ALIGNMX 88 | - Add support for FC_BYTE_COUNT_POINTER 89 | - Fix function name if a pdb file is used in IDA 90 | - Fix the address of the argument structure in the edit box 91 | - Wait that IDA has processed enerything in the queues before scanning 92 | - If RPC functions are not defined as function, ask IDA to define them (useful for inline functions) 93 | - Raise an Exception if the loop recursion limit is reached 94 | - Display information about the RPC stub in the decompilation window 95 | - Added ofile option for bash mode 96 | - Ported to IDA5.0 97 | 98 | v1.0.3 99 | ------ 100 | 101 | - Call msg instead of error if the plugin is skipped (else it closes IDA) 102 | 103 | v1.0.2 104 | ------ 105 | 106 | - Bugfix with some arguments 107 | 108 | v1.0.1 109 | ------ 110 | 111 | - Display the opcode in the IDL output 112 | 113 | v1.0.0 114 | ------ 115 | 116 | - Initial release -------------------------------------------------------------------------------- /buffer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include "buffer.h" 8 | #include "kernwin.hpp" 9 | #include "pro.h" 10 | 11 | buffer * init_buffer () 12 | { 13 | buffer * output_buffer; 14 | 15 | output_buffer = (buffer *) qalloc (sizeof(*output_buffer)); 16 | if (!output_buffer) 17 | { 18 | msg ("Error while allocating buffer structure, exiting.\n"); 19 | return NULL; 20 | } 21 | 22 | output_buffer->buffer = (char *) qalloc (1000); 23 | if (!output_buffer) 24 | { 25 | msg ("Error while allocating buffer, exiting.\n"); 26 | qfree (output_buffer); 27 | return NULL; 28 | } 29 | output_buffer->buffer[0] = '\0'; 30 | output_buffer->size = 1000; 31 | 32 | return output_buffer; 33 | } 34 | 35 | void free_buffer (buffer * buffer) 36 | { 37 | qfree (buffer->buffer); 38 | qfree (buffer); 39 | } 40 | 41 | 42 | void buffer_add_message (buffer * buffer, char * message) 43 | { 44 | char * tmp; 45 | 46 | while ((strlen (buffer->buffer) + strlen(message) + 1) > buffer->size) 47 | { 48 | tmp = (char *)qrealloc (buffer->buffer, buffer->size * 2); 49 | if (!tmp) 50 | { 51 | msg ("Memory allocation error durgin buffer_add_message.\n"); 52 | return; 53 | } 54 | 55 | buffer->buffer = tmp; 56 | buffer->size = buffer->size * 2; 57 | } 58 | 59 | qstrncat (buffer->buffer, message, buffer->size); 60 | } 61 | -------------------------------------------------------------------------------- /buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #ifndef _buffer_H_ 8 | #define _buffer_H_ 9 | 10 | typedef struct _buffer { 11 | char * buffer; 12 | size_t size; 13 | } buffer; 14 | 15 | 16 | buffer * init_buffer (); 17 | void free_buffer (buffer *); 18 | void buffer_add_message (buffer *, char *); 19 | 20 | #endif -------------------------------------------------------------------------------- /display.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include "display.h" 8 | #include "parser.h" 9 | #include "kernwin.hpp" 10 | 11 | 12 | void display_data (midl_arg_struct * arg, char * data) 13 | { 14 | qstrncat ((char *)arg->line_string, data, sizeof(arg->line_string)); 15 | } 16 | 17 | void display_pad (midl_arg_struct * arg) 18 | { 19 | char * ptr = NULL; 20 | 21 | switch(arg->type) 22 | { 23 | case FC_ALIGNM2: 24 | ptr = "FC_ALIGNM2"; 25 | break; 26 | case FC_ALIGNM4: 27 | ptr = "FC_ALIGNM4"; 28 | break; 29 | case FC_ALIGNM8: 30 | ptr = "FC_ALIGNM8"; 31 | break; 32 | case FC_STRUCTPAD1: 33 | ptr = "FC_STRUCTPAD1"; 34 | break; 35 | case FC_STRUCTPAD2: 36 | ptr = "FC_STRUCTPAD2"; 37 | break; 38 | case FC_STRUCTPAD3: 39 | ptr = "FC_STRUCTPAD3"; 40 | break; 41 | case FC_STRUCTPAD4: 42 | ptr = "FC_STRUCTPAD4"; 43 | break; 44 | case FC_STRUCTPAD5: 45 | ptr = "FC_STRUCTPAD5"; 46 | break; 47 | case FC_STRUCTPAD6: 48 | ptr = "FC_STRUCTPAD6"; 49 | break; 50 | case FC_STRUCTPAD7: 51 | ptr = "FC_STRUCTPAD7"; 52 | break; 53 | default: 54 | ptr = "UNKNOWN PAD"; 55 | } 56 | 57 | qsnprintf ((char *)arg->line_string, sizeof(arg->line_string), "/* %s */", ptr); 58 | } 59 | 60 | void display_unique (midl_arg_struct * arg) 61 | { 62 | if (arg->is_unique) 63 | display_data (arg, (char *)"[unique]"); 64 | } 65 | 66 | void display_reference (midl_arg_struct * arg) 67 | { 68 | if (arg->is_reference) 69 | display_data (arg, (char *)"[ref]"); 70 | } 71 | 72 | void display_ptr_ref (midl_arg_struct * arg) 73 | { 74 | if (arg->is_ptr) 75 | display_data (arg, (char *)"[ptr]"); 76 | } 77 | 78 | void display_string (midl_arg_struct * arg) 79 | { 80 | if (arg->is_string) 81 | display_data (arg, (char *)"[string]"); 82 | } 83 | 84 | unsigned int get_arg_number (function_parameter * args, unsigned int arg_num, unsigned long offset) 85 | { 86 | unsigned int i; 87 | 88 | for (i=0; i< arg_num; i++) 89 | { 90 | if (args[i].stack == offset) 91 | return i+1; 92 | } 93 | 94 | msg ("Error : unknown argument in get_arg_number !\n"); 95 | return 0; 96 | } 97 | 98 | unsigned int get_field_number (midl_structure * mstruct, unsigned long offset) 99 | { 100 | unsigned int i=0; 101 | midl_arg_struct_list * ptr = mstruct->elem; 102 | 103 | while (ptr) 104 | { 105 | if (!ptr->arg->is_pad) 106 | { 107 | if (ptr->arg->struct_offset == offset) 108 | return i+1; 109 | i++; 110 | } 111 | 112 | ptr = ptr->next; 113 | } 114 | 115 | msg ("Error : unknown field in get_field_number 0x%.8X !\n", mstruct->offset); 116 | ptr = mstruct->elem; 117 | 118 | return 0; 119 | } 120 | 121 | 122 | char* asprintf(const char *format, ...) 123 | { 124 | char * buf; 125 | unsigned long l; 126 | va_list argptr; 127 | va_start(argptr, format); 128 | 129 | 130 | 131 | l = _vscprintf(format, argptr); 132 | 133 | buf = (char*) malloc (l + 1); 134 | if (!buf) 135 | return NULL; 136 | 137 | _vsnprintf (buf, l+1, format, argptr); 138 | 139 | return buf; 140 | } 141 | 142 | 143 | char * display_expr (ea_t * pos, bool first, midl_arg_struct * arg, function_parameter * args, unsigned int arg_num, midl_structure * mstruct, int struct_type) 144 | { 145 | char * rexp, * lexp, * gexp; 146 | unsigned long l; 147 | 148 | expression exp; 149 | 150 | exp.expr_type = get_byte2 (pos); 151 | exp.expr_subtype = get_byte2 (pos); 152 | exp.offset = get_word2 (pos); 153 | 154 | if (exp.expr_type == FC_EXPR_OPER) 155 | { 156 | if (exp.expr_subtype < 1 || exp.expr_subtype > 0x26) 157 | { 158 | return asprintf ("%s", "unknown operation type"); 159 | } 160 | switch (exp.expr_subtype) 161 | { 162 | case OP_UNARY_PLUS: 163 | case OP_UNARY_MINUS: 164 | case OP_UNARY_NOT: 165 | case OP_UNARY_COMPLEMENT: 166 | case OP_UNARY_INDIRECTION: 167 | rexp = display_expr (pos, false, arg, args, arg_num, mstruct, struct_type); 168 | gexp = asprintf ("%s%s", op_unary_types[exp.expr_subtype], rexp); 169 | if (rexp) 170 | free (rexp); 171 | break; 172 | case OP_PRE_INCR: 173 | case OP_PRE_DECR: 174 | rexp = display_expr (pos, false, arg, args, arg_num, mstruct, struct_type); 175 | gexp = asprintf ("%s%s", op_cr_types[exp.expr_subtype - OP_PRE_INCR], rexp); 176 | if (rexp) 177 | free (rexp); 178 | break; 179 | case OP_POST_INCR: 180 | case OP_POST_DECR: 181 | rexp = display_expr (pos, false, arg, args, arg_num, mstruct, struct_type); 182 | gexp = asprintf ("%s%s", rexp, op_cr_types[exp.expr_subtype]); 183 | if (rexp) 184 | free (rexp); 185 | break; 186 | case OP_UNARY_CAST: 187 | rexp = display_expr (pos, false, arg, args, arg_num, mstruct, struct_type); 188 | gexp = asprintf ("(%s)%s", get_base_type(exp.offset), rexp); 189 | if (rexp) 190 | free (rexp); 191 | break; 192 | case OP_PLUS: 193 | case OP_MINUS: 194 | case OP_STAR: 195 | case OP_SLASH: 196 | case OP_MOD: 197 | case OP_LEFT_SHIFT: 198 | case OP_RIGHT_SHIFT: 199 | case OP_LESS: 200 | case OP_LESS_EQUAL: 201 | case OP_GREATER_EQUAL: 202 | case OP_GREATER: 203 | case OP_EQUAL: 204 | case OP_NOT_EQUAL: 205 | case OP_AND: 206 | case OP_OR: 207 | case OP_XOR: 208 | case OP_LOGICAL_AND: 209 | case OP_LOGICAL_OR: 210 | lexp = display_expr (pos, false, arg, args, arg_num, mstruct, struct_type); 211 | rexp = display_expr (pos, false, arg, args, arg_num, mstruct, struct_type); 212 | if (first) 213 | gexp = asprintf ("%s %s %s", lexp, op_types[exp.expr_subtype - OP_PLUS], rexp); 214 | else 215 | gexp = asprintf ("(%s %s %s)", lexp, op_types[exp.expr_subtype - OP_PLUS], rexp); 216 | if (lexp) 217 | free (lexp); 218 | if (rexp) 219 | free (rexp); 220 | break; 221 | default: 222 | return asprintf ("%s", "unsupported operation type"); 223 | } 224 | 225 | return gexp; 226 | } 227 | else if (exp.expr_type == FC_EXPR_VAR) 228 | { 229 | if (args) 230 | return asprintf ("arg_%d", get_arg_number (args, arg_num, exp.offset)); 231 | else if (mstruct &&(struct_type == 1)) 232 | return asprintf ("elem_%d", get_field_number (mstruct, arg->struct_offset + exp.offset)); 233 | else 234 | return asprintf ("elem_%d", get_field_number (mstruct, exp.offset)); 235 | } 236 | else if (exp.expr_type == FC_EXPR_CONST32) 237 | { 238 | if (exp.expr_subtype != FC_LONG) 239 | { 240 | msg ("unsupported subtype for FC_EXPR_CONST32"); 241 | return NULL; 242 | } 243 | else 244 | { 245 | l = get_long2 (pos); 246 | return asprintf ("%u", l); 247 | } 248 | } 249 | else 250 | { 251 | return asprintf ("%s", "unknown expression type"); 252 | } 253 | } 254 | 255 | 256 | void display_sarg (midl_arg_struct * arg, char * buf, size_t size, sarray_arg * sarg, function_parameter * args, unsigned int arg_num, midl_structure * mstruct, ea_t callback_table, ea_t expr_table) 257 | { 258 | unsigned long l; 259 | char tmp[100]; 260 | char * data; 261 | ea_t pos; 262 | 263 | if (sarg->flags & FLAG_CONSTANT) 264 | { 265 | l = sarg->arg.cons.size[1] + sarg->arg.cons.size[2]*256 + sarg->arg.cons.size[0]*256*256; 266 | qsnprintf (buf, size, (char *)"%u", l); 267 | } 268 | else if (sarg->flags & FLAG_PARAMETER) 269 | { 270 | if (!args) 271 | { 272 | msg ("Error: bug in display_sarg, FLAG_PARAMETER is used in non argument function !\n"); 273 | qsnprintf (buf, size, (char *)"unknown"); 274 | } 275 | 276 | else if (sarg->arg.var.type == FC_CALLBACK) 277 | qsnprintf (buf, size, (char *)"callback_0x%.8X", get_callback_address(sarg->arg.var.offset, callback_table)); 278 | else if (sarg->arg.var.type == FC_EXPR) 279 | { 280 | if (expr_table == BADADDR) 281 | { 282 | msg ("Error: FC_EXPR type found but expr_table is NULL.\n"); 283 | return; 284 | } 285 | 286 | pos = expr_table + sarg->arg.var.offset; 287 | data = display_expr (&pos, true, arg, args, arg_num, NULL, 0); 288 | qsnprintf (buf, size, (char *)data); 289 | 290 | if (data) 291 | free (data); 292 | } 293 | else 294 | { 295 | if (sarg->arg.var.type == FC_DEREFERENCE) 296 | qstrncat (buf, (char *) "*", size); 297 | 298 | qsnprintf ((char *) tmp, sizeof(tmp), "arg_%d", get_arg_number (args, arg_num, sarg->arg.var.offset)); 299 | qstrncat (buf, (char *) tmp, size); 300 | 301 | if (sarg->arg.var.type == FC_DIV_2) 302 | qstrncat (buf, (char *) "/2", size); 303 | if (sarg->arg.var.type == FC_MULT_2) 304 | qstrncat (buf, (char *) "*2", size); 305 | if (sarg->arg.var.type == FC_ADD_1) 306 | qstrncat (buf, (char *) "/2", size); 307 | if (sarg->arg.var.type == FC_SUB_1) 308 | qstrncat (buf, (char *) "/2", size); 309 | } 310 | } 311 | else if (sarg->flags & FLAG_FIELD) 312 | { 313 | if (!mstruct) 314 | { 315 | msg ("Error: bug in display_sarg, FLAG_FIELD is used in non structure element !\n"); 316 | qsnprintf (buf, size, (char *)"unknown"); 317 | } 318 | 319 | else if (sarg->arg.var.type == FC_CALLBACK) 320 | qsnprintf (buf, size, (char *)"callback_0x%.8X", get_callback_address(sarg->arg.var.offset, callback_table)); 321 | else if (sarg->arg.var.type == FC_EXPR) 322 | { 323 | if (expr_table == BADADDR) 324 | { 325 | msg ("Error: FC_EXPR type found but expr_table is NULL.\n"); 326 | return; 327 | } 328 | 329 | pos = expr_table + sarg->arg.var.offset; 330 | data = display_expr (&pos, true, arg, NULL, arg_num, mstruct, 0); 331 | qsnprintf (buf, size, (char *)data); 332 | 333 | if (data) 334 | free (data); 335 | } 336 | else 337 | { 338 | if (sarg->arg.var.type == FC_DEREFERENCE) 339 | qstrncat (buf, (char *) "*", size); 340 | 341 | qsnprintf ((char *) tmp, sizeof(tmp), "elem_%d", get_field_number (mstruct, sarg->arg.var.offset)); 342 | qstrncat (buf, (char *) tmp, size); 343 | 344 | if (sarg->arg.var.type == FC_DIV_2) 345 | qstrncat (buf, (char *) "/2", size); 346 | if (sarg->arg.var.type == FC_MULT_2) 347 | qstrncat (buf, (char *) "*2", size); 348 | if (sarg->arg.var.type == FC_ADD_1) 349 | qstrncat (buf, (char *) "/2", size); 350 | if (sarg->arg.var.type == FC_SUB_1) 351 | qstrncat (buf, (char *) "/2", size); 352 | } 353 | } 354 | else if (mstruct) 355 | { 356 | if (sarg->arg.var.type == FC_CALLBACK) 357 | qsnprintf (buf, size, (char *)"callback_0x%.8X", get_callback_address(sarg->arg.var.offset, callback_table)); 358 | else if (sarg->arg.var.type == FC_EXPR) 359 | { 360 | if (expr_table == BADADDR) 361 | { 362 | msg ("Error: FC_EXPR type found but expr_table is NULL.\n"); 363 | return; 364 | } 365 | 366 | pos = expr_table + sarg->arg.var.offset; 367 | data = display_expr (&pos, true, arg, NULL, arg_num, mstruct, 1); 368 | qsnprintf (buf, size, (char *)data); 369 | 370 | if (data) 371 | free (data); 372 | } 373 | else 374 | { 375 | if (sarg->arg.var.type == FC_DEREFERENCE) 376 | qstrncat (buf, (char *) "*", size); 377 | 378 | qsnprintf ((char *) tmp, sizeof(tmp), "elem_%d", get_field_number (mstruct, arg->struct_offset + sarg->arg.var.offset)); 379 | qstrncat (buf, (char *) tmp, size); 380 | 381 | if (sarg->arg.var.type == FC_DIV_2) 382 | qstrncat (buf, (char *) "/2", size); 383 | if (sarg->arg.var.type == FC_MULT_2) 384 | qstrncat (buf, (char *) "*2", size); 385 | if (sarg->arg.var.type == FC_ADD_1) 386 | qstrncat (buf, (char *) "/2", size); 387 | if (sarg->arg.var.type == FC_SUB_1) 388 | qstrncat (buf, (char *) "/2", size); 389 | } 390 | } 391 | else 392 | { 393 | msg ("Error: bug in display_sarg, unknown reference type !\n"); 394 | qsnprintf (buf, size, (char *)"unknown"); 395 | } 396 | 397 | } 398 | 399 | void display_ssize (midl_arg_struct * arg, sarray_struct * sstruct, function_parameter * args, unsigned int arg_num, midl_structure * mstruct, ea_t callback_table, ea_t expr_table) 400 | { 401 | unsigned char tmp[100]; 402 | 403 | if (sstruct->is_byte_count) 404 | { 405 | tmp[0] = '\0'; 406 | display_data (arg, (char *)"byte_count("); 407 | display_sarg (arg, (char*)tmp, sizeof(tmp), &sstruct->byte_count, args, arg_num, mstruct, callback_table, expr_table); 408 | display_data (arg, (char *)tmp); 409 | display_data (arg, (char *)")"); 410 | } 411 | if (sstruct->is_size) 412 | { 413 | tmp[0] = '\0'; 414 | display_data (arg, (char *)"size_is("); 415 | display_sarg (arg, (char*)tmp, sizeof(tmp), &sstruct->size, args, arg_num, mstruct, callback_table, expr_table); 416 | display_data (arg, (char *)tmp); 417 | display_data (arg, (char *)")"); 418 | } 419 | if (sstruct->is_length) 420 | { 421 | tmp[0] = '\0'; 422 | display_data (arg, (char *)", length_is("); 423 | display_sarg (arg, (char*)tmp, sizeof(tmp), &sstruct->length, args, arg_num, mstruct, callback_table, expr_table); 424 | display_data (arg, (char *)tmp); 425 | display_data (arg, (char *)")"); 426 | } 427 | 428 | } 429 | 430 | void display_size (midl_arg_struct * arg, function_parameter * args, unsigned int arg_num, midl_structure * mstruct, ea_t callback_table, ea_t expr_table) 431 | { 432 | unsigned int i; 433 | sarray_struct * sstruct; 434 | 435 | for (i = 0; i < arg->sstruct_num; i++) 436 | { 437 | sstruct = &arg->sstruct[i]; 438 | 439 | display_data (arg, (char *)"["); 440 | display_ssize (arg, sstruct, args, arg_num, mstruct, callback_table, expr_table); 441 | display_data (arg, (char *)"]"); 442 | } 443 | } 444 | 445 | void display_union (midl_arg_struct * arg, function_parameter * args, unsigned int arg_num, midl_structure * mstruct, ea_t callback_table, ea_t expr_table) 446 | { 447 | unsigned int i; 448 | char tmp[100]; 449 | 450 | for (i = 0; i < arg->sunion_num; i++) 451 | { 452 | tmp[0] = '\0'; 453 | display_data (arg, (char *)"[switch_is("); 454 | display_sarg (arg, (char*)tmp, sizeof(tmp), &arg->sunion[i], args, arg_num, mstruct, callback_table, expr_table); 455 | display_data (arg, (char *)tmp); 456 | display_data (arg, (char *)")]"); 457 | } 458 | } 459 | 460 | 461 | void display_handle (midl_arg_struct * arg) 462 | { 463 | if (arg->is_context) 464 | display_data (arg, (char *)"[context_handle]"); 465 | } 466 | 467 | void display_pipe (midl_arg_struct * arg) 468 | { 469 | if (arg->is_pipe) 470 | display_data (arg, (char *)" pipe"); 471 | } 472 | 473 | void display_user_marshal (midl_arg_struct * arg) 474 | { 475 | char tmp[100]; 476 | 477 | if (arg->is_user_marshal) 478 | { 479 | qsnprintf ((char *) tmp, sizeof(tmp), "[user_marshal(%u)]", arg->user_marshal_size); 480 | display_data (arg, (char *)tmp); 481 | } 482 | } 483 | 484 | void display_type (midl_arg_struct * arg) 485 | { 486 | display_data (arg, (char *)arg->type_name); 487 | } 488 | 489 | void display_ptr (midl_arg_struct * arg) 490 | { 491 | unsigned int i; 492 | 493 | for (i=0; iptr_num; i++) 494 | display_data (arg, (char *)"*"); 495 | 496 | if (arg->ptr_num > 0) 497 | display_data (arg, (char *)" "); 498 | } 499 | 500 | void display_arg (midl_arg_struct * arg) 501 | { 502 | display_data (arg, (char *)arg->arg_name); 503 | } 504 | 505 | void display_range (midl_arg_struct * arg) 506 | { 507 | char tmp[100]; 508 | 509 | if ((arg->is_range) && !arg->is_context) 510 | { 511 | qsnprintf ((char *)tmp, sizeof(tmp), "[range(%d,%d)]", arg->range.begin, arg->range.end); 512 | display_data (arg, (char *)tmp); 513 | } 514 | } 515 | 516 | 517 | void display_array (midl_arg_struct * arg) 518 | { 519 | unsigned int i; 520 | char tmp[20]; 521 | 522 | for (i=arg->sstruct_num; i>arg->ptr_num; i--) 523 | display_data (arg, (char *)"[]"); 524 | 525 | for (i=0; iarray_num; i++) 526 | { 527 | qsnprintf ((char *)tmp, sizeof(tmp), "[%u]", arg->astruct[i].size); 528 | display_data (arg, (char *) tmp); 529 | } 530 | } 531 | 532 | 533 | void arg_struct_to_string (midl_arg_struct * arg, function_parameter * args, unsigned int arg_num, midl_structure * mstruct, ea_t callback_table, ea_t expr_table) 534 | { 535 | if (arg->is_pad) 536 | { 537 | display_pad(arg); 538 | } 539 | else 540 | { 541 | display_unique (arg); 542 | display_reference (arg); 543 | display_ptr_ref (arg); 544 | display_range (arg); 545 | display_union (arg, args, arg_num, mstruct, callback_table, expr_table); 546 | display_string (arg); 547 | display_size (arg, args, arg_num, mstruct, callback_table, expr_table); 548 | display_handle (arg); 549 | display_pipe (arg); 550 | display_user_marshal (arg); 551 | display_type (arg); 552 | display_ptr (arg); 553 | display_arg (arg); 554 | display_array (arg); 555 | } 556 | } 557 | -------------------------------------------------------------------------------- /display.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #ifndef _DISPLAY_H_ 8 | #define _DISPLAY_H_ 9 | 10 | #include "midl.h" 11 | 12 | static char * op_types[] = { 13 | "+", 14 | "-", 15 | "*", 16 | "/", 17 | "%", 18 | "<<", 19 | ">>", 20 | "<", 21 | "<=", 22 | ">=", 23 | ">", 24 | "==", 25 | "!=", 26 | "&", 27 | "|", 28 | "^", 29 | "&&", 30 | "||" 31 | }; 32 | 33 | static char * op_unary_types[] = { 34 | "", 35 | "+", 36 | "-", 37 | "!", 38 | "~", 39 | "*", 40 | "", 41 | "", 42 | "", 43 | "" 44 | }; 45 | 46 | static char * op_cr_types[] = { 47 | "++", 48 | "--", 49 | "++", 50 | "--" 51 | }; 52 | 53 | 54 | void arg_struct_to_string (midl_arg_struct *, function_parameter *, unsigned int, midl_structure *, ea_t, ea_t); 55 | 56 | #endif -------------------------------------------------------------------------------- /mIDA.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 9.00 2 | # Visual Studio 2005 3 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mIDA", "mIDA.vcproj", "{E002FD7B-4549-4952-8254-E19A9FEB0CB4}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Win32 = Debug|Win32 8 | Release|Win32 = Release|Win32 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {E002FD7B-4549-4952-8254-E19A9FEB0CB4}.Debug|Win32.ActiveCfg = Debug|Win32 12 | {E002FD7B-4549-4952-8254-E19A9FEB0CB4}.Debug|Win32.Build.0 = Debug|Win32 13 | {E002FD7B-4549-4952-8254-E19A9FEB0CB4}.Release|Win32.ActiveCfg = Release|Win32 14 | {E002FD7B-4549-4952-8254-E19A9FEB0CB4}.Release|Win32.Build.0 = Release|Win32 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /mIDA.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 26 | 29 | 32 | 35 | 38 | 47 | 65 | 68 | 73 | 76 | 89 | 92 | 95 | 98 | 101 | 104 | 107 | 110 | 113 | 114 | 124 | 127 | 130 | 133 | 136 | 145 | 164 | 167 | 172 | 175 | 188 | 191 | 194 | 197 | 200 | 203 | 206 | 209 | 212 | 213 | 214 | 215 | 216 | 217 | 221 | 224 | 225 | 228 | 229 | 232 | 233 | 236 | 237 | 240 | 241 | 244 | 245 | 248 | 249 | 252 | 253 | 256 | 257 | 258 | 262 | 265 | 266 | 269 | 270 | 273 | 274 | 277 | 278 | 281 | 282 | 285 | 286 | 289 | 290 | 293 | 294 | 297 | 298 | 299 | 303 | 306 | 307 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | -------------------------------------------------------------------------------- /mida.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include 8 | 9 | #include "midl.h" 10 | #include "midl_scan.h" 11 | #include "midl_decompile.h" 12 | #include "buffer.h" 13 | #include "window.h" 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | char * ofile; 24 | DWORD mFlags; 25 | 26 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 27 | { 28 | mIDAhInst = hinstDLL; 29 | return TRUE; 30 | } 31 | 32 | 33 | static ulong idaapi sizer_fct(void *obj) 34 | { 35 | midl_interface * mi = (midl_interface *) obj; 36 | midl_fct_list * fct_list = mi->list; 37 | 38 | return fct_list->fct_num; 39 | } 40 | 41 | static void idaapi close_fct(void *obj) 42 | { 43 | midl_interface * mi = (midl_interface *) obj; 44 | 45 | qfree (mi->list); 46 | qfree (mi); 47 | } 48 | 49 | static void idaapi desc_fct(void *obj,ulong n,char * const *arrptr) 50 | { 51 | midl_interface * mi = (midl_interface *) obj; 52 | midl_fct_list * fct_list = mi->list; 53 | midl_function * mfcts = fct_list->list; 54 | 55 | /* header */ 56 | if (n == 0) 57 | { 58 | for (int i = 0; i < qnumber (header_fct); i++) 59 | qsnprintf(arrptr[i], MAXSTR, "%s", header_fct[i]); 60 | } 61 | else 62 | { 63 | qsnprintf(arrptr[0], MAXSTR, "0x%.2X", mfcts[n-1].opcode); 64 | qsnprintf(arrptr[1], MAXSTR, "0x%.8X", mfcts[n-1].offset); 65 | qsnprintf(arrptr[2], MAXSTR, "%s", mfcts[n-1].name); 66 | } 67 | } 68 | 69 | static void idaapi enter_cb_fct(void *obj,ulong n) 70 | { 71 | midl_interface * mi = (midl_interface *) obj; 72 | midl_fct_list * fct_list = mi->list; 73 | midl_function * mfcts = fct_list->list; 74 | 75 | jumpto (mfcts[n-1].offset); 76 | } 77 | 78 | 79 | static void idaapi edit_fct(void *obj,ulong n) 80 | { 81 | midl_interface * mi = (midl_interface *) obj; 82 | midl_fct_list * fct_list = mi->list; 83 | midl_function * mfcts = fct_list->list; 84 | 85 | // build the format string that creates the dialog. 86 | const char format[] = 87 | "STARTITEM 0\n" 88 | 89 | "Function preferences\n" // Title 90 | 91 | "\n" 92 | "\n" 93 | "\n\n" 94 | 95 | ; // End Dialog Format String 96 | 97 | // do the magic 98 | AskUsingForm_c(format, (char *)mfcts[n-1].name, &mfcts[n-1].arg_offset, &mi->type_raw); 99 | } 100 | 101 | static ulong idaapi decompile_fct(void *obj,ulong n) 102 | { 103 | midl_interface * mi = (midl_interface *) obj; 104 | midl_fct_list * fct_list = mi->list; 105 | midl_function * mfcts = fct_list->list; 106 | 107 | if (IS_START_SEL(n)) 108 | { 109 | mi->midl_struct = (midl_structure_list *) qalloc (sizeof(*mi->midl_struct)); 110 | if (!mi->midl_struct) 111 | { 112 | msg ("Error while allocating midl structure list\n"); 113 | return -1; 114 | } 115 | 116 | mi->fct_buffer = init_buffer(); 117 | if (!mi->fct_buffer) 118 | { 119 | qfree (mi->midl_struct); 120 | mi->midl_struct = NULL; 121 | return -1; 122 | } 123 | 124 | mi->struct_buffer = init_buffer(); 125 | if (!mi->struct_buffer) 126 | { 127 | free_buffer (mi->fct_buffer); 128 | qfree (mi->midl_struct); 129 | mi->midl_struct = NULL; 130 | return -1; 131 | } 132 | 133 | mi->midl_struct->num = 0; 134 | mi->midl_struct->mstruct = NULL; 135 | 136 | return 1; 137 | } 138 | else if (IS_END_SEL(n)) 139 | { 140 | buffer * buf; 141 | char tmp[2000]; 142 | HWND hWindow = NULL; 143 | FILE * fp; 144 | 145 | if (!mi->midl_struct) 146 | return -1; 147 | 148 | buf = init_buffer(); 149 | if (!buf) 150 | { 151 | msg ("Error while allocating final buffer !\n"); 152 | return -1; 153 | } 154 | 155 | decompile_struct_list (mi->midl_struct, mi->struct_buffer, mi->callback_table, mi->expr_table); 156 | free_midl_structure_list (mi->midl_struct); 157 | 158 | qsnprintf ((char *)tmp, sizeof(tmp), 159 | "/*\r\n" 160 | " * IDL code generated by mIDA v%s\r\n" 161 | " * Copyright (C) 2006, Tenable Network Security\r\n" 162 | " * http://cgi.tenablesecurity.com/tenable/mida.php\r\n" 163 | " * \r\n" 164 | " * \r\n" 165 | " * Decompilation information:\r\n" 166 | " * RPC stub type: %s\r\n" 167 | " */\r\n\r\n", 168 | MIDA_VERSION, 169 | mi->is_inline ? "inline" : "interpreted / fully interpreted"); 170 | buffer_add_message (buf, (char*) tmp); 171 | 172 | // create interface description 173 | qsnprintf ((char *)tmp, sizeof(tmp), "[\r\n uuid(%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x),\r\n version(%d.%d)\r\n]\r\n\r\ninterface %s\r\n{\r\n\r\n", 174 | mi->uuid.x1, mi->uuid.x2, mi->uuid.x3, 175 | mi->uuid.x4[0],mi->uuid.x4[1], 176 | mi->uuid.x4[2],mi->uuid.x4[3],mi->uuid.x4[4],mi->uuid.x4[5],mi->uuid.x4[6],mi->uuid.x4[7], 177 | mi->uuid.major, mi->uuid.minor, 178 | "mIDA_interface"); 179 | 180 | // final buffer = description + structures + functions 181 | buffer_add_message (buf, (char*)tmp); 182 | buffer_add_message (buf, (char*)mi->struct_buffer->buffer); 183 | buffer_add_message (buf, (char*)mi->fct_buffer->buffer); 184 | buffer_add_message (buf, (char*)"}\r\n"); 185 | 186 | if (ofile == NULL) 187 | { 188 | hWindow = AddMDIChild (); 189 | 190 | if (!hWindow) 191 | { 192 | msg ("Decompile Output :\n\n%s", buf->buffer); 193 | } 194 | else 195 | { 196 | SetMDIWindowText (hWindow, buf->buffer); 197 | } 198 | } 199 | else 200 | { 201 | fp = qfopen ((char *)ofile, (char *)"a"); 202 | if (fp) 203 | { 204 | qfwrite (fp, (void *)buf->buffer, strlen (buf->buffer)); 205 | qfclose (fp); 206 | } 207 | 208 | } 209 | 210 | free_buffer (buf); 211 | free_buffer (mi->fct_buffer); 212 | free_buffer (mi->struct_buffer); 213 | qfree (mi->midl_struct); 214 | mi->midl_struct = NULL; 215 | return 1; 216 | } 217 | else if (IS_SEL(n)) 218 | { 219 | if (!mi->midl_struct) 220 | return -1; 221 | 222 | __try 223 | { 224 | decompile_function (&mfcts[n-1], mi->type_raw, mi->fct_buffer, mi->midl_struct, mi->ndr_version, mi->callback_table, mi->expr_table); 225 | } 226 | __except (GetExceptionCode() == EXCEPTION_MIDA_LOOPLIMIT ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 227 | { 228 | free_buffer (mi->fct_buffer); 229 | free_buffer (mi->struct_buffer); 230 | qfree (mi->midl_struct); 231 | mi->midl_struct = NULL; 232 | return 0; 233 | } 234 | return 1; 235 | } 236 | 237 | return 1; 238 | } 239 | 240 | 241 | static void idaapi decompile_all_fct(void *obj) 242 | { 243 | midl_interface * mi = (midl_interface *) obj; 244 | midl_fct_list * fct_list = mi->list; 245 | unsigned int i, ret; 246 | 247 | __try 248 | { 249 | decompile_fct (obj, START_SEL); 250 | 251 | for (i=1; i<=fct_list->fct_num; i++) 252 | { 253 | ret = decompile_fct (obj, i); 254 | if (ret == 0) 255 | RaiseException (EXCEPTION_MIDA_LOOPLIMIT,0,0,NULL); 256 | } 257 | 258 | decompile_fct (obj, END_SEL); 259 | } 260 | __except (GetExceptionCode() == EXCEPTION_MIDA_LOOPLIMIT ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 261 | { 262 | return; 263 | } 264 | } 265 | 266 | 267 | int idaapi IDAP_init(void) 268 | { 269 | if (strncmp (inf.procName, "metapc", 8) != 0 || inf.filetype != f_PE) 270 | { 271 | msg ("mIDA: Can't be loaded (not a PE file or debugger mode)\n"); 272 | return PLUGIN_SKIP; 273 | } 274 | 275 | return PLUGIN_OK; 276 | } 277 | 278 | 279 | void idaapi IDAP_term(void) 280 | { 281 | CleanupMDIWindow (); 282 | } 283 | 284 | 285 | void idaapi IDAP_run(int arg) 286 | { 287 | const char * options = NULL; 288 | midl_interface_list * midl_list = NULL, * tmp_list = NULL; 289 | midl_interface * mi; 290 | unsigned char uuid_name[100]; 291 | long ret; 292 | HKEY hKey; 293 | DWORD len; 294 | DWORD type; 295 | 296 | InitializeMDIWindow (mIDAhInst); 297 | 298 | mFlags = 0; 299 | ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Tenable\\mIDA", 0, MAXIMUM_ALLOWED, &hKey); 300 | if (ret == ERROR_SUCCESS) 301 | { 302 | len = sizeof(mFlags); 303 | ret = RegQueryValueEx(hKey, "Debug", NULL, &type, (LPBYTE)&mFlags, &len); 304 | } 305 | 306 | msg ("\n---------------------------------------------------\n" 307 | "mIDA Plugin v%s\n" 308 | "Copyright (C) 2006, Tenable Network Security\n" 309 | "---------------------------------------------------\n\n", MIDA_VERSION); 310 | 311 | midl_list = midl_scan(); 312 | tmp_list = midl_list; 313 | 314 | options = get_plugin_options("ofile"); 315 | 316 | if (options == NULL) 317 | { 318 | ofile = NULL; 319 | 320 | while (tmp_list && tmp_list->mi) 321 | { 322 | mi = tmp_list->mi; 323 | 324 | qsnprintf ((char *)uuid_name, sizeof(uuid_name), "%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x v%d.%d", 325 | mi->uuid.x1, mi->uuid.x2, mi->uuid.x3, 326 | mi->uuid.x4[0],mi->uuid.x4[1], 327 | mi->uuid.x4[2],mi->uuid.x4[3],mi->uuid.x4[4],mi->uuid.x4[5],mi->uuid.x4[6],mi->uuid.x4[7], 328 | mi->uuid.major, mi->uuid.minor); 329 | 330 | if (mi->list != NULL) 331 | { 332 | choose2( 333 | CH_MULTI, // flags 334 | -1,-1,-1,-1, // autoposition 335 | (void*)mi, // pass the created function list to the window 336 | qnumber(header_fct), // number of columns 337 | widths_fct, // widths of columns 338 | sizer_fct, // function that returns number of lines 339 | desc_fct, // function that generates a line 340 | (const char*)uuid_name, // window title 341 | -1, // use the default icon for the window 342 | 0, // position the cursor on the first line 343 | decompile_fct, // "kill" callback 344 | decompile_all_fct, // "new" callback 345 | NULL, // "update" callback 346 | edit_fct, // "edit" callback 347 | enter_cb_fct, // function to call when the user pressed Enter 348 | close_fct, // function to call when the window is closed 349 | popup_fct, // use default popup menu items 350 | NULL); // use the same icon for all lines 351 | } 352 | tmp_list = tmp_list->next; 353 | } 354 | } 355 | else 356 | { 357 | ofile = (char *) options; 358 | 359 | while (tmp_list && tmp_list->mi) 360 | { 361 | decompile_all_fct ((void *)tmp_list->mi); 362 | tmp_list = tmp_list->next; 363 | } 364 | } 365 | 366 | free_interface_list (midl_list); 367 | } 368 | 369 | 370 | char IDAP_comment[] = "This is a MIDL decompiler plugin."; 371 | char IDAP_help[] = 372 | "A MIDL decompiler plugin for IDA\n" 373 | "\n" 374 | "This module extract MIDL structures from exe or dll.\n"; 375 | char IDAP_name[] = "mIDA (MIDL Analyzer plugin for IDA)"; 376 | char IDAP_hotkey[] = "Ctrl-7"; 377 | 378 | 379 | // Exported Plugin Object 380 | plugin_t PLUGIN = 381 | { 382 | IDP_INTERFACE_VERSION, 383 | PLUGIN_PROC, 384 | IDAP_init, 385 | IDAP_term, 386 | IDAP_run, 387 | IDAP_comment, 388 | IDAP_help, 389 | IDAP_name, 390 | IDAP_hotkey 391 | }; -------------------------------------------------------------------------------- /mida_res.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "afxres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (U.S.) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | #ifdef _WIN32 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | #pragma code_page(1252) 22 | #endif //_WIN32 23 | 24 | #ifdef APSTUDIO_INVOKED 25 | ///////////////////////////////////////////////////////////////////////////// 26 | // 27 | // TEXTINCLUDE 28 | // 29 | 30 | 1 TEXTINCLUDE 31 | BEGIN 32 | "resource.h\0" 33 | END 34 | 35 | 2 TEXTINCLUDE 36 | BEGIN 37 | "#include ""afxres.h""\r\n" 38 | "\0" 39 | END 40 | 41 | 3 TEXTINCLUDE 42 | BEGIN 43 | "\r\n" 44 | "\0" 45 | END 46 | 47 | #endif // APSTUDIO_INVOKED 48 | 49 | 50 | ///////////////////////////////////////////////////////////////////////////// 51 | // 52 | // Icon 53 | // 54 | 55 | // Icon with lowest ID value placed first to ensure application icon 56 | // remains consistent on all systems. 57 | IDI_ICON1 ICON "nessus_logo_16x16.ico" 58 | #endif // English (U.S.) resources 59 | ///////////////////////////////////////////////////////////////////////////// 60 | 61 | 62 | 63 | #ifndef APSTUDIO_INVOKED 64 | ///////////////////////////////////////////////////////////////////////////// 65 | // 66 | // Generated from the TEXTINCLUDE 3 resource. 67 | // 68 | 69 | 70 | ///////////////////////////////////////////////////////////////////////////// 71 | #endif // not APSTUDIO_INVOKED 72 | 73 | -------------------------------------------------------------------------------- /midl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include "midl.h" 8 | 9 | #include "bytes.hpp" 10 | #include "kernwin.hpp" 11 | #include "pro.h" 12 | 13 | // Use for debugging purpose 14 | 15 | bool debug_mode () 16 | { 17 | return true; 18 | } 19 | 20 | void free_fct_list (midl_fct_list * list) 21 | { 22 | if (list) 23 | { 24 | qfree (list->list); 25 | qfree (list); 26 | } 27 | } 28 | 29 | 30 | void free_interface_list (midl_interface_list * list) 31 | { 32 | if (list) 33 | { 34 | free_interface_list (list->next); 35 | 36 | qfree (list); 37 | } 38 | } 39 | 40 | 41 | void free_midl_structure (midl_structure * midl_struct) 42 | { 43 | midl_arg_struct_list * next_ptr, * ptr = midl_struct->elem; 44 | 45 | while (ptr != NULL) 46 | { 47 | next_ptr = ptr->next; 48 | free_midl_arg_struct (ptr->arg); 49 | qfree (ptr->arg); 50 | qfree (ptr); 51 | ptr = next_ptr; 52 | } 53 | 54 | } 55 | 56 | 57 | void free_midl_structure_list (midl_structure_list * midl_struct) 58 | { 59 | unsigned int i; 60 | 61 | for (i=0; inum; i++) 62 | { 63 | free_midl_structure (&midl_struct->mstruct[i]); 64 | } 65 | qfree (midl_struct->mstruct); 66 | } 67 | 68 | 69 | void init_midl_arg_struct (midl_arg_struct * arg_struct, midl_structure_list * midl_struct) 70 | { 71 | memset (arg_struct, '\0', sizeof(*arg_struct)); 72 | arg_struct->midl_struct = midl_struct; 73 | } 74 | 75 | 76 | void free_midl_arg_struct (midl_arg_struct * arg_struct) 77 | { 78 | if (arg_struct->array_num > 0) 79 | qfree (arg_struct->astruct); 80 | 81 | if (arg_struct->sstruct_num > 0) 82 | qfree (arg_struct->sstruct); 83 | 84 | if (arg_struct->sunion_num > 0) 85 | qfree (arg_struct->sunion); 86 | } 87 | 88 | 89 | midl_pp_list * init_pp_list () 90 | { 91 | midl_pp_list * tmp_list; 92 | 93 | tmp_list = (midl_pp_list *) qalloc (sizeof(*tmp_list)); 94 | if (!tmp_list) 95 | { 96 | msg ("Error: memory allocation failed during init_pp_list.\n"); 97 | return NULL; 98 | } 99 | 100 | tmp_list->pp_num = 0; 101 | tmp_list->ppstruct = NULL; 102 | 103 | return tmp_list; 104 | } 105 | 106 | 107 | void free_pp_list (midl_pp_list * pp_list) 108 | { 109 | if (!pp_list) 110 | return; 111 | 112 | if (pp_list->pp_num > 0) 113 | qfree (pp_list->ppstruct); 114 | 115 | qfree (pp_list); 116 | } 117 | 118 | 119 | bool add_pp_struct (fc_type type, unsigned short arg_offset, ea_t pos, midl_pp_list * pp_list) 120 | { 121 | midl_pp_struct * tmp; 122 | 123 | if (pp_list->ppstruct == NULL) 124 | tmp = (midl_pp_struct *) qalloc (sizeof(*tmp)); 125 | else 126 | tmp = (midl_pp_struct *) qrealloc (pp_list->ppstruct, (pp_list->pp_num+ 1) * sizeof (*tmp)); 127 | if (!tmp) 128 | { 129 | msg ("Memory allocation error during add_pp_struct !\n"); 130 | return false; 131 | } 132 | 133 | pp_list->ppstruct = tmp; 134 | pp_list->pp_num++; 135 | 136 | pp_list->ppstruct[pp_list->pp_num - 1].arg_offset = arg_offset; 137 | pp_list->ppstruct[pp_list->pp_num - 1].type = type; 138 | pp_list->ppstruct[pp_list->pp_num - 1].type_offset = pos; 139 | 140 | return true; 141 | } 142 | 143 | 144 | 145 | midl_pp_struct * get_pp_list_arg (midl_pp_list * pp_list, unsigned short offset) 146 | { 147 | unsigned int i; 148 | 149 | if (!pp_list) 150 | return NULL; 151 | 152 | for (i=0; ipp_num; i++) 153 | { 154 | if (pp_list->ppstruct[i].arg_offset == offset) 155 | return &pp_list->ppstruct[i]; 156 | } 157 | 158 | return NULL; 159 | } 160 | 161 | 162 | bool add_array (midl_arg_struct * arg) 163 | { 164 | array_struct * tmp; 165 | 166 | if (arg->astruct == NULL) 167 | tmp = (array_struct *) qalloc (sizeof(*tmp)); 168 | else 169 | tmp = (array_struct *) qrealloc (arg->astruct, (arg->array_num + 1) * sizeof (*tmp)); 170 | if (!tmp) 171 | { 172 | msg ("Memory allocation error during add_array !\n"); 173 | return false; 174 | } 175 | 176 | arg->astruct = tmp; 177 | arg->array_num++; 178 | 179 | memset (&arg->astruct[arg->array_num-1], '\0', sizeof (array_struct)); 180 | 181 | return true; 182 | } 183 | 184 | 185 | array_struct * get_current_array (midl_arg_struct * arg) 186 | { 187 | return &arg->astruct[arg->array_num-1]; 188 | } 189 | 190 | 191 | void set_array_size (midl_arg_struct * arg, unsigned int size) 192 | { 193 | arg->astruct[arg->array_num-1].size = size; 194 | } 195 | 196 | 197 | bool add_sarray (midl_arg_struct * arg) 198 | { 199 | sarray_struct * tmp; 200 | 201 | if (arg->sstruct == NULL) 202 | tmp = (sarray_struct *) qalloc (sizeof(*tmp)); 203 | else 204 | tmp = (sarray_struct *) qrealloc (arg->sstruct, (arg->sstruct_num+ 1) * sizeof (*tmp)); 205 | if (!tmp) 206 | { 207 | msg ("Memory allocation error during add_sarray !\n"); 208 | return false; 209 | } 210 | 211 | arg->sstruct = tmp; 212 | arg->sstruct_num++; 213 | 214 | memset (&arg->sstruct[arg->sstruct_num-1], '\0', sizeof (*tmp)); 215 | 216 | return true; 217 | } 218 | 219 | 220 | sarray_arg * get_current_sunion (midl_arg_struct * arg) 221 | { 222 | return &arg->sunion[arg->sunion_num-1]; 223 | } 224 | 225 | 226 | bool add_sunion (midl_arg_struct * arg) 227 | { 228 | sarray_arg * tmp; 229 | 230 | if (arg->sstruct == NULL) 231 | tmp = (sarray_arg *) qalloc (sizeof(*tmp)); 232 | else 233 | tmp = (sarray_arg *) qrealloc (arg->sstruct, (arg->sunion_num+ 1) * sizeof (*tmp)); 234 | if (!tmp) 235 | { 236 | msg ("Memory allocation error during add_sarray !\n"); 237 | return false; 238 | } 239 | 240 | arg->sunion = tmp; 241 | arg->sunion_num++; 242 | 243 | memset (&arg->sunion[arg->sunion_num-1], '\0', sizeof (*tmp)); 244 | 245 | return true; 246 | } 247 | 248 | 249 | int add_struct_to_list (midl_structure_list * midl_struct, ea_t offset, bool is_union) 250 | { 251 | unsigned int i; 252 | midl_structure * tmp; 253 | 254 | for (i=0; inum; i++) 255 | if (midl_struct->mstruct[i].offset == offset) 256 | return i+1; 257 | 258 | 259 | if (midl_struct->mstruct == NULL) 260 | tmp = (midl_structure *) qalloc (sizeof(*tmp)); 261 | else 262 | tmp = (midl_structure *) qrealloc (midl_struct->mstruct, (midl_struct->num + 1) * sizeof (*tmp)); 263 | if (!tmp) 264 | { 265 | msg ("Memory allocation error during add_struct_to_list !\n"); 266 | return -1; 267 | } 268 | 269 | midl_struct->mstruct = tmp; 270 | midl_struct->num++; 271 | 272 | midl_struct->mstruct[midl_struct->num - 1].offset = offset; 273 | midl_struct->mstruct[midl_struct->num - 1].is_union = is_union; 274 | midl_struct->mstruct[midl_struct->num - 1].elem = NULL; 275 | 276 | return midl_struct->num; 277 | } 278 | 279 | 280 | 281 | midl_arg_struct * new_arg_struct () 282 | { 283 | midl_arg_struct * tmp; 284 | 285 | tmp = (midl_arg_struct *) qalloc (sizeof(*tmp)); 286 | return tmp; 287 | } 288 | 289 | 290 | void add_struct_elem (midl_structure * mstruct, midl_arg_struct * arg) 291 | { 292 | midl_arg_struct_list * ptr = mstruct->elem; 293 | midl_arg_struct_list * list = (midl_arg_struct_list *) qalloc (sizeof(*list)); 294 | if (!list) 295 | { 296 | msg ("Error : memory allocation failed during add_struct_elem !.\n"); 297 | return; 298 | } 299 | 300 | list->next = NULL; 301 | list->arg = arg; 302 | 303 | if (ptr == NULL) 304 | { 305 | mstruct->elem = list; 306 | return; 307 | } 308 | 309 | 310 | while (ptr != NULL) 311 | { 312 | if (ptr->next == NULL) 313 | { 314 | ptr->next = list; 315 | break; 316 | } 317 | ptr = ptr->next; 318 | } 319 | } 320 | 321 | 322 | unsigned long get_long2 (ea_t * pos) 323 | { 324 | unsigned long l = get_long (*pos); 325 | *pos += sizeof (unsigned long); 326 | return l; 327 | } 328 | 329 | unsigned short get_word2 (ea_t * pos) 330 | { 331 | unsigned short w = get_word (*pos); 332 | *pos += sizeof (unsigned short); 333 | return w; 334 | } 335 | 336 | unsigned char get_byte2 (ea_t * pos) 337 | { 338 | unsigned char b = get_byte (*pos); 339 | *pos += sizeof (unsigned char); 340 | return b; 341 | } 342 | 343 | void GET_DATA (ea_t * pos, void * data, size_t s) 344 | { 345 | get_many_bytes (*pos, data, s); 346 | *pos += s; 347 | } 348 | 349 | ea_t get_callback_address(unsigned long l, ea_t callback_table) 350 | { 351 | if (callback_table == BADADDR) 352 | return callback_table; 353 | 354 | return get_long (callback_table + l*4); 355 | } 356 | 357 | static bool _is_fully_interpreted_stub = false; 358 | static bool _has_conformance_range = false; 359 | 360 | bool is_fully_interpreted_stub () 361 | { 362 | return _is_fully_interpreted_stub; 363 | } 364 | 365 | bool has_conformance_range () 366 | { 367 | return _has_conformance_range; 368 | } 369 | 370 | void set_fully_interpreted_stub (bool val) 371 | { 372 | _is_fully_interpreted_stub = val; 373 | } 374 | 375 | void set_conformance_range (bool val) 376 | { 377 | _has_conformance_range = val; 378 | } -------------------------------------------------------------------------------- /midl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #ifndef _MIDL_H_ 8 | #define _MIDL_H_ 9 | 10 | #include 11 | #include 12 | #include "buffer.h" 13 | 14 | #define MIDA_VERSION "1.0.10" 15 | 16 | #define MIDL_LANGUAGE "04 5D 88 8A EB 1C C9 11 9F E8 08 00 2B 10 48 60" 17 | 18 | typedef unsigned char fc_type; 19 | typedef unsigned char fc_flag; 20 | typedef short fc_offset; // signed ! 21 | 22 | #define RECURSION_LIMIT 10000 23 | 24 | #define EXCEPTION_MIDA_LOOPLIMIT 0x544E53 25 | 26 | typedef struct _uuid_version { 27 | unsigned long x1; 28 | unsigned short x2; 29 | unsigned short x3; 30 | unsigned char x4[8]; 31 | unsigned short major; 32 | unsigned short minor; 33 | } uuid_version; 34 | 35 | typedef struct _midl_structure_list midl_structure_list; 36 | 37 | typedef struct _midl_function { 38 | unsigned char name[50]; 39 | ea_t offset; 40 | unsigned short opcode; 41 | unsigned short arg_num; 42 | ea_t arg_offset; 43 | bool is_inline; 44 | bool has_conformance_range; 45 | } midl_function; 46 | 47 | typedef struct _midl_fct_list { 48 | unsigned int fct_num; 49 | unsigned long real_list_size; 50 | midl_function * list; 51 | } midl_fct_list; 52 | 53 | 54 | typedef struct _midl_interface { 55 | uuid_version uuid; 56 | ea_t fct_ptrs; 57 | ea_t fct_raw; 58 | ea_t type_raw; 59 | ea_t callback_table; 60 | ea_t expr_table; 61 | ea_t dispatch_table; 62 | ea_t format_string_offset_table; 63 | midl_fct_list * list; 64 | buffer * fct_buffer; 65 | buffer * struct_buffer; 66 | midl_structure_list * midl_struct; 67 | unsigned long ndr_version; 68 | bool is_inline; 69 | bool is_interpreted; 70 | } midl_interface; 71 | 72 | 73 | typedef struct _midl_interface_list { 74 | midl_interface * mi; 75 | struct _midl_interface_list * next; 76 | } midl_interface_list; 77 | 78 | typedef struct _function_parameter { 79 | unsigned short flags; 80 | unsigned short stack; 81 | union { 82 | unsigned char type; 83 | unsigned short offset; 84 | } info; 85 | } function_parameter; 86 | 87 | 88 | typedef struct _midl_range { 89 | unsigned long begin; 90 | unsigned long end; 91 | } midl_range; 92 | 93 | 94 | struct _arg_constant { 95 | unsigned char size[3]; // size is on 3 bytes 96 | }; 97 | 98 | struct _arg_variable { 99 | unsigned char type; 100 | short offset; 101 | }; 102 | 103 | 104 | typedef struct _sarray_arg { 105 | unsigned char flags; 106 | union { 107 | struct _arg_constant cons; 108 | struct _arg_variable var; 109 | } arg; 110 | unsigned short corr_flags; 111 | } sarray_arg; 112 | 113 | 114 | typedef struct _sarray_struct { 115 | bool is_size; 116 | bool is_length; 117 | bool is_byte_count; 118 | 119 | sarray_arg size; 120 | sarray_arg length; 121 | sarray_arg byte_count; 122 | } sarray_struct; 123 | 124 | 125 | typedef struct _array_struct { 126 | unsigned long size; 127 | } array_struct; 128 | 129 | 130 | 131 | typedef struct _midl_pp_struct { 132 | fc_type type; 133 | unsigned short arg_offset; 134 | ea_t type_offset; 135 | } midl_pp_struct; 136 | 137 | 138 | typedef struct _midl_pp_list { 139 | unsigned int pp_num; 140 | midl_pp_struct * ppstruct; 141 | } midl_pp_list; 142 | 143 | typedef struct _midl_arg_struct midl_arg_struct; 144 | typedef struct _midl_arg_struct_list * pmidl_arg_struct_list; 145 | 146 | typedef struct _midl_arg_struct_list { 147 | midl_arg_struct * arg; 148 | pmidl_arg_struct_list next; 149 | } midl_arg_struct_list; 150 | 151 | 152 | typedef struct _midl_structure { 153 | ea_t offset; 154 | bool is_union; 155 | midl_arg_struct_list * elem; 156 | } midl_structure; 157 | 158 | 159 | struct _midl_structure_list { 160 | unsigned int num; 161 | midl_structure * mstruct; 162 | }; 163 | 164 | struct _midl_arg_struct { 165 | // struct flags 166 | bool is_unique; 167 | bool is_string; 168 | bool is_range; 169 | bool is_context; 170 | bool is_union; 171 | bool is_ptr; 172 | bool is_reference; 173 | bool is_pipe; 174 | bool is_user_marshal; 175 | bool is_pad; 176 | 177 | // struct names 178 | unsigned char type_name[50]; 179 | unsigned char arg_name[50]; 180 | unsigned char line_string[500]; 181 | 182 | // struct data 183 | unsigned int ptr_num; 184 | midl_range range; 185 | unsigned int array_num; 186 | array_struct * astruct; 187 | unsigned int sstruct_num; 188 | sarray_struct * sstruct; 189 | unsigned int sunion_num; 190 | sarray_arg * sunion; 191 | 192 | // internal flags 193 | unsigned long loop_num; 194 | unsigned long last_struct_size; 195 | midl_structure_list * midl_struct; 196 | unsigned short struct_offset; 197 | unsigned short user_marshal_size; 198 | 199 | fc_type type; 200 | }; 201 | 202 | 203 | typedef struct _expression 204 | { 205 | unsigned char expr_type; 206 | unsigned char expr_subtype; 207 | short offset; 208 | } expression; 209 | 210 | 211 | typedef struct _conformance_range 212 | { 213 | unsigned char type; 214 | unsigned char unknown; 215 | unsigned long range_start; 216 | unsigned long range_end; 217 | } conformance_range; 218 | 219 | 220 | #define sarray_arg_SIZE 0 221 | #define sarray_arg_LENGTH 1 222 | #define sarray_arg_BYTE_COUNT 2 223 | 224 | 225 | #define FC_BYTE 0x01 // byte 226 | #define FC_CHAR 0x02 // char 227 | #define FC_SMALL 0x03 // small, boolean 228 | #define FC_USMALL 0x04 // unsigned small 229 | #define FC_WCHAR 0x05 // wchar_t 230 | #define FC_SHORT 0x06 // short 231 | #define FC_USHORT 0x07 // unsigned short 232 | #define FC_LONG 0x08 // int, __int32, long 233 | #define FC_ULONG 0x09 // unsigned long 234 | #define FC_FLOAT 0x0a // float 235 | #define FC_HYPER 0x0b // hyper, __int64, handle_t 236 | #define FC_DOUBLE 0x0c // double 237 | #define FC_ENUM16 0x0d // typedef enum {test1=1, test2, test3} test; 238 | #define FC_ENUM32 0x0e // typedef [v1_enum] enum {test1=1, test2, test3} test; 239 | #define FC_IGNORE 0x0f // handle_t 240 | #define FC_ERROR_STATUS_T 0x10 // error_status_t 241 | #define FC_RP 0x11 // [ref] / nothing 242 | #define FC_UP 0x12 // [unique] 243 | #define FC_FP 0x14 // [ptr] 244 | #define FC_STRUCT 0x15 // struct { char c;} 245 | #define FC_PSTRUCT 0x16 // struct { long * d; } 246 | #define FC_CSTRUCT 0x17 // struct with [size_is()] STRUCT t[] for last elem 247 | #define FC_CPSTRUCT 0x18 // struct with [size_is()] STRUCT t[] for last elem and one or more pointer as elem 248 | #define FC_CVSTRUCT 0x19 // struct with [size_is(),length_is()] STRUCT t[] for last elem and one or more pointer as elem 249 | #define FC_BOGUS_STRUCT 0x1a // struct { char c; struct {char c} d;} 250 | #define FC_CARRAY 0x1b // [size_is(12)] int * t; 251 | #define FC_CVARRAY 0x1c // [size_is(12), lenght_is(12)] char * c; 252 | #define FC_SMFARRAY 0x1d // small array : int c[50] 253 | #define FC_LGFARRAY 0x1e // large array : int c[1234567] 254 | #define FC_SMVARRAY 0x1f // small array : [last_is()] int c[50] 255 | #define FC_LGVARRAY 0x20 // large array : [first_is(12)] int c[1234567] 256 | #define FC_BOGUS_ARRAY 0x21 // [in] [size_is(11)] TEST * d, where TEST is a BOGUS_STRUCT 257 | #define FC_C_CSTRING 0x22 // [string] char * c; 258 | #define FC_C_WSTRING 0x25 // [string] wchar_t * c; 259 | #define FC_CSTRING 0x26 // [string] char[12]; 260 | #define FC_WSTRING 0x29 // [string] wchar_t[12]; 261 | #define FC_ENCAPSULATED_UNION 0x2a // union 262 | #define FC_NON_ENCAPSULATED_UNION 0x2b // union 263 | #define FC_BYTE_COUNT_POINTER 0x2c // [byte_count(arg)] in an acf file ... 264 | #define FC_IP 0x2F // interface 265 | #define FC_BIND_CONTEXT 0x30 // [context_handle] 266 | #define FC_BIND_GENERIC 0x31 267 | #define FC_BIND_PRIMITIVE 0x32 268 | #define FC_POINTER 0x36 // pointer in struct 269 | #define FC_ALIGNM2 0x37 // structure alignment on 2 bytes 270 | #define FC_ALIGNM4 0x38 // structure alignment on 2 bytes 271 | #define FC_ALIGNM8 0x39 // structure alignment on 2 bytes 272 | #define FC_STRUCTPAD1 0x3d // padding : 1 char 273 | #define FC_STRUCTPAD2 0x3e // padding : 2 chars 274 | #define FC_STRUCTPAD3 0x3f // padding : 3 chars 275 | #define FC_STRUCTPAD4 0x40 // padding : 4 chars 276 | #define FC_STRUCTPAD5 0x41 // padding : 5 chars 277 | #define FC_STRUCTPAD6 0x42 // padding : 6 chars 278 | #define FC_STRUCTPAD7 0x43 // padding : 7 chars 279 | #define FC_STRING_SIZED 0x44 // [size_is (12)] wchart_t tab[] 280 | #define FC_NO_REPEAT 0x46 // FC_PP (pstruct ?) 281 | #define FC_FIXED_REPEAT 0x47 // FC_PP (array/struct with change) 282 | #define FC_VARIABLE_REPEAT 0x48 // FC_PP (array) 283 | #define FC_PP 0x4b // pointer ref in struct/array 284 | #define FC_EMBEDDED_COMPLEX 0x4c // used inside BOGUS_ARRAY for struct array 285 | #define FC_IN_PARAM 0x4d // inline stub 286 | #define FC_IN_PARAM_BASETYPE 0x4e // inline stub 287 | #define FC_IN_OUT_PARAM 0x50 // inline stub 288 | #define FC_OUT_PARAM 0x51 // inline stub 289 | #define FC_RETURN_PARAM 0x52 // inline stub 290 | #define FC_RETURN_PARAM_BASETYPE 0x53 // inline stub 291 | #define FC_DEREFERENCE 0x54 // long *l, [size_is(*l)] char * c 292 | #define FC_DIV_2 0x55 // [size_is (t/2)] char * c 293 | #define FC_MULT_2 0x56 // [size_is (t*2)] char * c 294 | #define FC_ADD_1 0x57 // [size_is (t+1)] char * c 295 | #define FC_SUB_1 0x58 // [size_is (t-1)] char * c 296 | #define FC_CALLBACK 0x59 // long *..*l, [size_is(*...*l)] char * c 297 | #define FC_CONSTANT_IID 0x5a // 0000-000-000-0000-000000... 298 | #define FC_END 0x5b // (end of format string) 299 | #define FC_PAD 0x5c // (padding) 300 | #define FC_EXPR 0x5d // size_is ( (t+2) / 10 ) 301 | #define FC_FORCED_BOGUS_STRUCT 0xb1 302 | #define FC_USER_MARSHAL 0xb4 // typedef [user_marshal(FOUR_BYTE_DATA)] TWO_X_TWO_BYTE_DATA; in acf file 303 | #define FC_PIPE 0xb5 // pipe XXXX elem 304 | #define FC_SUPPLEMENT 0xb6 // range in wchar_t string 305 | #define FC_RANGE 0xb7 // [range(0,65535)] 306 | #define FC_INT3264 0xb8 // __int3264 307 | #define FC_UINT3264 0xb9 // unsigned __int3264 308 | 309 | #define FC_CRAFTED_RETURN_PARAM 0xFF 310 | 311 | #define FLAG_MUST_SIZE 0x01 // must size (ex: [in][string] char * in) 312 | #define FLAG_MUST_FREE 0x02 // must free (ex: [in][unique] char * in) - no way to get the original type with [unique] 313 | #define FLAG_IN 0x08 // [in] 314 | #define FLAG_OUT 0x10 // [out] 315 | #define FLAG_FIELD 0x10 // struct field 316 | #define FLAG_RETURN 0x20 // return value 317 | #define FLAG_PARAMETER 0x20 // parameter value for size_is 318 | #define FLAG_BASE_TYPE 0x40 // base type 319 | #define FLAG_CONSTANT 0x40 // constant value for size_is 320 | #define FLAG_VIA_POINTER 0x80 // [context_handle] void ** handle 321 | #define FLAG_SIMPLE_REF 0x100 // simple ref (pointer *) 322 | #define FLAG_SRV_ALLOC 0x2000 // srv alloc=8 (?) 323 | 324 | #define FLAG_ALLOCATED_ON_STACK 0x04 // 325 | #define FLAG_SIMPLE_POINTER 0x08 // ex: char * c 326 | #define FLAG_POINTER_DEREF 0x10 // ex: char ** c 327 | 328 | 329 | #define FC_EXPR_CONST32 0x01 330 | #define FC_EXPR_CONST64 0x02 331 | #define FC_EXPR_VAR 0x03 332 | #define FC_EXPR_OPER 0x04 333 | #define FC_EXPR_PAD 0x05 334 | 335 | 336 | #define OP_UNARY_PLUS 0x01 337 | #define OP_UNARY_MINUS 0x02 338 | #define OP_UNARY_NOT 0x03 339 | #define OP_UNARY_COMPLEMENT 0x04 340 | #define OP_UNARY_INDIRECTION 0x05 341 | #define OP_UNARY_CAST 0x06 342 | #define OP_UNARY_AND 0x07 343 | #define OP_UNARY_SIZEOF 0x08 344 | #define OP_UNARY_ALIGNOF 0x09 345 | #define OP_PRE_INCR 0x0a 346 | #define OP_PRE_DECR 0x0b 347 | #define OP_POST_INCR 0x0c 348 | #define OP_POST_DECR 0x0d 349 | #define OP_PLUS 0x0e 350 | #define OP_MINUS 0x0f 351 | #define OP_STAR 0x10 352 | #define OP_SLASH 0x11 353 | #define OP_MOD 0x12 354 | #define OP_LEFT_SHIFT 0x13 355 | #define OP_RIGHT_SHIFT 0x14 356 | #define OP_LESS 0x15 357 | #define OP_LESS_EQUAL 0x16 358 | #define OP_GREATER_EQUAL 0x17 359 | #define OP_GREATER 0x18 360 | #define OP_EQUAL 0x19 361 | #define OP_NOT_EQUAL 0x20 362 | #define OP_AND 0x21 363 | #define OP_OR 0x22 364 | #define OP_XOR 0x23 365 | #define OP_LOGICAL_AND 0x24 366 | #define OP_LOGICAL_OR 0x25 367 | #define OP_EXPRESSION 0x26 368 | 369 | #define OP_ASYNCSPLIT 0x31 370 | #define OP_CORR_POINTER 0x32 371 | #define OP_CORR_TOP_LEVEL 0x33 372 | 373 | // Note to myself 374 | // [in, context_handle] void * h -> flags = FLAG_MUST_IN, type = FC_CHAR, no extra 0 at the end 375 | 376 | 377 | // Define functions 378 | bool debug_mode (); 379 | void free_interface_list (midl_interface_list *); 380 | void free_fct_list (midl_fct_list *); 381 | void free_midl_structure (midl_structure *); 382 | void free_midl_structure_list (midl_structure_list *); 383 | midl_pp_list * init_pp_list (); 384 | void free_pp_list (midl_pp_list *); 385 | bool add_pp_struct (fc_type, unsigned short, ea_t, midl_pp_list *); 386 | void init_midl_arg_struct (midl_arg_struct *, midl_structure_list *); 387 | void free_midl_arg_struct (midl_arg_struct *); 388 | midl_pp_struct * get_pp_list_arg (midl_pp_list *, unsigned short); 389 | bool add_array (midl_arg_struct *); 390 | array_struct * get_current_array (midl_arg_struct *); 391 | void set_array_size (midl_arg_struct *, unsigned int); 392 | bool add_sarray (midl_arg_struct *); 393 | sarray_arg * get_current_sunion (midl_arg_struct *); 394 | bool add_sunion (midl_arg_struct *); 395 | int add_struct_to_list (midl_structure_list *, ea_t, bool); 396 | void add_struct_elem (midl_structure *, midl_arg_struct *); 397 | midl_arg_struct * new_arg_struct (); 398 | bool is_fully_interpreted_stub (); 399 | void set_fully_interpreted_stub (bool); 400 | bool has_conformance_range (); 401 | void set_conformance_range(bool); 402 | ea_t get_callback_address(unsigned long, ea_t); 403 | 404 | unsigned char get_byte2 (ea_t *); 405 | unsigned short get_word2 (ea_t *); 406 | unsigned long get_long2 (ea_t *); 407 | void GET_DATA (ea_t *, void *, size_t); 408 | 409 | static HINSTANCE mIDAhInst = NULL; 410 | 411 | // column widths 412 | static const int widths_fct[] = {5, 10, 32}; 413 | 414 | // column headers 415 | static const char *header_fct[] = 416 | { 417 | "Opcode", 418 | "Address", 419 | "Function Name", 420 | }; 421 | 422 | static const char * popup_null = "\0\0\0\0"; 423 | 424 | static const char * popup_fct[] = 425 | { 426 | "Decompile all", 427 | "Decompile", 428 | "Edit", 429 | NULL, 430 | }; 431 | 432 | static const char* title_fct = "mIDA"; 433 | 434 | #endif -------------------------------------------------------------------------------- /midl_decompile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include "midl_decompile.h" 8 | #include "buffer.h" 9 | #include "display.h" 10 | #include "parser.h" 11 | 12 | #include "kernwin.hpp" 13 | #include "bytes.hpp" 14 | 15 | extern DWORD mFlags; 16 | 17 | int decompile_struct (unsigned int struct_num, midl_structure_list * midl_struct) 18 | { 19 | ea_t pos = midl_struct->mstruct[struct_num].offset; 20 | unsigned int i, arg_num; 21 | int ret; 22 | int mod; 23 | fc_type next_type, type; 24 | midl_pp_list * pp_list = NULL; 25 | midl_arg_struct arg_struct, * tmp_struct; 26 | unsigned short offset; 27 | bool displayed = false; 28 | unsigned short size; 29 | short tmp_offset; 30 | unsigned char num; 31 | bool no_extra; 32 | ea_t tmp_pos = 0, pointer_pos, *p_pos=NULL; 33 | 34 | type = get_byte2 (&pos); 35 | if ( (type != FC_PSTRUCT) && (type != FC_STRUCT) && (type != FC_CPSTRUCT) && (type != FC_CVSTRUCT) && (type != FC_BOGUS_STRUCT) && (type != FC_CSTRUCT) && (type != FC_FORCED_BOGUS_STRUCT)) 36 | { 37 | msg ("Error : unsupported structure\n"); 38 | return -1; 39 | } 40 | 41 | num = get_byte2 (&pos); 42 | size = get_word2 (&pos); 43 | 44 | tmp_pos = pos; 45 | if ((type == FC_CVSTRUCT) || (type == FC_CPSTRUCT) || (type == FC_CSTRUCT) || (type == FC_BOGUS_STRUCT) || (type == FC_FORCED_BOGUS_STRUCT)) 46 | { 47 | tmp_offset = get_word2 (&pos); 48 | if (tmp_offset == 0) 49 | tmp_pos = 0; 50 | else 51 | tmp_pos += tmp_offset; 52 | } 53 | 54 | if ((type == FC_BOGUS_STRUCT) || (type == FC_FORCED_BOGUS_STRUCT)) 55 | { 56 | pointer_pos = pos; 57 | tmp_offset = get_word2 (&pos); 58 | pointer_pos += tmp_offset; 59 | p_pos = & pointer_pos; 60 | } 61 | 62 | offset = 0; 63 | arg_num = 0; 64 | no_extra = false; 65 | 66 | // limit research to FC_END for bugged MIDL structures (?) 67 | for (i=0; istruct_offset = offset; 102 | 103 | next_type = parse_pp_next (&offset, pp_list, &pos, tmp_struct, p_pos); 104 | 105 | if (next_type == FC_ALIGNM2) 106 | mod = 2; 107 | else if (next_type == FC_ALIGNM4) 108 | mod = 4; 109 | else if (next_type == FC_ALIGNM8) 110 | mod = 8; 111 | else 112 | mod = 0; 113 | 114 | if (mod != 0) 115 | while (offset % mod) 116 | offset++; 117 | 118 | if ((next_type != FC_PAD) && (mFlags != 0 || ((next_type < FC_STRUCTPAD1) || (next_type > FC_STRUCTPAD7)) && ((next_type < FC_ALIGNM2) || (next_type > FC_ALIGNM8))) ) 119 | { 120 | add_struct_elem (&midl_struct->mstruct[struct_num], tmp_struct); 121 | } 122 | else 123 | { 124 | free_midl_arg_struct (tmp_struct); 125 | qfree (tmp_struct); 126 | } 127 | } 128 | } 129 | 130 | if (i == RECURSION_LIMIT) 131 | { 132 | free_pp_list (pp_list); 133 | msg ("Error in decompile_struct : RECURSION_LIMIT has been reached !\n"); 134 | return -1; 135 | } 136 | 137 | if ( ((type == FC_CVSTRUCT) || (type == FC_CPSTRUCT) || (type == FC_CSTRUCT) || (type == FC_BOGUS_STRUCT) || (type == FC_FORCED_BOGUS_STRUCT)) && (tmp_pos != 0) && (no_extra == false)) 138 | { 139 | tmp_struct = new_arg_struct (); 140 | if (!tmp_struct) 141 | { 142 | free_pp_list (pp_list); 143 | return -1; 144 | } 145 | 146 | init_midl_arg_struct (tmp_struct, midl_struct); 147 | tmp_struct->struct_offset = offset; 148 | parse_type (&tmp_pos, false, tmp_struct); 149 | add_struct_elem (&midl_struct->mstruct[struct_num], tmp_struct); 150 | } 151 | 152 | free_pp_list (pp_list); 153 | 154 | return 0; 155 | } 156 | 157 | 158 | void decompile_structure (unsigned int i, midl_structure_list * midl_struct, buffer * output_buffer, ea_t callback_table, ea_t expr_table) 159 | { 160 | unsigned int j; 161 | midl_arg_struct_list * ptr; 162 | bool displayed; 163 | char tmp[100]; 164 | char * ptr_name; 165 | int ret; 166 | 167 | displayed = false; 168 | 169 | ret = decompile_struct (i, midl_struct); 170 | if (ret == -1) 171 | return; 172 | 173 | qsnprintf ((char *) tmp, sizeof(tmp), "typedef struct struct_%X {", i+1); 174 | 175 | buffer_add_message (output_buffer, (char *) tmp); 176 | 177 | ptr = midl_struct->mstruct[i].elem; 178 | 179 | j = 0; 180 | 181 | while (ptr != NULL) 182 | { 183 | if (displayed) 184 | buffer_add_message (output_buffer, (char *)";\r\n"); 185 | else 186 | { 187 | displayed = true; 188 | buffer_add_message (output_buffer, (char *)"\r\n"); 189 | } 190 | qsnprintf ((char *)ptr->arg->arg_name, sizeof(ptr->arg->arg_name), "elem_%d", j+1); 191 | arg_struct_to_string (ptr->arg, NULL, 0, &midl_struct->mstruct[i], callback_table, expr_table); 192 | buffer_add_message (output_buffer, (char *)" "); 193 | ptr_name = (char *)ptr->arg->line_string; 194 | if ((strlen (ptr_name) > 0) && (ptr_name[0] == ' ')) 195 | ptr_name++; 196 | buffer_add_message (output_buffer, ptr_name); 197 | 198 | ptr = ptr->next; 199 | j++; 200 | } 201 | 202 | qsnprintf ((char *) tmp, sizeof(tmp), ";\r\n} struct_%X ;\r\n\r\n", i+1); 203 | buffer_add_message (output_buffer, (char *)tmp); 204 | } 205 | 206 | 207 | void decompile_union (unsigned int i, midl_structure_list * midl_struct, buffer * output_buffer, ea_t callback_table, ea_t expr_table) 208 | { 209 | bool displayed; 210 | midl_arg_struct tmp_arg; 211 | short offset; 212 | unsigned int j, case_num; 213 | unsigned char field_num; 214 | fc_type type; 215 | unsigned char switch_type; 216 | char tmp[100]; 217 | ea_t pos = midl_struct->mstruct[i].offset, tmp_pos; 218 | 219 | displayed = false; 220 | 221 | type = get_byte2 (&pos); 222 | switch_type = get_byte2 (&pos); 223 | 224 | if (type == FC_NON_ENCAPSULATED_UNION) 225 | qsnprintf ((char *) tmp, sizeof(tmp), "typedef [switch_type(%s)] union union_%X {", get_base_type (switch_type), i+1); 226 | else 227 | qsnprintf ((char *) tmp, sizeof(tmp), "typedef union union_%X switch (long l1) U%u_TYPE {", i+1, i+1); 228 | 229 | buffer_add_message (output_buffer, (char *) tmp); 230 | 231 | if (type == FC_NON_ENCAPSULATED_UNION) 232 | { 233 | pos += 4; // don't get the switch flag; 234 | if (is_fully_interpreted_stub ()) 235 | { 236 | pos += 2; 237 | 238 | if (has_conformance_range ()) 239 | pos += 10; 240 | 241 | tmp_pos = pos; 242 | offset = get_word2 (&pos); 243 | pos = tmp_pos + offset; 244 | } 245 | } 246 | 247 | get_word2 (&pos); // size ? 248 | field_num = get_byte2 (&pos); 249 | get_byte2 (&pos); //? 250 | 251 | for (j=0; jmstruct[i], callback_table, expr_table); 281 | } 282 | if (type == FC_NON_ENCAPSULATED_UNION) 283 | qsnprintf ((char *) tmp, sizeof(tmp), " [case(%u)] %s", case_num, tmp_arg.line_string); 284 | else 285 | qsnprintf ((char *) tmp, sizeof(tmp), " case %u:\r\n %s", case_num, tmp_arg.line_string); 286 | free_midl_arg_struct (&tmp_arg); 287 | } 288 | 289 | buffer_add_message (output_buffer, (char *) tmp); 290 | } 291 | 292 | // default case 293 | tmp_pos = pos; 294 | offset = get_word2 (&pos); 295 | if (offset != -1) 296 | { 297 | if (displayed) 298 | buffer_add_message (output_buffer, (char *) ";\r\n"); 299 | else 300 | { 301 | displayed = true; 302 | buffer_add_message (output_buffer, (char *)"\r\n"); 303 | } 304 | 305 | if ((offset & 0xFF00) == 0x8000) 306 | { 307 | if (type == FC_NON_ENCAPSULATED_UNION) 308 | qsnprintf ((char *) tmp, sizeof(tmp), " [default] %s elem_%u", get_base_type (offset & 0x00FF), j+1); 309 | else 310 | qsnprintf ((char *) tmp, sizeof(tmp), " default:\r\n %s elem_%u", get_base_type (offset & 0x00FF), j+1); 311 | } 312 | else if (offset == 0) 313 | { 314 | if (type == FC_NON_ENCAPSULATED_UNION) 315 | qsnprintf ((char *) tmp, sizeof(tmp), " [default] "); 316 | else 317 | qsnprintf ((char *) tmp, sizeof(tmp), " default:\r\n "); 318 | } 319 | else 320 | { 321 | init_midl_arg_struct (&tmp_arg, midl_struct); 322 | tmp_pos += offset; 323 | parse_type (&tmp_pos, false, &tmp_arg); 324 | qsnprintf ((char *)tmp_arg.arg_name, sizeof(tmp_arg.arg_name), "elem_%u", j+1); 325 | arg_struct_to_string (&tmp_arg, NULL, 0, &midl_struct->mstruct[i], callback_table, expr_table); 326 | if (type == FC_NON_ENCAPSULATED_UNION) 327 | qsnprintf ((char *) tmp, sizeof(tmp), " [default] %s", tmp_arg.line_string); 328 | else 329 | qsnprintf ((char *) tmp, sizeof(tmp), " default:\r\n %s", tmp_arg.line_string); 330 | free_midl_arg_struct (&tmp_arg); 331 | } 332 | 333 | buffer_add_message (output_buffer, (char *) tmp); 334 | } 335 | 336 | 337 | if (displayed) 338 | buffer_add_message (output_buffer, (char *) ";"); 339 | 340 | qsnprintf ((char *) tmp, sizeof(tmp), "\r\n} union_%X;\r\n\r\n", i+1); 341 | buffer_add_message (output_buffer, (char *) tmp); 342 | } 343 | 344 | 345 | void decompile_struct_list (midl_structure_list * midl_struct, buffer * output_buffer, ea_t callback_table, ea_t expr_table) 346 | { 347 | unsigned int i; 348 | 349 | for (i=0; inum; i++) 350 | { 351 | if (midl_struct->mstruct[i].is_union) 352 | decompile_union (i, midl_struct, output_buffer, callback_table, expr_table); 353 | else 354 | decompile_structure (i, midl_struct, output_buffer, callback_table, expr_table); 355 | } 356 | } 357 | 358 | void decompile_interpreted_function (midl_function * fct, ea_t type_offset, buffer * output_buffer, midl_structure_list * midl_struct, unsigned long ndr_version, ea_t callback_table, ea_t expr_table) 359 | { 360 | unsigned char arg_line[1000]; 361 | unsigned char line[1000]; 362 | unsigned int i,j; 363 | ea_t pos, tmp; 364 | function_parameter * args; 365 | function_parameter tmp_arg; 366 | midl_arg_struct arg_struct; 367 | bool change, displayed; 368 | size_t buf_size = 0; 369 | 370 | if ((ndr_version == 0x50002) || (ndr_version == 0x50004) || (ndr_version == 0x60001)) 371 | set_fully_interpreted_stub (true); 372 | else 373 | set_fully_interpreted_stub (false); 374 | 375 | if (fct->has_conformance_range) 376 | set_conformance_range (true); 377 | else 378 | set_conformance_range (false); 379 | 380 | pos = fct->arg_offset; 381 | 382 | if (fct->arg_num > 0) 383 | { 384 | args = (function_parameter *) qalloc (sizeof(function_parameter) * fct->arg_num); 385 | if (!args) 386 | { 387 | msg ("Error while allocating function_parameter list, exiting.\n"); 388 | return; 389 | } 390 | } 391 | 392 | // Get the list 393 | for (i=0; iarg_num; i++) 394 | { 395 | GET_DATA (&pos, (void *)&args[i], sizeof(function_parameter)); 396 | } 397 | 398 | // sort parameter by stack offset. The return address has the higher address. 399 | // By default it is already sorted, but ... 400 | if (fct->arg_num > 0) 401 | for (i=0; i<(fct->arg_num-1); i++) 402 | { 403 | change = false; 404 | for (j=0; j<(fct->arg_num-1); j++) 405 | { 406 | if (args[i].stack > args[i+1].stack) 407 | { 408 | memcpy ((void *)&tmp_arg, (void *)&args[i], sizeof(function_parameter)); 409 | memcpy ((void *)&args[i], (void *)&args[i+1], sizeof(function_parameter)); 410 | memcpy ((void *)&args[i+1], (void *)&tmp_arg, sizeof(function_parameter)); 411 | change = true; 412 | } 413 | } 414 | if (!change) 415 | break; 416 | } 417 | 418 | if ((fct->arg_num > 0) && (args[fct->arg_num-1].flags & FLAG_RETURN)) 419 | { 420 | if (args[fct->arg_num-1].flags & FLAG_BASE_TYPE) 421 | qsnprintf ((char *)arg_line, sizeof(arg_line), "%s%s", get_base_type (args[fct->arg_num-1].info.type), get_ref (args[fct->arg_num-1].flags)); 422 | else 423 | { 424 | init_midl_arg_struct (&arg_struct, midl_struct); 425 | tmp = args[fct->arg_num-1].info.offset+type_offset; 426 | parse_type(&tmp, true, &arg_struct); 427 | if (args[fct->arg_num-1].flags & FLAG_SIMPLE_REF) 428 | arg_struct.ptr_num++; 429 | 430 | arg_struct_to_string (&arg_struct, args, fct->arg_num, NULL, callback_table, expr_table); 431 | qsnprintf ((char *)arg_line, sizeof(arg_line), "%s", (char *)arg_struct.line_string); 432 | free_midl_arg_struct (&arg_struct); 433 | } 434 | } 435 | else 436 | qsnprintf ((char *)arg_line, sizeof(arg_line), " void"); 437 | 438 | 439 | qsnprintf ((char *)line, sizeof(line), "\r\n/* opcode: 0x%.2X, address: 0x%.8X */\r\n\r\n%s %s (\r\n", fct->opcode, fct->offset, arg_line+1, fct->name); 440 | buffer_add_message (output_buffer, (char *)line); 441 | 442 | displayed = false; 443 | 444 | for (i=0; iarg_num; i++) 445 | { 446 | if (!(args[i].flags & FLAG_RETURN)) 447 | { 448 | if (displayed) 449 | { 450 | buffer_add_message (output_buffer, (char *)",\r\n"); 451 | } 452 | if (args[i].flags & FLAG_BASE_TYPE) 453 | { 454 | qsnprintf ((char *)line, sizeof(line), " %s%s%sarg_%d", get_io (args[i].flags), get_base_type (args[i].info.type), get_ref (args[i].flags),i+1); 455 | buffer_add_message (output_buffer, (char *)line); 456 | } 457 | else 458 | { 459 | init_midl_arg_struct (&arg_struct, midl_struct); 460 | tmp = args[i].info.offset+type_offset; 461 | parse_type (&tmp, true, &arg_struct); 462 | qsnprintf ((char *)arg_struct.arg_name, sizeof(arg_struct.arg_name), "arg_%d", i+1); 463 | if (args[i].flags & FLAG_SIMPLE_REF) 464 | arg_struct.ptr_num++; 465 | 466 | arg_struct_to_string (&arg_struct, args, fct->arg_num, NULL, callback_table, expr_table); 467 | 468 | qsnprintf ((char *)line, sizeof(line), " %s%s", get_io (args[i].flags), (char *)arg_struct.line_string); 469 | buffer_add_message (output_buffer, (char *)line); 470 | free_midl_arg_struct (&arg_struct); 471 | } 472 | displayed = true; 473 | } 474 | } 475 | buffer_add_message (output_buffer, (char *)"\r\n);\r\n\r\n"); 476 | 477 | if (fct->arg_num > 0) 478 | qfree (args); 479 | } 480 | 481 | 482 | void decompile_inline_function (midl_function * fct, ea_t type_offset, buffer * output_buffer, midl_structure_list * midl_struct, unsigned long ndr_version, ea_t callback_table, ea_t expr_table) 483 | { 484 | unsigned char arg_line[1000]; 485 | unsigned char line[1000]; 486 | unsigned char stack, byte; 487 | unsigned int i; 488 | ea_t pos, tmp; 489 | function_parameter * args = NULL, * tmp_args; 490 | midl_arg_struct arg_struct; 491 | bool displayed; 492 | size_t buf_size = 0; 493 | unsigned long stack_pos; 494 | 495 | pos = fct->arg_offset; 496 | 497 | if (pos == BADADDR) 498 | { 499 | msg ("Function %X : argument offset is unknown. Assuming there is no argument.\n", fct->opcode); 500 | qsnprintf ((char *)line, sizeof(line), "unknown %s (\r\n", fct->name); 501 | buffer_add_message (output_buffer, (char *)line); 502 | buffer_add_message (output_buffer, (char *)");\r\n\r\n"); 503 | return; 504 | } 505 | 506 | fct->arg_num = 0; 507 | 508 | set_fully_interpreted_stub (false); 509 | stack_pos = 0; 510 | 511 | for (i=0; i< 1000; i++) 512 | { 513 | byte = get_byte2 (&pos); 514 | if ( (byte != FC_END) && (byte != FC_PAD) ) 515 | { 516 | if (!args) 517 | { 518 | args = (function_parameter *) qalloc (sizeof(function_parameter) * (i+1)); 519 | if (!args) 520 | { 521 | msg ("Error while allocating function_parameter list, exiting.\n"); 522 | return; 523 | } 524 | } 525 | else 526 | { 527 | tmp_args = (function_parameter *) qrealloc (args, sizeof(function_parameter) * (i+1)); 528 | if (!tmp_args) 529 | { 530 | msg ("Error while reallocating function_parameter list, exiting.\n"); 531 | qfree (args); 532 | return; 533 | } 534 | 535 | args = tmp_args; 536 | } 537 | 538 | fct->arg_num++; 539 | 540 | args[i].flags = byte; 541 | args[i].stack = stack_pos; 542 | stack_pos += sizeof(long); 543 | 544 | if ( (byte == FC_RETURN_PARAM) || (byte == FC_IN_PARAM) || (byte == FC_OUT_PARAM) || (byte == FC_IN_OUT_PARAM) ) 545 | { 546 | stack = get_byte2 (&pos); 547 | args[i].info.offset = get_word2 (&pos); 548 | } 549 | else if ( (byte == FC_IN_PARAM_BASETYPE) || (byte == FC_RETURN_PARAM_BASETYPE) ) 550 | args[i].info.type = get_byte2 (&pos); 551 | else 552 | { 553 | pos--; 554 | args[i].flags = FC_CRAFTED_RETURN_PARAM; 555 | args[i].stack = (pos) >> 16; 556 | args[i].info.offset = pos & 0xFFFF; 557 | byte = FC_END; 558 | } 559 | 560 | } 561 | 562 | if ((byte == FC_END) || (byte == FC_RETURN_PARAM) || (byte == FC_RETURN_PARAM_BASETYPE)) 563 | break; 564 | } 565 | 566 | 567 | if ((fct->arg_num > 0) && ( (args[fct->arg_num-1].flags == FC_RETURN_PARAM) || (args[fct->arg_num-1].flags == FC_RETURN_PARAM_BASETYPE) || (args[fct->arg_num-1].flags == FC_CRAFTED_RETURN_PARAM)) ) 568 | { 569 | if (args[fct->arg_num-1].flags == FC_RETURN_PARAM_BASETYPE) 570 | qsnprintf ((char *)arg_line, sizeof(arg_line), "%s ", get_base_type (args[fct->arg_num-1].info.type)); 571 | else 572 | { 573 | init_midl_arg_struct (&arg_struct, midl_struct); 574 | if (args[fct->arg_num-1].flags == FC_CRAFTED_RETURN_PARAM) 575 | tmp = (args[fct->arg_num-1].stack << 16) + args[fct->arg_num-1].info.offset; 576 | else 577 | tmp = args[fct->arg_num-1].info.offset+type_offset; 578 | parse_type(&tmp, true, &arg_struct); 579 | arg_struct_to_string (&arg_struct, args, fct->arg_num, NULL, callback_table, expr_table); 580 | qsnprintf ((char *)arg_line, sizeof(arg_line), "%s", (char *)arg_struct.line_string); 581 | free_midl_arg_struct (&arg_struct); 582 | } 583 | } 584 | else 585 | qsnprintf ((char *)arg_line, sizeof(arg_line), " void"); 586 | 587 | 588 | qsnprintf ((char *)line, sizeof(line), "\r\n/* opcode: 0x%.2X, address: 0x%.8X */\r\n\r\n%s %s (\r\n", fct->opcode, fct->offset, (arg_line[0] == ' ') ? arg_line+1 : arg_line, fct->name); 589 | buffer_add_message (output_buffer, (char *)line); 590 | 591 | displayed = false; 592 | 593 | for (i=0; iarg_num; i++) 594 | { 595 | if ((args[i].flags != FC_RETURN_PARAM) && (args[i].flags != FC_RETURN_PARAM_BASETYPE) && (args[i].flags != FC_CRAFTED_RETURN_PARAM)) 596 | { 597 | if (displayed) 598 | { 599 | buffer_add_message (output_buffer, (char *)",\r\n"); 600 | } 601 | if (args[i].flags == FC_IN_PARAM_BASETYPE) 602 | { 603 | qsnprintf ((char *)line, sizeof(line), " %s%s arg_%d", get_io2 (args[i].flags), get_base_type (args[i].info.type),i+1); 604 | buffer_add_message (output_buffer, (char *)line); 605 | } 606 | else 607 | { 608 | init_midl_arg_struct (&arg_struct, midl_struct); 609 | tmp = args[i].info.offset+type_offset; 610 | parse_type (&tmp, true, &arg_struct); 611 | qsnprintf ((char *)arg_struct.arg_name, sizeof(arg_struct.arg_name), "arg_%d", i+1); 612 | 613 | arg_struct_to_string (&arg_struct, args, fct->arg_num, NULL, callback_table, expr_table); 614 | 615 | qsnprintf ((char *)line, sizeof(line), " %s%s", get_io2 (args[i].flags), (char *)arg_struct.line_string); 616 | buffer_add_message (output_buffer, (char *)line); 617 | 618 | free_midl_arg_struct (&arg_struct); 619 | } 620 | displayed = true; 621 | } 622 | } 623 | buffer_add_message (output_buffer, (char *)"\r\n);\r\n\r\n"); 624 | 625 | qfree (args); 626 | } 627 | 628 | 629 | void decompile_function (midl_function * fct, ea_t type_offset, buffer * output_buffer, midl_structure_list * midl_struct, unsigned long ndr_version, ea_t callback_table, ea_t expr_table) 630 | { 631 | if (fct->is_inline) 632 | decompile_inline_function (fct, type_offset, output_buffer, midl_struct, ndr_version, callback_table, expr_table); 633 | else 634 | decompile_interpreted_function (fct, type_offset, output_buffer, midl_struct, ndr_version, callback_table, expr_table); 635 | } -------------------------------------------------------------------------------- /midl_decompile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #ifndef _MIDL_DECOMPILE_H_ 8 | #define _MIDL_DECOMPILE_H_ 9 | 10 | #include "midl.h" 11 | #include "buffer.h" 12 | 13 | void decompile_function (midl_function *, ea_t, buffer *, midl_structure_list *, unsigned long, ea_t, ea_t); 14 | void decompile_struct_list (midl_structure_list *, buffer *, ea_t, ea_t); 15 | void free_midl_structure_list (midl_structure_list *); 16 | 17 | #endif -------------------------------------------------------------------------------- /midl_scan.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include "midl_scan.h" 8 | #include "midl.h" 9 | #include "tracer.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | midl_interface * extract_midl (ea_t ea) 20 | { 21 | unsigned char b; 22 | ea_t pos,ptr,tmp,expr; 23 | midl_interface * midl_int; 24 | 25 | // First byte is size and must be 0x44 26 | b = get_byte (ea); 27 | if (b != 0x44) 28 | return NULL; 29 | 30 | midl_int = (midl_interface *) qalloc (sizeof(midl_interface)); 31 | if (!midl_int) 32 | return NULL; 33 | 34 | pos = ea + sizeof(unsigned long); 35 | midl_int->expr_table = BADADDR; 36 | 37 | // Extract interface uuid 38 | midl_int->uuid.x1 = get_long2 (&pos); 39 | midl_int->uuid.x2 = get_word2 (&pos); 40 | midl_int->uuid.x3 = get_word2 (&pos); 41 | GET_DATA (&pos, (void *) midl_int->uuid.x4, 8); 42 | midl_int->uuid.major = get_word2 (&pos); 43 | midl_int->uuid.minor = get_word2 (&pos); 44 | 45 | // Get pointer to info structure 46 | pos += 5*sizeof(unsigned long); 47 | midl_int->dispatch_table = get_long2 (&pos); 48 | pos += 3*sizeof(unsigned long); 49 | ptr = get_long (pos); 50 | if (ptr == 0) 51 | { 52 | if (midl_int->dispatch_table != NULL) 53 | { 54 | midl_int->is_inline = true; 55 | midl_int->is_interpreted = false; 56 | } 57 | midl_int->fct_ptrs = BADADDR; 58 | midl_int->fct_raw = BADADDR; 59 | midl_int->callback_table = BADADDR; 60 | midl_int->format_string_offset_table = BADADDR; 61 | } 62 | else 63 | { 64 | midl_int->is_inline = false; 65 | midl_int->is_interpreted = true; 66 | tmp = get_long2(&ptr); 67 | midl_int->callback_table = get_long ( tmp + 6*sizeof(long) ); 68 | if (midl_int->callback_table == 0) 69 | midl_int->callback_table = BADADDR; 70 | midl_int->type_raw = get_long ( tmp + 8*sizeof(long) ); 71 | midl_int->ndr_version = get_long ( tmp + 10*sizeof(long) ); 72 | expr = get_long ( tmp + 19*sizeof(long) ); 73 | if (expr != 0) 74 | { 75 | expr = get_long (expr + sizeof(long)); 76 | if (expr != 0) 77 | midl_int->expr_table = expr; 78 | } 79 | midl_int->fct_ptrs = get_long2 (&ptr); 80 | midl_int->fct_raw = get_long2 (&ptr); 81 | midl_int->format_string_offset_table = get_long2 (&ptr); 82 | } 83 | 84 | // Remove interfaces without structures 85 | /* 86 | if ((midl_int->fct_ptrs == BADADDR) || (midl_int->fct_raw == BADADDR)) 87 | { 88 | qfree (midl_int); 89 | return NULL; 90 | } 91 | */ 92 | 93 | return midl_int; 94 | } 95 | 96 | 97 | void get_inline_arg_offset (ea_t ea, ea_t * arg_offset, ea_t * format_offset) 98 | { 99 | unsigned int i; 100 | ea_t stub; 101 | flags_t flags; 102 | char buffer[200]; 103 | 104 | //flags = getFlags (ea); 105 | //if (!isCode (flags)) 106 | //{ 107 | // msg ("Function at address %.8X is not defined. Please decompile it before launching mIDA.\n", ea); 108 | // return; 109 | //} 110 | 111 | // 100 should be enough first (a full scanner would be better though ;-) 112 | for (i=0; i<100; i++) 113 | { 114 | flags = getFlags (ea); 115 | if (!isCode (flags)) 116 | break; 117 | 118 | generate_disasm_line(ea,(char*)buffer,sizeof(buffer)); 119 | tag_remove((char*)buffer,(char*)buffer,sizeof(buffer)); 120 | 121 | if ( (format_offset != NULL) && (strstr((char*)buffer, "pStubDescriptor")) ) 122 | { 123 | stub = get_first_dref_from (ea); 124 | *format_offset = get_long (stub + sizeof(long)*8); 125 | } 126 | else if (strstr((char*)buffer, "pFormat")) 127 | { 128 | *arg_offset = get_first_dref_from (ea); 129 | return; 130 | } 131 | 132 | ea += get_item_size(ea); 133 | } 134 | } 135 | 136 | 137 | void clean_name (char * name, size_t len) 138 | { 139 | int i; 140 | 141 | for (i=0; idispatch_table; 163 | ea_t * format_offset; 164 | 165 | fct_num = get_long2 (&pos); 166 | if (fct_num > 1024) 167 | { 168 | msg ("There are more than 1024 RPC functions, this may be a bug !\n"); 169 | return NULL; 170 | } 171 | 172 | mi->fct_ptrs = get_long2 (&pos); 173 | 174 | fct_list = (midl_fct_list *) qalloc (sizeof(midl_fct_list)); 175 | if (!fct_list) 176 | return NULL; 177 | 178 | fct_list->fct_num = fct_num; 179 | fct_list->list = (midl_function *) qalloc (sizeof(midl_function)*fct_num); 180 | if (!fct_list->list) 181 | { 182 | qfree (fct_list); 183 | return NULL; 184 | } 185 | 186 | pos = mi->fct_ptrs; 187 | 188 | for (i=0; ilist[i]; 191 | fct->offset = get_long2 (&pos); 192 | ida_define_fct (fct->offset); 193 | fct->arg_num = 0; 194 | fct->is_inline = true; 195 | fct->opcode = (unsigned short)i; 196 | get_func_name (fct->offset, (char *)fct->name, sizeof(fct->name)); 197 | 198 | if (strlen((char *)fct->name) <= 0) 199 | qsnprintf ((char *)fct->name, sizeof(fct->name), "function_%.2X", fct->opcode); 200 | 201 | clean_name ((char *)fct->name, strlen((char *)fct->name)); 202 | 203 | if (mi->format_string_offset_table == BADADDR) 204 | format_offset = &mi->type_raw; 205 | else 206 | format_offset = NULL; 207 | 208 | fct->arg_offset = BADADDR; 209 | //get_inline_arg_offset (fct->offset, &fct->arg_offset, format_offset); 210 | trace_rpc_func (fct->offset, &fct->arg_offset, format_offset); 211 | 212 | if (debug_mode()) 213 | msg ("Opcode : 0x%.2X , address : 0x%.8X, name : %s\n", fct->opcode, fct->offset, fct->name); 214 | } 215 | 216 | return fct_list; 217 | } 218 | 219 | 220 | midl_fct_list * decompile_midl_interpreted (midl_interface * mi) 221 | { 222 | midl_function * fct = NULL; 223 | midl_fct_list * fct_list = NULL; 224 | ea_t pos, table_pos, old_pos; 225 | unsigned char handle_type, old_flags, context_type, context_flags, context_value, padding, ext_flags; 226 | unsigned char oi2_flags, arg_num, fct_head_size, next; 227 | unsigned long unknown_long, unknown_word1, unknown_word2; 228 | unsigned short opcode, stack_size, context_stack; 229 | unsigned long fct_num, i; 230 | 231 | fct_num = get_long (mi->dispatch_table); 232 | if (fct_num > 1024) 233 | { 234 | msg ("There are more than 1024 RPC functions, this may be a bug !\n"); 235 | return NULL; 236 | } 237 | 238 | fct_list = (midl_fct_list *) qalloc (sizeof(midl_fct_list)); 239 | if (!fct_list) 240 | return NULL; 241 | 242 | fct_list->fct_num = fct_num; 243 | fct_list->list = (midl_function *)qalloc (sizeof(midl_function)*fct_num); 244 | if (!fct_list->list) 245 | { 246 | qfree (fct_list); 247 | return NULL; 248 | } 249 | 250 | table_pos = mi->format_string_offset_table; 251 | 252 | for (i=0; ilist[i]; 255 | fct->offset = BADADDR; 256 | fct->arg_num = 0; 257 | fct->is_inline = false; 258 | 259 | old_pos = pos = mi->fct_raw + get_word2 (&table_pos); 260 | 261 | handle_type = get_byte2 (&pos); 262 | old_flags = get_byte2 (&pos); 263 | 264 | unknown_long = get_long2 (&pos); 265 | opcode = get_word2 (&pos); 266 | stack_size = get_word2 (&pos); 267 | 268 | if (handle_type == 0) 269 | { 270 | context_type = get_byte2 (&pos); 271 | if ((context_type == FC_BIND_CONTEXT) || (context_type == FC_BIND_GENERIC)) 272 | { 273 | context_flags = get_byte2 (&pos); 274 | context_stack = get_word2 (&pos); 275 | context_value = get_byte2 (&pos); 276 | padding = get_byte2 (&pos); 277 | } 278 | else if (context_type == FC_BIND_PRIMITIVE) 279 | { 280 | context_flags = get_byte2 (&pos); 281 | context_stack = get_word2 (&pos); 282 | } 283 | else if ( ((mi->ndr_version == 0x20000) || (mi->ndr_version == 0x20000)) && ((context_type == FC_IN_PARAM_BASETYPE) || 284 | (context_type == FC_IN_PARAM) || 285 | (context_type == FC_IN_OUT_PARAM) || 286 | (context_type == FC_OUT_PARAM) || 287 | (context_type == FC_RETURN_PARAM) || 288 | (context_type == FC_RETURN_PARAM_BASETYPE) ) ) 289 | { 290 | fct->opcode = opcode; 291 | fct->arg_num = 0; 292 | fct->arg_offset = pos - 1; 293 | fct->is_inline = true; 294 | fct->offset = get_long (mi->fct_ptrs + opcode*sizeof(unsigned long)); 295 | ida_define_fct (fct->offset); 296 | get_func_name (fct->offset, (char *)fct->name, sizeof(fct->name)); 297 | if (strlen((char *)fct->name) <= 0) 298 | qsnprintf ((char *)fct->name, sizeof(fct->name), "function_%.2X", fct->opcode); 299 | 300 | clean_name ((char *)fct->name, strlen((char *)fct->name)); 301 | } 302 | else 303 | { 304 | msg ("Unsupported function bind type : %.2X\n", context_type); 305 | free_fct_list (fct_list); 306 | return NULL; 307 | } 308 | } 309 | else if (mi->ndr_version == 0x10001) 310 | { 311 | pos = old_pos; 312 | opcode = i; 313 | } 314 | 315 | if (!fct->is_inline) 316 | { 317 | next = get_byte (pos); 318 | if ( ((mi->ndr_version == 0x20000) || (mi->ndr_version == 0x10001)) && ((handle_type != 0) || (context_type == FC_BIND_PRIMITIVE)) && 319 | ( (next == FC_IN_PARAM_BASETYPE) || 320 | (next == FC_IN_PARAM) || 321 | (next == FC_IN_OUT_PARAM) || 322 | (next == FC_OUT_PARAM) || 323 | (next == FC_RETURN_PARAM) || 324 | (next == FC_RETURN_PARAM_BASETYPE) ) ) 325 | { 326 | fct->opcode = opcode; 327 | fct->arg_num = 0; 328 | fct->arg_offset = pos; 329 | fct->is_inline = true; 330 | fct->offset = get_long (mi->fct_ptrs + opcode*sizeof(unsigned long)); 331 | ida_define_fct (fct->offset); 332 | get_func_name (fct->offset, (char *)fct->name, sizeof(fct->name)); 333 | if (strlen((char *)fct->name) <= 0) 334 | qsnprintf ((char *)fct->name, sizeof(fct->name), "function_%.2X", fct->opcode); 335 | 336 | clean_name ((char *)fct->name, strlen((char *)fct->name)); 337 | } 338 | 339 | if (!fct->is_inline) 340 | { 341 | fct->has_conformance_range = false; 342 | 343 | unknown_word1 = get_word2 (&pos); 344 | unknown_word2 = get_word2 (&pos); 345 | oi2_flags = get_byte2 (&pos); 346 | arg_num = get_byte2 (&pos); 347 | 348 | // only for fully interpreted stubs 349 | if ((mi->ndr_version == 0x50002) ||(mi->ndr_version == 0x50004) || (mi->ndr_version == 0x60001)) 350 | { 351 | fct_head_size = get_byte2 (&pos); 352 | if ((fct_head_size > 0) && (mi->ndr_version == 0x60001)) 353 | { 354 | ext_flags = get_byte (pos); 355 | if (ext_flags & 0x40) // has_conformance_range 356 | fct->has_conformance_range = true; 357 | } 358 | 359 | pos += fct_head_size - 1; 360 | } 361 | 362 | fct->opcode = opcode; 363 | fct->arg_num = arg_num; 364 | fct->arg_offset = pos; 365 | fct->offset = get_long (mi->fct_ptrs + opcode*sizeof(unsigned long)); 366 | ida_define_fct (fct->offset); 367 | get_func_name (fct->offset, (char *)fct->name, sizeof(fct->name)); 368 | if (strlen((char *)fct->name) <= 0) 369 | qsnprintf ((char *)fct->name, sizeof(fct->name), "function_%.2X", fct->opcode); 370 | 371 | clean_name ((char *)fct->name, strlen((char *)fct->name)); 372 | 373 | pos += (3 * sizeof(unsigned short)) * arg_num; 374 | } 375 | } 376 | 377 | if (debug_mode()) 378 | msg ("Opcode : 0x%.2X , address : 0x%.8X, name : %s\n", fct->opcode, fct->offset, fct->name); 379 | } 380 | 381 | return fct_list; 382 | } 383 | 384 | 385 | 386 | midl_fct_list * decompile_midl(midl_interface * mi) 387 | { 388 | if (mi->dispatch_table == NULL) 389 | { 390 | // client stub 391 | return NULL; 392 | } 393 | else if (mi->fct_raw == BADADDR) 394 | { 395 | // inline stub 396 | return decompile_midl_inline (mi); 397 | } 398 | else 399 | { 400 | // interpreted stub 401 | if ((mi->ndr_version != 0x50002) && (mi->ndr_version != 0x50004) && (mi->ndr_version != 0x20000) && (mi->ndr_version != 0x60001) && (mi->ndr_version != 0x10001)) 402 | { 403 | msg ("Unsupported NDR version !\n"); 404 | return NULL; 405 | } 406 | 407 | return decompile_midl_interpreted (mi); 408 | } 409 | } 410 | 411 | 412 | midl_interface_list * midl_scan () 413 | { 414 | ea_t ea_begin, ea_end, midl_ea; 415 | unsigned int num_struct = 0; 416 | midl_interface * mi; 417 | midl_fct_list * fct_list; 418 | midl_interface_list * int_list, * org_list; 419 | 420 | int_list = (midl_interface_list *) qalloc (sizeof (midl_interface_list)); 421 | if (!int_list) 422 | { 423 | msg ("Can't allocate midl_interface_list structure, exiting.\n"); 424 | return NULL; 425 | } 426 | int_list->mi = NULL; 427 | int_list->next = NULL; 428 | 429 | org_list = int_list; 430 | 431 | /* 432 | ea_begin = seg->startEA; 433 | ea_end = seg->endEA; 434 | */ 435 | ea_begin = inf.minEA; 436 | ea_end = inf.maxEA; 437 | 438 | show_wait_box ("MIDL interface scanning is in progress"); 439 | msg ("Scanning database for MIDL structures ...\n"); 440 | 441 | autoWait(); 442 | 443 | do 444 | { 445 | midl_ea = find_binary (ea_begin, ea_end, MIDL_LANGUAGE, 0, SEARCH_DOWN); 446 | if (midl_ea != BADADDR) 447 | { 448 | // midl structure start is 6 DWORD before the language version 449 | mi = extract_midl (midl_ea-(4*6)); 450 | if (mi != NULL) 451 | { 452 | if (debug_mode()) 453 | { 454 | msg ("Found MIDL structure at address 0x%.8X : %.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x v%d.%d\n", 455 | midl_ea-(4*6), 456 | mi->uuid.x1, mi->uuid.x2, mi->uuid.x3, 457 | mi->uuid.x4[0],mi->uuid.x4[1], 458 | mi->uuid.x4[2],mi->uuid.x4[3],mi->uuid.x4[4],mi->uuid.x4[5],mi->uuid.x4[6],mi->uuid.x4[7], 459 | mi->uuid.major, mi->uuid.minor); 460 | } 461 | 462 | num_struct ++; 463 | if (mi->dispatch_table != NULL) 464 | { 465 | fct_list = decompile_midl (mi); 466 | 467 | mi->list = fct_list; 468 | int_list->mi = mi; 469 | 470 | int_list->next = (midl_interface_list *) qalloc (sizeof (midl_interface_list)); 471 | if (!int_list) 472 | { 473 | msg ("Can't allocate midl_interface_list structure, exiting.\n"); 474 | break; 475 | } 476 | int_list = int_list->next; 477 | int_list->mi = NULL; 478 | int_list->next = NULL; 479 | } 480 | } 481 | ea_begin = midl_ea + 1; 482 | } 483 | } 484 | while (midl_ea != BADADDR); 485 | 486 | msg ("Number of MIDL structures found: %d\n", num_struct); 487 | hide_wait_box (); 488 | 489 | return org_list; 490 | } 491 | -------------------------------------------------------------------------------- /midl_scan.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #ifndef _MIDL_SCAN_H_ 8 | #define _MIDL_SCAN_H_ 9 | 10 | #include "midl.h" 11 | 12 | midl_interface_list * midl_scan (); 13 | 14 | #endif -------------------------------------------------------------------------------- /nessus_logo_16x16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tenable/mIDA/3f821d815570d079417029a0e6c303442ffbad94/nessus_logo_16x16.ico -------------------------------------------------------------------------------- /parser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include "parser.h" 8 | 9 | #include "bytes.hpp" 10 | #include "kernwin.hpp" 11 | 12 | 13 | unsigned char * get_base_type (unsigned char type) 14 | { 15 | switch (type) 16 | { 17 | case FC_BYTE: 18 | return (unsigned char *) " byte "; 19 | case FC_CHAR: 20 | return (unsigned char *) " char "; 21 | case FC_SMALL: 22 | return (unsigned char *) " small "; 23 | case FC_USMALL: 24 | return (unsigned char *) " small "; 25 | case FC_WCHAR: 26 | return (unsigned char *) " wchar_t "; 27 | case FC_SHORT: 28 | return (unsigned char *) " short "; 29 | case FC_USHORT: 30 | return (unsigned char *) " unsigned short "; 31 | case FC_LONG: 32 | return (unsigned char *) " long "; 33 | case FC_ULONG: 34 | return (unsigned char *) " unsigned long "; 35 | case FC_FLOAT: 36 | return (unsigned char *) " float "; 37 | case FC_HYPER: 38 | return (unsigned char *) " hyper "; 39 | case FC_DOUBLE: 40 | return (unsigned char *) " double "; 41 | case FC_ENUM16: 42 | return (unsigned char *) " /* enum16 */ short "; 43 | case FC_ENUM32: 44 | return (unsigned char *) " /* enum32 */ long "; 45 | case FC_ERROR_STATUS_T: 46 | return (unsigned char *) " error_status_t "; 47 | case FC_INT3264: 48 | return (unsigned char *) " __int3264 "; 49 | case FC_UINT3264: 50 | return (unsigned char *) " unsigned __int3264 "; 51 | case FC_IGNORE: 52 | return (unsigned char *) " handle_t "; 53 | default: 54 | msg ("Unknown base type : %.2X.\n", type); 55 | return (unsigned char *) " unknown "; 56 | } 57 | } 58 | 59 | 60 | unsigned long get_base_type_length (unsigned char type) 61 | { 62 | switch (type) 63 | { 64 | case FC_BYTE: 65 | case FC_CHAR: 66 | case FC_SMALL: 67 | case FC_USMALL: 68 | return 1; 69 | case FC_WCHAR: 70 | case FC_SHORT: 71 | case FC_USHORT: 72 | return 2; 73 | case FC_ERROR_STATUS_T: 74 | case FC_ENUM16: 75 | case FC_ENUM32: 76 | case FC_LONG: 77 | case FC_ULONG: 78 | return 4; 79 | case FC_FLOAT: 80 | case FC_HYPER: 81 | case FC_DOUBLE: 82 | case FC_INT3264: 83 | case FC_UINT3264: 84 | return 8; 85 | case FC_IGNORE: 86 | return 0; 87 | default: 88 | msg ("Unknown base type : %.2X.\n", type); 89 | return 1; 90 | } 91 | } 92 | 93 | 94 | bool is_base_type (unsigned char type) 95 | { 96 | switch (type) 97 | { 98 | case FC_BYTE: 99 | case FC_CHAR: 100 | case FC_SMALL: 101 | case FC_USMALL: 102 | case FC_WCHAR: 103 | case FC_SHORT: 104 | case FC_USHORT: 105 | case FC_LONG: 106 | case FC_ULONG: 107 | case FC_FLOAT: 108 | case FC_DOUBLE: 109 | case FC_HYPER: 110 | case FC_ENUM16: 111 | case FC_ENUM32: 112 | case FC_ERROR_STATUS_T: 113 | case FC_INT3264: 114 | case FC_UINT3264: 115 | case FC_IGNORE: 116 | return true; 117 | default: 118 | return false; 119 | } 120 | } 121 | 122 | unsigned char * get_io (unsigned int type) 123 | { 124 | if (type & FLAG_RETURN) 125 | return (unsigned char *) ""; 126 | 127 | if ((type & FLAG_IN) && (type & FLAG_OUT)) 128 | return (unsigned char *) "[in, out]"; 129 | 130 | if (type & FLAG_IN) 131 | return (unsigned char *) "[in]"; 132 | 133 | if (type & FLAG_OUT) 134 | return (unsigned char *) "[out]"; 135 | 136 | return (unsigned char *) "[?]"; 137 | } 138 | 139 | unsigned char * get_io2 (unsigned int type) 140 | { 141 | if ((type == FC_RETURN_PARAM) || (type == FC_RETURN_PARAM_BASETYPE)) 142 | return (unsigned char *) ""; 143 | 144 | if (type == FC_IN_OUT_PARAM) 145 | return (unsigned char *) "[in, out]"; 146 | 147 | if ((type == FC_IN_PARAM) || (type == FC_IN_PARAM_BASETYPE)) 148 | return (unsigned char *) "[in]"; 149 | 150 | if (type == FC_OUT_PARAM) 151 | return (unsigned char *) "[out]"; 152 | 153 | return (unsigned char *) "[?]"; 154 | } 155 | 156 | unsigned char * get_ref (unsigned int type) 157 | { 158 | if (type & FLAG_SIMPLE_REF) 159 | { 160 | return (unsigned char *) "* "; 161 | } 162 | 163 | return (unsigned char *) ""; 164 | } 165 | 166 | 167 | unsigned int get_argument_number (unsigned long offset, function_parameter * args, unsigned int arg_num) 168 | { 169 | int i; 170 | 171 | for (i=0; arg_num; i++) 172 | { 173 | if (args[i].stack == offset) 174 | return i; 175 | } 176 | 177 | return -1; 178 | } 179 | 180 | void set_last_size (midl_arg_struct * arg, unsigned long size) 181 | { 182 | arg->last_struct_size = size; 183 | } 184 | 185 | 186 | unsigned char get_next_type (ea_t * pos) 187 | { 188 | return get_byte (*pos); 189 | } 190 | 191 | 192 | // pointer struct : 193 | // byte type 194 | // byte flags 195 | // union { 196 | // char type; // if flags == FLAGS_SIMPLE_POINTER 197 | // short offset; 198 | // } 199 | 200 | fc_type parse_pointer (fc_type type, ea_t * pos, bool first, midl_arg_struct * arg) 201 | { 202 | fc_flag flags; 203 | fc_offset offset; 204 | ea_t tmp; 205 | unsigned char padding; 206 | 207 | // increase pointer number 208 | arg->ptr_num++; 209 | 210 | // if unique set to unique 211 | if ((type == FC_UP) && first) 212 | arg->is_unique = true; 213 | 214 | if ((type == FC_RP) && first) 215 | arg->is_reference = true; 216 | 217 | if ((type == FC_FP) && first) 218 | arg->is_ptr = true; 219 | 220 | flags = get_byte2 (pos); 221 | if (flags & FLAG_SIMPLE_POINTER) 222 | { 223 | tmp = *pos; 224 | parse_type (pos, false, arg); // Base type 225 | if (*pos-tmp<2) 226 | padding = get_byte2 (pos); 227 | } 228 | else 229 | { 230 | tmp = *pos; 231 | offset = get_word2 (pos); 232 | tmp += offset; 233 | 234 | parse_type (&tmp, false, arg); 235 | } 236 | 237 | return type; 238 | } 239 | 240 | 241 | // embedded complex struct : 242 | // byte type 243 | // byte flags 244 | // short offset; 245 | 246 | fc_type parse_embedded_complex (ea_t * pos, midl_arg_struct * arg) 247 | { 248 | fc_flag flags; 249 | fc_offset offset; 250 | ea_t tmp; 251 | 252 | flags = get_byte2 (pos); 253 | tmp = *pos; 254 | offset = get_word2 (pos); 255 | tmp += offset; 256 | 257 | parse_type (&tmp, false, arg); 258 | 259 | return FC_EMBEDDED_COMPLEX; 260 | } 261 | 262 | // range struct : 263 | // byte type 264 | // byte value_type 265 | // long range_first 266 | // long range_end 267 | 268 | fc_type parse_range (ea_t * pos, midl_arg_struct * arg) 269 | { 270 | arg->is_range = true; 271 | 272 | parse_type (pos, false, arg); 273 | arg->range.begin = get_long2 (pos); 274 | arg->range.end = get_long2 (pos); 275 | 276 | return FC_RANGE; 277 | } 278 | 279 | void set_arg_type_name (midl_arg_struct * arg, char * name) 280 | { 281 | qstrncpy ((char *)arg->type_name, (char *) name, sizeof(arg->type_name)); 282 | } 283 | 284 | 285 | // Base type struct : 286 | // byte type 287 | 288 | fc_type parse_base_type (fc_type type, ea_t * pos, midl_arg_struct * arg) 289 | { 290 | set_arg_type_name (arg, (char *)get_base_type (type)); 291 | set_last_size (arg, get_base_type_length(type)); 292 | return type; 293 | } 294 | 295 | fc_type parse_structpad (fc_type type, ea_t * pos, midl_arg_struct * arg) 296 | { 297 | set_last_size (arg,type - (FC_STRUCTPAD1-1)); 298 | arg->is_pad = TRUE; 299 | arg->type = type; 300 | return type; 301 | } 302 | 303 | fc_type parse_alignment (fc_type type, ea_t * pos, midl_arg_struct * arg) 304 | { 305 | // don't know how to handle exactly - can't recreate that type 306 | // set_last_size (arg, 2); 307 | arg->is_pad = TRUE; 308 | arg->type = type; 309 | return type; 310 | } 311 | 312 | 313 | // 0x46, /* FC_NO_REPEAT */ 314 | // 0x5c, /* FC_PAD */ 315 | // NdrFcShort( 0x4 ), /* 4 */ 316 | // NdrFcShort( 0x4 ), /* 4 */ 317 | // 0x12, 0x0, /* FC_UP */ 318 | // NdrFcShort( 0xffe0 ), /* Offset= -32 (10) */ 319 | 320 | // 0x48, /* FC_VARIABLE_REPEAT */ 321 | // 0x49, /* FC_FIXED_OFFSET */ 322 | // NdrFcShort( 0x8 ), /* 8 */ 323 | // NdrFcShort( 0x0 ), /* 0 */ 324 | // NdrFcShort( 0x1 ), /* 1 */ 325 | // NdrFcShort( 0x4 ), /* 4 */ 326 | // NdrFcShort( 0x4 ), /* 4 */ 327 | // 0x12, 0x0, /* FC_UP */ 328 | // NdrFcShort( 0xffbe ), /* Offset= -66 (10) */ 329 | 330 | // 0x47, /* FC_FIXED_REPEAT */ 331 | // 0x5c, /* FC_PAD */ 332 | // NdrFcShort( 0xc ), /* 12 */ 333 | // NdrFcShort( 0x4 ), /* 4 */ 334 | // NdrFcShort( 0x0 ), /* 0 */ 335 | // NdrFcShort( 0x1 ), /* 1 */ 336 | // NdrFcShort( 0x0 ), /* 0 */ 337 | // NdrFcShort( 0x0 ), /* 0 */ 338 | // 0x12, 0x8, /* FC_UP [simple_pointer] */ 339 | 340 | fc_type parse_repeat (midl_pp_list * pp_list, ea_t * pos, fc_type type, midl_arg_struct * arg) 341 | { 342 | unsigned char value_type; 343 | unsigned int i; 344 | unsigned short elem_num = 0, offset1, offset2, size; 345 | midl_arg_struct tmp_arg; 346 | 347 | value_type = get_byte2 (pos); 348 | 349 | if (type == FC_NO_REPEAT) 350 | elem_num = 1; 351 | 352 | if (type == FC_FIXED_REPEAT) 353 | { 354 | size = get_word2 (pos); // array elements 355 | } 356 | 357 | if ((type == FC_FIXED_REPEAT) || (type == FC_VARIABLE_REPEAT)) 358 | { 359 | get_word2 (pos); 360 | get_word2 (pos); // unknown 361 | elem_num = get_word2 (pos); // number of element 362 | } 363 | 364 | for (i=0; i< elem_num; i++) 365 | { 366 | offset1 = get_word2 (pos); 367 | offset2 = get_word2 (pos); 368 | 369 | init_midl_arg_struct (&tmp_arg, arg->midl_struct); 370 | 371 | add_pp_struct (type, offset1, *pos, pp_list); 372 | parse_type (pos, false, &tmp_arg); 373 | 374 | free_midl_arg_struct (&tmp_arg); 375 | } 376 | 377 | return type; 378 | } 379 | 380 | 381 | 382 | 383 | // PP struct : 384 | // byte type 385 | // byte padding 386 | // byte flag1 387 | // byte flag2 388 | // short u1 389 | // short u1 390 | // short u1 391 | // short u1 392 | // short u1 393 | // byte value_type 394 | // [extra value_type infos] 395 | // [padding] 396 | // byte end 397 | 398 | int parse_pointer_pointer (midl_pp_list ** pp_list, ea_t * pos, midl_arg_struct * arg) 399 | { 400 | fc_type type; 401 | unsigned int i; 402 | unsigned char padding; 403 | midl_pp_list * tmp_list; 404 | 405 | if (*pp_list == NULL) 406 | { 407 | tmp_list = init_pp_list (); 408 | if (!tmp_list) 409 | return -1; 410 | } 411 | else 412 | { 413 | msg ("Error : 2 FC_PP structures found inside struct or array !\n"); 414 | free_pp_list (*pp_list); 415 | return -1; 416 | } 417 | 418 | type = get_byte2 (pos); // FC_PP 419 | padding = get_byte2 (pos); 420 | 421 | // limit research to FC_END for bugged MIDL structures (?) 422 | for (i=0; itype_offset; 461 | midl_arg_struct tmp_arg; 462 | 463 | type = parse_type (&tmp_pos, false, arg); 464 | 465 | init_midl_arg_struct (&tmp_arg, arg->midl_struct); 466 | parse_type (pos, false, &tmp_arg); 467 | arg->last_struct_size = tmp_arg.last_struct_size; 468 | free_midl_arg_struct (&tmp_arg); 469 | 470 | return type; 471 | } 472 | 473 | 474 | fc_type parse_pp_next (unsigned short * offset, midl_pp_list * pp_list, ea_t * pos, midl_arg_struct * arg, ea_t * pointer_pos) 475 | { 476 | midl_pp_struct * ppstruct; 477 | fc_type type; 478 | 479 | type = get_next_type (pos); 480 | if ((type == FC_EMBEDDED_COMPLEX) || ((type >= FC_STRUCTPAD1) && (type <= FC_STRUCTPAD7)) || ((type >= FC_ALIGNM2) && (type <= FC_ALIGNM8)) ) 481 | ppstruct = NULL; 482 | else if (type == FC_POINTER) 483 | { 484 | /* 485 | if (!pointer_pos) 486 | { 487 | msg ("FC_POINTER has been detected in non FC_BOGUS_STRUCT !\n"); 488 | *offset += 4; 489 | *pos += 1; 490 | 491 | return FC_POINTER; 492 | } 493 | */ 494 | 495 | type = parse_type (pointer_pos, false, arg); 496 | *offset += 4; 497 | *pos += 1; 498 | return type; 499 | } 500 | else 501 | ppstruct = get_pp_list_arg (pp_list, *offset); 502 | 503 | if (ppstruct) 504 | { 505 | type = parse_pp_type (ppstruct, pos, arg); 506 | } 507 | else 508 | { 509 | type = parse_type (pos, false, arg); 510 | } 511 | 512 | *offset += arg->last_struct_size; 513 | return type; 514 | } 515 | 516 | 517 | 518 | // FC_(C/W)STRING ( [string] char/wchar_t t[12] ) 519 | // cstring struct : 520 | // byte type 521 | // byte padding 522 | // unsigned short size 523 | 524 | fc_type parse_array_string (fc_type type, ea_t * pos, midl_arg_struct * arg) 525 | { 526 | unsigned char padding; 527 | unsigned short size; 528 | char * name; 529 | 530 | if (type == FC_CSTRING) 531 | name = " char "; 532 | else 533 | name = " wchar_t "; 534 | 535 | set_arg_type_name (arg, name); 536 | 537 | // [string] and array[] 538 | arg->is_string = true; 539 | if (!add_array (arg)) 540 | return type; 541 | 542 | padding = get_byte2 (pos); 543 | size = get_word2 (pos); 544 | 545 | set_array_size (arg, size); 546 | 547 | return type; 548 | } 549 | 550 | 551 | void get_sarray_arg (ea_t * pos, sarray_arg * sarg, midl_arg_struct * arg) 552 | { 553 | conformance_range range; 554 | 555 | sarg->flags = get_byte2 (pos); 556 | if (sarg->flags & FLAG_CONSTANT) 557 | { 558 | GET_DATA (pos, sarg->arg.cons.size, 3); 559 | } 560 | else 561 | { 562 | sarg->arg.var.type = get_byte2 (pos); 563 | sarg->arg.var.offset = get_word2 (pos); 564 | } 565 | 566 | // ugly hack to fix inline stub :/ 567 | if (is_fully_interpreted_stub ()) 568 | { 569 | sarg->corr_flags = get_word2 (pos); 570 | 571 | if (has_conformance_range ()) 572 | { 573 | range.type = get_byte2 (pos); 574 | range.unknown = get_byte2 (pos); 575 | range.range_start = get_long2 (pos); 576 | range.range_end = get_long2 (pos); 577 | if (!arg->is_range && (range.type & 1)) 578 | { 579 | arg->is_range = true; 580 | arg->range.begin = range.range_start; 581 | arg->range.end = range.range_end; 582 | } 583 | } 584 | } 585 | } 586 | 587 | sarray_struct * get_current_sarray (midl_arg_struct * arg) 588 | { 589 | return &arg->sstruct[arg->sstruct_num-1]; 590 | } 591 | 592 | 593 | void get_sarray (unsigned int type, ea_t * pos, midl_arg_struct * arg) 594 | { 595 | sarray_struct * sstruct = get_current_sarray (arg); 596 | 597 | if (type == sarray_arg_SIZE) 598 | { 599 | sstruct->is_size++; 600 | get_sarray_arg (pos, &sstruct->size, arg); 601 | } 602 | else if (type == sarray_arg_LENGTH) 603 | { 604 | sstruct->is_length++; 605 | get_sarray_arg (pos, &sstruct->length, arg); 606 | } 607 | else 608 | { 609 | sstruct->is_byte_count++; 610 | get_sarray_arg (pos, &sstruct->byte_count, arg); 611 | } 612 | } 613 | 614 | 615 | 616 | void get_sunion (ea_t * pos, midl_arg_struct * arg) 617 | { 618 | sarray_arg * sunion = get_current_sunion (arg); 619 | 620 | get_sarray_arg (pos, sunion, arg); 621 | } 622 | 623 | 624 | 625 | // complex array struct : 626 | // byte type; 627 | // byte flags; 628 | // short size; 629 | // sarray_arg size; 630 | // [only with FC_CVARRAY] sarray_arg length; 631 | // byte value_type; 632 | // [byte padding; ...] 633 | // byte array_end; 634 | 635 | fc_type parse_complex_array (fc_type type, ea_t * pos, midl_arg_struct * arg) 636 | { 637 | fc_flag flags; 638 | unsigned short size; 639 | unsigned int i; 640 | int ret; 641 | fc_type next_type; 642 | midl_pp_list * pp_list = NULL; 643 | unsigned short offset; 644 | 645 | if (!add_sarray (arg)) 646 | return type; 647 | 648 | flags = get_byte2 (pos); 649 | size = get_word2 (pos); 650 | 651 | get_sarray (sarray_arg_SIZE, pos, arg); 652 | 653 | if (type == FC_CVARRAY) 654 | { 655 | get_sarray (sarray_arg_LENGTH, pos, arg); 656 | } 657 | 658 | offset = 0; 659 | 660 | // limit research to FC_END for bugged MIDL structures (?) 661 | for (i=0; i 0) 719 | { 720 | if (!add_array (arg)) 721 | return type; 722 | 723 | set_array_size (arg, size); 724 | set_last_size (arg, size); 725 | } 726 | 727 | if (is_sarray_arg (pos)) 728 | { 729 | if (!add_sarray (arg)) 730 | return type; 731 | 732 | sarray_set = true; 733 | get_sarray (sarray_arg_SIZE, pos, arg); 734 | } 735 | else 736 | { 737 | *pos += 4; 738 | if (is_fully_interpreted_stub ()) 739 | { 740 | *pos += 2; 741 | 742 | if (has_conformance_range ()) 743 | { 744 | range.type = get_byte2 (pos); 745 | range.unknown = get_byte2 (pos); 746 | range.range_start = get_long2 (pos); 747 | range.range_end = get_long2 (pos); 748 | if (!arg->is_range && (range.type & 1)) 749 | { 750 | arg->is_range = true; 751 | arg->range.begin = range.range_start; 752 | arg->range.end = range.range_end; 753 | } 754 | } 755 | } 756 | } 757 | 758 | if (is_sarray_arg (pos)) 759 | { 760 | if (!sarray_set) 761 | if (!add_sarray (arg)) 762 | return type; 763 | get_sarray (sarray_arg_LENGTH, pos, arg); 764 | } 765 | else 766 | { 767 | *pos += 4; 768 | if (is_fully_interpreted_stub ()) 769 | { 770 | *pos += 2; 771 | 772 | if (has_conformance_range ()) 773 | { 774 | range.type = get_byte2 (pos); 775 | range.unknown = get_byte2 (pos); 776 | range.range_start = get_long2 (pos); 777 | range.range_end = get_long2 (pos); 778 | if (!arg->is_range && (range.type & 1)) 779 | { 780 | arg->is_range = true; 781 | arg->range.begin = range.range_start; 782 | arg->range.end = range.range_end; 783 | } 784 | } 785 | } 786 | } 787 | 788 | 789 | offset = 0; 790 | 791 | // limit research to FC_END for bugged MIDL structures (?) 792 | for (i=0; ilast_struct_size != 0) 878 | astruct->size = size / arg->last_struct_size; 879 | else 880 | astruct->size = size; 881 | break; 882 | } 883 | 884 | if (next_type == FC_PP) 885 | { 886 | ret = parse_pointer_pointer (&pp_list, pos, arg); 887 | if (ret == -1) 888 | return type; 889 | } 890 | else 891 | { 892 | parse_pp_next (&offset, pp_list, pos, arg, NULL); 893 | } 894 | } 895 | 896 | free_pp_list (pp_list); 897 | 898 | set_last_size (arg, size); 899 | 900 | if (i == 10000) 901 | { 902 | msg ("Error in parse_array : recursion loop reached 10000 !.\n"); 903 | } 904 | 905 | return type; 906 | } 907 | 908 | 909 | 910 | fc_type parse_context (ea_t * pos, midl_arg_struct * arg) 911 | { 912 | arg->ptr_num++; 913 | arg->is_context = true; 914 | 915 | set_arg_type_name (arg, " void "); 916 | get_byte2 (pos); // ctx flag 917 | get_word2 (pos); // unknown 918 | 919 | return FC_BIND_CONTEXT; 920 | } 921 | 922 | 923 | // string struct : 924 | // byte type 925 | // byte padding 926 | 927 | fc_type parse_string (fc_type type, ea_t * pos, midl_arg_struct * arg) 928 | { 929 | parse_type (pos, false, arg); 930 | 931 | arg->is_string = true; 932 | 933 | if (type == FC_C_CSTRING) 934 | set_arg_type_name (arg, " char "); 935 | else 936 | set_arg_type_name (arg, " wchar_t "); 937 | 938 | return type; 939 | } 940 | 941 | // string size struct : 942 | // byte type; 943 | // sarray_arg size; 944 | 945 | fc_type parse_string_size (ea_t * pos, midl_arg_struct * arg) 946 | { 947 | if (!add_sarray (arg)) 948 | return FC_STRING_SIZED; 949 | 950 | get_sarray (sarray_arg_SIZE, pos, arg); 951 | 952 | return FC_STRING_SIZED; 953 | } 954 | 955 | 956 | fc_type parse_default_type (fc_type type, ea_t * pos, midl_arg_struct * arg) 957 | { 958 | char tmp[100]; 959 | 960 | msg ("Unknown type %X found at %.8X!\n", type, *pos-1); 961 | qsnprintf ((char *)tmp, sizeof(tmp), " UNKNOWN_TYPE_%X ", type); 962 | qstrncpy ((char *)arg->type_name, (char *) tmp, sizeof(arg->type_name)); 963 | 964 | return type; 965 | } 966 | 967 | 968 | 969 | // byte type 970 | // byte flag 971 | // unsigned short length 972 | 973 | fc_type parse_struct (fc_type type, ea_t * pos, midl_arg_struct * arg) 974 | { 975 | char tmp[100]; 976 | int num; 977 | 978 | num = add_struct_to_list (arg->midl_struct, *pos - 1, false); 979 | 980 | get_byte2 (pos); // flag 981 | 982 | qsnprintf ((char *)tmp, sizeof(tmp), " struct struct_%X ", num); 983 | qstrncpy ((char *)arg->type_name, (char *) tmp, sizeof(arg->type_name)); 984 | 985 | set_last_size (arg, get_word2 (pos)); 986 | 987 | return type; 988 | } 989 | 990 | 991 | // byte type 992 | // byte value_type 993 | // unsigned short length 994 | // sarray_arg size; 995 | 996 | fc_type parse_union (fc_type type, ea_t * pos, midl_arg_struct * arg) 997 | { 998 | char tmp[100]; 999 | int num; 1000 | ea_t tmp_pos; 1001 | short offset; 1002 | unsigned short size; 1003 | 1004 | num = add_struct_to_list (arg->midl_struct, *pos - 1, true); 1005 | 1006 | qsnprintf ((char *)tmp, sizeof(tmp), " union union_%X ", num); 1007 | qstrncpy ((char *)arg->type_name, (char *) tmp, sizeof(arg->type_name)); 1008 | 1009 | if (type == FC_NON_ENCAPSULATED_UNION) 1010 | { 1011 | get_byte2 (pos); // value_type 1012 | 1013 | arg->is_union = true; 1014 | 1015 | if (!add_sunion (arg)) 1016 | return type; 1017 | 1018 | get_sunion (pos, arg); 1019 | 1020 | tmp_pos = *pos; 1021 | offset = get_word2 (pos); 1022 | tmp_pos += offset; 1023 | 1024 | set_last_size (arg, get_word2 (&tmp_pos)); 1025 | } 1026 | else 1027 | { 1028 | get_byte2 (pos); // value_type 1029 | size = get_word2 (pos); 1030 | size += 4; // switch 1031 | set_last_size (arg, size); 1032 | } 1033 | 1034 | return type; 1035 | } 1036 | 1037 | 1038 | // 0x2f, /* FC_IP */ 1039 | // 0x5a, /* FC_CONSTANT_IID */ 1040 | // NdrFcLong( 0x12 ), /* 18 */ 1041 | // NdrFcShort( 0xeaf3 ), /* -5389 */ 1042 | // NdrFcShort( 0x4a7a ), /* 19066 */ 1043 | // 0xa0, /* 160 */ 1044 | // 0xf2, /* 242 */ 1045 | // 0xbc, /* 188 */ 1046 | // 0xe4, /* 228 */ 1047 | // 0xc3, /* 195 */ 1048 | // 0xd, /* 13 */ 1049 | // 0xa7, /* 167 */ 1050 | // 0x7e, /* 126 */ 1051 | 1052 | fc_type parse_ip (ea_t * pos, midl_arg_struct * arg) 1053 | { 1054 | uuid_version uuid; 1055 | unsigned char flag; 1056 | char tmp[100]; 1057 | 1058 | flag = get_byte2 (pos); 1059 | if (flag != FC_CONSTANT_IID) 1060 | { 1061 | msg ("Error : unknown interface flag !\n"); 1062 | return FC_IP; 1063 | } 1064 | // Extract interface uuid 1065 | uuid.x1 = get_long2 (pos); 1066 | uuid.x2 = get_word2 (pos); 1067 | uuid.x3 = get_word2 (pos); 1068 | GET_DATA (pos, (void *) uuid.x4, 8); 1069 | 1070 | 1071 | qsnprintf ((char *)tmp, sizeof(tmp), " interface(%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x) ", 1072 | uuid.x1, uuid.x2, uuid.x3, 1073 | uuid.x4[0],uuid.x4[1], 1074 | uuid.x4[2],uuid.x4[3],uuid.x4[4],uuid.x4[5],uuid.x4[6],uuid.x4[7]); 1075 | 1076 | qstrncpy ((char *)arg->type_name, (char *) tmp, sizeof(arg->type_name)); 1077 | arg->ptr_num++; 1078 | 1079 | return FC_IP; 1080 | } 1081 | 1082 | 1083 | ///* 558 */ 0x5, /* FC_WCHAR */ 1084 | // 0x5c, /* FC_PAD */ 1085 | ///* 560 */ 0xb5, /* FC_PIPE */ 1086 | // 0x1, /* 1 */ 1087 | ///* 562 */ NdrFcShort( 0xfffc ), /* Offset= -4 (558) */ 1088 | ///* 564 */ NdrFcShort( 0x2 ), /* 2 */ 1089 | ///* 566 */ NdrFcShort( 0x2 ), /* 2 */ 1090 | 1091 | fc_type parse_pipe (ea_t * pos, midl_arg_struct * arg) 1092 | { 1093 | unsigned char flags; 1094 | short offset; 1095 | ea_t tmp_pos; 1096 | 1097 | flags = get_byte2 (pos); 1098 | tmp_pos = *pos; 1099 | offset = get_word2 (pos); 1100 | tmp_pos += offset; 1101 | get_word2 (pos); 1102 | get_word2 (pos); 1103 | 1104 | arg->is_pipe = true; 1105 | 1106 | parse_type (&tmp_pos, false, arg); 1107 | 1108 | return FC_PIPE; 1109 | } 1110 | 1111 | 1112 | ///* 56 */ 0x2c, /* FC_BYTE_COUNT_POINTER */ 1113 | // 0x5c, /* FC_PAD */ 1114 | ///* 58 */ 0x28, /* 40 */ 1115 | // 0x0, /* 0 */ 1116 | ///* 60 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ 1117 | ///* 62 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ 1118 | ///* 64 */ NdrFcShort( 0xfff4 ), /* Offset= -12 (52) */ 1119 | 1120 | fc_type parse_byte_count_pointer(ea_t * pos, midl_arg_struct * arg) 1121 | { 1122 | fc_type type; 1123 | short offset; 1124 | ea_t tmp_pos; 1125 | 1126 | arg->ptr_num++; 1127 | type = parse_type (pos, false, arg); 1128 | 1129 | if (!add_sarray (arg)) 1130 | return FC_STRING_SIZED; 1131 | 1132 | get_sarray (sarray_arg_BYTE_COUNT, pos, arg); 1133 | 1134 | if (type == FC_PAD) 1135 | { 1136 | tmp_pos = *pos; 1137 | offset = get_word2 (pos); 1138 | tmp_pos += offset; 1139 | 1140 | parse_type (&tmp_pos, false, arg); 1141 | } 1142 | 1143 | return FC_BYTE_COUNT_POINTER; 1144 | } 1145 | 1146 | 1147 | fc_type parse_user_marshal(ea_t * pos, midl_arg_struct * arg) 1148 | { 1149 | fc_type type; 1150 | short offset; 1151 | unsigned short size; 1152 | ea_t tmp_pos; 1153 | 1154 | type = get_byte2 (pos); 1155 | get_word2 (pos); // unknown 1156 | size = get_word2 (pos); 1157 | get_word2 (pos); 1158 | 1159 | tmp_pos = *pos; 1160 | offset = get_word2 (pos); 1161 | tmp_pos += offset; 1162 | 1163 | arg->is_user_marshal = true; 1164 | arg->user_marshal_size = size; 1165 | 1166 | parse_type (&tmp_pos, false, arg); 1167 | 1168 | return FC_USER_MARSHAL; 1169 | } 1170 | 1171 | fc_type parse_supplement(ea_t * pos, midl_arg_struct * arg) 1172 | { 1173 | fc_type type; 1174 | short offset; 1175 | ea_t tmp_pos; 1176 | 1177 | type = get_byte2 (pos); 1178 | tmp_pos = *pos; 1179 | offset = get_word2 (pos); 1180 | tmp_pos += offset; 1181 | 1182 | if (!arg->is_range) 1183 | { 1184 | arg->is_range = true; 1185 | arg->range.begin = get_long2 (pos); 1186 | arg->range.end = get_long2 (pos); 1187 | } 1188 | 1189 | parse_type (&tmp_pos, false, arg); 1190 | 1191 | return FC_USER_MARSHAL; 1192 | } 1193 | 1194 | fc_type parse_type (ea_t * pos, bool first, midl_arg_struct * arg) 1195 | { 1196 | fc_type type; 1197 | 1198 | // Check on recursion to avoid infinite loop in bugged MIDL structures 1199 | if (++arg->loop_num >= RECURSION_LIMIT) 1200 | { 1201 | msg ("Error in parse_type : recursive loop reached 10000 !.\n"); 1202 | RaiseException (EXCEPTION_MIDA_LOOPLIMIT,0,0,NULL); 1203 | return FC_END; 1204 | } 1205 | 1206 | type = get_byte2 (pos); 1207 | 1208 | switch (type) 1209 | { 1210 | case FC_UP: 1211 | case FC_RP: 1212 | case FC_FP: 1213 | return parse_pointer (type, pos, first, arg); 1214 | case FC_EMBEDDED_COMPLEX: 1215 | return parse_embedded_complex (pos, arg); 1216 | case FC_RANGE: 1217 | return parse_range (pos, arg); 1218 | case FC_CSTRING: 1219 | case FC_WSTRING: 1220 | return parse_array_string (type, pos, arg); 1221 | case FC_STRING_SIZED: 1222 | return parse_string_size (pos, arg); 1223 | case FC_C_CSTRING: 1224 | case FC_C_WSTRING: 1225 | return parse_string (type, pos, arg); 1226 | case FC_SMFARRAY: 1227 | case FC_LGFARRAY: 1228 | case FC_SMVARRAY: 1229 | case FC_LGVARRAY: 1230 | return parse_array (type, pos, arg); 1231 | case FC_BOGUS_ARRAY: 1232 | return parse_bogus_array (type, pos, arg); 1233 | case FC_CARRAY: 1234 | case FC_CVARRAY: 1235 | return parse_complex_array (type, pos, arg); 1236 | case FC_BIND_CONTEXT: 1237 | return parse_context (pos, arg); 1238 | case FC_BYTE: 1239 | case FC_CHAR: 1240 | case FC_SMALL: 1241 | case FC_WCHAR: 1242 | case FC_SHORT: 1243 | case FC_LONG: 1244 | case FC_FLOAT: 1245 | case FC_DOUBLE: 1246 | case FC_HYPER: 1247 | case FC_ENUM16: 1248 | case FC_ENUM32: 1249 | case FC_ERROR_STATUS_T: 1250 | case FC_INT3264: 1251 | case FC_UINT3264: 1252 | return parse_base_type (type, pos, arg); 1253 | case FC_STRUCTPAD1: 1254 | case FC_STRUCTPAD2: 1255 | case FC_STRUCTPAD3: 1256 | case FC_STRUCTPAD4: 1257 | case FC_STRUCTPAD5: 1258 | case FC_STRUCTPAD6: 1259 | case FC_STRUCTPAD7: 1260 | return parse_structpad (type, pos, arg); 1261 | case FC_ALIGNM2: 1262 | case FC_ALIGNM4: 1263 | case FC_ALIGNM8: 1264 | return parse_alignment (type, pos, arg); 1265 | case FC_PAD: 1266 | case FC_END: 1267 | return type; 1268 | case FC_STRUCT: 1269 | case FC_PSTRUCT: 1270 | case FC_BOGUS_STRUCT: 1271 | case FC_FORCED_BOGUS_STRUCT: 1272 | case FC_CPSTRUCT: 1273 | case FC_CVSTRUCT: 1274 | case FC_CSTRUCT: 1275 | return parse_struct (type, pos, arg); 1276 | case FC_NON_ENCAPSULATED_UNION: 1277 | case FC_ENCAPSULATED_UNION: 1278 | return parse_union (type, pos, arg); 1279 | case FC_IP: 1280 | return parse_ip (pos, arg); 1281 | case FC_PIPE: 1282 | return parse_pipe (pos, arg); 1283 | case FC_BYTE_COUNT_POINTER: 1284 | return parse_byte_count_pointer (pos, arg); 1285 | case FC_USER_MARSHAL: 1286 | return parse_user_marshal (pos, arg); 1287 | case FC_SUPPLEMENT: 1288 | return parse_supplement (pos, arg); 1289 | default: 1290 | return parse_default_type (type, pos, arg); 1291 | } 1292 | } 1293 | -------------------------------------------------------------------------------- /parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #ifndef _PARSER_H_ 8 | #define _PARSER_H_ 9 | 10 | #include "midl.h" 11 | 12 | #include "bytes.hpp" 13 | 14 | 15 | fc_type parse_type (ea_t *, bool, midl_arg_struct *); 16 | unsigned char * get_base_type (unsigned char); 17 | unsigned char * get_io (unsigned int); 18 | unsigned char * get_io2 (unsigned int); 19 | unsigned char * get_ref (unsigned int); 20 | unsigned char get_next_type (ea_t *); 21 | unsigned long get_base_type_length (unsigned char); 22 | int parse_pointer_pointer (midl_pp_list **, ea_t *, midl_arg_struct *); 23 | fc_type parse_pp_next (unsigned short *, midl_pp_list *, ea_t *, midl_arg_struct *, ea_t *); 24 | 25 | #endif -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by mida_res.rc 4 | // 5 | #define IDI_ICON1 107 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 111 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /tracer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | // COMES FROM PATCHDIFF // 8 | #include "tracer.h" 9 | #include "bytes.hpp" 10 | #include "xref.hpp" 11 | #include "kernwin.hpp" 12 | #include "pro.h" 13 | 14 | 15 | struct instr 16 | { 17 | ea_t ea; 18 | unsigned char _byte; 19 | }; 20 | 21 | 22 | /* A block of code is represented by : 23 | - start address 24 | - end address 25 | - list of instructions 26 | */ 27 | 28 | struct code_block 29 | { 30 | ea_t start; 31 | ea_t end; 32 | ea_t ref; 33 | ea_t jmp; 34 | bool l; 35 | }; 36 | 37 | 38 | typedef struct _list_code_block list_code_block; 39 | 40 | struct _list_code_block { 41 | code_block block; 42 | list_code_block * next; 43 | }; 44 | 45 | 46 | typedef struct _list_ea_t list_ea_t; 47 | 48 | struct _list_ea_t { 49 | ea_t ea; 50 | list_ea_t * next; 51 | }; 52 | 53 | void list_code_block_push (list_code_block ** list, code_block block) 54 | { 55 | list_code_block * tmp; 56 | 57 | tmp = (list_code_block *) qalloc (sizeof(*tmp)); 58 | if (!tmp) 59 | { 60 | msg ("Memory allocation error during list_code_block_push.\n"); 61 | return; 62 | } 63 | 64 | tmp->block = block; 65 | tmp->next = *list; 66 | 67 | *list = tmp; 68 | } 69 | 70 | 71 | void list_code_block_pop (list_code_block ** list) 72 | { 73 | list_code_block * tmp; 74 | 75 | if (*list == NULL) 76 | return; 77 | 78 | tmp = *list; 79 | *list = (*list)->next; 80 | 81 | qfree (tmp); 82 | } 83 | 84 | 85 | bool list_code_block_empty (list_code_block ** list) 86 | { 87 | if (*list == NULL) 88 | return true; 89 | 90 | return false; 91 | } 92 | 93 | 94 | void free_list_code_block (list_code_block ** list) 95 | { 96 | list_code_block * tmp = *list, * old; 97 | 98 | while (tmp) 99 | { 100 | old = tmp->next; 101 | qfree (tmp); 102 | tmp = old; 103 | } 104 | 105 | *list = NULL; 106 | } 107 | 108 | 109 | void list_ea_t_push (list_ea_t ** list, ea_t ea) 110 | { 111 | list_ea_t * tmp; 112 | 113 | tmp = (list_ea_t *) qalloc (sizeof(*tmp)); 114 | if (!tmp) 115 | { 116 | msg ("Memory allocation error during list_ea_t_push.\n"); 117 | return; 118 | } 119 | 120 | tmp->ea = ea; 121 | tmp->next = *list; 122 | 123 | *list = tmp; 124 | } 125 | 126 | 127 | void list_ea_t_pop (list_ea_t ** list) 128 | { 129 | list_ea_t * tmp; 130 | 131 | if (*list == NULL) 132 | return; 133 | 134 | tmp = *list; 135 | *list = (*list)->next; 136 | 137 | qfree (tmp); 138 | } 139 | 140 | 141 | ea_t list_ea_t_last (list_ea_t ** list) 142 | { 143 | if (*list == NULL) 144 | return BADADDR; 145 | 146 | return (*list)->ea; 147 | } 148 | 149 | 150 | bool list_ea_t_empty (list_ea_t ** list) 151 | { 152 | if (*list == NULL) 153 | return true; 154 | 155 | return false; 156 | } 157 | 158 | 159 | void free_list_ea_t (list_ea_t ** list) 160 | { 161 | list_ea_t * tmp = *list, * old; 162 | 163 | while (tmp) 164 | { 165 | old = tmp->next; 166 | qfree (tmp); 167 | tmp = old; 168 | } 169 | 170 | *list = NULL; 171 | } 172 | 173 | 174 | void parse_code (unsigned char val, ea_t ea, unsigned char * newval) 175 | { 176 | unsigned char tmp; 177 | 178 | tmp = val; 179 | *newval = tmp; 180 | } 181 | 182 | 183 | /*------------------------------------------------*/ 184 | /* function : is_jump */ 185 | /* arguments: unsigned char _byte */ 186 | /* description: detect if instruction is a jump */ 187 | /* (jnz, je, jmp ...) */ 188 | /* note: set cond to 1 if jump is conditionnal */ 189 | /*------------------------------------------------*/ 190 | 191 | bool is_jump (unsigned char _byte, unsigned char * cond, ea_t ea) 192 | { 193 | unsigned short val = get_word (ea); 194 | val = (val & 0xFF00) >> 8; 195 | 196 | if ( (( _byte == 0x0F ) && ( val >= 0x80 ) && ( val <= 0x8F)) || // cond jmp long 197 | ( ( _byte >= 0x70 ) && ( _byte <= 0x7F) ) ) // cond jmp short 198 | { 199 | *cond = 1; 200 | return true; 201 | } 202 | if ( ( _byte == 0xEB ) || ( _byte == 0xEA) || ( _byte == 0xE9) ) // jmp short & long 203 | { 204 | *cond = 0; 205 | return true; 206 | } 207 | if (_byte == 0xFF) 208 | { 209 | if (val == 0x24) 210 | { 211 | *cond = 2; 212 | return true; 213 | } 214 | } 215 | 216 | return false; 217 | } 218 | 219 | 220 | /*------------------------------------------------*/ 221 | /* function : is_end_block */ 222 | /* arguments: unsigned char _byte, ea_t ea */ 223 | /* description: detect if instruction is end of */ 224 | /* block (jmp, ret) */ 225 | /*------------------------------------------------*/ 226 | 227 | bool is_end_block (unsigned char _byte, ea_t ea) 228 | { 229 | unsigned short val; 230 | 231 | // if jmp or ret 232 | if ( (_byte == 0xC2) || (_byte == 0xC3) ) 233 | return true; 234 | 235 | if (_byte == 0xFF) 236 | { 237 | val = get_word (ea); 238 | val = (val & 0xFF00) >> 8; 239 | 240 | if ( ((val >= 0x20) && (val <= 0x27)) || // jmp dword ptr [reg] 241 | ((val >= 0xE0) && (val <= 0xE7)) || // jmp reg 242 | ((val >= 0x60) && (val <= 0x67)) // jmp dword ptr [reg + xx] 243 | ) 244 | return true; 245 | } 246 | 247 | return false; 248 | } 249 | 250 | 251 | /*------------------------------------------------*/ 252 | /* function : get_jump */ 253 | /* arguments: ea_t ea */ 254 | /* description: return address to jump to */ 255 | /*------------------------------------------------*/ 256 | 257 | ea_t get_jump (ea_t ea) 258 | { 259 | return get_first_fcref_from (ea); 260 | } 261 | 262 | 263 | 264 | /*------------------------------------------------*/ 265 | /* function : isTraced */ 266 | /* arguments: ea, traced, block */ 267 | /* description: detect if instruction is already */ 268 | /* traced. */ 269 | /* note: if instruction is already traced and */ 270 | /* block is not empty, we mark as end of */ 271 | /* block and add it to traced. */ 272 | /* if instruction is in the middle of */ 273 | /* existing block we change block end and */ 274 | /* continue tracing */ 275 | /*------------------------------------------------*/ 276 | 277 | bool isTraced (ea_t ea, list_code_block ** traced, code_block * block) 278 | { 279 | list_code_block * list = *traced; 280 | 281 | while (list) 282 | { 283 | if (list->block.start == ea) 284 | { 285 | list->block.ref = 2; 286 | 287 | if (!list->block.l) 288 | { 289 | list_code_block_push (traced, *block); 290 | } 291 | else 292 | block->l = false; 293 | 294 | return true; 295 | } 296 | else if (ea > (list->block.start) && (ea <= list->block.end) ) 297 | { 298 | list->block.end = get_item_head(ea-1); 299 | block->ref = 2; 300 | 301 | return false; 302 | } 303 | 304 | list = list->next; 305 | 306 | } 307 | 308 | return false; 309 | } 310 | 311 | 312 | /*------------------------------------------------*/ 313 | /* function : trace_func */ 314 | /* arguments: - */ 315 | /* description: trace a function */ 316 | /* note: must be called until l is empty */ 317 | /*------------------------------------------------*/ 318 | 319 | bool trace_func (list_ea_t ** l, list_code_block ** traced, ea_t * arg_offset, ea_t * format_offset, ea_t * ref) 320 | { 321 | ea_t ea, old_ea; 322 | ea_t stub; 323 | flags_t flags; 324 | unsigned char val, _byte, cond; 325 | code_block block; 326 | instr instruction; 327 | char buffer[200]; 328 | 329 | // we take the first address to trace and remove it from list 330 | ea = list_ea_t_last (l); 331 | list_ea_t_pop (l); 332 | 333 | block.start = ea; 334 | block.end = ea; 335 | block.ref = 1; 336 | block.jmp = BADADDR; 337 | block.l = false; 338 | 339 | while (1) 340 | { 341 | // if instruction already traced we stop tracing 342 | // isTraced change blocks if necessary 343 | if (isTraced (ea, traced, &block)) 344 | return false; 345 | 346 | // we only trace code 347 | flags = getFlags (ea); 348 | if (!isCode (flags)) 349 | break; 350 | 351 | val = get_byte (ea); 352 | parse_code (val, ea, &_byte); 353 | 354 | instruction.ea = ea; 355 | instruction._byte = _byte; 356 | 357 | // if jump we add jmp address to l for tracing and stop 358 | // if cond jump we add next addr too 359 | if (is_jump(_byte, &cond, ea)) 360 | { 361 | block.l = true; 362 | block.end = ea; 363 | 364 | if (cond == 2) 365 | { 366 | xrefblk_t xb; 367 | for ( bool ok=xb.first_from(ea, XREF_ALL); ok; ok=xb.next_from() ) 368 | { 369 | list_ea_t_push (l, xb.to); 370 | } 371 | } 372 | 373 | /* conditionnal jump */ 374 | if (cond == 1) 375 | { 376 | list_ea_t_push (l, get_jump(ea)); 377 | //ea = next_visea (ea); 378 | ea += get_item_size(ea); 379 | if (ea != BADADDR) 380 | list_ea_t_push (l, ea); 381 | } 382 | 383 | /* unconditionnal jump */ 384 | if (cond == 0) 385 | { 386 | DWORD jval; 387 | ea_t jea; 388 | 389 | //jmp $5 390 | jval = get_long(ea+1); 391 | if ((_byte == 0xe9) && (jval == 0)) 392 | { 393 | //ea = next_visea (ea); 394 | jea = ea + get_item_size(ea); 395 | if (jea != BADADDR) 396 | list_ea_t_push (l, jea); 397 | 398 | block.jmp = jea; 399 | } 400 | else 401 | { 402 | list_ea_t_push (l, get_jump(ea)); 403 | block.jmp = get_jump(ea); 404 | } 405 | } 406 | 407 | break; 408 | } 409 | // else we just add the current instruction to the block 410 | else 411 | { 412 | block.l = true; 413 | block.end = ea; 414 | 415 | generate_disasm_line(ea,(char*)buffer,sizeof(buffer)); 416 | tag_remove((char*)buffer,(char*)buffer,sizeof(buffer)); 417 | 418 | if ( strstr ((char*)buffer, "offset")) 419 | *ref = get_first_dref_from (ea); 420 | 421 | if ( (format_offset != NULL) && (strstr((char*)buffer, "pStubDescriptor")) ) 422 | { 423 | *format_offset = get_long (*ref + sizeof(long)*8); 424 | } 425 | else if (strstr((char*)buffer, "pFormat")) 426 | { 427 | *arg_offset = *ref; 428 | return true; 429 | } 430 | } 431 | 432 | // if end of block we stop tracing 433 | if (is_end_block (_byte, ea)) 434 | break; 435 | 436 | // we take next visible address 437 | //ea = next_visea (ea); 438 | ea += get_item_size(ea); 439 | if (ea == BADADDR) 440 | break; 441 | } 442 | 443 | // if tracing is finished and block is not empty 444 | // we add it to list of blocks 445 | if (block.l) 446 | list_code_block_push (traced, block); 447 | else 448 | block.l = false; 449 | 450 | return false; 451 | } 452 | 453 | 454 | void trace_rpc_func (ea_t ea, ea_t * arg_offset, ea_t * format_offset) 455 | { 456 | list_ea_t * ea_l = NULL; 457 | list_code_block * traced = NULL; 458 | ea_t ref = BADADDR; 459 | 460 | list_ea_t_push (&ea_l, ea); 461 | 462 | // we trace the function 463 | 464 | while (!list_ea_t_empty (&ea_l)) 465 | { 466 | if (trace_func (&ea_l, &traced, arg_offset, format_offset, &ref)) 467 | break; 468 | } 469 | 470 | free_list_ea_t (&ea_l); 471 | free_list_code_block (&traced); 472 | } -------------------------------------------------------------------------------- /tracer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #ifndef _TRACER_H_ 8 | #define _TRACER_H_ 9 | 10 | #include "midl.h" 11 | 12 | void trace_rpc_func (ea_t, ea_t *, ea_t *); 13 | 14 | #endif -------------------------------------------------------------------------------- /window.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mIDA - MIDL Analyzer plugin for IDA 3 | * (c) 2005 - Nicolas Pouvesle / Tenable Network Security 4 | * 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include "kernwin.hpp" 11 | #include "window.h" 12 | 13 | #include "resource.h" 14 | 15 | 16 | void DisplayError () 17 | { 18 | DWORD dw = GetLastError (); 19 | TCHAR szBuf[200]; 20 | LPVOID lpMsgBuf = NULL; 21 | 22 | FormatMessage( 23 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 24 | FORMAT_MESSAGE_FROM_SYSTEM, 25 | NULL, 26 | dw, 27 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 28 | (LPTSTR) &lpMsgBuf, 29 | 0, NULL ); 30 | 31 | qsnprintf(szBuf, sizeof(szBuf), 32 | "AddMDIWindow failed with error %d: %s", 33 | dw, lpMsgBuf); 34 | 35 | msg ("%s\n", szBuf); 36 | 37 | LocalFree (lpMsgBuf); 38 | } 39 | 40 | 41 | window_handle_list * GetHandlePtr () 42 | { 43 | return mIDA_handle_list; 44 | } 45 | 46 | 47 | void SetHandlePtr (window_handle_list * ptr) 48 | { 49 | mIDA_handle_list = ptr; 50 | } 51 | 52 | 53 | HWND GetMDIWindowHandle () 54 | { 55 | return MDIhWnd; 56 | } 57 | 58 | 59 | void SetMDIWindowHandle (HWND hWnd) 60 | { 61 | MDIhWnd = hWnd; 62 | } 63 | 64 | HWND GetTabWindowHandle () 65 | { 66 | return TABhWnd; 67 | } 68 | 69 | 70 | void SetTabWindowHandle (HWND hWnd) 71 | { 72 | TABhWnd = hWnd; 73 | } 74 | 75 | 76 | HINSTANCE GetIDAHinstance () 77 | { 78 | return IDAhInst; 79 | } 80 | 81 | 82 | void SetIDAHinstance (HINSTANCE hInst) 83 | { 84 | IDAhInst = hInst; 85 | } 86 | 87 | 88 | int GetHandleNumber () 89 | { 90 | int i = 0; 91 | window_handle_list *ptr = GetHandlePtr (); 92 | 93 | while (ptr != NULL) 94 | { 95 | i++; 96 | ptr = ptr->next; 97 | } 98 | 99 | return i; 100 | } 101 | 102 | 103 | int GetRealTabCount () 104 | { 105 | return TabCtrl_GetItemCount (GetTabWindowHandle()) + GetHandleNumber (); 106 | } 107 | 108 | 109 | 110 | void AddTabEntry (char * name) 111 | { 112 | TCITEM tie; 113 | 114 | tie.mask = TCIF_TEXT; 115 | tie.iImage = -1; 116 | tie.pszText = name; 117 | 118 | TabCtrl_InsertItem (GetTabWindowHandle(), GetRealTabCount (), &tie); 119 | } 120 | 121 | 122 | void RemoveTabEntry (char * name) 123 | { 124 | unsigned int i; 125 | TCITEM tie; 126 | char tmp[50]; 127 | HWND hWnd = GetTabWindowHandle(); 128 | 129 | for (i=0; ihandle.hWnd == hWnd) 162 | { 163 | RemoveTabEntry ((char *)ptr->handle.name); 164 | 165 | if (prev == NULL) 166 | { 167 | SetHandlePtr (ptr->next); 168 | } 169 | else 170 | { 171 | prev->next = ptr->next; 172 | } 173 | 174 | qfree (ptr); 175 | return true; 176 | } 177 | 178 | prev = ptr; 179 | ptr = ptr->next; 180 | } 181 | 182 | return false; 183 | } 184 | 185 | 186 | void RemoveHandles () 187 | { 188 | window_handle_list * list = GetHandlePtr (); 189 | 190 | while (list != NULL) 191 | { 192 | // WM_DESTROY will call RemoveHandle 193 | DestroyWindow (list->handle.hWnd); 194 | list = GetHandlePtr (); 195 | } 196 | } 197 | 198 | 199 | void CleanupMDIWindow () 200 | { 201 | RemoveHandles (); 202 | RestoreProcs (); 203 | } 204 | 205 | 206 | bool AddHandle (HWND hWnd, char * name) 207 | { 208 | window_handle_list * new_handle; 209 | 210 | new_handle = (window_handle_list *) qalloc (sizeof(*new_handle)); 211 | if (!new_handle) 212 | { 213 | msg ("Error : memory allocation failed during AddHandle !\n"); 214 | return false; 215 | } 216 | else 217 | { 218 | new_handle->next = NULL; 219 | new_handle->handle.hWnd = hWnd; 220 | qsnprintf ((char *)new_handle->handle.name, sizeof (new_handle->handle.name), "%s", name); 221 | AddTabEntry ((char *)new_handle->handle.name); 222 | 223 | if (GetHandlePtr() != NULL) 224 | { 225 | new_handle->next = GetHandlePtr(); 226 | } 227 | 228 | SetHandlePtr (new_handle); 229 | 230 | return true; 231 | } 232 | } 233 | 234 | 235 | bool isMIDAHandle (HWND hWnd) 236 | { 237 | window_handle_list *ptr = GetHandlePtr (); 238 | 239 | while (ptr != NULL) 240 | { 241 | if (ptr->handle.hWnd == hWnd) 242 | return true; 243 | 244 | ptr = ptr->next; 245 | } 246 | 247 | return false; 248 | } 249 | 250 | 251 | HWND GetMIDAHandleByName (char * name) 252 | { 253 | window_handle_list *ptr = GetHandlePtr (); 254 | 255 | while (ptr != NULL) 256 | { 257 | if (strcmp ((char *)ptr->handle.name, name) == 0) 258 | return ptr->handle.hWnd; 259 | 260 | ptr = ptr->next; 261 | } 262 | 263 | return NULL; 264 | } 265 | 266 | 267 | char * GetMIDAHandleName (HWND hWnd) 268 | { 269 | window_handle_list *ptr = GetHandlePtr (); 270 | 271 | while (ptr != NULL) 272 | { 273 | if (ptr->handle.hWnd == hWnd) 274 | return ptr->handle.name; 275 | 276 | ptr = ptr->next; 277 | } 278 | 279 | return NULL; 280 | } 281 | 282 | 283 | // This procedure replace (and call) the TTabcontrol message handler procedure 284 | 285 | LRESULT CALLBACK TabProc (HWND hWnd, unsigned int wMsg, WPARAM wParam, LPARAM lParam) 286 | { 287 | HWND tmphWnd; 288 | TCITEM tie; 289 | char tmp[50]; 290 | HWND ThWnd; 291 | 292 | switch (wMsg) 293 | { 294 | case WM_RBUTTONDOWN: 295 | case WM_LBUTTONUP: 296 | { 297 | tie.mask = TCIF_TEXT; 298 | tie.iImage = -1; 299 | tie.pszText = (char *)tmp; 300 | tie.cchTextMax = sizeof(tmp); 301 | 302 | ThWnd = GetTabWindowHandle(); 303 | 304 | if (wMsg == WM_LBUTTONUP) 305 | TabCtrl_GetItem (ThWnd, TabCtrl_GetCurSel (ThWnd), &tie); 306 | else 307 | TabCtrl_GetItem (ThWnd, TabCtrl_GetCurFocus (ThWnd), &tie); 308 | tmphWnd = GetMIDAHandleByName ((char *)tmp); 309 | if (tmphWnd) 310 | { 311 | SendMessage (GetMDIWindowHandle (), WM_MDIACTIVATE, (WPARAM) tmphWnd, NULL); 312 | } 313 | break; 314 | } 315 | // We hide the presence of custom windows to IDA/VCL. 316 | case TCM_GETITEMCOUNT: 317 | { 318 | return oldTabProc (hWnd, wMsg, wParam, lParam) - GetHandleNumber (); 319 | } 320 | } 321 | 322 | return oldTabProc (hWnd, wMsg, wParam, lParam); 323 | } 324 | 325 | 326 | LRESULT CALLBACK WndProc (HWND hWnd, unsigned int wMsg, WPARAM wParam, LPARAM lParam) 327 | { 328 | HWND hEdit, ThWnd; 329 | RECT rcClient; 330 | HGDIOBJ hfDefault; 331 | TCITEM tie; 332 | char tmp[50], name[50]; 333 | int i; 334 | 335 | switch (wMsg) 336 | { 337 | case WM_CREATE: 338 | { 339 | hEdit = CreateWindowEx (WS_EX_CLIENTEDGE, "EDIT", "", 340 | WS_CHILD | WS_VISIBLE | WS_VSCROLL 341 | | WS_HSCROLL | ES_MULTILINE | ES_NOHIDESEL 342 | | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 343 | 0, 0, 100, 100, hWnd, (HMENU)IDC_MAIN_EDIT, 344 | NULL, NULL); 345 | 346 | if (!hEdit) 347 | { 348 | DestroyWindow (hWnd); 349 | break; 350 | } 351 | 352 | GetWindowText (hWnd, name, sizeof(name)); 353 | if (!AddHandle (hWnd, (char *)name)) 354 | { 355 | DestroyWindow (hWnd); 356 | return NULL; 357 | } 358 | 359 | hfDefault = GetStockObject (DEFAULT_GUI_FONT); 360 | SendMessage (hEdit, WM_SETFONT, (WPARAM) hfDefault, 0); 361 | break; 362 | } 363 | case WM_DESTROY: 364 | { 365 | RemoveHandle ((HWND)hWnd); 366 | break; 367 | } 368 | case WM_SIZE: 369 | { 370 | GetClientRect (hWnd, &rcClient); 371 | hEdit = GetDlgItem (hWnd, IDC_MAIN_EDIT); 372 | SetWindowPos (hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER); 373 | 374 | break; 375 | } 376 | case WM_MDIACTIVATE: 377 | { 378 | tie.mask = TCIF_TEXT; 379 | tie.iImage = -1; 380 | tie.pszText = (char *)tmp; 381 | tie.cchTextMax = sizeof(tmp); 382 | 383 | ThWnd = GetTabWindowHandle(); 384 | 385 | TabCtrl_GetItem (ThWnd, TabCtrl_GetCurSel (ThWnd), &tie); 386 | GetWindowText ((HWND)lParam, name, sizeof(name)); 387 | 388 | if (strlen(name) > 0) 389 | { 390 | if (strcmp (name, (char *)tmp) != 0) 391 | { 392 | for (i=0; i 11 | 12 | 13 | typedef struct _window_handle { 14 | HWND hWnd; 15 | char name[50]; 16 | } window_handle; 17 | 18 | 19 | typedef struct _window_handle_list { 20 | window_handle handle; 21 | struct _window_handle_list * next; 22 | } window_handle_list; 23 | 24 | 25 | #define IDC_MAIN_EDIT 101 26 | 27 | // address of the original MDIClient Window Procedure 28 | typedef LRESULT (*windowproc) (HWND, unsigned int, WPARAM, LPARAM); 29 | 30 | static windowproc oldTabProc = NULL; 31 | 32 | // save the MDIClient window handle 33 | static HWND MDIhWnd = NULL; 34 | static HWND TABhWnd = NULL; 35 | static HINSTANCE IDAhInst = NULL; 36 | static window_handle_list * mIDA_handle_list = NULL; 37 | 38 | HWND AddMDIChild (); 39 | void SetMDIWindowText (HWND, char *); 40 | void CleanupMDIWindow (); 41 | bool InitializeMDIWindow (HINSTANCE); 42 | 43 | #endif --------------------------------------------------------------------------------