IDA Pro: working with library code (not WinAPI)
When working in the IDA, I, and probably also you, often have to deal with applications that have a fairly large amount of code, do not have symbolic information and, moreover, contain a lot of library code. Often such code needs to be able to be distinguished from that written by the user. And, if only CDMY0CDMY, CDMY1CDMY and CDMY2CDMY are sent to the library code, you can get off with only signatures (sig files created using the FLAIR utilities). But, if you need structures, arguments, their number, you can’t do without additional magic... As an example, I will work with a game for Sony Playstation 1, written using CDMY3CDMY.
Imagine a situation: you came across firmware from some piece of hardware. The usual Bare-metal ROM (you can even with RTOS). Or ROM games. In such cases, most likely, when compiling, some SDK/DDK was used, which has a set of LIB / H / OBJ files that pasted by the linker into the final file.
Our action plan will be something like this:
- Take all the lib / obj files and create signatures from them (or a set of signatures). This will help us separate the statically linked library code.
- Take all h-files and create a type library from them. This library stores not only data types, but also information about the names and types of arguments of functions in which the declared types are used.
- Apply signatures so that we can define library functions and their names.
- Apply type libraries to apply function prototypes and used data types.
Create sig files
To create a signature file, you must use the set of FLAIR utilities available to licensed IDA users. The list of necessary utilities is as follows:
- CDMY4CDMY - LIB/OBJ-parser, creates a PAT-file from COFF-object files
- CDMY5CDMY - LIB/OBJ parser, creates a PAT file from ELF files (Unix)
- CDMY6CDMY - LIB/OBJ-parser, creates a PAT-file from OMF-object files
- CDMY7CDMY - MACH-O-parser, creates a PAT-file from MACH-O-files (MacOS)
- CDMY8CDMY - an OBJ parser that creates a PAT file from PSYQ library files
- CDMY9CDMY - an OBJ parser that creates a PAT file from Trimedia library files
- CDMY10CDMY - converts a previously created PAT file into a SIG file, digested by IDA
In my case, it is CDMY11CDMY. I collect a bat-file in which I list all the CDMY12CDMY and CDMY13CDMY files, and add a call to CDMY14CDMY to each line to form the final PAT-file. It turned out the following content:
@echo off ppsx -a 2MBYTE.OBJ psyq47.pat ppsx -a 8MBYTE.OBJ psyq47.pat ppsx -a LIBAPI.LIB psyq47.pat ppsx -a LIBC.LIB psyq47.pat ppsx -a LIBC2.LIB psyq47.pat ppsx -a LIBCARD.LIB psyq47.pat ppsx -a LIBCD.LIB psyq47.pat ppsx -a LIBCOMB.LIB psyq47.pat ppsx -a LIBDS.LIB psyq47.pat ppsx -a LIBETC.LIB psyq47.pat ppsx -a LIBGPU.LIB psyq47.pat ppsx -a LIBGS.LIB psyq47.pat ppsx -a LIBGTE.LIB psyq47.pat ppsx -a LIBGUN.LIB psyq47.pat ppsx -a LIBHMD.LIB psyq47.pat ppsx -a LIBMATH.LIB psyq47.pat ppsx -a LIBMCRD.LIB psyq47.pat ppsx -a LIBMCX.LIB psyq47.pat ppsx -a LIBPAD.LIB psyq47.pat ppsx -a LIBPRESS.LIB psyq47.pat ppsx -a LIBSIO.LIB psyq47.pat ppsx -a ashldi3.obj psyq47.pat ppsx -a ashrdi3.obj psyq47.pat ppsx -a CACHE.OBJ psyq47.pat ppsx -a clear_cache.obj psyq47.pat ppsx -a CLOSE.OBJ psyq47.pat ppsx -a cmpdi2.obj psyq47.pat ppsx -a CREAT.OBJ psyq47.pat ppsx -a ctors.obj psyq47.pat ppsx -a divdi3.obj psyq47.pat ppsx -a dummy.obj psyq47.pat ppsx -a eh.obj psyq47.pat ppsx -a eh_compat.obj psyq47.pat ppsx -a exit.obj psyq47.pat ppsx -a ffsdi2.obj psyq47.pat ppsx -a fixdfdi.obj psyq47.pat ppsx -a fixsfdi.obj psyq47.pat ppsx -a fixtfdi.obj psyq47.pat ppsx -a fixunsdfdi.obj psyq47.pat ppsx -a fixunsdfsi.obj psyq47.pat ppsx -a fixunssfdi.obj psyq47.pat ppsx -a fixunssfsi.obj psyq47.pat ppsx -a fixunstfdi.obj psyq47.pat ppsx -a fixunsxfdi.obj psyq47.pat ppsx -a fixunsxfsi.obj psyq47.pat ppsx -a fixxfdi.obj psyq47.pat ppsx -a floatdidf.obj psyq47.pat ppsx -a floatdisf.obj psyq47.pat ppsx -a floatditf.obj psyq47.pat ppsx -a floatdixf.obj psyq47.pat ppsx -a FSINIT.OBJ psyq47.pat ppsx -a gcc_bcmp.obj psyq47.pat ppsx -a LSEEK.OBJ psyq47.pat ppsx -a lshrdi3.obj psyq47.pat ppsx -a moddi3.obj psyq47.pat ppsx -a muldi3.obj psyq47.pat ppsx -a negdi2.obj psyq47.pat ppsx -a new_handler.obj psyq47.pat ppsx -a op_delete.obj psyq47.pat ppsx -a op_new.obj psyq47.pat ppsx -a op_vdel.obj psyq47.pat ppsx -a op_vnew.obj psyq47.pat ppsx -a OPEN.OBJ psyq47.pat ppsx -a PROFILE.OBJ psyq47.pat ppsx -a pure.obj psyq47.pat ppsx -a read.obj psyq47.pat ppsx -a shtab.obj psyq47.pat ppsx -a snctors.obj psyq47.pat ppsx -a SNDEF.OBJ psyq47.pat ppsx -a SNMAIN.OBJ psyq47.pat ppsx -a SNREAD.OBJ psyq47.pat ppsx -a SNWRITE.OBJ psyq47.pat ppsx -a trampoline.obj psyq47.pat ppsx -a ucmpdi2.obj psyq47.pat ppsx -a udiv_w_sdiv.obj psyq47.pat ppsx -a udivdi3.obj psyq47.pat ppsx -a udivmoddi4.obj psyq47.pat ppsx -a umoddi3.obj psyq47.pat ppsx -a varargs.obj psyq47.pat ppsx -a write.obj psyq47.pat ppsx -a LIBSND.LIB psyq47.pat ppsx -a LIBSPU.LIB psyq47.pat ppsx -a LIBTAP.LIB psyq47.pat ppsx -a LOW.OBJ psyq47.pat ppsx -a MCGUI.OBJ psyq47.pat ppsx -a MCGUI_E.OBJ psyq47.pat ppsx -a NOHEAP.OBJ psyq47.pat ppsx -a NONE3.OBJ psyq47.pat ppsx -a NOPRINT.OBJ psyq47.pat ppsx -a POWERON.OBJ psyq47.pat
CDMY15CDMY file has a format different from other libraries, so I had to decompose it into OBJ files with the CDMY16CDMY utility, which is included in the PSYQ package. We start CDMY17CDMY. We get the following exhaust:
2MBYTE.OBJ: skipped 0, total 1 8MBYTE.OBJ: skipped 0, total 1 LIBAPI.LIB: skipped 0, total 89 LIBC.LIB: skipped 0, total 55 LIBC2.LIB: skipped 0, total 50 LIBCARD.LIB: skipped 0, total 18 LIBCD.LIB: skipped 0, total 51 LIBCOMB.LIB: skipped 0, total 3 LIBDS.LIB: skipped 0, total 36 LIBETC.LIB: skipped 0, total 8 LIBGPU.LIB: skipped 0, total 60 LIBGS.LIB: skipped 0, total 167 LIBGTE.LIB: skipped 0, total 535 LIBGUN.LIB: skipped 0, total 2 LIBHMD.LIB: skipped 0, total 585 LIBMATH.LIB: skipped 0, total 59 LIBMCRD.LIB: skipped 0, total 7 LIBMCX.LIB: skipped 0, total 31 LIBPAD.LIB: skipped 0, total 21 LIBPRESS.LIB: skipped 0, total 7 LIBSIO.LIB: skipped 0, total 4 ashldi3.obj: skipped 0, total 1 ashrdi3.obj: skipped 0, total 1 CACHE.OBJ: skipped 0, total 1 clear_cache.obj: skipped 0, total 1 CLOSE.OBJ: skipped 0, total 1 cmpdi2.obj: skipped 0, total 1 CREAT.OBJ: skipped 0, total 1 ctors.obj: skipped 0, total 0 divdi3.obj: skipped 0, total 1 dummy.obj: skipped 0, total 1 Fatal: Illegal relocation information at file pos 0000022D eh_compat.obj: skipped 0, total 1 exit.obj: skipped 0, total 1 ffsdi2.obj: skipped 0, total 1 fixdfdi.obj: skipped 0, total 1 fixsfdi.obj: skipped 0, total 1 fixtfdi.obj: skipped 0, total 0 fixunsdfdi.obj: skipped 0, total 1 fixunsdfsi.obj: skipped 0, total 1 fixunssfdi.obj: skipped 0, total 1 fixunssfsi.obj: skipped 0, total 1 fixunstfdi.obj: skipped 0, total 0 fixunsxfdi.obj: skipped 0, total 0 fixunsxfsi.obj: skipped 0, total 0 fixxfdi.obj: skipped 0, total 0 floatdidf.obj: skipped 0, total 1 floatdisf.obj: skipped 0, total 1 floatditf.obj: skipped 0, total 0 floatdixf.obj: skipped 0, total 0 FSINIT.OBJ: skipped 0, total 1 gcc_bcmp.obj: skipped 0, total 1 LSEEK.OBJ: skipped 0, total 1 lshrdi3.obj: skipped 0, total 1 moddi3.obj: skipped 0, total 1 muldi3.obj: skipped 0, total 1 negdi2.obj: skipped 0, total 1 Fatal: Illegal relocation information at file pos 0000013D op_delete.obj: skipped 0, total 1 op_new.obj: skipped 0, total 1 op_vdel.obj: skipped 0, total 1 op_vnew.obj: skipped 0, total 1 OPEN.OBJ: skipped 0, total 1 PROFILE.OBJ: skipped 0, total 1 pure.obj: skipped 0, total 1 Fatal: Unknown record type 60 at 0000015F shtab.obj: skipped 0, total 0 Fatal: Unknown record type 60 at 000000EE SNDEF.OBJ: skipped 0, total 0 SNMAIN.OBJ: skipped 0, total 1 SNREAD.OBJ: skipped 0, total 1 SNWRITE.OBJ: skipped 0, total 1 trampoline.obj: skipped 0, total 0 ucmpdi2.obj: skipped 0, total 1 udiv_w_sdiv.obj: skipped 0, total 1 udivdi3.obj: skipped 0, total 1 udivmoddi4.obj: skipped 0, total 1 umoddi3.obj: skipped 0, total 1 varargs.obj: skipped 0, total 1 Fatal: Unknown record type 60 at 00000160 LIBSND.LIB: skipped 0, total 223 LIBSPU.LIB: skipped 0, total 126 LIBTAP.LIB: skipped 0, total 1 LOW.OBJ: skipped 0, total 1 Fatal: can't find symbol F003 MCGUI_E.OBJ: skipped 0, total 1 NOHEAP.OBJ: skipped 0, total 1 NONE3.OBJ: skipped 0, total 1 NOPRINT.OBJ: skipped 0, total 1 POWERON.OBJ: skipped 0, total 1
We see a certain number of parsing errors, but in those files there is only 1 signature (total 1), so I think that this is not critical. Next, convert the PAT file to a SIG file:
sigmake -n"PsyQ v4.7" psyq47.pat psyq47.sig psyq47.sig: modules/leaves: 1345/2177, COLLISIONS: 21 See the documentation to learn how to resolve collisions.
As a result, we get the following list of files:
- CDMY18CDMY - we don’t touch it
- CDMY19CDMY - you will need to edit it
- CDMY20CDMY - we don’t touch him either
Open the CDMY21CDMY file for editing. We see:
;--------- (delete these lines to allow sigmake to read this file) ; add '+' at the start of a line to select a module ; add '-' if you are not sure about the selection ; do nothing if you want to exclude all modules
If you remove CDMY22CDMY, everything contained in the file below will be taken into account. Let's take a look at what is there. Here is an example:
CdPosToInt 60 A21C 0000839001008690022903008010050021104500401002000F00633021104300 DsPosToInt 60 A21C 0000839001008690022903008010050021104500401002000F00633021104300
We see that the two functions have the same signature, and we need to choose which one to use.To do this, put CDMY23CDMY on the left, next to the name of the desired function. I choose the first. Repeat the same with the rest of the lines.
As a result, if everything is done correctly, we get a SIG file. You need to put it in the appropriate folder in the IDA installation directory.
Create til files
These files are needed to store information about types, function arguments, etc. Default. They are created using the utility CDMY24CDMY, which must be put in the directory with Ida (for some reason, she needs the CDMY25CDMY file).
This utility needs to feed the include files of your SDK/DDK. Moreover, parsing by this utility differs from that by the " Parse C header file. " tool in the IDA itself. Here is the description from readme:
Its functionality overlaps with "Parse C header file." from IDA Pro.
However, this utility is easier to use and provides more control
over the output. Also, it can handle the preprocessor symbols, while
the built-in command ignores them.
This utility has one nuance: by default it uses the mode when characters are manged up or have a lower underscore at the beginning of the name. If you are working with statically linked code, you must disable this mode with the CDMY26CDMY flag.
By default, this utility accepts only one include file. If there are a lot of files, you need to build an include-file of the following content:
#include "header1.h" #include "header2.h" #include "header3.h"//...
This file is transferred using the CDMY27CDMY flag. Next, we pass the search path for the remaining header files and get the following command line:
tilib -c -Gn -I. -hpsyq47.h psyq47.til
The output is a usable til file. We put it in the appropriate IDA directory: CDMY28CDMY.
Check the result
We upload the ROM-file in the IDA, wait for the analysis to complete. Next, you must specify the compiler. To do this, go to CDMY29CDMY- > CDMY30CDMY:
Now just change CDMY31CDMY to CDMY32CDMY (in the case of PSX). We leave the rest as is:
Now click CDMY33CDMY (or menu CDMY34CDMY- > CDMY35CDMY- > CDMY36CDMY), click CDMY37CDMY and select the desired signature file:
We press CDMY38CDMY and wait while the signatures are applied (I got 482 recognized functions).
Next, you need to apply the type library (til file). To do this, press CDMY39CDMY (or CDMY40CDMY- > CDMY41CDMY- > CDMY42CDMY) and understand that the compiler cannot determine the IDA (despite the fact that we have already specified it):
But it still doesn’t hurt us to choose a til-file (all the same, via CDMY43CDMY):
We get what we wanted so much:
Now the decompiler successfully picks up type information, and the exhaust gets much better:
I hope you find this information helpful. Good reverse engineering!.