reversing scripts moved to df_misc
@ -1,75 +0,0 @@
|
|||||||
.rodata:08773064 t_building_templest
|
|
||||||
.rodata:08772FE4 t_building_dark_towerst
|
|
||||||
.rodata:08772EE4 t_building_home_apartment_roomst
|
|
||||||
.rodata:08772F24 t_building_home_apartmentst
|
|
||||||
.rodata:08772F64 t_building_home_singlest
|
|
||||||
.rodata:08773024 t_building_keepst
|
|
||||||
.rodata:08772FA4 t_building_mead_hallst
|
|
||||||
.rodata:087730A4 t_building_storest
|
|
||||||
.rodata:08776784 23building_constructionst
|
|
||||||
.rodata:087771E4 21building_road_pavedst
|
|
||||||
.rodata:08777064 20building_road_dirtst
|
|
||||||
.rodata:08777AC4 15building_roadst
|
|
||||||
.rodata:08779424 16building_wagonst
|
|
||||||
.rodata:087792A4 21building_tradedepotst
|
|
||||||
.rodata:087789C4 19building_workshopst
|
|
||||||
.rodata:08778E44 18building_furnacest
|
|
||||||
.rodata:08778244 21building_animaltrapst
|
|
||||||
.rodata:08778FC4 19building_farmplotst
|
|
||||||
.rodata:08777644 17building_windowst
|
|
||||||
.rodata:087777C4 17building_statuest
|
|
||||||
.rodata:08777944 15building_wellst
|
|
||||||
.rodata:08777364 17building_coffinst
|
|
||||||
.rodata:087795A4 15building_shopst
|
|
||||||
.rodata:087783C4 16building_chairst
|
|
||||||
.rodata:08777C44 16building_tablest
|
|
||||||
.rodata:08777C44 14building_bedst
|
|
||||||
.rodata:08778B44 22building_siegeenginest
|
|
||||||
.rodata:08776D64 15building_cagest
|
|
||||||
.rodata:08776EE4 16building_chainst
|
|
||||||
.rodata:08776184 19building_windmillst
|
|
||||||
.rodata:08776304 22building_water_wheelst
|
|
||||||
.rodata:08776004 21building_screw_pumpst
|
|
||||||
.rodata:08778844 24building_archerytargetst
|
|
||||||
.rodata:08778544 17building_weaponst
|
|
||||||
.rodata:087786C4 18building_supportst
|
|
||||||
.rodata:08776604 24building_axle_verticalst
|
|
||||||
.rodata:08776484 26building_axle_horizontalst
|
|
||||||
.rodata:08776BE4 24building_gear_assemblyst
|
|
||||||
.rodata:08778CC4 15building_trapst
|
|
||||||
.rodata:08779EA4 21building_bars_floorst
|
|
||||||
.rodata:0877A024 24building_bars_verticalst
|
|
||||||
.rodata:0877A324 22building_grate_floorst
|
|
||||||
.rodata:0877A1A4 21building_grate_wallst
|
|
||||||
.rodata:0877A4A4 20building_floodgatest
|
|
||||||
.rodata:08779D24 17building_bridgest
|
|
||||||
.rodata:08779A24 16building_hatchst
|
|
||||||
.rodata:08779BA4 15building_doorst
|
|
||||||
.rodata:08777DC4 21building_armorstandst
|
|
||||||
.rodata:08777F44 21building_weaponrackst
|
|
||||||
.rodata:087798A4 18building_cabinetst
|
|
||||||
.rodata:08779724 14building_boxst
|
|
||||||
.rodata:08776A64 17building_actualst
|
|
||||||
.rodata:08779144 18building_civzonest
|
|
||||||
.rodata:087774E4 20building_stockpilest
|
|
||||||
0:FFFFFFFF 21building_window_gemst
|
|
||||||
0:FFFFFFFF 23building_window_glassst
|
|
||||||
.rodata:08787664 t_building_interactst
|
|
||||||
.rodata:08788DE4 n_building_selectorst
|
|
||||||
.rodata:08788E44 n_building_permit_foreign_armorst
|
|
||||||
.rodata:08788E24 n_building_permit_itemst
|
|
||||||
.rodata:08788E64 n_building_permit_foreign_siegeammost
|
|
||||||
.rodata:08788E84 n_building_permit_foreign_weaponst
|
|
||||||
.rodata:08788EA4 n_building_permit_trapcompst
|
|
||||||
.rodata:08788F04 n_building_new_jobst
|
|
||||||
.rodata:08788EC4 n_building_category_selectorst
|
|
||||||
.rodata:08788EE4 n_building_material_selectorst
|
|
||||||
0:FFFFFFFF f_building_well_tagst
|
|
||||||
0:FFFFFFFF E_BUILDING_TEMPLE
|
|
||||||
0:FFFFFFFF E_BUILDING_KEEP
|
|
||||||
0:FFFFFFFF f_building_civzone_assignedst
|
|
||||||
0:FFFFFFFF f_building_triggerst
|
|
||||||
0:FFFFFFFF f_building_triggertargetst
|
|
||||||
0:FFFFFFFF f_building_chainst
|
|
||||||
0:FFFFFFFF f_building_cagedst
|
|
||||||
0:FFFFFFFF f_building_holderst
|
|
@ -1,5 +0,0 @@
|
|||||||
FF - retractable
|
|
||||||
00 - west
|
|
||||||
01 - east
|
|
||||||
02 - north
|
|
||||||
03 - south
|
|
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 16 KiB |
@ -1,81 +0,0 @@
|
|||||||
0x00cdfd950
|
|
||||||
0x0000 e8 69 6c 08
|
|
||||||
0x0004 90 00 00 00
|
|
||||||
0x0008 8f 00 00 00
|
|
||||||
0x000c 90 00 00 00
|
|
||||||
|
|
||||||
0x0010 90 00 00 00
|
|
||||||
0x0014 8f 00 00 00
|
|
||||||
0x0018 8f 00 00 00
|
|
||||||
0x001c 0f 00 00 00
|
|
||||||
|
|
||||||
0x0020 01 00 00 00
|
|
||||||
0x0024 01 00 87 00
|
|
||||||
0x0028 00 00 00 00
|
|
||||||
0x002c f8 dc 0d 10
|
|
||||||
|
|
||||||
0x0030 f8 c6 0d 10
|
|
||||||
0x0034 78 c2 0d 10
|
|
||||||
0x0038 b0 7c 0d 10
|
|
||||||
0x003c fe 52 01 00
|
|
||||||
|
|
||||||
0x0040 a6 00 df 0a
|
|
||||||
0x0044 1b ee 00 00
|
|
||||||
0x0048 30 96 a7 10
|
|
||||||
0x004c 30 96 a7 10
|
|
||||||
|
|
||||||
0x0050 34 96 a7 10
|
|
||||||
0x0054 00 00 00 00
|
|
||||||
0x0058 00 00 00 00
|
|
||||||
0x005c 00 00 00 00
|
|
||||||
|
|
||||||
0x0060 00 00 00 00
|
|
||||||
0x0064 00 00 00 00
|
|
||||||
0x0068 00 00 00 00
|
|
||||||
0x006c 00 00 00 00
|
|
||||||
|
|
||||||
0x0070 00 00 00 00
|
|
||||||
0x0074 00 00 00 00
|
|
||||||
0x0078 00 00 00 00
|
|
||||||
0x007c 00 00 00 00
|
|
||||||
|
|
||||||
0x0080 00 00 00 00
|
|
||||||
0x0084 00 00 00 00
|
|
||||||
0x0088 00 00 00 00
|
|
||||||
0x008c 00 00 00 00
|
|
||||||
|
|
||||||
0x0090 00 00 00 00
|
|
||||||
0x0094 00 00 00 00
|
|
||||||
0x0098 01 00 00 00
|
|
||||||
0x009c 00 47 e4 0d
|
|
||||||
|
|
||||||
0x00a0 18 47 e4 0d
|
|
||||||
0x00a4 18 47 e4 0d
|
|
||||||
0x00a8 00 00 00 00
|
|
||||||
0x00ac 00 00 00 00
|
|
||||||
|
|
||||||
0x00b0 00 00 00 00
|
|
||||||
0x00b4 00 00 00 00
|
|
||||||
0x00b8 80 47 e4 0d
|
|
||||||
0x00bc 94 47 e4 0d
|
|
||||||
|
|
||||||
0x00c0 94 47 e4 0d
|
|
||||||
0x00c4 00 00 00 00
|
|
||||||
0x00c8 00 00 00 00
|
|
||||||
0x00cc 00 00 00 00
|
|
||||||
|
|
||||||
0x00d0 00 00 00 00
|
|
||||||
0x00d4 00 00 00 00
|
|
||||||
0x00d8 00 00 00 00
|
|
||||||
0x00dc 00 00 00 00
|
|
||||||
|
|
||||||
0x00e0 c0 c6 2d 00
|
|
||||||
0x00e4 05 00 00 00
|
|
||||||
0x00e8 14 00 00 00
|
|
||||||
0x00ec 01 07 01 07
|
|
||||||
|
|
||||||
0x00f0 10 00 00 00
|
|
||||||
0x00f4 b9 00 00 00
|
|
||||||
0x00f8 68 59 6c 08
|
|
||||||
0x00fc 98 00 00 00
|
|
||||||
Done. Press any key to continue
|
|
@ -1,81 +0,0 @@
|
|||||||
0x00cdfd950
|
|
||||||
0x0000 e8 69 6c 08
|
|
||||||
0x0004 90 00 00 00
|
|
||||||
0x0008 8f 00 00 00
|
|
||||||
0x000c 90 00 00 00
|
|
||||||
|
|
||||||
0x0010 90 00 00 00
|
|
||||||
0x0014 8f 00 00 00
|
|
||||||
0x0018 8f 00 00 00
|
|
||||||
0x001c 0f 00 00 00
|
|
||||||
|
|
||||||
0x0020 01 00 00 00
|
|
||||||
0x0024 01 00 87 00
|
|
||||||
0x0028 00 00 00 00
|
|
||||||
0x002c f8 dc 0d 10
|
|
||||||
|
|
||||||
0x0030 f8 c6 0d 10
|
|
||||||
0x0034 78 c2 0d 10
|
|
||||||
0x0038 b0 7c 0d 10
|
|
||||||
0x003c 34 51 01 00
|
|
||||||
|
|
||||||
0x0040 a6 00 df 0a
|
|
||||||
0x0044 1b ee 00 00
|
|
||||||
0x0048 00 00 00 00
|
|
||||||
0x004c 00 00 00 00
|
|
||||||
|
|
||||||
0x0050 00 00 00 00
|
|
||||||
0x0054 00 00 00 00
|
|
||||||
0x0058 00 00 00 00
|
|
||||||
0x005c 00 00 00 00
|
|
||||||
|
|
||||||
0x0060 00 00 00 00
|
|
||||||
0x0064 00 00 00 00
|
|
||||||
0x0068 00 00 00 00
|
|
||||||
0x006c 00 00 00 00
|
|
||||||
|
|
||||||
0x0070 00 00 00 00
|
|
||||||
0x0074 00 00 00 00
|
|
||||||
0x0078 00 00 00 00
|
|
||||||
0x007c 00 00 00 00
|
|
||||||
|
|
||||||
0x0080 00 00 00 00
|
|
||||||
0x0084 00 00 00 00
|
|
||||||
0x0088 00 00 00 00
|
|
||||||
0x008c 00 00 00 00
|
|
||||||
|
|
||||||
0x0090 00 00 00 00
|
|
||||||
0x0094 00 00 00 00
|
|
||||||
0x0098 01 00 00 00
|
|
||||||
0x009c 00 47 e4 0d
|
|
||||||
|
|
||||||
0x00a0 18 47 e4 0d
|
|
||||||
0x00a4 18 47 e4 0d
|
|
||||||
0x00a8 00 00 00 00
|
|
||||||
0x00ac 00 00 01 00
|
|
||||||
|
|
||||||
0x00b0 00 00 00 00
|
|
||||||
0x00b4 00 00 00 00
|
|
||||||
0x00b8 80 47 e4 0d
|
|
||||||
0x00bc 94 47 e4 0d
|
|
||||||
|
|
||||||
0x00c0 94 47 e4 0d
|
|
||||||
0x00c4 00 00 00 00
|
|
||||||
0x00c8 00 00 00 00
|
|
||||||
0x00cc 00 00 00 00
|
|
||||||
|
|
||||||
0x00d0 00 00 00 00
|
|
||||||
0x00d4 00 00 00 00
|
|
||||||
0x00d8 00 00 00 00
|
|
||||||
0x00dc 00 00 00 00
|
|
||||||
|
|
||||||
0x00e0 c0 c6 2d 00
|
|
||||||
0x00e4 05 00 00 00
|
|
||||||
0x00e8 14 00 00 00
|
|
||||||
0x00ec 01 07 01 07
|
|
||||||
|
|
||||||
0x00f0 10 00 00 00
|
|
||||||
0x00f4 b9 00 00 00
|
|
||||||
0x00f8 68 59 6c 08
|
|
||||||
0x00fc 98 00 00 00
|
|
||||||
Done. Press any key to continue
|
|
@ -1,23 +0,0 @@
|
|||||||
< OFF
|
|
||||||
> ON
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
20c20
|
|
||||||
< 15 0x003c 1c 53 01 00
|
|
||||||
---
|
|
||||||
> 15 0x003c 39 55 01 00
|
|
||||||
28,30c28,30
|
|
||||||
< 21 0x0054 00 00 00 00
|
|
||||||
< 22 0x0058 00 00 00 00
|
|
||||||
< 23 0x005c 00 00 00 00
|
|
||||||
---
|
|
||||||
> 21 0x0054 e0 53 a1 01
|
|
||||||
> 22 0x0058 e0 53 a1 01
|
|
||||||
> 23 0x005c e4 53 a1 01
|
|
||||||
|
|
||||||
this is a good candidate for lever state
|
|
||||||
82c82
|
|
||||||
< 64 0x0100 00 00 00 00
|
|
||||||
---
|
|
||||||
> 64 0x0100 00 00 01 00
|
|
@ -1,75 +0,0 @@
|
|||||||
import ghidra.app.script.*;
|
|
||||||
import ghidra.program.model.address.*;
|
|
||||||
import ghidra.program.model.data.*;
|
|
||||||
import ghidra.program.model.mem.*;
|
|
||||||
|
|
||||||
public class find_df_globals extends GhidraScript {
|
|
||||||
public void run() throws Exception {
|
|
||||||
int ptrSize = currentProgram.getDefaultPointerSize();
|
|
||||||
byte[] dfInit = new byte[ptrSize * 2];
|
|
||||||
int i = 0;
|
|
||||||
dfInit[i++] = 0x78;
|
|
||||||
dfInit[i++] = 0x56;
|
|
||||||
dfInit[i++] = 0x34;
|
|
||||||
dfInit[i++] = 0x12;
|
|
||||||
if (ptrSize >= 8) {
|
|
||||||
dfInit[i++] = 0x78;
|
|
||||||
dfInit[i++] = 0x56;
|
|
||||||
dfInit[i++] = 0x34;
|
|
||||||
dfInit[i++] = 0x12;
|
|
||||||
dfInit[i++] = 0x21;
|
|
||||||
dfInit[i++] = 0x43;
|
|
||||||
dfInit[i++] = 0x65;
|
|
||||||
dfInit[i++] = (byte)0x87;
|
|
||||||
}
|
|
||||||
dfInit[i++] = 0x21;
|
|
||||||
dfInit[i++] = 0x43;
|
|
||||||
dfInit[i++] = 0x65;
|
|
||||||
dfInit[i++] = (byte)0x87;
|
|
||||||
byte[] mask = new byte[ptrSize * 2];
|
|
||||||
for (i = 0; i < ptrSize * 2; i++) {
|
|
||||||
mask[i] = (byte)0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataTypeManager dtm = currentProgram.getDataTypeManager();
|
|
||||||
StructureDataType dfGlobalsMapElement = new StructureDataType("df_globals_map_element", 0);
|
|
||||||
dfGlobalsMapElement.add(new PointerDataType(CharDataType.dataType, ptrSize), "name", null);
|
|
||||||
dfGlobalsMapElement.add(new PointerDataType(DataType.DEFAULT, ptrSize), "addr", null);
|
|
||||||
StructureDataType dfGlobalsMap = new StructureDataType("df_globals_map", 0);
|
|
||||||
dfGlobalsMap.add(DWordDataType.dataType, "magic0", "12345678");
|
|
||||||
if (ptrSize < 8) {
|
|
||||||
dfGlobalsMap.add(DWordDataType.dataType, "magic1", "87654321");
|
|
||||||
} else {
|
|
||||||
dfGlobalsMap.add(DWordDataType.dataType, "magic1", "12345678");
|
|
||||||
dfGlobalsMap.add(DWordDataType.dataType, "magic2", "87654321");
|
|
||||||
dfGlobalsMap.add(DWordDataType.dataType, "magic3", "87654321");
|
|
||||||
}
|
|
||||||
|
|
||||||
Memory mem = currentProgram.getMemory();
|
|
||||||
Address globalAddr = mem.findBytes(currentProgram.getMinAddress(), dfInit, mask, true, monitor);
|
|
||||||
|
|
||||||
int globalCount = 0;
|
|
||||||
while (mem.getLong(globalAddr.add((globalCount + 1) * ptrSize * 2)) != 0) {
|
|
||||||
globalCount++;
|
|
||||||
Address nameAddr;
|
|
||||||
Address dataAddr;
|
|
||||||
if (ptrSize >= 8) {
|
|
||||||
nameAddr = globalAddr.getNewAddress(mem.getLong(globalAddr.add(globalCount * ptrSize * 2)));
|
|
||||||
dataAddr = globalAddr.getNewAddress(mem.getLong(globalAddr.add(globalCount * ptrSize * 2 + ptrSize)));
|
|
||||||
} else {
|
|
||||||
nameAddr = globalAddr.getNewAddress(mem.getInt(globalAddr.add(globalCount * ptrSize * 2)));
|
|
||||||
dataAddr = globalAddr.getNewAddress(mem.getInt(globalAddr.add(globalCount * ptrSize * 2 + ptrSize)));
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = StringDataInstance.getStringDataInstance(DataUtilities.createData(currentProgram, nameAddr, TerminatedStringDataType.dataType, 0, false, DataUtilities.ClearDataMode.CLEAR_ALL_CONFLICT_DATA)).getStringValue();
|
|
||||||
|
|
||||||
createLabel(dataAddr, name, true);
|
|
||||||
}
|
|
||||||
dfGlobalsMap.add(new ArrayDataType(dfGlobalsMapElement, globalCount, ptrSize * 2), "globals", null);
|
|
||||||
|
|
||||||
dtm.addDataType(dfGlobalsMapElement, DataTypeConflictHandler.DEFAULT_HANDLER);
|
|
||||||
dtm.addDataType(dfGlobalsMap, DataTypeConflictHandler.DEFAULT_HANDLER);
|
|
||||||
|
|
||||||
currentProgram.getListing().createData(globalAddr, dfGlobalsMap);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
.rodata:08779424 16building_wagonst
|
|
@ -1,816 +0,0 @@
|
|||||||
//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;
|
|
||||||
// 8B 54 24 08 mov edx, [esp+8]
|
|
||||||
if (matchBytes(x,"8B5424088D02"))
|
|
||||||
x = x+6;
|
|
||||||
// 8D 02 lea eax, [edx]
|
|
||||||
else if (matchBytes(x,"8B5424088D42"))
|
|
||||||
x = x+7;
|
|
||||||
// 8D 42 xx lea eax, [edx+XXh]
|
|
||||||
else if (matchBytes(x,"8B5424088D82"))
|
|
||||||
x = x+10;
|
|
||||||
// 8D 82 xx xx xx xx lea eax, [edx+XXh]
|
|
||||||
else {
|
|
||||||
Message("Function at %08X not recognized as exception handler!\n",x);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//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
|
|
||||||
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,"83C0"))
|
|
||||||
x = x + 3;
|
|
||||||
// 8B 4A xx add eax, XXh
|
|
||||||
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) {
|
|
||||||
// 8B 4A xx xx xx mov eax, offset FuncInfo
|
|
||||||
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());
|
|
||||||
}
|
|
@ -1,660 +0,0 @@
|
|||||||
#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();
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
#local $/ = "\n\n";
|
|
||||||
while(<>){
|
|
||||||
if(/([0-9A-Z]+).*?([a-z]+_.+?)st\n/s){
|
|
||||||
print "<class vtable=\"0x$1\" name=\"$2\" />\n";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
#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@");
|
|
||||||
}
|
|