commit
						69ef04d5e6
					
				| @ -1,138 +0,0 @@ | |||||||
| Here's how you build dfhack! |  | ||||||
| ---------------------------- |  | ||||||
| 
 |  | ||||||
| First, there is one dependency, regardless of the OS you use: |  | ||||||
|   cmake - it's the build system |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Building on Linux: |  | ||||||
| -------------------- |  | ||||||
| 
 |  | ||||||
| * To run in the output folder (without installing): |  | ||||||
| 
 |  | ||||||
| building the library is simple. Enter the build folder, run the tools. Like this: |  | ||||||
|      |  | ||||||
| cd build |  | ||||||
| cmake .. -DCMAKE_BUILD_TYPE:string=Release |  | ||||||
| make |  | ||||||
| 
 |  | ||||||
| This will build the library and its tools and place them in /output. |  | ||||||
| You can also use a cmake-friendly IDE like KDevelop 4 or the cmake GUI program. |  | ||||||
| 
 |  | ||||||
| * To be installed into the system or packaged |  | ||||||
| 
 |  | ||||||
| cd build |  | ||||||
| cmake -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/usr -DMEMXML_DATA_PATH:path=/usr/share/dfhack .. |  | ||||||
| make |  | ||||||
| make install |  | ||||||
| 
 |  | ||||||
| With this dfhack installs: |  | ||||||
| library to $CMAKE_INSTALL_PREFIX/lib |  | ||||||
| executables to $CMAKE_INSTALL_PREFIX/bin |  | ||||||
| The Memory.xml file to /usr/share/dfhack |  | ||||||
| 
 |  | ||||||
| See the section on the shared memory hook library (SHM). |  | ||||||
| 
 |  | ||||||
| Building on Windows: |  | ||||||
| -------------------- |  | ||||||
| 
 |  | ||||||
| You need cmake. Get the win32 installer version from the official site: http://www.cmake.org/cmake/resources/software.html |  | ||||||
| It has the usual installer wizard thing. |  | ||||||
| 
 |  | ||||||
| * Using mingw: |  | ||||||
| 
 |  | ||||||
| You also need a compiler. I build dfhack using mingw. You can get it from the mingw site: |  | ||||||
| Get the automated installer, it will download newest version of mingw and set things up nicely. |  | ||||||
| You'll have to add C:\MinGW\ to your PATH variable. |  | ||||||
| 
 |  | ||||||
|  - Building: |  | ||||||
|  open up cmd and navigate to the dfhack\build folder, run cmake and the mingw version of make: |  | ||||||
|  cd build |  | ||||||
|  cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release |  | ||||||
|  mingw32-make |  | ||||||
| 
 |  | ||||||
| * Using MSVC |  | ||||||
| 
 |  | ||||||
| open up cmd and navigate to the dfhack\build folder, run cmake: |  | ||||||
| cd build |  | ||||||
| cmake .. |  | ||||||
| 
 |  | ||||||
| This will generate MSVC solution and project files. Note that: you are working in the /build folder. |  | ||||||
| Files added to projects will end up there! (and that's wrong). Any changes to the build system should |  | ||||||
| be done by changing cmake configs and running cmake on them! |  | ||||||
| 
 |  | ||||||
| * Using some other compiler: |  | ||||||
| 
 |  | ||||||
| I'm afraid you are on your own. dfhack wasn't tested with any other compiler. |  | ||||||
| Try using a different cmake generator that's intended for your tools. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Building the shared memory hook library (SHM) |  | ||||||
| --------------------------------------------- |  | ||||||
| 
 |  | ||||||
| Unlike the rest of DFHack, The SHM needs special treatment when it comes to compilation. |  | ||||||
| Because it shares the memory space with DF itself, it has to be built with the same tools as DF |  | ||||||
| and use the same C and C++/STL libraries. |  | ||||||
| 
 |  | ||||||
| For DF 40d15 - 40d17 on Windows, use MSVC 2008. You can get the Express edition for free from Microsoft. |  | ||||||
| 
 |  | ||||||
| Windows dependencies can be determined by a tool like depends.exe (google it). Both the fake SDL.dll |  | ||||||
| and DF have to use the same version of the C runtime (MSVCRT). |  | ||||||
| The SHM can't be debugged, because debug builds in MSVC use a different CRT! |  | ||||||
| 
 |  | ||||||
| Linux dependencies can be determined by setting the LD_DEBUG variable and running ./df: |  | ||||||
| export LD_DEBUG=versions |  | ||||||
| ./df |  | ||||||
| 
 |  | ||||||
| Example of (a part of a) relevant output from a working SHM installation: |  | ||||||
|      24472:     checking for version `GLIBC_2.0' in file /opt/lib32/lib/libpthread.so.0 [0] required by file ./dwarfort.exe [0]                                                                                               |  | ||||||
|      24472:     checking for version `GCC_3.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0]                                                                                                           |  | ||||||
|      24472:     checking for version `GLIBC_2.0' in file ./libs/libgcc_s.so.1 [0] required by file ./dwarfort.exe [0]                                                                                                         |  | ||||||
|      24472:     checking for version `GLIBC_2.1' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                     |  | ||||||
|      24472:     checking for version `GLIBC_2.0' in file /opt/lib32/lib/libm.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                     |  | ||||||
|      24472:     checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                   |  | ||||||
|      24472:     checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                   |  | ||||||
|      24472:     checking for version `GLIBC_2.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                     |  | ||||||
|      24472:     checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                     |  | ||||||
|      24472:     checking for version `GLIBCXX_3.4.9' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                    |  | ||||||
|      24472:     checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                       |  | ||||||
|      24472:     checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./dwarfort.exe [0]                                                                                                      |  | ||||||
|      24472:     checking for version `CXXABI_1.3' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0]                                                                                               |  | ||||||
|      24472:     checking for version `GLIBCXX_3.4' in file ./libs/libstdc++.so.6 [0] required by file ./libs/libdfconnect.so [0]                                                                                              |  | ||||||
|      24472:     checking for version `GLIBC_2.1.3' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]                                                                                           |  | ||||||
|      24472:     checking for version `GLIBC_2.2' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]                                                                                             |  | ||||||
|      24472:     checking for version `GLIBC_2.3.4' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]                                                                                           |  | ||||||
|      24472:     checking for version `GLIBC_2.0' in file /opt/lib32/lib/libc.so.6 [0] required by file ./libs/libdfconnect.so [0]     |  | ||||||
| 
 |  | ||||||
| libdfconnect is the SHM. Both are compiled against the same C++ library and share the same CXXABI version. |  | ||||||
| 
 |  | ||||||
| Precompiled SHM libraries are provided in binary releases. |  | ||||||
| 
 |  | ||||||
| * Checking strings support |  | ||||||
| 
 |  | ||||||
| Strings are one of the important C++ types and a great indicator that the SHM works. Tools like Dwarf Therapist depend |  | ||||||
| on string support. Reading of strings can be checked by running any of the tools that deal with materials. |  | ||||||
| 
 |  | ||||||
| String writing is best tested with a fresh throw-away fort and dfrenamer. Embark, give one dwarf a very long name using dfrenamer |  | ||||||
| and save/exit. If DF crashes during the save sequence, your SHM is not compatible with DF and the throw-away fort is lost. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Build targets |  | ||||||
| ------------- |  | ||||||
| 
 |  | ||||||
| dfhack has a few build targets. If you're only after the library run 'make dfhack'. |  | ||||||
| 'make' will build everything. |  | ||||||
| 'make expbench' will build the expbench throughput testing program and the library. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Build types |  | ||||||
| ----------- |  | ||||||
| 
 |  | ||||||
| cmake allows you to pick a build type by changing this variable: CMAKE_BUILD_TYPE |  | ||||||
| 
 |  | ||||||
| cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE |  | ||||||
| 
 |  | ||||||
| Without specifying a build type or 'None', cmake uses the CMAKE_CXX_FLAGS variable for building. |  | ||||||
| Valid build types include 'Release' and 'Debug'. There are others, but they aren't really that useful. |  | ||||||
| 
 |  | ||||||
| Have fun. |  | ||||||
| @ -1,174 +0,0 @@ | |||||||
| Introduction |  | ||||||
| ------------ |  | ||||||
| 
 |  | ||||||
| DFHack is a Dwarf Fortress memory access library and a set of basic tools using  |  | ||||||
| this library. The library is a work in progress, so things might change as more |  | ||||||
| tools are written for it. |  | ||||||
| 
 |  | ||||||
| It is an attempt to unite the various ways tools access DF memory and allow for |  | ||||||
| easier development of new tools. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Getting DFHack |  | ||||||
| ---------------- |  | ||||||
| The project is currently hosted on github: |  | ||||||
|   http://github.com/peterix/dfhack |  | ||||||
| 
 |  | ||||||
| There's an SVN repository at sourceforge, but will only be updated for major releases: |  | ||||||
|   https://sourceforge.net/projects/dfhack/ |  | ||||||
| * subversion access:  |  | ||||||
|   svn co https://dfhack.svn.sourceforge.net/svnroot/dfhack/trunk dfhack  |  | ||||||
| 
 |  | ||||||
| Compatibility |  | ||||||
| ------------- |  | ||||||
| 
 |  | ||||||
| DFHack works on Windows XP, Vista, 7 or any modern Linux distribution. |  | ||||||
| 
 |  | ||||||
| Windows 2000 is currently *not supported* due to missing OS functionality. |  | ||||||
| If you know how to easily suspend processes, you can fix it :) |  | ||||||
| 
 |  | ||||||
| OSX is also not supported due to lack of developers with a Mac. |  | ||||||
| 
 |  | ||||||
| Currently supported Dwarf Fortress versions: |  | ||||||
| * Windows |  | ||||||
|   40d |  | ||||||
|   40d9 - 40d18 |  | ||||||
| 
 |  | ||||||
| * Linux |  | ||||||
|   40d9 - 40d18 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Using the library |  | ||||||
| ----------------- |  | ||||||
| 
 |  | ||||||
| The library is compilable under Linux with GCC and under Windows with MinGW32 |  | ||||||
| and MSVC compilers. It is using the cmake build system. See COMPILE for details. |  | ||||||
| 
 |  | ||||||
| DFHack is using the zlib/libpng license. This makes it easy to link to it, use |  | ||||||
| it in-source or add your own extensions. Contributing back to the dfhack |  | ||||||
| repository is welcome and the right thing to do :) |  | ||||||
| 
 |  | ||||||
| At the time of writing there's no API reference or documentation. The code does |  | ||||||
| have a lot of comments though. |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Using DFHack Tools |  | ||||||
| ------------------ |  | ||||||
| 
 |  | ||||||
| The project comes with a special extra library you should add to your DF |  | ||||||
| installation. It's used to boost the transfer speed between DF and DFHack, and |  | ||||||
| provide data consistency and synchronization. DFHack will work without the |  | ||||||
| library, but at suboptimal speeds and the consistency of data written back |  | ||||||
| to DF is questionable. |  | ||||||
| 
 |  | ||||||
| !!!     on Windows this currently only works with DF 40d15 - 40d18      !!! |  | ||||||
|      On Linux, it works with the whole range of supported DF versions. |  | ||||||
| 
 |  | ||||||
| !!! use the pre-compiled library intended for your OS and version of DF !!! |  | ||||||
|                You can find them in the 'precompiled' folder. |  | ||||||
|                 |  | ||||||
| 
 |  | ||||||
|  ** Installing on Windows |  | ||||||
|  - Open your DF folder, locate SDL.dll and rename it to SDLreal.dll (making |  | ||||||
|    a backup of it is a good idea) |  | ||||||
|  - Copy the right DFHack SDL.dll into your DF folder. |  | ||||||
|  - Restart DF if it is running |  | ||||||
| 
 |  | ||||||
|  ** Unistalling on Windows |  | ||||||
|  - Open your DF folder, locate SDL.dll and delete it |  | ||||||
|  - Rename SDLreal.dll to SDL.dll |  | ||||||
|  - Restart DF if it is running |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  ** Installing on Linux |  | ||||||
|  - Open your DF folder and the libs folder within it |  | ||||||
|  - copy DFHack libdfconnect.so to the libs folder |  | ||||||
|  - copy the df startup script, name it dfhacked |  | ||||||
|  - open the new dfhacked startup script and add this line: |  | ||||||
|      export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF! |  | ||||||
|    just before the line that launches DF |  | ||||||
| 
 |  | ||||||
|    Here's an example how the file can look after the change: |  | ||||||
| #!/bin/sh |  | ||||||
| DF_DIR=$(dirname "$0") |  | ||||||
| cd "${DF_DIR}" |  | ||||||
| export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch. |  | ||||||
| #export SDL_VIDEO_CENTERED=1 # Centre the screen.  Messes up resizing. |  | ||||||
| ldd dwarfort.exe | grep SDL_image | grep -qv "not found$" |  | ||||||
| if [ $? -eq 0 ]; then |  | ||||||
|  mkdir unused_libs |  | ||||||
|  mv libs/libSDL* unused_libs/ |  | ||||||
| fi |  | ||||||
| export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"./libs" # Update library search path. |  | ||||||
| export LD_PRELOAD="./libs/libdfconnect.so" # Hack DF! |  | ||||||
| ./dwarfort.exe $* # Go, go, go! :) |  | ||||||
| 
 |  | ||||||
|  - Use this new startup script to start DF |  | ||||||
| 
 |  | ||||||
|  ** Uninstalling on Linux |  | ||||||
|  - Open your DF and DF/libs folders |  | ||||||
|  - Delete libdfconnect.so and the dfhacked startup script |  | ||||||
|  - Go back to using the df startup script |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| Tools |  | ||||||
| ----- |  | ||||||
| 
 |  | ||||||
| All the DFHack tools are terminal programs. This might seem strange to Windows |  | ||||||
| users, but these are meant mostly as examples for developers. Still, they can |  | ||||||
| be useful and are cross-platform just like the library itself. |  | ||||||
| 
 |  | ||||||
| If the tool writes back to DF's memory, make sure you are using the shared |  | ||||||
| memory interface mentioned in the previous section! |  | ||||||
| 
 |  | ||||||
| * reveal     - plain old reveal tool. It reveals all the map blocks already |  | ||||||
|                initialized by DF. |  | ||||||
| 
 |  | ||||||
| * prospector - scans the map for minerals. by default it only scans only visible |  | ||||||
|                veins. You can make it show hidden things with '-a' and base rock |  | ||||||
|                and soil layers with '-b'. These can be combined ('-ab') |  | ||||||
| 
 |  | ||||||
| * cleanmap   - cleans mud, vomit, snow and all kinds of mess from the map. |  | ||||||
|                It will clean your irrigated farms too, so consider yourself |  | ||||||
|                warned. |  | ||||||
| 
 |  | ||||||
| * incremental - incremental search utility. |  | ||||||
| 
 |  | ||||||
| * bauxite - converts all mechanisms into bauxite mechanisms. |  | ||||||
| 
 |  | ||||||
| * itemdesignator - Allows mass-designating items by type and material - dump, |  | ||||||
|                    forbid, melt and set on fire ;) |  | ||||||
| * digger         - allows designating tiles for digging/cutting/ramp removal |  | ||||||
| 
 |  | ||||||
|   A list of accepted tile classes: |  | ||||||
|         1  = WALL |  | ||||||
|         2  = PILLAR |  | ||||||
|         3  = FORTIFICATION |  | ||||||
|          |  | ||||||
|         4  = STAIR_UP |  | ||||||
|         5  = STAIR_DOWN |  | ||||||
|         6  = STAIR_UPDOWN |  | ||||||
|          |  | ||||||
|         7  = RAMP |  | ||||||
|          |  | ||||||
|         8  = FLOOR |  | ||||||
|         9  = TREE_DEAD |  | ||||||
|         10 = TREE_OK |  | ||||||
|         11 = SAPLING_DEAD |  | ||||||
|         12 = SAPLING_OK |  | ||||||
|         13 = SHRUB_DEAD |  | ||||||
|         14 = SHRUB_OK |  | ||||||
|         15 = BOULDER |  | ||||||
|         16 = PEBBLES |  | ||||||
|    |  | ||||||
|   Example : dfdigger -o 100,100,15 -t 9,10 -m 10 |  | ||||||
|   This will start looking for trees at coords 100,100,15 and designate ten of them for cutting. |  | ||||||
| 
 |  | ||||||
|   |  | ||||||
| Memory offset definitions |  | ||||||
| ------------------------- |  | ||||||
| 
 |  | ||||||
| The file with memory offset definitions used by dfhack can be found in the |  | ||||||
| output folder.  |  | ||||||
| 
 |  | ||||||
| ~ EOF ~ |  | ||||||
| @ -0,0 +1,46 @@ | |||||||
|  | // Just show some position data
 | ||||||
|  | 
 | ||||||
|  | #include <iostream> | ||||||
|  | #include <climits> | ||||||
|  | #include <integers.h> | ||||||
|  | #include <vector> | ||||||
|  | #include <sstream> | ||||||
|  | #include <ctime> | ||||||
|  | using namespace std; | ||||||
|  | 
 | ||||||
|  | #include <DFTypes.h> | ||||||
|  | #include <DFHackAPI.h> | ||||||
|  | #include <DFProcess.h> | ||||||
|  | 
 | ||||||
|  | int main (int numargs, const char ** args) | ||||||
|  | { | ||||||
|  |     uint32_t addr; | ||||||
|  |     if (numargs == 2) | ||||||
|  |     { | ||||||
|  |         istringstream input (args[1],istringstream::in); | ||||||
|  |         input >> std::hex >> addr; | ||||||
|  |     } | ||||||
|  |     DFHack::API DF("Memory.xml"); | ||||||
|  |     if(!DF.Attach()) | ||||||
|  |     { | ||||||
|  |         cerr << "DF not found" << endl; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         DFHack::Process* p = DF.getProcess(); | ||||||
|  |         #ifdef LINUX_BUILD | ||||||
|  |         cout << "start 0x" << hex << p->readDWord(addr+0x0) << endl; | ||||||
|  |         cout << "end   0x" << hex << p->readDWord(addr+0x4) << endl; | ||||||
|  |         cout << "cap   0x" << hex << p->readDWord(addr+0x8) << endl; | ||||||
|  |         #else | ||||||
|  |         cout << "start 0x" << hex << p->readDWord(addr+0x4) << endl; | ||||||
|  |         cout << "end   0x" << hex << p->readDWord(addr+0x8) << endl; | ||||||
|  |         cout << "cap   0x" << hex << p->readDWord(addr+0xC) << endl; | ||||||
|  |         #endif | ||||||
|  |     } | ||||||
|  |     #ifndef LINUX_BUILD | ||||||
|  |     cout << "Done. Press any key to continue" << endl; | ||||||
|  |     cin.ignore(); | ||||||
|  |     #endif | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								| @ -0,0 +1,802 @@ | |||||||
|  | //Microsoft Visual C++ Win32 SEH/C++ EH info parser
 | ||||||
|  | //Version 3.0 2006.03.02 Igor Skochinsky <skochinsky@mail.ru>
 | ||||||
|  | 
 | ||||||
|  | #include <idc.idc> | ||||||
|  | #define __INCLUDED | ||||||
|  | #include <ms_rtti.idc> | ||||||
|  | 
 | ||||||
|  | static getEHRec() | ||||||
|  | { | ||||||
|  |   auto id; | ||||||
|  |   id = GetStrucIdByName("EHRegistrationNode"); | ||||||
|  |   if (id==-1) | ||||||
|  |   { | ||||||
|  |     id = AddStruc(-1,"EHRegistrationNode"); | ||||||
|  |     ForceDWMember(id, 0, "pNext"); | ||||||
|  |     ForceDWMember(id, 4, "frameHandler"); | ||||||
|  |     ForceDWMember(id, 8, "state"); | ||||||
|  |   } | ||||||
|  |   return id; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static getEHRecCatch() | ||||||
|  | { | ||||||
|  |   auto id; | ||||||
|  |   id = GetStrucIdByName("EHRegistrationNodeCatch"); | ||||||
|  |   if (id==-1) | ||||||
|  |   { | ||||||
|  |     id = AddStruc(-1,"EHRegistrationNodeCatch"); | ||||||
|  |     ForceDWMember(id, 0, "SavedESP"); | ||||||
|  |     ForceDWMember(id, 4, "pNext"); | ||||||
|  |     ForceDWMember(id, 8, "frameHandler"); | ||||||
|  |     ForceDWMember(id, 12, "state"); | ||||||
|  |   } | ||||||
|  |   return id; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static CommentStackEH(start, hasESP, EHCookie, GSCookie) | ||||||
|  | {   | ||||||
|  |   if (hasESP) | ||||||
|  |     CommentStack(start,-16, "__$EHRec$", getEHRecCatch()); | ||||||
|  |   else | ||||||
|  |     CommentStack(start,-12, "__$EHRec$", getEHRec()); | ||||||
|  |   if (GSCookie) | ||||||
|  |     CommentStack(start,-GSCookie, "__$GSCookie$",-1); | ||||||
|  |   if (EHCookie) | ||||||
|  |     CommentStack(start,-EHCookie, "__$EHCookie$",-1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* from frame.obj
 | ||||||
|  | typedef struct _s_FuncInfo { | ||||||
|  |   unsigned int magicNumber; | ||||||
|  |   int maxState; | ||||||
|  |   const struct _s_UnwindMapEntry * pUnwindMap; | ||||||
|  |   unsigned int nTryBlocks; | ||||||
|  |   const struct _s_TryBlockMapEntry * pTryBlockMap; | ||||||
|  |   unsigned int nIPMapEntries; | ||||||
|  |   void * pIPtoStateMap; | ||||||
|  |   const struct _s_ESTypeList * pESTypeList; | ||||||
|  | } FuncInfo; | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | //handler:
 | ||||||
|  | //  mov     eax, offset funcInfo
 | ||||||
|  | //  jmp     ___CxxFrameHandler
 | ||||||
|  | static ParseCxxHandler(func, handler, fixFunc) | ||||||
|  | { | ||||||
|  |   auto x, start, y, z, end, i, count, t, u, i2, cnt2, a, hasESP; | ||||||
|  |   auto EHCookieOffset, GSCookieOffset; | ||||||
|  |   start = func; | ||||||
|  |   x = handler; | ||||||
|  |   y = x; | ||||||
|  |   z = x; | ||||||
|  |   EHCookieOffset=0; GSCookieOffset=0; | ||||||
|  |   if (matchBytes(x,"8B5424088D420C")) | ||||||
|  |     // 8B 54 24 08                       mov     edx, [esp+8]
 | ||||||
|  |     // 8D 42 0C                          lea     eax, [edx+0Ch]
 | ||||||
|  |   { | ||||||
|  |     //EH cookie check:
 | ||||||
|  |     // 8B 4A xx                          mov     ecx, [edx-XXh]
 | ||||||
|  |     //   OR
 | ||||||
|  |     // 8B 8A xx xx xx xx                 mov     ecx, [edx-XXh]
 | ||||||
|  |     // 33 C8                             xor     ecx, eax
 | ||||||
|  |     // E8 xx xx xx xx                    call    __security_check_cookie
 | ||||||
|  |     x = x+7; | ||||||
|  |     if (matchBytes(x,"8B4A??33C8E8")) | ||||||
|  |     { | ||||||
|  |       //byte argument
 | ||||||
|  |       EHCookieOffset = (~Byte(x+2)+1)&0xFF; | ||||||
|  |       EHCookieOffset = 12 + EHCookieOffset; | ||||||
|  |       x = x+10; | ||||||
|  |     } | ||||||
|  |     else if (matchBytes(x,"8B8A????????33C8E8")) | ||||||
|  |     { | ||||||
|  |       //dword argument
 | ||||||
|  |       EHCookieOffset = (~Dword(x+2)+1); | ||||||
|  |       EHCookieOffset = 12 + EHCookieOffset; | ||||||
|  |       x = x+13; | ||||||
|  |     } | ||||||
|  |     if (matchBytes(x,"8B4A??33C8E8")) | ||||||
|  |     { | ||||||
|  |       // 8B 4A xx                          mov     ecx, [edx-XXh]
 | ||||||
|  |       // 33 C8                             xor     ecx, eax
 | ||||||
|  |       // E8 xx xx xx xx                    call    __security_check_cookie
 | ||||||
|  |       GSCookieOffset = (~Byte(x+2)+1)&0xFF; | ||||||
|  |       GSCookieOffset = 12 + GSCookieOffset; | ||||||
|  |       x = x+10; | ||||||
|  |     } | ||||||
|  |     else if (matchBytes(x,"8B8A????????33C8E8")) | ||||||
|  |     { | ||||||
|  |       //dword argument
 | ||||||
|  |       GSCookieOffset = (~Dword(x+9)+1); | ||||||
|  |       GSCookieOffset = 12 + GSCookieOffset; | ||||||
|  |       x = x+13; | ||||||
|  |     } | ||||||
|  |     //Message("EH3: EH Cookie=%02X, GSCookie=%02X\n",EHCookieOffset, GSCookieOffset);
 | ||||||
|  |   } | ||||||
|  |   if (Byte(x)==0xB8) { | ||||||
|  |     x = Dword(x+1); | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     Message("\"mov eax, offset FuncInfo\" not found at offset %08X!\n",x); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (Dword(x)-0x19930520>0xF) { | ||||||
|  |     Message("Magic is not 1993052Xh!\n"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   Message(form("Detected function start at %08X\n",start)); | ||||||
|  |   u = x; //FuncInfo;
 | ||||||
|  |    | ||||||
|  |   //parse unwind handlers
 | ||||||
|  |   count = Dword(u+4); //maxState
 | ||||||
|  |   i=0; | ||||||
|  |   x = Dword(u+8); //pUnwindMap
 | ||||||
|  |   while (i<count) { | ||||||
|  |     t = Dword(x+4); //unwind action address
 | ||||||
|  |     if (t<MAXADDR && t>y) y=t;   //find lowest
 | ||||||
|  |     if (t!=0 && t<z) z=t;   //find highest
 | ||||||
|  |     x = x+8; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  |   if (y==0) { | ||||||
|  |     Message("All pointers are NULL!\n"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (z>y) | ||||||
|  |   { | ||||||
|  |     Message("Something's very wrong!\n"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   end = FindFuncEnd(y); | ||||||
|  |   if (end==BADADDR) { | ||||||
|  |     if (fixFunc) MakeUnkn(y, 1); | ||||||
|  |     if (BADADDR == FindFuncEnd(y)) | ||||||
|  |     { | ||||||
|  |       Message(form("Can't find function end at 0x%08X\n",y)); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   Message(form("Handlers block: %08X-%08X\n", z, y)); | ||||||
|  |   if (GetFunctionFlags(start) == -1) | ||||||
|  |   { | ||||||
|  |     if (fixFunc)  | ||||||
|  |     {  | ||||||
|  |       MakeUnkn(start, 1); | ||||||
|  |       MakeCode(start); | ||||||
|  |       MakeFunction(start, BADADDR); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       Message("There is no function defined at 0x%08X!\n", start); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   a = FindFuncEnd(start); | ||||||
|  |   Message("Function end: %08X\n", a); | ||||||
|  |   if (fixFunc) AnalyseArea(start,a); | ||||||
|  |   if (1)//(z>a) && ((z-a)>0x20))
 | ||||||
|  |   { | ||||||
|  |     //the handlers block is too far from the function end, make it a separate chunk
 | ||||||
|  |     if (fixFunc) | ||||||
|  |     { | ||||||
|  |       Message("Making separate handlers block\n"); | ||||||
|  |       Unknown(z, y-z); | ||||||
|  |       MakeCode(z); | ||||||
|  |       MakeFunction(z,y); | ||||||
|  |       AnalyseArea(z,y); | ||||||
|  |       MakeCode(y); | ||||||
|  |       MakeFunction(y,BADADDR); | ||||||
|  |     } | ||||||
|  |     SetFunctionFlags(z, GetFunctionFlags(start) | FUNC_FRAME); | ||||||
|  |     SetFunctionCmt(z, form("Unwind handlers of %08X", start), 0); | ||||||
|  |   } | ||||||
|  |   else if (fixFunc) | ||||||
|  |   { | ||||||
|  |     Message("Merging handlers block with main function.\n"); | ||||||
|  |     Unknown(start, y-start); | ||||||
|  |     MakeCode(start); | ||||||
|  |     MakeFunction(start,y); | ||||||
|  |     AnalyseArea(start,y); | ||||||
|  |   } | ||||||
|  | /*
 | ||||||
|  | typedef const struct _s_TryBlockMapEntry { | ||||||
|  |   int tryLow;                                  //00
 | ||||||
|  |   int tryHigh;                                 //04
 | ||||||
|  |   int catchHigh;                               //08
 | ||||||
|  |   int nCatches;                                //0C
 | ||||||
|  |   const struct _s_HandlerType * pHandlerArray; //10
 | ||||||
|  | } TryBlockMapEntry; | ||||||
|  | 
 | ||||||
|  | typedef const struct _s_HandlerType { | ||||||
|  |   unsigned int adjectives;          //00
 | ||||||
|  |   struct TypeDescriptor * pType;    //04
 | ||||||
|  |   int dispCatchObj;                 //08
 | ||||||
|  |   void * addressOfHandler;          //0C
 | ||||||
|  | } | ||||||
|  | */   | ||||||
|  | 
 | ||||||
|  |   //parse catch blocks
 | ||||||
|  |   y = 0; | ||||||
|  |   z = 0x7FFFFFFF; | ||||||
|  |   i=0; | ||||||
|  |   count = Dword(u+12); //nTryBlocks
 | ||||||
|  |   x = Dword(u+16);     //pTryBlocksMap
 | ||||||
|  |   Message("%d try blocks\n",count); | ||||||
|  |   while (i<count) {     | ||||||
|  |     cnt2 = Dword(x+12);        //nCatches
 | ||||||
|  |     a = Dword(x+16);           //pHandlerArray
 | ||||||
|  |     i2 = 0; | ||||||
|  |     Message("   %d catches\n",cnt2); | ||||||
|  |     while (i2<cnt2) | ||||||
|  |     { | ||||||
|  |       t = Dword(a+12); | ||||||
|  |       //Message("    t=0x%08.8X\n",t);
 | ||||||
|  |       if (t!=BADADDR && t>y) | ||||||
|  |         y=t;      //find lowest
 | ||||||
|  |       if (z>t) | ||||||
|  |         z=t;      //find highest
 | ||||||
|  |       a = a+16; | ||||||
|  |       i2 = i2+1; | ||||||
|  |     } | ||||||
|  |     x = x+20; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  |   hasESP = 0; | ||||||
|  |   if (count>0) | ||||||
|  |   { | ||||||
|  |     hasESP = 1; | ||||||
|  |     //Message("y=0x%08.8X, z=0x%08.8X\n",y,z);
 | ||||||
|  |     end = FindFuncEnd(y); | ||||||
|  |     if (end==BADADDR) { | ||||||
|  |       if (fixFunc)  | ||||||
|  |       {  | ||||||
|  |         MakeUnkn(y, 1); | ||||||
|  |         MakeCode(y); | ||||||
|  |       } | ||||||
|  |       if (BADADDR == FindFuncEnd(y)) | ||||||
|  |       { | ||||||
|  |         Message(form("Can't find function end at 0x%08X\n",y)); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     Message(form("Catch blocks: %08X-%08X\n", z, end)); | ||||||
|  |     y = FindFuncEnd(start); | ||||||
|  |     if (y ==-1 || end > y) | ||||||
|  |     { | ||||||
|  |       if (fixFunc) | ||||||
|  |       { | ||||||
|  |         Message("Merging catch blocks with main function.\n"); | ||||||
|  |         Unknown(start, end-start); | ||||||
|  |         MakeCode(start); | ||||||
|  |         MakeFunction(start,end); | ||||||
|  |         AnalyseArea(start,end); | ||||||
|  |       } | ||||||
|  |       else | ||||||
|  |         Message("Catch blocks are not inside the function!\n"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   //comment unwind handlers
 | ||||||
|  |   i=0; | ||||||
|  |   count = Dword(u+4); //maxState
 | ||||||
|  |   x = Dword(u+8); //pUnwindMap
 | ||||||
|  |   while (i<count) { | ||||||
|  |     t = Dword(x+4); //unwind action address
 | ||||||
|  |     if (t!=0) | ||||||
|  |       MakeComm(t, form("state %d -> %d",i, Dword(x))); | ||||||
|  |     x = x+8; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  |   Parse_FuncInfo(u, 0); | ||||||
|  |   CommentStackEH(func, hasESP, EHCookieOffset, GSCookieOffset); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static fixCxx(s, doSEH, fixFunc) { | ||||||
|  |   auto x, start; | ||||||
|  |   start = s; | ||||||
|  |   if ((Word(start) != 0xA164) || (Dword(start+2)!=0)) { | ||||||
|  |     Message("Should start with \"move eax, large fs:0\"!\n"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if ( !doSEH && (Byte(start-10) == 0x55) && (Dword(start-9) == 0xFF6AEC8B)) | ||||||
|  |   { | ||||||
|  |     //(ebp frame)
 | ||||||
|  |     //00: 55                   push    ebp
 | ||||||
|  |     //01: 8B EC                mov     ebp, esp
 | ||||||
|  |     //03: 6A FF                push    0FFFFFFFFh
 | ||||||
|  |     //05: 68 xx xx xx xx       push    loc_xxxxxxxx
 | ||||||
|  |     //0A: 64 A1 00 00 00 00    mov     eax, large fs:0
 | ||||||
|  |     //10: 50                   push    eax
 | ||||||
|  |     //11: 64 89 25 00 00 00 00 mov     large fs:0, esp
 | ||||||
|  |     start = start - 10; | ||||||
|  |     x = Dword(start+6); | ||||||
|  |     //Message("Match 1\n");
 | ||||||
|  |   } | ||||||
|  |   else if (!doSEH && (Word(start+9) == 0xFF6A) && (Byte(start+11)==0x68)) | ||||||
|  |   { | ||||||
|  |     //00: 64 A1 00 00 00 00    mov     eax, large fs:0
 | ||||||
|  |     //06: xx xx xx
 | ||||||
|  |     //09: 6A FF                push    0FFFFFFFFh
 | ||||||
|  |     //0B: 68 xx xx xx xx       push    loc_xxxxxxxx
 | ||||||
|  |     //10: 50                   push    eax
 | ||||||
|  |     //
 | ||||||
|  |     x = Dword(start+12); | ||||||
|  |     //Message("Match 2\n");
 | ||||||
|  |   } | ||||||
|  |   else if (!doSEH && (Word(start-7) == 0xFF6A) && (Byte(start-5)==0x68)) | ||||||
|  |   { | ||||||
|  |     //-7: 6A FF                push    0FFFFFFFFh
 | ||||||
|  |     //-5: 68 xx xx xx xx       push    loc_xxxxxxxx
 | ||||||
|  |     //00: 64 A1 00 00 00 00    mov     eax, large fs:0
 | ||||||
|  |     //06: 50                   push    eax
 | ||||||
|  |     //07: 64 89 25 00 00 00 00 mov     large fs:0, esp
 | ||||||
|  |     //
 | ||||||
|  |     x = Dword(start-4); | ||||||
|  |     start = start-7; | ||||||
|  |     //Message("Match 3\n");
 | ||||||
|  |   } | ||||||
|  |   else if (!doSEH && (Word(start+6) == 0xFF6A) && (Byte(start+8)==0x68)) | ||||||
|  |   { | ||||||
|  |    //00: 64 A1 00 00 00 00    mov     eax, large fs:0
 | ||||||
|  |    //06: 6A FF                push    0FFFFFFFFh
 | ||||||
|  |    //08: 68 xx xx xx xx       push    loc_xxxxxxxx
 | ||||||
|  |    //0D: 50                   push    eax
 | ||||||
|  |    //0E: 64 89 25 00 00 00 00 mov     large fs:0, esp
 | ||||||
|  |     x = Dword(start+9); | ||||||
|  |     //Message("Match 4\n");
 | ||||||
|  |   } | ||||||
|  |   else if (doSEH && (Byte(start-5)==0x68) && (Byte(start-10)==0x68) && (Dword(start-15)==0x6AEC8B55)) | ||||||
|  |   { | ||||||
|  |    //-15: 55                  push    ebp
 | ||||||
|  |    //-14: 8B EC               mov     ebp, esp
 | ||||||
|  |    //-12: 6A F?               push    0FFFFFFF?h
 | ||||||
|  |    //-10: 68 xx xx xx xx      push    offset __sehtable$_func1
 | ||||||
|  |    //-5 : 68 xx xx xx xx      push    offset _except_handlerx
 | ||||||
|  |    //00 : 64 A1 00 00 00 00   mov     eax, large fs:0
 | ||||||
|  |    x = Dword(start-9); | ||||||
|  |    //Message("Match 5\n");
 | ||||||
|  |    if (Byte(start-11) == 0xFF) //-1 = SEH3
 | ||||||
|  |      fixSEHFunc(start-15,x, 3, fixFunc); | ||||||
|  |    else if (Byte(start-11) == 0xFE) //-2 = SEH4
 | ||||||
|  |      fixSEHFunc(start-15,x, 4, fixFunc); | ||||||
|  |    else | ||||||
|  |      Message("Unknown SEH handler!\n"); | ||||||
|  |    return; | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     //probably a custom handler
 | ||||||
|  |     //Message("\"push 0FFFFFFFFh; push offset loc\" not found!\n");
 | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   Message(form("Fixing function at 0x%08X\n",start)); | ||||||
|  |   ParseCxxHandler(start, x, fixFunc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static doEHProlog(name,fixFunc) | ||||||
|  | { | ||||||
|  |   auto i,s,a; | ||||||
|  |   a=LocByName(name); | ||||||
|  |   if (a==BADADDR) | ||||||
|  |     return; | ||||||
|  |   Message("%s = %08X\n",name,a);   | ||||||
|  |   i=RfirstB(a); | ||||||
|  |   while(i!=BADADDR) | ||||||
|  |   { | ||||||
|  |     Message("- %08X - ",i); | ||||||
|  | 
 | ||||||
|  |     //  -5: mov  eax, offset loc_XXXXXX
 | ||||||
|  |     //   0: call __EH_prolog
 | ||||||
|  |     if (Byte(i-5)==0xB8) | ||||||
|  |       ParseCxxHandler(i-5, Dword(i-4),fixFunc); | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       Message(form("No mov eax, offset loc_XXXXXX at %08X!!!\n",i-5)); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (SetFunctionFlags(i,GetFunctionFlags(i) | FUNC_FRAME)) | ||||||
|  |     { | ||||||
|  |       MakeFrame(i,GetFrameLvarSize(i), 4, GetFrameArgsSize(i)); | ||||||
|  |       if (fixFunc) AnalyseArea(i, FindFuncEnd(i)+1); | ||||||
|  |       Message("OK\n"); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |       Message("Error\n"); | ||||||
|  |     i=RnextB(a,i); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static doEHPrologs(name, fixFunc) | ||||||
|  | { | ||||||
|  |   doEHProlog("j"+name,fixFunc); | ||||||
|  |   doEHProlog("j_"+name,fixFunc); | ||||||
|  |   doEHProlog(name,fixFunc); | ||||||
|  |   doEHProlog("_"+name,fixFunc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static fixEHPrologs(fixFunc) | ||||||
|  | { | ||||||
|  |   doEHPrologs("_EH_prolog",fixFunc); | ||||||
|  |   doEHPrologs("_EH_prolog3",fixFunc); | ||||||
|  |   doEHPrologs("_EH_prolog3_catch",fixFunc); | ||||||
|  |   doEHPrologs("_EH_prolog3_GS",fixFunc); | ||||||
|  |   doEHPrologs("_EH_prolog3_catch_GS",fixFunc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static isInCodeSeg(a) | ||||||
|  | { | ||||||
|  |   if (SegName(a)==".text") | ||||||
|  |     return 1; | ||||||
|  |   else | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //check a scopetable entry
 | ||||||
|  | static checkEntry(a,i,ver) | ||||||
|  | { | ||||||
|  |   auto x; | ||||||
|  |   x = Dword(a); | ||||||
|  |   //EnclosingLevel should be negative or less than i
 | ||||||
|  |   if (x&0x80000000) | ||||||
|  |   { | ||||||
|  |     if (ver==3 && x!=0xFFFFFFFF) | ||||||
|  |       return 0; | ||||||
|  |     if (ver==4 && x!=0xFFFFFFFE) | ||||||
|  |       return 0; | ||||||
|  |   } | ||||||
|  |   else if (x>=i) | ||||||
|  |     return 0; | ||||||
|  | 
 | ||||||
|  |   x = Dword(a+4); | ||||||
|  |   if ((x!=0) && !isInCodeSeg(x)) //filter should be zero or point to the code
 | ||||||
|  |     return 0; | ||||||
|  |   x = Dword(a+8); | ||||||
|  |   if (!isInCodeSeg(x)) //handler should point to the code
 | ||||||
|  |     return 0; | ||||||
|  | 
 | ||||||
|  |   //check if there are xref to fields (i.e. after the end of the scopetable)
 | ||||||
|  |   if (((ver!=3)||(i>0)) && isRef(GetFlags(a))) | ||||||
|  |       return 0; | ||||||
|  |   if (isRef(GetFlags(a+4)) || isRef(GetFlags(a+8))) | ||||||
|  |       return 0; | ||||||
|  |   return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //check if there's a valid scopetable and calculate number of entries in it
 | ||||||
|  | static checkScopeTable(a, ver) | ||||||
|  | { | ||||||
|  |   auto i,k; | ||||||
|  |   if (ver==4) | ||||||
|  |   { | ||||||
|  |     k = Dword(a); | ||||||
|  |     if ((k&0x80000000)==0) //first field should be negative
 | ||||||
|  |       return 0; | ||||||
|  |     if ((k!=0xFFFFFFFE) && (k&3)!=0) //GS cookie offset should be -2 or dword-aligned
 | ||||||
|  |       return 0; | ||||||
|  |     k = Dword(a+8); | ||||||
|  |     if ((k&0x80000000)==0) //offset should be negative
 | ||||||
|  |       return 0; | ||||||
|  |     if ((k&3)!=0) //EH cookie offset should be dword-aligned
 | ||||||
|  |       return 0; | ||||||
|  |     a = a+16; //move to the scope entries list
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   i = 0; | ||||||
|  |   while (checkEntry(a,i,ver)) | ||||||
|  |   { | ||||||
|  |     i = i+1; | ||||||
|  |     a = a+12; | ||||||
|  |   } | ||||||
|  |   return i; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  | struct _EH4_EXCEPTION_REGISTRATION_RECORD { | ||||||
|  | 	void* SavedESP; | ||||||
|  | 	_EXCEPTION_POINTERS* ExceptionPointers; | ||||||
|  | 	_EXCEPTION_REGISTRATION_RECORD* Next; | ||||||
|  | 	enum _EXCEPTION_DISPOSITION (*Handler)(_EXCEPTION_RECORD*, void*, _CONTEXT*, void*); | ||||||
|  | 	DWORD EncodedScopeTable; | ||||||
|  | 	unsigned long TryLevel; | ||||||
|  | }; | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | static getSEHRec() | ||||||
|  | { | ||||||
|  |   auto id; | ||||||
|  |   id = GetStrucIdByName("SEHRegistrationNode"); | ||||||
|  |   if (id==-1) | ||||||
|  |   { | ||||||
|  |     id = AddStruc(-1,"SEHRegistrationNode"); | ||||||
|  |     ForceDWMember(id, 0, "SavedESP"); | ||||||
|  |     ForceDWMember(id, 4, "ExceptionPointers"); | ||||||
|  |     ForceDWMember(id, 8, "Next"); | ||||||
|  |     ForceDWMember(id, 12, "Handler"); | ||||||
|  |     ForceDWMember(id, 16, "EncodedScopeTable"); | ||||||
|  |     ForceDWMember(id, 20, "TryLevel"); | ||||||
|  |   } | ||||||
|  |   return id; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static CommentStackSEH(start, scopetable) | ||||||
|  | { | ||||||
|  |   auto x; | ||||||
|  |   CommentStack(start,-24, "__$SEHRec$", getSEHRec()); | ||||||
|  |   if (scopetable) | ||||||
|  |   { | ||||||
|  |     x = Dword(scopetable); | ||||||
|  |     if (x!=-2) | ||||||
|  |       CommentStack(start,x, "__$GSCookie$", -1); | ||||||
|  |     x = Dword(scopetable+8); | ||||||
|  |     CommentStack(start,x, "__$EHCookie$", -1); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static fixSEHFunc(func, scopetable, ver, fixFunc) | ||||||
|  | { | ||||||
|  |   auto k,i,t,u,x,y,z,hasESP,end; | ||||||
|  |   k = checkScopeTable(scopetable, ver); | ||||||
|  |   if (k==0) | ||||||
|  |   { | ||||||
|  |     Message("Bad scopetable\n"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   Message("function: %08X, scopetable: %08X (%d entries)\n", func, scopetable, k); | ||||||
|  |   x = scopetable; | ||||||
|  |   if (ver==4) x = x+16; | ||||||
|  | 
 | ||||||
|  |   //parse the scopetable!
 | ||||||
|  |   y = 0; | ||||||
|  |   z = 0x7FFFFFFF; | ||||||
|  |   i = 0; | ||||||
|  |   hasESP = 0; | ||||||
|  |   while (i<k) {        | ||||||
|  |     t = Dword(x+4); | ||||||
|  |     if (t) { | ||||||
|  |       hasESP=1; | ||||||
|  |       if (t>y) y=t; //find lowest
 | ||||||
|  |       if (z>t) z=t; //find highest
 | ||||||
|  |       //Message("t=0x%08.8X\n",t);
 | ||||||
|  |       //check the code just before, it could be jump to the end of try
 | ||||||
|  |       if (Byte(t-2)==0xEB) | ||||||
|  |         t = getRelJmpTarget(t-2); | ||||||
|  |       else if (Byte(t-5)==0xE9) | ||||||
|  |         t = getRelJmpTarget(t-5); | ||||||
|  |       //Message("t=0x%08.8X\n",t);
 | ||||||
|  |       if (t>y) y=t; //find lowest
 | ||||||
|  |       if (z>t) z=t; //find highest
 | ||||||
|  |     } | ||||||
|  |     t = Dword(x+8); | ||||||
|  |       //check the code just before, it could be jump to the end of try
 | ||||||
|  |     if (t>y) y=t; //find lowest
 | ||||||
|  |     if (z>t) z=t; //find highest
 | ||||||
|  |     //Message("t=0x%08.8X\n",t);
 | ||||||
|  |       if (Byte(t-2)==0xEB) | ||||||
|  |         t = getRelJmpTarget(t-2); | ||||||
|  |       else if (Byte(t-5)==0xE9) | ||||||
|  |         t = getRelJmpTarget(t-5); | ||||||
|  |     //Message("t=0x%08.8X\n",t);
 | ||||||
|  |     if (t>y) y=t; //find lowest
 | ||||||
|  |     if (z>t) z=t; //find highest
 | ||||||
|  |     x = x+12; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  | 
 | ||||||
|  |   //Message("y=0x%08.8X, z=0x%08.8X\n",y,z);
 | ||||||
|  |   if (1) | ||||||
|  |   { | ||||||
|  |     end = FindFuncEnd(y); | ||||||
|  |     if (end==BADADDR) { | ||||||
|  |       if (fixFunc) | ||||||
|  |       { | ||||||
|  |         MakeUnkn(y, 1); | ||||||
|  |         MakeCode(y); | ||||||
|  |       } | ||||||
|  |       if (BADADDR == FindFuncEnd(y)) | ||||||
|  |       { | ||||||
|  |         Message(form("Can't find function end at 0x%08X\n",y)); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     //Message(form("Except blocks: %08X-%08X\n", z, end));
 | ||||||
|  |     z = FindFuncEnd(func); | ||||||
|  |     if (z ==-1 || end > z && fixFunc) | ||||||
|  |     { | ||||||
|  |       //Message("Merging except blocks with main function.\n");
 | ||||||
|  |       Unknown(func, end-func); | ||||||
|  |       MakeCode(func); | ||||||
|  |       MakeFunction(func,end); | ||||||
|  |       AnalyseArea(func,end); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   //walk once more and fix finally entries
 | ||||||
|  |   x = scopetable; | ||||||
|  |   if (ver==4) x = x+16; | ||||||
|  |   i = 0; | ||||||
|  |   while (fixFunc && i<k) { | ||||||
|  |     if (Dword(x+4)==0 && Dword(x+8)==y) | ||||||
|  |     { | ||||||
|  |       //the last handler is a finally handler
 | ||||||
|  |       //check that it ends with a ret, call or jmp
 | ||||||
|  |       z = FindFuncEnd(y); | ||||||
|  |       if (z!=BADADDR &&  | ||||||
|  |           !(Byte(z-1)==0xC3 || Byte(z-5)==0xE9 || Byte(z-5)==0xE8 ||  | ||||||
|  |             Byte(z-2)==0xEB || Byte(z-1)==0xCC || Word(z-6)==0x15FF) ) | ||||||
|  |       {         | ||||||
|  |         //we need to add the following funclet to our function
 | ||||||
|  |         end = FindFuncEnd(z); | ||||||
|  |         if (end!=BADADDR) | ||||||
|  |         { | ||||||
|  |           Unknown(z, end-z); | ||||||
|  |           MakeCode(z); | ||||||
|  |           SetFunctionEnd(func,end); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     x = x+12; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   //comment the table and handlers
 | ||||||
|  |   x = scopetable; | ||||||
|  |   ExtLinA(x,0,form("; SEH scopetable for %08X",func)); | ||||||
|  |   if (ver==4)  | ||||||
|  |   { | ||||||
|  |     OffCmt(x,"GSCookieOffset"); | ||||||
|  |     OffCmt(x+4,"GSCookieXOROffset"); | ||||||
|  |     OffCmt(x+8,"EHCookieOffset"); | ||||||
|  |     OffCmt(x+12,"EHCookieXOROffset"); | ||||||
|  |     x = x+16; | ||||||
|  |     CommentStackSEH(func,scopetable); | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |     CommentStackSEH(func,0); | ||||||
|  |   i = 0; | ||||||
|  |   while (i<k) { | ||||||
|  |     ForceDword(x); | ||||||
|  |     SoftOff(x+4); | ||||||
|  |     SoftOff(x+8); | ||||||
|  |     MakeComm(x, form("try block %d, enclosed by %d",i, Dword(x))); | ||||||
|  |     t = Dword(x+4); //exception filter
 | ||||||
|  |     if (t!=0) | ||||||
|  |       ExtLinA(t,0,form("; __except() filter for try block %d",i)); | ||||||
|  |     u = Dword(x+8); | ||||||
|  |     if (t!=0) | ||||||
|  |       ExtLinA(u,0,form("; __except {} handler for try block %d",i)); | ||||||
|  |     else | ||||||
|  |       ExtLinA(u,0,form("; __finally {} handler for try block %d",i)); | ||||||
|  |     x = x+12; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static doSEHProlog(name, ver, fixFunc) | ||||||
|  | { | ||||||
|  |   auto i,s,locals,scopetable,k,l,func,a; | ||||||
|  |   a=LocByName(name); | ||||||
|  |   if (a==BADADDR) | ||||||
|  |     return; | ||||||
|  |   Message("%s = %08X\n",name,a);   | ||||||
|  |   i=RfirstB(a); | ||||||
|  |   while(i!=BADADDR) | ||||||
|  |   { | ||||||
|  |     Message("- %08X - ",i); | ||||||
|  | 
 | ||||||
|  |     // -10 68 xx xx xx xx   push    xx
 | ||||||
|  |     //   or
 | ||||||
|  |     // -7  6A xx            push    xx
 | ||||||
|  |     // -5  68 xx xx xx xx   push    OFFSET __sehtable$_func
 | ||||||
|  |     // 0   e8 00 00 00 00   call    __SEH_prolog
 | ||||||
|  |     //   
 | ||||||
|  |     //
 | ||||||
|  |     locals = -1; scopetable=0; | ||||||
|  |     if (Byte(i-5)==0x68)  | ||||||
|  |     {       | ||||||
|  |       scopetable = Dword(i-4); | ||||||
|  |       if (Byte(i-7)==0x6A) | ||||||
|  |       { | ||||||
|  |         func = i-7; | ||||||
|  |         locals = Byte(func+1); | ||||||
|  |       } | ||||||
|  |       else if (Byte(i-10)==0x68) | ||||||
|  |       { | ||||||
|  |         func = i-10; | ||||||
|  |         locals = Dword(func+1); | ||||||
|  |       } | ||||||
|  |       if (GetFunctionFlags(func)==-1 && fixFunc) | ||||||
|  |       { | ||||||
|  |         MakeUnkn(func, 1); | ||||||
|  |         MakeCode(func); | ||||||
|  |         MakeFunction(func, BADADDR); | ||||||
|  |       } | ||||||
|  |       if (SetFunctionFlags(func,GetFunctionFlags(func)|FUNC_FRAME)) | ||||||
|  |       { | ||||||
|  |         MakeFrame(func, GetFrameLvarSize(func), 4, GetFrameArgsSize(func)); | ||||||
|  |         fixSEHFunc(func, scopetable, ver, fixFunc); | ||||||
|  |         Message("OK\n"); | ||||||
|  |       } | ||||||
|  |       else | ||||||
|  |         Message("Error\n"); | ||||||
|  |     }   | ||||||
|  |     i=RnextB(a,i); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static doSEHPrologs(name, ver, fixFunc) | ||||||
|  | { | ||||||
|  |   doSEHProlog("j"+name, ver, fixFunc); | ||||||
|  |   doSEHProlog("j_"+name, ver, fixFunc); | ||||||
|  |   doSEHProlog(name, ver, fixFunc); | ||||||
|  |   doSEHProlog("_"+name, ver, fixFunc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static fixSEHPrologs(fixFunc) | ||||||
|  | { | ||||||
|  |   doSEHPrologs("_SEH_prolog",3, fixFunc); | ||||||
|  |   doSEHPrologs("__SEH_prolog",3, fixFunc); | ||||||
|  |   doSEHPrologs("_SEH_prolog4",4, fixFunc); | ||||||
|  |   doSEHPrologs("__SEH_prolog4",4, fixFunc); | ||||||
|  |   doSEHPrologs("_SEH_prolog4_GS",4, fixFunc);  | ||||||
|  |   doSEHPrologs("__SEH_prolog4_GS",4, fixFunc);  | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static findFunc(name) | ||||||
|  | { | ||||||
|  |   auto a; | ||||||
|  |   a = LocByName("j_"+name);  | ||||||
|  |   if (a==BADADDR) | ||||||
|  |     a = LocByName(name); | ||||||
|  |   return a; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static doSEH(fixFunc) | ||||||
|  | { | ||||||
|  |   auto start, a; | ||||||
|  |   start = 0; | ||||||
|  |   while (1) { | ||||||
|  |     //mov eax, large fs:0
 | ||||||
|  |     start = FindBinary(start+1, 3, "64 A1 00 00 00 00"); | ||||||
|  |     if (start==BADADDR) | ||||||
|  |       break; | ||||||
|  |     fixCxx(start,1,fixFunc); | ||||||
|  |   } | ||||||
|  |   fixSEHPrologs(fixFunc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static doEH(fixFunc) | ||||||
|  | { | ||||||
|  |   auto start, a; | ||||||
|  |   start = 0; | ||||||
|  |   while (1) { | ||||||
|  |     //mov eax, large fs:0
 | ||||||
|  |     start = FindBinary(start+1, 3, "64 A1 00 00 00 00"); | ||||||
|  |     if (start==BADADDR) | ||||||
|  |       break; | ||||||
|  |     fixCxx(start,0,fixFunc); | ||||||
|  |   } | ||||||
|  |   fixEHPrologs(fixFunc); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static main(void) | ||||||
|  | { | ||||||
|  |   auto seh, fixseh, eh, fixeh; | ||||||
|  |   seh = AskYN(1, "Do you wish to parse all Win32 SEH handlers?"); | ||||||
|  |   if (seh==-1) return; | ||||||
|  |   if (seh) { | ||||||
|  |     fixseh = AskYN(1, "Do you wish to fix function boundaries as needed?"); | ||||||
|  |     if (fixseh==-1) return; | ||||||
|  |   } | ||||||
|  |   eh = AskYN(1, "Do you wish to parse all C++ EH handlers?"); | ||||||
|  |   if (eh==-1) return; | ||||||
|  |   if (eh) { | ||||||
|  |     fixeh = AskYN(1, "Do you wish to fix function boundaries as needed?"); | ||||||
|  |     if (fixeh==-1) return; | ||||||
|  |   } | ||||||
|  |   if (seh) doSEH(fixseh); | ||||||
|  |   if (eh) doEH(fixeh); | ||||||
|  |   //fixCxx(ScreenEA());
 | ||||||
|  | } | ||||||
| @ -0,0 +1,995 @@ | |||||||
|  | #include <idc.idc> | ||||||
|  | //Microsoft C++ RTTI support for IDA
 | ||||||
|  | //Version 3.0 2006.01.20 Igor Skochinsky <skochinsky@mail.ru>
 | ||||||
|  | 
 | ||||||
|  | //#define DEBUG
 | ||||||
|  | 
 | ||||||
|  | //////////////////////////////////////
 | ||||||
|  | // Unknown(long ea, long length)
 | ||||||
|  | //////////////////////////////////////
 | ||||||
|  | // Mark the ea as unknown for a length
 | ||||||
|  | // of length, but don't propagate.
 | ||||||
|  | static Unknown( ea, length ) | ||||||
|  | { | ||||||
|  |   auto i; | ||||||
|  |   if (ea==BADADDR) | ||||||
|  |     return; | ||||||
|  | //  Message("Unknown(%x,%d)\n",ea, length);
 | ||||||
|  |   for(i=0; i < length; i++) | ||||||
|  |      { | ||||||
|  |        MakeUnkn(ea+i,0); | ||||||
|  |      } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ForceQword( x ) {  //Make dword, undefine as needed
 | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |  if (!MakeQword( x )) | ||||||
|  |  { | ||||||
|  |    Unknown(x,8); | ||||||
|  |    MakeQword(x); | ||||||
|  |  } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ForceDword( x ) {  //Make dword, undefine as needed
 | ||||||
|  |  if (x==BADADDR || x==0) | ||||||
|  |    return; | ||||||
|  |  if (!MakeDword( x )) | ||||||
|  |  { | ||||||
|  |    Unknown(x,4); | ||||||
|  |    MakeDword(x); | ||||||
|  |  } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ForceWord( x ) {  //Make word, undefine as needed
 | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |  if (!MakeWord( x )) | ||||||
|  |  { | ||||||
|  |    Unknown(x,2); | ||||||
|  |    MakeWord( x ); | ||||||
|  |  } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ForceByte( x ) {  //Make byte, undefine as needed
 | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |  if (!MakeByte( x )) | ||||||
|  |  { | ||||||
|  |    MakeUnkn(x,0); | ||||||
|  |    MakeByte( x ); | ||||||
|  |  } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static SoftOff ( x ) { //Make offset if !=0
 | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |  ForceDword(x); | ||||||
|  |  if (Dword(x)>0 && Dword(x)<=MaxEA()) OpOff(x,0,0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static GetAsciizStr(x) | ||||||
|  | { | ||||||
|  |   auto s,c; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return ""; | ||||||
|  |   s = ""; | ||||||
|  |   while (c=Byte(x)) | ||||||
|  |   { | ||||||
|  |     s = form("%s%c",s,c); | ||||||
|  |     x = x+1; | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //check if Dword(vtbl-4) points to typeinfo record and extract the type name from it
 | ||||||
|  | static GetTypeName(vtbl) | ||||||
|  | { | ||||||
|  |   auto x, s, c; | ||||||
|  |   if (vtbl==BADADDR) | ||||||
|  |     return; | ||||||
|  |   x = Dword(vtbl-4); | ||||||
|  |   if ((!x) || (x==BADADDR)) return ""; | ||||||
|  | //  if (Dword(x)||Dword(x+4)||Dword(x+8)) return "";
 | ||||||
|  |   x = Dword(x+12); | ||||||
|  |   if ((!x) || (x==BADADDR)) return ""; | ||||||
|  |   s = ""; | ||||||
|  |   x = x+8; | ||||||
|  |   while (c=Byte(x)) | ||||||
|  |   { | ||||||
|  |     s = form("%s%c",s,c); | ||||||
|  |     x = x+1; | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DwordCmt(x, cmt) | ||||||
|  | { | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   ForceDword(x); | ||||||
|  |   MakeComm(x, cmt); | ||||||
|  | } | ||||||
|  | static OffCmt(x, cmt) | ||||||
|  | { | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   SoftOff(x); | ||||||
|  |   MakeComm(x, cmt); | ||||||
|  | } | ||||||
|  | static StrCmt(x, cmt) | ||||||
|  | { | ||||||
|  |   auto save_str; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   MakeUnkn(x, 0); | ||||||
|  |   save_str = GetLongPrm(INF_STRTYPE); | ||||||
|  |   SetLongPrm(INF_STRTYPE,0); | ||||||
|  |   MakeStr(x, BADADDR); | ||||||
|  |   MakeName(x, ""); | ||||||
|  |   MakeComm(x, cmt); | ||||||
|  |   SetLongPrm(INF_STRTYPE,save_str); | ||||||
|  | } | ||||||
|  | static DwordArrayCmt(x, n, cmt) | ||||||
|  | { | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   Unknown(x,4*n); | ||||||
|  |   ForceDword(x); | ||||||
|  |   MakeArray(x,n); | ||||||
|  |   MakeComm(x, cmt); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //check if values match a pattern
 | ||||||
|  | static matchBytes(addr,match) | ||||||
|  | { | ||||||
|  |   auto i,len,s; | ||||||
|  |   len = strlen(match); | ||||||
|  |   if (len%2)  | ||||||
|  |   {  | ||||||
|  |     Warning("Bad match string in matchBytes: %s",match); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   i=0; | ||||||
|  |   while (i<len) | ||||||
|  |   { | ||||||
|  |     s = substr(match,i,i+2); | ||||||
|  |     if (s!="??" && form("%02X",Byte(addr))!=s) | ||||||
|  |       return 0;//mismatch
 | ||||||
|  |     i = i+2; | ||||||
|  |     addr++; | ||||||
|  |   } | ||||||
|  |   return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ForceDWMember(id, offset, name) | ||||||
|  | { | ||||||
|  |   if (0!=AddStrucMember(id, name,offset, FF_DWRD, -1, 4)) | ||||||
|  |     SetMemberName(id, offset, name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ForceStrucMember(id, offset, sub_id, name) | ||||||
|  | { | ||||||
|  |   auto a,i; | ||||||
|  |   i = GetStrucSize(sub_id); | ||||||
|  |   if (0!=AddStrucMember(id,name,offset,FF_DATA|FF_STRU,sub_id,i)) | ||||||
|  |   { | ||||||
|  |     for (a=offset;a<offset+i;a++) | ||||||
|  |       DelStrucMember(id,a); | ||||||
|  |     AddStrucMember(id,name,offset,FF_DATA|FF_STRU,sub_id,i); | ||||||
|  |     //SetMemberName(id, offset, name);
 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //add (or rename) a stack variable named name at frame offset offset (i.e. bp-based)
 | ||||||
|  | //struc_id = structure variable
 | ||||||
|  | //if struc_id == -1, then add a dword
 | ||||||
|  | static CommentStack(start, offset, name, struc_id) | ||||||
|  | { | ||||||
|  |   auto id,l,bp; | ||||||
|  |   id = GetFrame(start); | ||||||
|  |   l = GetFrameLvarSize(start); | ||||||
|  |   if ( (GetFunctionFlags(start) & FUNC_FRAME) == 0) | ||||||
|  |     l = l + GetFrameRegsSize(start); | ||||||
|  |   l = l+offset; | ||||||
|  |   //Message("%a: ebp offset = %02Xh\n",start,l);
 | ||||||
|  |   if (l<0) | ||||||
|  |   {     | ||||||
|  |     //Message("growing the frame to locals=%d, regs=4, args=%d.\n",-offset, GetFrameArgsSize(start));
 | ||||||
|  |     //we need to grow the locals
 | ||||||
|  |     MakeFrame(start, -offset, GetFrameRegsSize(start), GetFrameArgsSize(start)); | ||||||
|  |     l = 0; | ||||||
|  |   } | ||||||
|  |   if (struc_id==-1) | ||||||
|  |     ForceDWMember(id, l, name); | ||||||
|  |   else | ||||||
|  |     ForceStrucMember(id, l, struc_id, name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static getRelJmpTarget(a) | ||||||
|  | { | ||||||
|  |   auto b; | ||||||
|  |   b = Byte(a); | ||||||
|  |   if (b == 0xEB) | ||||||
|  |   { | ||||||
|  |     b = Byte(a+1); | ||||||
|  |     if (b&0x80) | ||||||
|  |       return a+2-((~b&0xFF)+1); | ||||||
|  |     else | ||||||
|  |       return a+2+b; | ||||||
|  |   } | ||||||
|  |   else if (b==0xE9) | ||||||
|  |   { | ||||||
|  |     b = Dword(a+1); | ||||||
|  |     if (b&0x80000000) | ||||||
|  |       return a+5-(~b+1); | ||||||
|  |     else | ||||||
|  |       return a+5+b; | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |     return BADADDR; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static getRelCallTarget(a) | ||||||
|  | { | ||||||
|  |   auto b; | ||||||
|  |   b = Byte(a); | ||||||
|  |   if (b==0xE8) | ||||||
|  |   { | ||||||
|  |     b = Dword(a+1); | ||||||
|  |     if (b&0x80000000) | ||||||
|  |       return a+5-(~b+1); | ||||||
|  |     else | ||||||
|  |       return a+5+b; | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |     return BADADDR; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static MangleNumber(x) | ||||||
|  | { | ||||||
|  | //
 | ||||||
|  | // 0 = A@
 | ||||||
|  | // X = X-1 (1<=X<=10)
 | ||||||
|  | // -X = ?(X-1)
 | ||||||
|  | // 0x0..0xF = 'A'..'P'
 | ||||||
|  | 
 | ||||||
|  |   auto s, sign; | ||||||
|  |   s=""; sign=0; | ||||||
|  |   if (x<0) | ||||||
|  |   { | ||||||
|  |     sign = 1; | ||||||
|  |     x = -x; | ||||||
|  |   }   | ||||||
|  |   if (x==0) | ||||||
|  |     return "A@"; | ||||||
|  |   else if (x<=10) | ||||||
|  |     return form("%s%d",sign?"?":"",x-1); | ||||||
|  |   else | ||||||
|  |   { | ||||||
|  |     while (x>0) | ||||||
|  |     { | ||||||
|  |       s = form("%c%s",'A'+x%16,s); | ||||||
|  |       x = x / 16; | ||||||
|  |     } | ||||||
|  |     return sign?"?":""+s+"@"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | static Parse_BCD(x, indent) | ||||||
|  | { | ||||||
|  |   auto indent_str,i,a,s; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  | /*
 | ||||||
|  | struct _s_RTTIBaseClassDescriptor | ||||||
|  | { | ||||||
|  |     struct TypeDescriptor* pTypeDescriptor; //type descriptor of the class
 | ||||||
|  |     DWORD numContainedBases; //number of nested classes following in the array
 | ||||||
|  |     struct PMD where;        //some displacement info
 | ||||||
|  |     DWORD attributes;        //usually 0, sometimes 10h
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct PMD | ||||||
|  | { | ||||||
|  |     int mdisp;  //member displacement
 | ||||||
|  |     int pdisp;  //vbtable displacement
 | ||||||
|  |     int vdisp;  //displacement inside vbtable
 | ||||||
|  | }; | ||||||
|  | */ | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"0x%08.8X: RTTIBaseClassDescriptor\n", x); | ||||||
|  |   Message(indent_str+"    pTypeDescriptor:   %08.8Xh (%s)\n", Dword(x), GetAsciizStr(Dword(x)+8)); | ||||||
|  |   Message(indent_str+"    numContainedBases: %08.8Xh\n", Dword(x+4)); | ||||||
|  |   Message(indent_str+"    PMD where:         (%d,%d,%d)\n", Dword(x+8), Dword(x+12), Dword(x+16)); | ||||||
|  |   Message(indent_str+"    attributes:        %08.8Xh\n", Dword(x+20)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   OffCmt(x, "pTypeDescriptor"); | ||||||
|  |   DwordCmt(x+4, "numContainedBases"); | ||||||
|  |   DwordArrayCmt(x+8, 3, "PMD where"); | ||||||
|  |   DwordCmt(x+20, "attributes"); | ||||||
|  | 
 | ||||||
|  |   s = Parse_TD(Dword(x), indent+1); | ||||||
|  |   //??_R1A@?0A@A@B@@8 = B::`RTTI Base Class Descriptor at (0,-1,0,0)'
 | ||||||
|  |   MakeName(x,"??_R1"+MangleNumber(Dword(x+8))+MangleNumber(Dword(x+12))+ | ||||||
|  |            MangleNumber(Dword(x+16))+MangleNumber(Dword(x+20))+substr(s,4,-1)+'8'); | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static GetClassName(p) | ||||||
|  | { | ||||||
|  |   /*auto s;
 | ||||||
|  |   s = GetAsciizStr(Dword(p)+8); | ||||||
|  |   Message("demangling %s\n",s); | ||||||
|  |   return DemangleTIName(s);*/ | ||||||
|  |   auto s,s2; | ||||||
|  |   s = "??_7"+GetAsciizStr(Dword(p)+12)+"6B@"; | ||||||
|  |   //Message("demangling %s\n",s);
 | ||||||
|  |   s2 = Demangle(s,8); | ||||||
|  |   if (s2!=0) | ||||||
|  |     //CObject::`vftable'
 | ||||||
|  |     return substr(s2,0,strlen(s2)-11); | ||||||
|  |   else | ||||||
|  |     return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DumpNestedClass(x, indent, contained) | ||||||
|  | { | ||||||
|  |   auto indent_str,i,a,n,p,s,off; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  |   i=0; | ||||||
|  |   //indent=indent+1;
 | ||||||
|  |   a = x; | ||||||
|  |   while(i<contained) | ||||||
|  |   { | ||||||
|  |     p = Dword(a); | ||||||
|  |     off = Dword(p+8); | ||||||
|  |     s = form("%.4X: ",off); | ||||||
|  |     Message("%s%s%s\n", s, indent_str, GetClassName(p)); | ||||||
|  |     //fprintf(f, form("%s%s%s\n",s,indent_str,GetClassName(p)));
 | ||||||
|  |     n = Dword(p+4); | ||||||
|  |     if (n>0) //check numContainedBases
 | ||||||
|  |       DumpNestedClass(a+4, indent+1, n); //nested classes following
 | ||||||
|  |     a=a+4*(n+1); | ||||||
|  |     i=i+n+1; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_CHD(x, indent) | ||||||
|  | { | ||||||
|  |   auto indent_str,i,a,n,p,s; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  |   //Message(indent_str+"0x%08.8X: RTTIClassHierarchyDescriptor\n", x);
 | ||||||
|  |   /*
 | ||||||
|  |   struct _s_RTTIClassHierarchyDescriptor | ||||||
|  |   { | ||||||
|  |       DWORD signature;      //always zero?
 | ||||||
|  |       DWORD attributes;     //bit 0 = multiple inheritance, bit 1 = virtual inheritance
 | ||||||
|  |       DWORD numBaseClasses; //number of classes in pBaseClassArray
 | ||||||
|  |       struct _s_RTTIBaseClassArray* pBaseClassArray; | ||||||
|  |   }; | ||||||
|  |   */ | ||||||
|  |   a = Dword(x+4); | ||||||
|  |   if ((a&3)==1) | ||||||
|  |     p = "(MI)"; | ||||||
|  |   else if ((a&3)==2) | ||||||
|  |     p = "(VI)"; | ||||||
|  |   else if ((a&3)==3) | ||||||
|  |     p = "(MI VI)"; | ||||||
|  |   else | ||||||
|  |     p="(SI)"; | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"    signature:         %08.8Xh\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    attributes:        %08.8Xh %s\n", a, p); | ||||||
|  |   Message(indent_str+"    numBaseClasses:    %08.8Xh\n", n); | ||||||
|  |   Message(indent_str+"    pBaseClassArray:   %08.8Xh\n", a); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   DwordCmt(x, "signature"); | ||||||
|  |   DwordCmt(x+4, "attributes"); | ||||||
|  |   DwordCmt(x+8, "numBaseClasses"); | ||||||
|  |   OffCmt(x+12, "pBaseClassArray"); | ||||||
|  | 
 | ||||||
|  |   a=Dword(x+12); | ||||||
|  |   n=Dword(x+8); | ||||||
|  |   i=0; | ||||||
|  |   DumpNestedClass(a, indent, n); | ||||||
|  |   indent=indent+1; | ||||||
|  |   while(i<n) | ||||||
|  |   { | ||||||
|  |     p = Dword(a); | ||||||
|  |     //Message(indent_str+"    BaseClass[%02d]:  %08.8Xh\n", i, p);
 | ||||||
|  |     OffCmt(a, form("BaseClass[%02d]", i)); | ||||||
|  |     if (i==0) | ||||||
|  |     { | ||||||
|  |       s = Parse_BCD(p,indent); | ||||||
|  |       //??_R2A@@8 = A::`RTTI Base Class Array'
 | ||||||
|  |       MakeName(a,"??_R2"+substr(s,4,-1)+'8'); | ||||||
|  |       //??_R3A@@8 = A::`RTTI Class Hierarchy Descriptor'
 | ||||||
|  |       MakeName(x,"??_R3"+substr(s,4,-1)+'8'); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |       Parse_BCD(p,indent); | ||||||
|  |     i=i+1; | ||||||
|  |     a=a+4; | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_TD(x, indent) | ||||||
|  | { | ||||||
|  |   auto indent_str,i,a; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  |   //Message(indent_str+"0x%08.8X: TypeDescriptor\n", x);
 | ||||||
|  | /*
 | ||||||
|  | struct TypeDescriptor | ||||||
|  | { | ||||||
|  |     void* pVFTable;  //always pointer to type_info::vftable ?
 | ||||||
|  |     void* spare;     //seems to be zero for most classes, and default constructor for exceptions
 | ||||||
|  |     char name[0];    //mangled name, starting with .?A (.?AV=classes, .?AU=structs)
 | ||||||
|  | }; | ||||||
|  | */ | ||||||
|  |   a = GetAsciizStr(x+8); | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"    pVFTable:          %08.8Xh\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    spare:             %08.8Xh\n", Dword(x+4)); | ||||||
|  |   Message(indent_str+"    name:              '%s'\n", a); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   OffCmt(x, "pVFTable"); | ||||||
|  |   OffCmt(x+4, "spare"); | ||||||
|  |   StrCmt(x+8, "name"); | ||||||
|  | 
 | ||||||
|  |   //??_R0?AVA@@@8 = A `RTTI Type Descriptor'
 | ||||||
|  |   MakeName(x,"??_R0"+substr(a,1,-1)+"@8"); | ||||||
|  |   return a; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | static Parse_COL(x, indent) | ||||||
|  | { | ||||||
|  | /*
 | ||||||
|  | struct _s_RTTICompleteObjectLocator | ||||||
|  | { | ||||||
|  |     DWORD signature; //always zero ?
 | ||||||
|  |     DWORD offset;    //offset of this vtable in the class ?
 | ||||||
|  |     DWORD cdOffset;  //no idea
 | ||||||
|  |     struct TypeDescriptor* pTypeDescriptor; //TypeDescriptor of the class
 | ||||||
|  |     struct _s_RTTIClassHierarchyDescriptor* pClassDescriptor; //inheritance hierarchy
 | ||||||
|  | };*/ | ||||||
|  |   auto indent_str,i,a,s; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  |   s = GetAsciizStr(Dword(x+12)+8); | ||||||
|  |   //Message(indent_str+"0x%08.8X: RTTICompleteObjectLocator\n", x);
 | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"    signature:         %08.8Xh\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    offset:            %08.8Xh\n", Dword(x+4)); | ||||||
|  |   Message(indent_str+"    cdOffset:          %08.8Xh\n", Dword(x+8)); | ||||||
|  |   Message(indent_str+"    pTypeDescriptor:   %08.8Xh (%s)\n", Dword(x+12), DemangleTIName(s)); | ||||||
|  |   Message(indent_str+"    pClassDescriptor:  %08.8Xh\n", Dword(x+16)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   DwordCmt(x, "signature"); | ||||||
|  |   DwordCmt(x+4, "offset"); | ||||||
|  |   DwordCmt(x+8, "cdOffset"); | ||||||
|  |   OffCmt(x+12, "pTypeDescriptor"); | ||||||
|  |   OffCmt(x+16, "pClassDescriptor"); | ||||||
|  | 
 | ||||||
|  |   //
 | ||||||
|  |   Parse_CHD(Dword(x+16),indent+1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_CT(x, indent) | ||||||
|  | { | ||||||
|  |   auto indent_str,i,a,s; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  | /*
 | ||||||
|  | typedef const struct _s__CatchableType { | ||||||
|  |   unsigned int properties; | ||||||
|  |   _TypeDescriptor *pType; | ||||||
|  |   _PMD thisDisplacement; | ||||||
|  |   int sizeOrOffset; | ||||||
|  |   _PMFN copyFunction; | ||||||
|  | } _CatchableType; | ||||||
|  | 
 | ||||||
|  | struct PMD | ||||||
|  | { | ||||||
|  |     int mdisp;  //members displacement ???
 | ||||||
|  |     int pdisp;  //
 | ||||||
|  |     int vdisp;  //vtable displacement ???
 | ||||||
|  | }; | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  |   s = GetAsciizStr(Dword(x+4)+8); | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"0x%08.8X: CatchableType\n", x); | ||||||
|  |   Message(indent_str+"    properties:        %08.8Xh\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    pType:             %08.8Xh (%s)\n", Dword(x+4), DemangleTIName(s)); | ||||||
|  |   Message(indent_str+"    thisDisplacement:  (%d,%d,%d)\n", Dword(x+8), Dword(x+12), Dword(x+16)); | ||||||
|  |   Message(indent_str+"    sizeOrOffset:      %08.8Xh\n", Dword(x+20)); | ||||||
|  |   Message(indent_str+"    copyFunction:      %08.8Xh\n", Dword(x+24)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   a = "properties"; | ||||||
|  |   i = Dword(x); | ||||||
|  |   if (i!=0) a = a+":"; | ||||||
|  |   if (i&1) a = a+" simple type"; | ||||||
|  |   if (i&2) a = a+" byref only"; | ||||||
|  |   if (i&4) a = a+" has vbases"; | ||||||
|  | 
 | ||||||
|  |   DwordCmt(x, a); | ||||||
|  |   OffCmt(x+4, "pType"); | ||||||
|  |   DwordArrayCmt(x+8, 3, "thisDisplacement"); | ||||||
|  |   DwordCmt(x+20, "sizeOrOffset"); | ||||||
|  |   OffCmt(x+24, "copyFunction"); | ||||||
|  |   ForceDword(x+28); | ||||||
|  | 
 | ||||||
|  |   //__CT??_R0 ?AVCTest@@ @81 = CTest::`catchable type'
 | ||||||
|  |   MakeName(x,"__CT??_R0?"+substr(s,1,-1)+"@81"); | ||||||
|  | 
 | ||||||
|  |   if (Dword(x+24)) //we have a copy constructor
 | ||||||
|  |   //.?AVexception@@ -> ??0exception@@QAE@ABV0@@Z = exception::exception(exception const &)
 | ||||||
|  |      MakeName(Dword(x+24),"??0"+substr(s,4,-1)+"QAE@ABV0@@Z"); | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_CTA(x, indent) | ||||||
|  | { | ||||||
|  | /*
 | ||||||
|  | typedef const struct _s__CatchableTypeArray { | ||||||
|  |   int nCatchableTypes; | ||||||
|  |   _CatchableType *arrayOfCatchableTypes[]; | ||||||
|  | } _CatchableTypeArray; | ||||||
|  | */   | ||||||
|  | 
 | ||||||
|  |   auto indent_str,i,a,n,p,s; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"    nCatchableTypes:         %08.8Xh\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    arrayOfCatchableTypes:   %08.8Xh\n", Dword(x+4)); | ||||||
|  | #endif | ||||||
|  |   DwordCmt(x, "nCatchableTypes"); | ||||||
|  |   //OffCmt(x+4, "arrayOfCatchableTypes");
 | ||||||
|  | 
 | ||||||
|  |   a=x+4; | ||||||
|  |   n=Dword(x); | ||||||
|  |   i=0; | ||||||
|  |   indent=indent+1; | ||||||
|  |   while(i<n) | ||||||
|  |   { | ||||||
|  |     p = Dword(a); | ||||||
|  |     //Message(indent_str+"    BaseClass[%02d]:  %08.8Xh\n", i, p);
 | ||||||
|  |     OffCmt(a, form("CatchableType[%02d]", i)); | ||||||
|  |     if (i==0) | ||||||
|  |     { | ||||||
|  |       s = Parse_CT(p,indent); | ||||||
|  |       //__CTA1 ?AVCTest@@ = CTest::`catchable type array'
 | ||||||
|  |       MakeName(x,"__CTA1?"+substr(s,1,-1)); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |       Parse_CT(p,indent); | ||||||
|  |     i=i+1; | ||||||
|  |     a=a+4; | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //demangle names like .?AVxxx, .PAD, .H etc
 | ||||||
|  | static DemangleTIName(s) | ||||||
|  | { | ||||||
|  |   auto i; | ||||||
|  |   if (substr(s,0,1)!=".") | ||||||
|  |     return ""; | ||||||
|  |   s = Demangle("??_R0"+substr(s,1,-1)+"@8",8); | ||||||
|  |   i = strstr(s,"`RTTI Type Descriptor'"); | ||||||
|  |   if (i==-1) | ||||||
|  |     return ""; | ||||||
|  |   else | ||||||
|  |   { | ||||||
|  |     s = substr(s,0,i-1); | ||||||
|  |     //Message("throw %s;\n",s);
 | ||||||
|  |     return s; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_ThrowInfo(x, indent) | ||||||
|  | { | ||||||
|  | /*
 | ||||||
|  | typedef const struct _s__ThrowInfo { | ||||||
|  |   unsigned int attributes; | ||||||
|  |   _PMFN pmfnUnwind; | ||||||
|  |   int (__cdecl*pForwardCompat)(...); | ||||||
|  |   _CatchableTypeArray *pCatchableTypeArray; | ||||||
|  | } _ThrowInfo; | ||||||
|  | */ | ||||||
|  |   auto indent_str,i,a,s; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"0x%08.8X: ThrowInfo\n", x); | ||||||
|  |   Message(indent_str+"    attributes:            %08.8Xh\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    pmfnUnwind:            %08.8Xh\n", Dword(x+4)); | ||||||
|  |   Message(indent_str+"    pForwardCompat:        %08.8Xh\n", Dword(x+8)); | ||||||
|  |   Message(indent_str+"    pCatchableTypeArray:   %08.8Xh\n", Dword(x+12)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   a = "attributes"; | ||||||
|  |   i = Dword(x); | ||||||
|  |   if (i!=0) a = a+":"; | ||||||
|  |   if (i&1) a = a+" const"; | ||||||
|  |   if (i&2) a = a+" volatile"; | ||||||
|  | 
 | ||||||
|  |   DwordCmt(x, a); | ||||||
|  |   OffCmt(x+4, "pmfnUnwind"); | ||||||
|  |   OffCmt(x+8, "pForwardCompat"); | ||||||
|  |   OffCmt(x+12, "pCatchableTypeArray"); | ||||||
|  |   s = Parse_CTA(Dword(x+12), indent+1); | ||||||
|  |   if (s!="") | ||||||
|  |   { | ||||||
|  |     MakeName(x,"__TI1?"+substr(s,1,-1)); | ||||||
|  |     if (Dword(x+4)) //we have a destructor
 | ||||||
|  |       //.?AVexception@@ -> ??1exception@@UAE@XZ = exception::~exception(void)
 | ||||||
|  |       MakeName(Dword(x+4),"??1"+substr(s,4,-1)+"UAE@XZ"); | ||||||
|  |     i = Dword(x); //attributes
 | ||||||
|  |     a = DemangleTIName(s); | ||||||
|  |     if (i&1) a = "const "+a; | ||||||
|  |     if (i&2) a = "volatile "+a; | ||||||
|  |     a = "throw "+a; | ||||||
|  |     Message("%s\n",a); | ||||||
|  |     MakeRptCmt(x, a); | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_TryBlock(x, indent) | ||||||
|  | { | ||||||
|  | /*
 | ||||||
|  | typedef const struct _s_TryBlockMapEntry { | ||||||
|  |   int tryLow;                                  //00
 | ||||||
|  |   int tryHigh;                                 //04
 | ||||||
|  |   int catchHigh;                               //08
 | ||||||
|  |   int nCatches;                                //0C
 | ||||||
|  |   const struct _s_HandlerType * pHandlerArray; //10
 | ||||||
|  | } TryBlockMapEntry; | ||||||
|  | 
 | ||||||
|  | typedef const struct _s_HandlerType { | ||||||
|  |   unsigned int adjectives;          //00
 | ||||||
|  |   struct TypeDescriptor * pType;    //04
 | ||||||
|  |   int dispCatchObj;                 //08
 | ||||||
|  |   void * addressOfHandler;          //0C
 | ||||||
|  | } | ||||||
|  | */   | ||||||
|  |   auto indent_str,i,a,n,p,s; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"    tryLow:          %d\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    tryHigh:         %d\n", Dword(x+4)); | ||||||
|  |   Message(indent_str+"    catchHigh:       %d\n", Dword(x+8)); | ||||||
|  |   Message(indent_str+"    nCatches:        %d\n", Dword(x+12)); | ||||||
|  |   Message(indent_str+"    pHandlerArray:   %08.8Xh\n", Dword(x+16)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   DwordCmt(x, "tryLow"); | ||||||
|  |   DwordCmt(x+4, "tryHigh"); | ||||||
|  |   DwordCmt(x+8, "catchHigh"); | ||||||
|  |   DwordCmt(x+12, "nCatches"); | ||||||
|  |   OffCmt(x+16, "pHandlerArray"); | ||||||
|  | 
 | ||||||
|  |   a=Dword(x+16); | ||||||
|  |   n=Dword(x+12); | ||||||
|  |   if (a==BADADDR || a==0 || n==0) | ||||||
|  |     return; | ||||||
|  |   i=0; | ||||||
|  |   indent=indent+1; | ||||||
|  |   while(i<n) | ||||||
|  |   { | ||||||
|  | #ifdef DEBUG | ||||||
|  |     Message(indent_str+"        adjectives:       %08.8Xh\n", Dword(a)); | ||||||
|  |     Message(indent_str+"        pType:            %08.8Xh\n", Dword(a+4)); | ||||||
|  |     Message(indent_str+"        dispCatchObj:     %08.8Xh\n", Dword(a+8)); | ||||||
|  |     Message(indent_str+"        addressOfHandler: %08.8Xh\n", Dword(a+12)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |     DwordCmt(a, "adjectives"); | ||||||
|  |     OffCmt(a+4,"pType"); | ||||||
|  |     DwordCmt(a+8, "dispCatchObj"); | ||||||
|  |     OffCmt(a+12,"addressOfHandler"); | ||||||
|  | 
 | ||||||
|  |     p = Dword(a+4); | ||||||
|  |     if (p) | ||||||
|  |     { | ||||||
|  |       s = DemangleTIName(Parse_TD(p, indent+1)); | ||||||
|  |       if (Dword(a)&8) //reference
 | ||||||
|  |         s = s+"&"; | ||||||
|  |       if (Dword(a)&2) //volatile
 | ||||||
|  |         s = "volatile "+s; | ||||||
|  |       if (Dword(a)&1) //const
 | ||||||
|  |         s = "const "+s; | ||||||
|  |       s = s+" e"; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |       s = "..."; | ||||||
|  | 
 | ||||||
|  |     p = Dword(a+12); | ||||||
|  |     if (p!=0 && p!=BADADDR) | ||||||
|  |     { | ||||||
|  |       ExtLinA(Dword(a+12),0,form("; catch (%s)",s)); | ||||||
|  |       ExtLinA(Dword(a+12),1,form("; states %d..%d",Dword(x),Dword(x+4))); | ||||||
|  |       p = Dword(a+8); | ||||||
|  |       if (p) | ||||||
|  |       { | ||||||
|  |         if (p&0x80000000) | ||||||
|  |           s = form("; e = [epb-%Xh]",-p); | ||||||
|  |         else | ||||||
|  |           s = form("; e = [epb+%Xh]",p); | ||||||
|  |         ExtLinA(Dword(a+12),2,s); | ||||||
|  |       }       | ||||||
|  |     } | ||||||
|  |     i=i+1; | ||||||
|  |     a=a+16; | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_FuncInfo(x, indent) | ||||||
|  | { | ||||||
|  | /*
 | ||||||
|  | typedef const struct _s_FuncInfo { | ||||||
|  |   unsigned int magicNumber:29;                      //0
 | ||||||
|  |   unsigned int bbtFlags:3; | ||||||
|  |   int maxState;                                     //4
 | ||||||
|  |   const struct _s_UnwindMapEntry * pUnwindMap;      //8
 | ||||||
|  |   unsigned int nTryBlocks;                          //C
 | ||||||
|  |   const struct _s_TryBlockMapEntry * pTryBlockMap;  //10
 | ||||||
|  |   unsigned int nIPMapEntries;                       //14
 | ||||||
|  |   void * pIPtoStateMap;                             //18
 | ||||||
|  |   const struct _s_ESTypeList * pESTypeList;         //1C
 | ||||||
|  |   int EHFlags; //present only in vc8?               //20
 | ||||||
|  | } FuncInfo; | ||||||
|  | typedef const struct _s_UnwindMapEntry { | ||||||
|  |   int toState;          //0
 | ||||||
|  |   function  * action;   //4
 | ||||||
|  | } UnwindMapEntry; | ||||||
|  | */   | ||||||
|  |   auto indent_str,i,a,s,n; | ||||||
|  |   if (x==BADADDR || x==0) | ||||||
|  |     return; | ||||||
|  |   if ((Dword(x)^0x19930520)>0xF) { | ||||||
|  |     Message("Magic is not 1993052Xh!\n"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"0x%08.8X: FuncInfo\n", x); | ||||||
|  |   Message(indent_str+"    magicNumber:            %08.8Xh\n", Dword(x)); | ||||||
|  |   Message(indent_str+"    maxState:               %d\n", Dword(x+4)); | ||||||
|  |   Message(indent_str+"    pUnwindMap:             %08.8Xh\n", Dword(x+8)); | ||||||
|  | #endif | ||||||
|  |   n = Dword(x+4); | ||||||
|  |   i = 0; a = Dword(x+8); | ||||||
|  |   while (i<n) | ||||||
|  |   { | ||||||
|  | #ifdef DEBUG | ||||||
|  |     Message(indent_str+"        toState:              %d\n", Dword(a)); | ||||||
|  |     Message(indent_str+"        action:               %08.8Xh\n", Dword(a+4)); | ||||||
|  | #endif | ||||||
|  |     DwordCmt(a, "toState"); | ||||||
|  |     OffCmt(a+4, "action"); | ||||||
|  |     a = a+8; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"    nTryBlocks:             %d\n", Dword(x+12)); | ||||||
|  |   Message(indent_str+"    pTryBlockMap:           %08.8Xh\n", Dword(x+16)); | ||||||
|  | #endif | ||||||
|  |   n = Dword(x+12); | ||||||
|  |   i = 0; a = Dword(x+16); | ||||||
|  |   while (i<n) | ||||||
|  |   { | ||||||
|  |     Parse_TryBlock(a, indent+1); | ||||||
|  |     a = a+20; | ||||||
|  |     i = i+1; | ||||||
|  |   } | ||||||
|  | #ifdef DEBUG | ||||||
|  |   Message(indent_str+"    nIPMapEntries:          %d\n", Dword(x+20)); | ||||||
|  |   Message(indent_str+"    pIPtoStateMap:          %08.8Xh\n", Dword(x+24)); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  |   DwordCmt(x, "magicNumber"); | ||||||
|  |   DwordCmt(x+4, "maxState"); | ||||||
|  |   OffCmt(x+8, "pUnwindMap"); | ||||||
|  |   //Parse_UnwindMap(Dword(x+8), indent+1);
 | ||||||
|  |   DwordCmt(x+12, "nTryBlocks"); | ||||||
|  |   OffCmt(x+16, "pTryBlockMap"); | ||||||
|  |   DwordCmt(x+20, "nIPMapEntries"); | ||||||
|  |   OffCmt(x+24, "pIPtoStateMap"); | ||||||
|  |   if ((Dword(x+8)-x)>=32 || Dword(x)>0x19930520) | ||||||
|  |   { | ||||||
|  | #ifdef DEBUG | ||||||
|  |     Message(indent_str+"    pESTypeList:            %08.8Xh\n", Dword(x+28)); | ||||||
|  | #endif | ||||||
|  |     OffCmt(x+28, "pESTypeList"); | ||||||
|  |   } | ||||||
|  |   if ((Dword(x+8)-x)>=36 || Dword(x)>0x19930521) | ||||||
|  |   { | ||||||
|  | #ifdef DEBUG | ||||||
|  |     Message(indent_str+"    EHFlags:                %08.8Xh\n", Dword(x+32)); | ||||||
|  | #endif | ||||||
|  |     OffCmt(x+32, "EHFlags"); | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //get class name for this vtable instance
 | ||||||
|  | static GetVtableClass(x) | ||||||
|  | { | ||||||
|  |   auto offset, n, i, s, a, p; | ||||||
|  |   offset = Dword(x+4); | ||||||
|  |   x = Dword(x+16); //Class Hierarchy Descriptor
 | ||||||
|  | 
 | ||||||
|  |   a=Dword(x+12); //pBaseClassArray
 | ||||||
|  |   n=Dword(x+8);  //numBaseClasses
 | ||||||
|  |   i = 0; | ||||||
|  |   s = ""; | ||||||
|  |   while(i<n) | ||||||
|  |   { | ||||||
|  |     p = Dword(a); | ||||||
|  |     //Message(indent_str+"    BaseClass[%02d]:  %08.8Xh\n", i, p);
 | ||||||
|  |     if (Dword(p+8)==offset) | ||||||
|  |     { | ||||||
|  |       //found it
 | ||||||
|  |       s = GetAsciizStr(Dword(p)+8); | ||||||
|  |       return s; | ||||||
|  |     } | ||||||
|  |     i=i+1; | ||||||
|  |     a=a+4; | ||||||
|  |   } | ||||||
|  |   //didn't find matching one, let's get the first vbase
 | ||||||
|  |   i=0; | ||||||
|  |   a=Dword(x+12); | ||||||
|  |   while(i<n) | ||||||
|  |   { | ||||||
|  |     p = Dword(a); | ||||||
|  |     if (Dword(p+12)!=-1) | ||||||
|  |     { | ||||||
|  |       s = GetAsciizStr(Dword(p)+8); | ||||||
|  |       return s; | ||||||
|  |     } | ||||||
|  |     i=i+1; | ||||||
|  |     a=a+4; | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_Vtable(a) | ||||||
|  | { | ||||||
|  |   auto i,s,s2; | ||||||
|  |   s=GetTypeName(a); | ||||||
|  |   if (substr(s,0,3)==".?A") | ||||||
|  |   { | ||||||
|  | #ifdef DEBUG | ||||||
|  |     Message("RTTICompleteObjectLocator:      %08.8Xh\n", Dword(a-4)); | ||||||
|  | #endif | ||||||
|  |     Parse_COL(Dword(a-4),0); | ||||||
|  |     Unknown(a-4,4); | ||||||
|  |     SoftOff(a-4); | ||||||
|  |     i = Dword(a-4);  //COL
 | ||||||
|  |     s2 = Dword(i+4); //offset
 | ||||||
|  |     i = Dword(i+16); //CHD
 | ||||||
|  |     i = Dword(i+4);  //Attributes
 | ||||||
|  |     if ((i&3)==0  && s2==0) | ||||||
|  |     { //Single inheritance, so we don't need to worry about duplicate names (several vtables)
 | ||||||
|  |       s=substr(s,4,-1); | ||||||
|  |       MakeName(a,"??_7"+s+"6B@"); | ||||||
|  |       MakeName(Dword(a-4),"??_R4"+s+"6B@"); | ||||||
|  |     } | ||||||
|  |     else// if ((i&3)==1)
 | ||||||
|  |     {  | ||||||
|  |       //Message("Multiple inheritance\n");
 | ||||||
|  |       s2 = GetVtableClass(Dword(a-4)); | ||||||
|  |       s2 = substr(s2,4,-1); | ||||||
|  |       s  = substr(s,4,-1); | ||||||
|  |       s = s+"6B"+s2+"@"; | ||||||
|  |       MakeName(a,"??_7"+s); | ||||||
|  |       MakeName(Dword(a-4),"??_R4"+s); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ParseVtbl() | ||||||
|  | { | ||||||
|  |   Parse_Vtable(ScreenEA()); | ||||||
|  | } | ||||||
|  | static ParseExc() | ||||||
|  | { | ||||||
|  |   Parse_ThrowInfo(ScreenEA(), 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ParseFI() | ||||||
|  | { | ||||||
|  |   Parse_FuncInfo(ScreenEA(), 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static AddHotkeys() | ||||||
|  | { | ||||||
|  |   AddHotkey("Alt-F7","ParseFI"); | ||||||
|  |   AddHotkey("Alt-F8","ParseVtbl"); | ||||||
|  |   AddHotkey("Alt-F9","ParseExc"); | ||||||
|  |   Message("Use Alt-F7 to parse FuncInfo\n"); | ||||||
|  |   Message("Use Alt-F8 to parse vtable\n"); | ||||||
|  |   Message("Use Alt-F9 to parse throw info\n"); | ||||||
|  | } | ||||||
|  | #ifndef __INCLUDED | ||||||
|  | static main(void) | ||||||
|  | { | ||||||
|  |   AddHotkeys(); | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -0,0 +1,660 @@ | |||||||
|  | #include <idc.idc> | ||||||
|  | #include "vtable.idc" | ||||||
|  | #include "ms_rtti.idc" | ||||||
|  | 
 | ||||||
|  | static GetAsciizStr(x) | ||||||
|  | { | ||||||
|  |   auto s,c; | ||||||
|  |   s = ""; | ||||||
|  |   while (c=Byte(x)) | ||||||
|  |   { | ||||||
|  |     s = form("%s%c",s,c); | ||||||
|  |     x = x+1; | ||||||
|  |   } | ||||||
|  |   return s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ??1?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@UAE@XZ
 | ||||||
|  | // ??_G CWin32Heap@ATL @@UAEPAXI@Z
 | ||||||
|  | // ATL::CWin32Heap::`scalar deleting destructor'(uint)
 | ||||||
|  | // .?AV?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@
 | ||||||
|  | // ??_7?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@6B@
 | ||||||
|  | // ??_G?$CEventingNode@VCMsgrAppInfoImpl@@PAUIMsgrUser@@ABUtagVARIANT@@@@@@UAEPAXI@Z
 | ||||||
|  | 
 | ||||||
|  | #define SN_constructor 1 | ||||||
|  | #define SN_destructor  2 | ||||||
|  | #define SN_vdestructor 3 | ||||||
|  | #define SN_scalardtr   4 | ||||||
|  | #define SN_vectordtr   5 | ||||||
|  | 
 | ||||||
|  | static MakeSpecialName(name, type, adj) | ||||||
|  | { | ||||||
|  |   auto basename; | ||||||
|  |   //.?AUA@@ = typeid(struct A)
 | ||||||
|  |   //basename = A@@
 | ||||||
|  |   basename = substr(name,4,-1); | ||||||
|  |   if (type==SN_constructor) | ||||||
|  |   { | ||||||
|  |     //??0A@@QAE@XZ = public: __thiscall A::A(void)
 | ||||||
|  |     if (adj==0) | ||||||
|  |       return "??0"+basename+"QAE@XZ"; | ||||||
|  |     else | ||||||
|  |       return "??0"+basename+"W"+MangleNumber(adj)+"AE@XZ"; | ||||||
|  |   } | ||||||
|  |   else if (type==SN_destructor) | ||||||
|  |   { | ||||||
|  |     //??1A@@QAE@XZ = "public: __thiscall A::~A(void)"
 | ||||||
|  |     if (adj==0) | ||||||
|  |       return "??1"+basename+"QAE@XZ"; | ||||||
|  |     else | ||||||
|  |       return "??1"+basename+"W"+MangleNumber(adj)+"AE@XZ"; | ||||||
|  |   } | ||||||
|  |   else if (type==SN_vdestructor) | ||||||
|  |   { | ||||||
|  |     //??1A@@UAE@XZ = public: virtual __thiscall A::~A(void)
 | ||||||
|  |     if (adj==0) | ||||||
|  |       return "??1"+basename+"UAE@XZ"; | ||||||
|  |     else | ||||||
|  |       return "??1"+basename+"W"+MangleNumber(adj)+"AE@XZ"; | ||||||
|  |   } | ||||||
|  |   else if (type==SN_scalardtr) //
 | ||||||
|  |   { | ||||||
|  |     //??_GA@@UAEPAXI@Z = public: virtual void * __thiscall A::`scalar deleting destructor'(unsigned int)
 | ||||||
|  |     if (adj==0) | ||||||
|  |       return "??_G"+basename+"UAEPAXI@Z"; | ||||||
|  |     else | ||||||
|  |       return "??_G"+basename+"W"+MangleNumber(adj)+"AEPAXI@Z"; | ||||||
|  |   } | ||||||
|  |   else if (type==SN_vectordtr) | ||||||
|  |   { | ||||||
|  |     //.?AUA@@ = typeid(struct A)
 | ||||||
|  |     //??_EA@@UAEPAXI@Z = public: virtual void * __thiscall A::`vector deleting destructor'(unsigned int)
 | ||||||
|  |     if (adj==0) | ||||||
|  |       return "??_E"+basename+"QAEPAXI@Z"; | ||||||
|  |     else | ||||||
|  |       return "??_E"+basename+"W"+MangleNumber(adj)+"AEPAXI@Z"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static DumpNestedClass2(x, indent, contained, f) | ||||||
|  | { | ||||||
|  |   auto indent_str,i,a,n,p,s,off; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  |   i=0; | ||||||
|  |   //indent=indent+1;
 | ||||||
|  |   a = x; | ||||||
|  |   while(i<contained) | ||||||
|  |   { | ||||||
|  |     p = Dword(a); | ||||||
|  |     off = Dword(p+8); | ||||||
|  |     s = form("%.4X: ",off); | ||||||
|  |     //Message("%s%s%s\n", s, indent_str, GetClassName(p));
 | ||||||
|  |     fprintf(f, form("%s%s%s\n",s,indent_str,GetClassName(p))); | ||||||
|  |     n = Dword(p+4); | ||||||
|  |     if (n>0) //check numContainedBases
 | ||||||
|  |       DumpNestedClass2(a+4, indent+1, n, f); //nested classes following
 | ||||||
|  |     a=a+4*(n+1); | ||||||
|  |     i=i+n+1; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static Parse_CHD2(x, indent, f) | ||||||
|  | { | ||||||
|  |   auto indent_str,i,a,n,p,s,off; | ||||||
|  |   indent_str="";i=0; | ||||||
|  |   while(i<indent) | ||||||
|  |   { | ||||||
|  |     indent_str=indent_str+"    "; | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  |   a = Dword(x+4); | ||||||
|  |   if ((a&3)==1) | ||||||
|  |     p = "(MI)"; | ||||||
|  |   else if ((a&3)==2) | ||||||
|  |     p = "(VI)"; | ||||||
|  |   else if ((a&3)==3) | ||||||
|  |     p = "(MI VI)"; | ||||||
|  |   else | ||||||
|  |     p="(SI)"; | ||||||
|  | 
 | ||||||
|  |   fprintf(f, form("%s%s\n",indent_str,p)); | ||||||
|  |   a=Dword(x+12); | ||||||
|  |   n=Dword(x+8); | ||||||
|  |   DumpNestedClass2(a, indent, n, f); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static GetTypeName2(col) | ||||||
|  | { | ||||||
|  |   auto x, s, c; | ||||||
|  |   //Message("GetTypeName2(%X)\n",col)
 | ||||||
|  |   x = Dword(col+12); | ||||||
|  |   if ((!x) || (x==BADADDR)) return ""; | ||||||
|  |   return GetAsciizStr(x+8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static GetVtblName2(col) | ||||||
|  | { | ||||||
|  |   auto i, s, s2; | ||||||
|  |   s = GetTypeName2(col); | ||||||
|  |   i = Dword(col+16); //CHD
 | ||||||
|  |   i = Dword(i+4);  //Attributes
 | ||||||
|  |   if ((i&3)==0 && Dword(col+4)==0) | ||||||
|  |   {  | ||||||
|  |     //Single inheritance, so we don't need to worry about duplicate names (several vtables)
 | ||||||
|  |     s=substr(s,4,-1); | ||||||
|  |     return "??_7"+s+"6B@"; | ||||||
|  |   } | ||||||
|  |   else //if ((i&3)==1) //multiple inheritance
 | ||||||
|  |   {  | ||||||
|  |     s2 = GetVtableClass(col); | ||||||
|  |     s2 = substr(s2,4,-1); | ||||||
|  |     s  = substr(s,4,-1); | ||||||
|  |     s = s+"6B"+s2+"@"; | ||||||
|  |     return "??_7"+s; | ||||||
|  |   } | ||||||
|  |   return ""; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //check if Dword(vtbl-4) points to typeinfo record and extract the type name from it
 | ||||||
|  | static IsValidCOL(col) | ||||||
|  | { | ||||||
|  |   auto x, s, c; | ||||||
|  |   x = Dword(col+12); | ||||||
|  |   if ((!x) || (x==BADADDR)) return ""; | ||||||
|  |   x = Dword(x+8); | ||||||
|  |   if ((x&0xFFFFFF) == 0x413F2E) //.?A
 | ||||||
|  |     return 1; | ||||||
|  |   else | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static funcStart(ea) | ||||||
|  | { | ||||||
|  |   if (GetFunctionFlags(ea) == -1) | ||||||
|  |     return -1; | ||||||
|  | 
 | ||||||
|  |   if ((GetFlags(ea)&FF_FUNC)!=0) | ||||||
|  |     return ea; | ||||||
|  |   else | ||||||
|  |     return PrevFunction(ea); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Add ea to "Sorted Address List"
 | ||||||
|  | static AddAddr(ea) | ||||||
|  | { | ||||||
|  |   auto id, idx, val; | ||||||
|  |    | ||||||
|  |   if ( (id = GetArrayId("AddrList")) == -1 ) | ||||||
|  |   { | ||||||
|  |     id  = CreateArray("AddrList"); | ||||||
|  |     SetArrayLong(id, 0, ea); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) | ||||||
|  |   { | ||||||
|  |     val = GetArrayElement(AR_LONG, id, idx); | ||||||
|  |     if ( val == ea ) | ||||||
|  |       return; | ||||||
|  |     if ( val > ea )    // InSort
 | ||||||
|  |     { | ||||||
|  |       for ( ; idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) | ||||||
|  |       { | ||||||
|  |         val = GetArrayElement(AR_LONG, id, idx); | ||||||
|  |         SetArrayLong(id, idx, ea); | ||||||
|  |         ea = val; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   SetArrayLong(id, GetLastIndex(AR_LONG, id) + 1, ea); | ||||||
|  | } | ||||||
|  | static getArraySize(id) | ||||||
|  | { | ||||||
|  |   auto idx, count; | ||||||
|  |   count = 0; | ||||||
|  |   for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) | ||||||
|  |   { | ||||||
|  |     count++; | ||||||
|  |   } | ||||||
|  |   return count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static doAddrList(name,f) | ||||||
|  | { | ||||||
|  |   auto idx, id, val, ctr, dtr; | ||||||
|  |   id = GetArrayId("AddrList"); | ||||||
|  |   ctr = 0; dtr = 0; | ||||||
|  |   if ( name!=0 && id != -1 ) | ||||||
|  |   { | ||||||
|  |     Message("refcount:%d\n",getArraySize(id)); | ||||||
|  |     if (getArraySize(id)!=2) | ||||||
|  |       return; | ||||||
|  |     for ( idx = GetFirstIndex(AR_LONG, id); idx != -1; idx = GetNextIndex(AR_LONG, id, idx) ) | ||||||
|  |     { | ||||||
|  |       val = GetArrayElement(AR_LONG, id, idx); | ||||||
|  |       if (Byte(val)==0xE9) | ||||||
|  |         val = getRelJmpTarget(val); | ||||||
|  |       if ((substr(Name(val),0,3)=="??1")) | ||||||
|  |         dtr = val; | ||||||
|  |       else | ||||||
|  |         ctr = val; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (ctr!=0 && dtr!=0) | ||||||
|  |   { | ||||||
|  |     Message("  constructor at %a\n",ctr); | ||||||
|  |     fprintf(f, "  constructor: %08.8Xh\n",ctr); | ||||||
|  |     MakeName(ctr, MakeSpecialName(name,SN_constructor,0)); | ||||||
|  |   } | ||||||
|  |   DeleteArray(GetArrayId("AddrList")); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //check if there's a vtable at a and dump into to f
 | ||||||
|  | //returns position after the end of vtable
 | ||||||
|  | static DoVtable(a,f) | ||||||
|  | { | ||||||
|  |   auto x,y,s,p,q,i,name; | ||||||
|  | 
 | ||||||
|  |   //check if it looks like a vtable
 | ||||||
|  |   y = GetVtableSize(a); | ||||||
|  |   if (y==0) | ||||||
|  |     return a+4; | ||||||
|  |   s = form("%08.8Xh: possible vtable (%d methods)\n", a, y); | ||||||
|  |   Message(s); | ||||||
|  |   fprintf(f,s); | ||||||
|  | 
 | ||||||
|  |   //check if it's named as a vtable
 | ||||||
|  |   name = Name(a); | ||||||
|  |   if (substr(name,0,4)!="??_7") name=0; | ||||||
|  |   | ||||||
|  |   x = Dword(a-4);   | ||||||
|  |   //otherwise try to get it from RTTI
 | ||||||
|  |   if (IsValidCOL(x)) | ||||||
|  |   { | ||||||
|  |     Parse_Vtable(a); | ||||||
|  |     if (name==0) | ||||||
|  |       name = GetVtblName2(x); | ||||||
|  |     //only output object tree for main vtable
 | ||||||
|  |     if (Dword(x+4)==0) | ||||||
|  |       Parse_CHD2(Dword(x+16),0,f); | ||||||
|  |     MakeName(a, name); | ||||||
|  |   } | ||||||
|  |   if (name!=0) | ||||||
|  |   { | ||||||
|  |     s = Demangle(name, 0x00004006); | ||||||
|  |     Message("%s\n",s); | ||||||
|  |     fprintf(f, "%s\n", s); | ||||||
|  |     //convert vtable name into typeinfo name
 | ||||||
|  |     name = ".?AV"+substr(name, 4, strstr(name,"@@6B")+2); | ||||||
|  |   } | ||||||
|  |   { | ||||||
|  |     DeleteArray(GetArrayId("AddrList")); | ||||||
|  |     Message("  referencing functions: \n"); | ||||||
|  |     fprintf(f,"  referencing functions: \n"); | ||||||
|  |     q = 0; i = 1; | ||||||
|  |     for ( x=DfirstB(a); x != BADADDR; x=DnextB(a,x) ) | ||||||
|  |     { | ||||||
|  |        p = funcStart(x); | ||||||
|  |        if (p!=-1) | ||||||
|  |        {  | ||||||
|  |          if (q==p)  | ||||||
|  |            i++; | ||||||
|  |          else | ||||||
|  |          {            | ||||||
|  |            if (q) { | ||||||
|  |              if (i>1) s = form("  %a (%d times)",q,i); | ||||||
|  |              else s = form("  %a",q); | ||||||
|  |              //if (strstr(Name(p),"sub_")!=0 && strstr(Name(p),"j_sub_")!=0)
 | ||||||
|  |              if (hasName(GetFlags(q))) | ||||||
|  |                s = s+" ("+Demangle(Name(q),8)+")"; | ||||||
|  |              s = s+"\n"; | ||||||
|  |              Message(s);fprintf(f,s); | ||||||
|  |              AddAddr(q); | ||||||
|  |            } | ||||||
|  |            i = 1; | ||||||
|  |            q = p; | ||||||
|  |          } | ||||||
|  |        } | ||||||
|  |     } | ||||||
|  |     if (q) | ||||||
|  |     {            | ||||||
|  |        if (i>1) s = form("  %a (%d times)",q,i); | ||||||
|  |        else s = form("  %a",q); | ||||||
|  |        if (hasName(GetFlags(q))) | ||||||
|  |          s = s+" ("+Demangle(Name(q),8)+")"; | ||||||
|  |        s = s+"\n"; | ||||||
|  |        Message(s);fprintf(f,s); | ||||||
|  |        AddAddr(q); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     x = a; | ||||||
|  |     while (y>0) | ||||||
|  |     { | ||||||
|  |       p = Dword(x); | ||||||
|  |       if (GetFunctionFlags(p) == -1) | ||||||
|  |       { | ||||||
|  |         MakeCode(p); | ||||||
|  |         MakeFunction(p, BADADDR); | ||||||
|  |       } | ||||||
|  |       checkSDD(p,name,a,0,f); | ||||||
|  |       y--; | ||||||
|  |       x = x+4; | ||||||
|  |     } | ||||||
|  |     doAddrList(name,f); | ||||||
|  |     Message("\n"); | ||||||
|  |     fprintf(f,"\n"); | ||||||
|  |   } | ||||||
|  |   return x; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static scan_for_vtables(void) | ||||||
|  | { | ||||||
|  |   auto rmin, rmax, cmin, cmax, s, a, x, y,f; | ||||||
|  |   s = FirstSeg(); | ||||||
|  |   f = fopen("objtree.txt","w"); | ||||||
|  |   rmin = 0; rmax = 0; | ||||||
|  |   while (s!=BADADDR) | ||||||
|  |   { | ||||||
|  |     if (SegName(s)==".rdata") | ||||||
|  |     { | ||||||
|  |       rmin = s; | ||||||
|  |       rmax = NextSeg(s); | ||||||
|  |     } | ||||||
|  |     else if (SegName(s)==".text") | ||||||
|  |     { | ||||||
|  |       cmin = s; | ||||||
|  |       cmax = NextSeg(s); | ||||||
|  |     } | ||||||
|  |     s = NextSeg(s); | ||||||
|  |   } | ||||||
|  |   if (rmin==0) {rmin=cmin; rmax=cmax;} | ||||||
|  |   a = rmin; | ||||||
|  |   Message(".rdata: %08.8Xh - %08.8Xh, .text %08.8Xh - %08.8Xh\n", rmin, rmax, cmin, cmax); | ||||||
|  |   while (a<rmax) | ||||||
|  |   { | ||||||
|  |     x = Dword(a); | ||||||
|  |     if (x>=cmin && x<cmax) //methods should reside in .text
 | ||||||
|  |     { | ||||||
|  |        a = DoVtable(a,f); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |       a = a + 4; | ||||||
|  |   } | ||||||
|  |   Message("Done\n"); | ||||||
|  |   fclose(f); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //check for `scalar deleting destructor'
 | ||||||
|  | static checkSDD(x,name,vtable,gate,f) | ||||||
|  | { | ||||||
|  |   auto a,s,t; | ||||||
|  |   //Message("checking function at %a\n",x);
 | ||||||
|  | 
 | ||||||
|  |   t = 0; a = BADADDR; | ||||||
|  | 
 | ||||||
|  |   if ((name!=0) && (substr(Name(x),0,3)=="??_") && (strstr(Name(x),substr(name,4,-1))==4)) | ||||||
|  |     name=0; //it's already named
 | ||||||
|  | 
 | ||||||
|  |   if (Byte(x)==0xE9 || Byte(x)==0xEB) { | ||||||
|  |     //E9 xx xx xx xx   jmp   xxxxxxx
 | ||||||
|  |     return checkSDD(getRelJmpTarget(x),name,vtable,1,f); | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"83E9??E9")) { | ||||||
|  |     //thunk
 | ||||||
|  |     //83 E9 xx        sub     ecx, xx
 | ||||||
|  |     //E9 xx xx xx xx  jmp     class::`scalar deleting destructor'(uint)
 | ||||||
|  |     a = getRelJmpTarget(x+3); | ||||||
|  |     Message("  %a: thunk to %a\n",x,a); | ||||||
|  |     t = checkSDD(a,name,vtable,0,f); | ||||||
|  |     if (t && name!=0) | ||||||
|  |     { | ||||||
|  |       //rename this function as a thunk
 | ||||||
|  |       MakeName(x, MakeSpecialName(name,t,Byte(x+2))); | ||||||
|  |     } | ||||||
|  |     return t; | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"81E9????????E9")) { | ||||||
|  |     //thunk
 | ||||||
|  |     //81 E9 xx xx xx xx        sub     ecx, xxxxxxxx
 | ||||||
|  |     //E9 xx xx xx xx           jmp     class::`scalar deleting destructor'(uint)
 | ||||||
|  |     a = getRelJmpTarget(x+6); | ||||||
|  |     Message("  %a: thunk to %a\n",x,a); | ||||||
|  |     t = checkSDD(a,name,vtable,0,f); | ||||||
|  |     if (t && name!=0) | ||||||
|  |     { | ||||||
|  |       //rename this function as a thunk
 | ||||||
|  |       MakeName(x, MakeSpecialName(name,t,Dword(x+2))); | ||||||
|  |     } | ||||||
|  |     return t; | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"568BF1E8????????F64424080174") && matchBytes(x+15+Byte(x+14),"8BC65EC20400")) | ||||||
|  |   { | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //8B F1                          mov     esi, ecx
 | ||||||
|  |     //E8 xx xx xx xx                 call    class::~class()
 | ||||||
|  |     //F6 44 24 08 01                 test    [esp+arg_0], 1
 | ||||||
|  |     //74 07                          jz      short @@no_free
 | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //                               
 | ||||||
|  |     //                           call operator delete();
 | ||||||
|  |      | ||||||
|  |     //   @@no_free:
 | ||||||
|  |     //8B C6                          mov     eax, esi
 | ||||||
|  |     //5E                             pop     esi
 | ||||||
|  |     //C2 04 00                       retn    4
 | ||||||
|  | 
 | ||||||
|  |     t = SN_scalardtr; | ||||||
|  |     a = getRelCallTarget(x+3); | ||||||
|  |     if (gate && Byte(a)==0xE9) | ||||||
|  |     { | ||||||
|  |       //E9 xx xx xx xx   jmp   xxxxxxx
 | ||||||
|  |       a = getRelJmpTarget(a); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"568BF1FF15????????F64424080174") && matchBytes(x+16+Byte(x+15),"8BC65EC20400")) | ||||||
|  |   { | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //8B F1                          mov     esi, ecx
 | ||||||
|  |     //FF 15 xx xx xx xx              call    class::~class() //dllimport
 | ||||||
|  |     //F6 44 24 08 01                 test    [esp+arg_0], 1
 | ||||||
|  |     //74 07                          jz      short @@no_free
 | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //                               
 | ||||||
|  |     //                           call operator delete();
 | ||||||
|  |      | ||||||
|  |     //   @@no_free:
 | ||||||
|  |     //8B C6                          mov     eax, esi
 | ||||||
|  |     //5E                             pop     esi
 | ||||||
|  |     //C2 04 00                       retn    4
 | ||||||
|  | 
 | ||||||
|  |     t = SN_scalardtr; | ||||||
|  |     /*a = getRelCallTarget(x+3);
 | ||||||
|  |     if (gate && Byte(a)==0xE9) | ||||||
|  |     { | ||||||
|  |       //E9 xx xx xx xx   jmp   xxxxxxx
 | ||||||
|  |       a = getRelJmpTarget(a); | ||||||
|  |     }*/ | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"558BEC51894DFC8B4DFCE8????????8B450883E00185C0740C8B4DFC51E8????????83C4048B45FC8BE55DC20400") || | ||||||
|  |            matchBytes(x,"558BEC51894DFC8B4DFCE8????????8B450883E00185C074098B4DFC51E8????????8B45FC8BE55DC20400")) | ||||||
|  |   { | ||||||
|  |     //55                             push    ebp
 | ||||||
|  |     //8B EC                          mov     ebp, esp
 | ||||||
|  |     //51                             push    ecx
 | ||||||
|  |     //89 4D FC                       mov     [ebp+var_4], ecx
 | ||||||
|  |     //8B 4D FC                       mov     ecx, [ebp+var_4]
 | ||||||
|  |     //E8 xx xx xx xx                 call    sub_10001099
 | ||||||
|  |     //8B 45 08                       mov     eax, [ebp+arg_0]
 | ||||||
|  |     //83 E0 01                       and     eax, 1
 | ||||||
|  |     //85 C0                          test    eax, eax
 | ||||||
|  |     //74 0C                          jz      short skip
 | ||||||
|  |     //8B 4D FC                       mov     ecx, [ebp+var_4]
 | ||||||
|  |     //51                             push    ecx
 | ||||||
|  |     //E8 F0 56 05 00                 call    operator delete(void *)
 | ||||||
|  |     //83 C4 04                       add     esp, 4
 | ||||||
|  |     //
 | ||||||
|  |     //               skip:
 | ||||||
|  |     //8B 45 FC                       mov     eax, [ebp+var_4]
 | ||||||
|  |     //8B E5                          mov     esp, ebp
 | ||||||
|  |     //5D                             pop     ebp
 | ||||||
|  |     //C2 04 00                       retn    4
 | ||||||
|  | 
 | ||||||
|  |     t = SN_scalardtr; | ||||||
|  |     a = getRelCallTarget(x+10); | ||||||
|  |     if (gate && Byte(a)==0xE9) | ||||||
|  |     { | ||||||
|  |       //E9 xx xx xx xx   jmp   xxxxxxx
 | ||||||
|  |       a = getRelJmpTarget(a); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"568D71??578D7E??8BCFE8????????F644240C01")) | ||||||
|  |   { | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //8D 71 xx                       lea     esi, [ecx-XX]
 | ||||||
|  |     //57                             push    edi
 | ||||||
|  |     //8D 7E xx                       lea     edi, [esi+XX]
 | ||||||
|  |     //8B CF                          mov     ecx, edi
 | ||||||
|  |     //E8 xx xx xx xx                 call    class::~class()
 | ||||||
|  |     //F6 44 24 0C 01                 test    [esp+4+arg_0], 1
 | ||||||
|  |     a = getRelCallTarget(x+10); | ||||||
|  |     if (gate && Byte(a)==0xE9) | ||||||
|  |     { | ||||||
|  |       a = getRelJmpTarget(a); | ||||||
|  |     } | ||||||
|  |     t=SN_scalardtr; | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"568DB1????????578DBE????????8BCFE8????????F644240C01")) | ||||||
|  |   { | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //8D B1 xx xx xx xx              lea     esi, [ecx-XX]
 | ||||||
|  |     //57                             push    edi
 | ||||||
|  |     //8D BE xx xx xx xx              lea     edi, [esi+XX]
 | ||||||
|  |     //8B CF                          mov     ecx, edi
 | ||||||
|  |     //E8 xx xx xx xx                 call    class::~class()
 | ||||||
|  |     //F6 44 24 0C 01                 test    [esp+4+arg_0], 1
 | ||||||
|  |     a = getRelCallTarget(x+16); | ||||||
|  |     if (gate && Byte(a)==0xE9) | ||||||
|  |     { | ||||||
|  |       a = getRelJmpTarget(a); | ||||||
|  |     } | ||||||
|  |     t = SN_scalardtr; | ||||||
|  |   } | ||||||
|  |   else if ((matchBytes(x,"F644240401568BF1C706") /*&& Dword(x+10)==vtable*/) ||  | ||||||
|  |            (matchBytes(x,"8A442404568BF1A801C706") /*&& Dword(x+11)==vtable */) || | ||||||
|  |            (matchBytes(x,"568BF1C706????????E8????????F64424080174") && matchBytes(x+21+Byte(x+20),"8BC65EC20400")) | ||||||
|  |           ) | ||||||
|  |   { | ||||||
|  |     //F6 44 24 04 01                 test    [esp+arg_0], 1
 | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //8B F1                          mov     esi, ecx
 | ||||||
|  |     //  OR
 | ||||||
|  |     //8A 44 24 04                    mov     al, [esp+arg_0]
 | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //8B F1                          mov     esi, ecx
 | ||||||
|  |     //A8 01                          test    al, 1
 | ||||||
|  | 
 | ||||||
|  |     //C7 06 xx xx xx xx              mov     dword ptr [esi], xxxxxxx //offset vtable
 | ||||||
|  |     //                           <inlined destructor>
 | ||||||
|  |     //74 07                          jz      short @@no_free
 | ||||||
|  |     //56                             push    esi
 | ||||||
|  |     //E8 CA 2D 0D 00                 call    operator delete(void *)
 | ||||||
|  |     //59                             pop     ecx
 | ||||||
|  |     //   @@no_free:
 | ||||||
|  |     //8B C6                          mov     eax, esi
 | ||||||
|  |     //5E                             pop     esi
 | ||||||
|  |     //C2 04 00                       retn    4  
 | ||||||
|  |     t = SN_scalardtr; | ||||||
|  |   } | ||||||
|  |   else if (matchBytes(x,"538A5C2408568BF1F6C302742B8B46FC578D7EFC68????????506A??56E8") ||  | ||||||
|  |            matchBytes(x,"538A5C2408F6C302568BF1742E8B46FC5768????????8D7EFC5068????????56E8")) | ||||||
|  |   { | ||||||
|  |      //53                            push    ebx
 | ||||||
|  |      //8A 5C 24 08                   mov     bl, [esp+arg_0]
 | ||||||
|  |      //56                            push    esi
 | ||||||
|  |      //8B F1                         mov     esi, ecx
 | ||||||
|  |      //F6 C3 02                      test    bl, 2
 | ||||||
|  |      //74 2B                         jz      short loc_100037F8
 | ||||||
|  |      //8B 46 FC                      mov     eax, [esi-4]
 | ||||||
|  |      //57                            push    edi
 | ||||||
|  |      //8D 7E FC                      lea     edi, [esi-4]
 | ||||||
|  |      //68 xx xx xx xx                push    offset class::~class(void)
 | ||||||
|  |      //50                            push    eax
 | ||||||
|  |      //6A xx                         push    xxh
 | ||||||
|  |      //56                            push    esi
 | ||||||
|  |      //E8 xx xx xx xx                call    `eh vector destructor iterator'(void *,uint,int,void (*)(void *))
 | ||||||
|  |     t = SN_vectordtr; | ||||||
|  |     Message("  vector deleting destructor at %a\n",x); | ||||||
|  |     if (name!=0) | ||||||
|  |     a = Dword(x+21); | ||||||
|  |     if (gate && Byte(a)==0xE9) | ||||||
|  |     { | ||||||
|  |       a = getRelJmpTarget(a); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (t>0) | ||||||
|  |   { | ||||||
|  |     if (t==SN_vectordtr) | ||||||
|  |       s = "vector"; | ||||||
|  |     else | ||||||
|  |       s = "scalar"; | ||||||
|  |     Message("  %s deleting destructor at %a\n",s,x); | ||||||
|  |     fprintf(f, "  %s deleting destructor: %08.8Xh\n",s,x); | ||||||
|  |     if (name!=0) | ||||||
|  |       MakeName(x, MakeSpecialName(name,t,0)); | ||||||
|  |     if (a!=BADADDR) | ||||||
|  |     { | ||||||
|  |       Message("  virtual destructor at %a\n",a); | ||||||
|  |       fprintf(f, "  destructor: %08.8Xh\n",a); | ||||||
|  |       if (name!=0) | ||||||
|  |         MakeName(a, MakeSpecialName(name,SN_vdestructor,0)); | ||||||
|  |     } | ||||||
|  |     CommentStack(x, 4, "__flags$",-1); | ||||||
|  |   } | ||||||
|  |   return t; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static ParseVtbl2() | ||||||
|  | { | ||||||
|  |   auto a, n; | ||||||
|  |   a = ScreenEA(); | ||||||
|  |   if (GetVtableSize(a)==0) | ||||||
|  |   { | ||||||
|  |     Warning("This location doesn't look like a vtable!"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (!hasName(GetFlags(a)) && !IsValidCOL(Dword(a-4))) | ||||||
|  |   { | ||||||
|  |     n = AskStr("","Enter class name"); | ||||||
|  |     if (n!=0) | ||||||
|  |       MakeName(a,"??_7"+n+"@@6B@"); | ||||||
|  |   } | ||||||
|  |   DoVtable(a,0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static AddHotkeys() | ||||||
|  | { | ||||||
|  |   AddHotkey("Alt-F7","ParseFI"); | ||||||
|  |   AddHotkey("Alt-F8","ParseVtbl2"); | ||||||
|  |   AddHotkey("Alt-F9","ParseExc"); | ||||||
|  |   Message("Use Alt-F7 to parse FuncInfo\n"); | ||||||
|  |   Message("Use Alt-F8 to parse vtable\n"); | ||||||
|  |   Message("Use Alt-F9 to parse throw info\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static main(void) | ||||||
|  | { | ||||||
|  |   if(AskYN(1, "Do you wish to scan the executable for vtables/RTTI?")) | ||||||
|  |   { | ||||||
|  |     Message("Scanning..."); | ||||||
|  |     scan_for_vtables(); | ||||||
|  |     //Message("See objtree.txt for the class list/hierarchy.\n");
 | ||||||
|  |     Exec("objtree.txt"); | ||||||
|  |   } | ||||||
|  |   AddHotkeys(); | ||||||
|  | } | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | #!/usr/bin/perl | ||||||
|  | 
 | ||||||
|  | #local $/ = "\n\n"; | ||||||
|  | while(<>){ | ||||||
|  |     if(/([0-9A-Z]+).*?([a-z]+_.+?)st\n/s){ | ||||||
|  |         print "<class vtable=\"0x$1\" name=\"$2\" />\n"; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,43 @@ | |||||||
|  | #include <idc.idc> | ||||||
|  | 
 | ||||||
|  | static main(void) | ||||||
|  | { | ||||||
|  |   auto SearchString; | ||||||
|  |   auto searchStart; | ||||||
|  |   auto searchTest; | ||||||
|  |   auto occurances; | ||||||
|  |   auto szFilePath,hFile; | ||||||
|  |   auto strSize; | ||||||
|  |   auto vTablePtr; | ||||||
|  |   auto vTableLoc; | ||||||
|  |   auto myString; | ||||||
|  |   auto nextAddress; | ||||||
|  |   auto byteVal; | ||||||
|  |   occurances = 0; | ||||||
|  |   searchStart = 0; | ||||||
|  | 
 | ||||||
|  |   SearchString = AskStr("", "What vtable binary to search?"); | ||||||
|  |   szFilePath = AskFile(1, "*.txt", "Select output dump file:"); | ||||||
|  |   hFile = fopen(szFilePath, "wb"); | ||||||
|  |     Message("Scanning..."); | ||||||
|  |     searchStart = FindBinary(searchStart, SEARCH_DOWN, SearchString); | ||||||
|  |     while(searchStart != BADADDR){ | ||||||
|  |         MakeStr(searchStart-2, BADADDR); | ||||||
|  |         myString = GetString(searchStart-2,-1,GetStringType(searchStart-2)); | ||||||
|  |         strSize = strlen(myString); | ||||||
|  |         nextAddress = searchStart-2+strSize+1; | ||||||
|  |         byteVal = Byte(nextAddress); | ||||||
|  |         while(byteVal == 0){ | ||||||
|  |             nextAddress++; | ||||||
|  |             byteVal = Byte(nextAddress); | ||||||
|  |         } | ||||||
|  |         MakeDword(nextAddress); | ||||||
|  |         vTableLoc = FindBinary(141301056,SEARCH_DOWN, form("%X", nextAddress)); | ||||||
|  |         MakeDword(nextAddress+4); | ||||||
|  |         fprintf(hFile,"%a\t%s\n",vTableLoc,myString); | ||||||
|  |         searchStart = FindBinary(searchStart+1, SEARCH_DOWN, SearchString); | ||||||
|  |         occurances++; | ||||||
|  |     } | ||||||
|  |     fclose(hFile); | ||||||
|  |     Message("Found %i Occurances",occurances); | ||||||
|  | } | ||||||
| @ -0,0 +1,114 @@ | |||||||
|  | #include <idc.idc> | ||||||
|  | static GetVtableSize(a) | ||||||
|  | { | ||||||
|  |   auto b,c,f; | ||||||
|  |   b = BADADDR; | ||||||
|  |   f = GetFlags(a); | ||||||
|  |   //Message("checking vtable at: %a\n",a);
 | ||||||
|  |   do { | ||||||
|  |     f = GetFlags(a); | ||||||
|  |     if (b == BADADDR) //first entry
 | ||||||
|  |     { | ||||||
|  |       b=a; | ||||||
|  |       if (!(isRef(f) && (hasName(f) || (f&FF_LABL)))) | ||||||
|  |       { | ||||||
|  |         //Message("Start of vtable should have a xref and a name (auto or manual)\n");
 | ||||||
|  |         return 0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     else if (isRef(f)) //might mean start of next vtable
 | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |     //Message("hasValue(f):%d, isData(f):%d, isOff0(f):%d, (f & DT_TYPE) != FF_DWRD:%d\n",
 | ||||||
|  |     //  hasValue(f), isData(f), isOff0(f), (f & DT_TYPE) != FF_DWRD);
 | ||||||
|  |     if (!hasValue(f) || !isData(f) /*|| !isOff0(f) || (f & DT_TYPE) != FF_DWRD*/) | ||||||
|  |       break; | ||||||
|  |     c = Dword(a); | ||||||
|  |     if (c) | ||||||
|  |     { | ||||||
|  |       f = GetFlags(c); | ||||||
|  |       if (!hasValue(f) || !isCode(f) || Dword(c)==0) | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |     a = a+4; | ||||||
|  |   } | ||||||
|  |   while (1); | ||||||
|  |   if (b!=BADADDR) | ||||||
|  |   { | ||||||
|  |     c = (a-b)/4; | ||||||
|  |     //Message("vtable: %08X-%08X, methods: %d\n",b,a,c);
 | ||||||
|  |     return c; | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |   { | ||||||
|  |     //Message("no vtable at this EA\n");
 | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static main(void) | ||||||
|  | { | ||||||
|  |   auto a, c, k, name, i, struct_id, bNameMethods,e, methName; | ||||||
|  |   a = ScreenEA(); | ||||||
|  |   k = GetVtableSize(a); | ||||||
|  |   if (k>100) | ||||||
|  |   { | ||||||
|  |     if (1!=AskYN(0,form("%08X: This vtable appears to have %d methods. Are you sure you want to continue?",a,k))) | ||||||
|  |       return; | ||||||
|  |   } | ||||||
|  |   if (hasName(GetFlags(a))) | ||||||
|  |     name = Name(a); | ||||||
|  |   else | ||||||
|  |     name = ""; | ||||||
|  |   if (substr(name,0,4)=="??_7") | ||||||
|  |     name = substr(name,4,strlen(name)-5); | ||||||
|  |   name = AskStr(name,"Please enter the class name"); | ||||||
|  |   if (name==0) | ||||||
|  |     return; | ||||||
|  |   struct_id = GetStrucIdByName(name+"_vtable"); | ||||||
|  |   if (struct_id != -1) | ||||||
|  |   { | ||||||
|  |     i = AskYN(0,form("A vtable structure for %s already exists. Are you sure you want to remake it?",name)); | ||||||
|  |     if (i==-1) | ||||||
|  |       return; | ||||||
|  |     if (i==1) | ||||||
|  |     { | ||||||
|  |       DelStruc(struct_id); | ||||||
|  |       struct_id = AddStrucEx(-1,name+"_vtable",0); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |     struct_id = AddStrucEx(-1,name+"_vtable",0); | ||||||
|  |   if (struct_id == -1) | ||||||
|  |     Warning("Could not create the vtable structure!.\nPlease check the entered class name."); | ||||||
|  |   bNameMethods = (1==AskYN(0,form("Would you like to assign auto names to the virtual methods (%s_virtXX)?",name))); | ||||||
|  |   for (i=0;i<k;i++) | ||||||
|  |   { | ||||||
|  |     c = Dword(a+i*4); | ||||||
|  |     if (bNameMethods && !hasName(GetFlags(c))) | ||||||
|  |         MakeName(c,form("%s_virt%02X",name,i*4)); | ||||||
|  |     if (hasName(GetFlags(c))) | ||||||
|  |     { | ||||||
|  |       methName = Name(c); | ||||||
|  |       if (substr(methName,0,1)=="?") | ||||||
|  |       { | ||||||
|  |         methName = substr(methName,1,strstr(methName,"@")); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |       methName = form("virt%02X",i*4); | ||||||
|  |     e = AddStrucMember(struct_id,methName,i*4,FF_DWRD|FF_DATA,-1,4); | ||||||
|  |     if (0!=e) | ||||||
|  |     { | ||||||
|  |       if (e!=-2 && e!=-1) | ||||||
|  |       { | ||||||
|  |         Warning(form("Error adding a vtable entry (%d)!",e)); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       else if (substr(GetMemberName(struct_id, i*4),0,6)=="field_") | ||||||
|  |         SetMemberName(struct_id, i*4, form("virt%02X",i*4)); | ||||||
|  |     } | ||||||
|  |     SetMemberComment(struct_id,i*4,form("-> %08X, args: 0x%X",c,GetFrameArgsSize(c)),1); | ||||||
|  |   } | ||||||
|  |   MakeName(a,"??_7"+name+"@@6B@"); | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue