Reverse engineering MS C++ exception handling
I have a function (compiled originally with VS .NET 2003) in IDA that looks like this:
Code:
.text:10038AD0 ; int __thiscall W3dExportClass::DoExport(W3dExportClass *this, const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options)
.text:10038AD0 W3dExportClass__DoExport proc near ; DATA XREF: .rdata:1007AE04↓o
.text:10038AD0
.text:10038AD0 anonymous_0 = dword ptr -0E58h
.text:10038AD0 var_E50 = dword ptr -0E50h
.text:10038AD0 var_23C = RawFileClass ptr -23Ch
.text:10038AD0 var_220 = dword ptr -220h
.text:10038AD0 Caption = byte ptr -21Ch
.text:10038AD0 Dir = byte ptr -118h
.text:10038AD0 var_14 = dword ptr -14h
.text:10038AD0 var_10 = dword ptr -10h
.text:10038AD0 var_C = dword ptr -0Ch
.text:10038AD0 var_4 = dword ptr -4
.text:10038AD0 name = dword ptr 8
.text:10038AD0 ei = dword ptr 0Ch
.text:10038AD0 i = dword ptr 10h
.text:10038AD0 suppressPrompts = dword ptr 14h
.text:10038AD0 options = dword ptr 18h
.text:10038AD0
.text:10038AD0 ; FUNCTION CHUNK AT .text:10072A00 SIZE 0000000B BYTES
.text:10038AD0
.text:10038AD0 ; __unwind { // SEH_10038AD0
.text:10038AD0 push ebp
.text:10038AD1 mov ebp, esp
.text:10038AD3 push 0FFFFFFFFh
.text:10038AD5 push offset SEH_10038AD0
.text:10038ADA mov eax, large fs:0
.text:10038AE0 push eax
.text:10038AE1 mov large fs:0, esp
.text:10038AE8 sub esp, 0E44h
.text:10038AEE mov eax, ___security_cookie
.text:10038AF3 push ebx
.text:10038AF4 push esi
.text:10038AF5 mov esi, ecx
.text:10038AF7 push edi
.text:10038AF8 mov edi, [ebp+i]
.text:10038AFB xor ebx, ebx
.text:10038AFD mov [ebp+var_14], eax
.text:10038B00 mov eax, [ebp+ei]
.text:10038B03 mov ecx, edi ; this
.text:10038B05 mov [esi+W3dExportClass.ExpInt], eax
.text:10038B0B mov [esi+W3dExportClass.Int], edi
.text:10038B11 mov [esi+W3dExportClass.field_47C], ebx
.text:10038B17 mov [esi+W3dExportClass.OriginNodeList], ebx
.text:10038B1D mov [esi+W3dExportClass.DamageNodeList], ebx
.text:10038B23 mov [esi+W3dExportClass.HierarchyStruct], ebx
.text:10038B29 mov edx, [ecx]
.text:10038B2B mov [ebp+var_10], esp
.text:10038B2E mov [ebp+var_220], esi
.text:10038B34 ; try {
.text:10038B34 mov [ebp+var_4], ebx
.text:10038B37 call [edx+InterfaceVtable.GetTime]
.text:10038B3D mov [esi+W3dExportClass.Time], eax
.text:10038B43 call ds:GetFrameRate(void)
.text:10038B49 mov [esi+W3dExportClass.FrameRate], eax
.text:10038B4F push ebx ; Ext
.text:10038B50 lea eax, [ebp+Caption]
.text:10038B56 push eax ; Filename
.text:10038B57 mov eax, [ebp+name]
.text:10038B5A lea ecx, [ebp+Dir]
.text:10038B60 push ecx ; Dir
.text:10038B61 lea edx, [ebp+ei]
.text:10038B64 push edx ; Drive
.text:10038B65 push eax ; FullPath
.text:10038B66 mov [esi+W3dExportClass.field_478], 2
.text:10038B70 call __splitpath
.text:10038B75 lea ecx, [ebp+Dir]
.text:10038B7B push ecx
.text:10038B7C lea edx, [ebp+ei]
.text:10038B7F push edx
.text:10038B80 push offset aSS ; "%s%s"
.text:10038B85 push offset buf ; char *
.text:10038B8A call _sprintf
.text:10038B8F lea eax, [ebp+Caption]
.text:10038B95 add esp, 24h
.text:10038B98 lea edx, [eax+1]
.text:10038B9B jmp short loc_10038BA0
.text:10038B9B ; ---------------------------------------------------------------------------
.text:10038B9D align 10h
.text:10038BA0
.text:10038BA0 loc_10038BA0: ; CODE XREF: W3dExportClass__DoExport+CB↑j
.text:10038BA0 ; W3dExportClass__DoExport+D5↓j
.text:10038BA0 mov cl, [eax]
.text:10038BA2 inc eax
.text:10038BA3 cmp cl, bl
.text:10038BA5 jnz short loc_10038BA0
.text:10038BA7 sub eax, edx
.text:10038BA9 cmp eax, 0Fh
.text:10038BAC jbe short loc_10038BC5
.text:10038BAE cmp [ebp+suppressPrompts], ebx
.text:10038BB1 jnz short loc_10038BC5
.text:10038BB3 push ebx ; uType
.text:10038BB4 push offset aWarning ; "Warning"
.text:10038BB9 push offset aWarningW3dFile ; "Warning: W3D filenames should be 15 cha"...
.text:10038BBE push ebx ; hWnd
.text:10038BBF call ds:MessageBoxA
.text:10038BC5
.text:10038BC5 loc_10038BC5: ; CODE XREF: W3dExportClass__DoExport+DC↑j
.text:10038BC5 ; W3dExportClass__DoExport+E1↑j
.text:10038BC5 mov eax, [edi]
.text:10038BC7 mov ecx, edi ; Interface *
.text:10038BC9 call [eax+InterfaceVtable.GetCurFilePath]
.text:10038BCF mov ecx, eax
.text:10038BD1 call ds:CStr::operator char *(void)
.text:10038BD7 push ebx ; Ext
.text:10038BD8 push ebx ; Filename
.text:10038BD9 lea ecx, [ebp+Dir]
.text:10038BDF push ecx ; Dir
.text:10038BE0 lea edx, [ebp+ei]
.text:10038BE3 push edx ; Drive
.text:10038BE4 push eax ; FullPath
.text:10038BE5 call __splitpath
.text:10038BEA lea eax, [ebp+Dir]
.text:10038BF0 push eax
.text:10038BF1 lea ecx, [ebp+ei]
.text:10038BF4 push ecx
.text:10038BF5 lea edx, [esi+W3dExportClass.Path]
.text:10038BF8 push offset aSS ; "%s%s"
.text:10038BFD push edx ; char *
.text:10038BFE call _sprintf
.text:10038C03 mov eax, [ebp+suppressPrompts]
.text:10038C06 add esp, 24h
.text:10038C09 push eax ; suppressPrompts
.text:10038C0A mov ecx, esi ; this
.text:10038C0C call W3DExportClass__DoExportDialog
.text:10038C11 cmp al, bl
.text:10038C13 jz loc_10038DA5
.text:10038C19 cmp [esi+W3dExportClass.ExportStruct.ExportSkeleton], bl
.text:10038C1F jnz short loc_10038C35
.text:10038C21 cmp [esi+W3dExportClass.ExportStruct.ExportAnimation], bl
.text:10038C27 jnz short loc_10038C35
.text:10038C29 cmp [esi+W3dExportClass.ExportStruct.ExportGeometry], bl
.text:10038C2F jz loc_10038DA5
.text:10038C35
.text:10038C35 loc_10038C35: ; CODE XREF: W3dExportClass__DoExport+14F↑j
.text:10038C35 ; W3dExportClass__DoExport+157↑j
.text:10038C35 push ebx
.text:10038C36 call CreateLogDialog
.text:10038C3B mov ecx, [ebp+name]
.text:10038C3E add esp, 4
.text:10038C41 push ecx ; filename
.text:10038C42 lea ecx, [ebp+var_23C] ; this
.text:10038C48 call RawFileClass__RawFileClass
.text:10038C4D push 2 ; a2
.text:10038C4F lea ecx, [ebp+var_23C] ; this
.text:10038C4F ; } // starts at 10038B34
.text:10038C55 ; try {
.text:10038C55 mov byte ptr [ebp+var_4], 1
.text:10038C59 call RawFileClass::Open(int)
.text:10038C5E cmp eax, ebx
.text:10038C60 jnz short loc_10038C8B
.text:10038C62 push 10000h ; uType
.text:10038C67 push offset aError ; "Error"
.text:10038C6C push offset aUnableToOpenFi ; "Unable to open file."
.text:10038C71 push ebx ; hWnd
.text:10038C72 call ds:MessageBoxA
.text:10038C78 lea ecx, [ebp+var_23C] ; this
.text:10038C78 ; } // starts at 10038C55
.text:10038C7E ; try {
.text:10038C7E mov byte ptr [ebp+var_4], bl
.text:10038C81 call RawFileClass::~RawFileClass()
.text:10038C86 jmp loc_10038DA5
.text:10038C8B ; ---------------------------------------------------------------------------
.text:10038C8B
.text:10038C8B loc_10038C8B: ; CODE XREF: W3dExportClass__DoExport+190↑j
.text:10038C8B lea edx, [ebp+var_23C]
.text:10038C91 push edx ; _DWORD
.text:10038C92 lea ecx, [ebp+var_E50]
.text:10038C98 call ChunkSaveClass::ChunkSaveClass(FileClass *)
.text:10038C9D mov ecx, esi ; this
.text:10038C9F call W3dExportClass__CreateOriginNodeList
.text:10038CA4 cmp eax, ebx
.text:10038CA6 jz short loc_10038CBD
.text:10038CA8 lea eax, [ebp+var_E50]
.text:10038CAE push eax ; int
.text:10038CAF lea ecx, [ebp+Caption]
.text:10038CB5 push ecx ; lpCaption
.text:10038CB6 mov ecx, esi
.text:10038CB8 call W3dExportClass__ExportData
.text:10038CBD
.text:10038CBD loc_10038CBD: ; CODE XREF: W3dExportClass__DoExport+1D6↑j
.text:10038CBD lea ecx, [ebp+var_23C]
.text:10038CC3 call RawFileClass::Close(void)
.text:10038CC8 mov edi, [esi+48Ch]
.text:10038CCE cmp edi, ebx
.text:10038CD0 jz short loc_10038CE8
.text:10038CD2 mov ecx, edi ; this
.text:10038CD4 call HierarchySave__DHierarchySave
.text:10038CD9 push edi ; void *
.text:10038CDA call MAX_delete(void *)
.text:10038CDF add esp, 4
.text:10038CE2 mov [esi+W3dExportClass.HierarchyStruct], ebx
.text:10038CE8
.text:10038CE8 loc_10038CE8: ; CODE XREF: W3dExportClass__DoExport+200↑j
.text:10038CE8 mov edi, [esi+W3dExportClass.OriginNodeList]
.text:10038CEE cmp edi, ebx
.text:10038CF0 jz short loc_10038D08
.text:10038CF2 mov ecx, edi ; this
.text:10038CF4 call INodeListClass__destructor2
.text:10038CF9 push edi ; void *
.text:10038CFA call MAX_delete(void *)
.text:10038CFF add esp, 4
.text:10038D02 mov [esi+W3dExportClass.OriginNodeList], ebx
.text:10038D08
.text:10038D08 loc_10038D08: ; CODE XREF: W3dExportClass__DoExport+220↑j
.text:10038D08 mov edi, [esi+W3dExportClass.DamageNodeList]
.text:10038D0E cmp edi, ebx
.text:10038D10 jz short loc_10038D28
.text:10038D12 mov ecx, edi ; this
.text:10038D14 call INodeListClass__destructor2
.text:10038D19 push edi ; void *
.text:10038D1A call MAX_delete(void *)
.text:10038D1F add esp, 4
.text:10038D22 mov [esi+W3dExportClass.DamageNodeList], ebx
.text:10038D28
.text:10038D28 loc_10038D28: ; CODE XREF: W3dExportClass__DoExport+240↑j
.text:10038D28 lea ecx, [ebp+var_23C] ; this
.text:10038D28 ; } // starts at 10038C7E
.text:10038D2E ; try {
.text:10038D2E mov byte ptr [ebp+var_4], bl
.text:10038D31 call RawFileClass::~RawFileClass()
.text:10038D36 jmp short loc_10038D6D
.text:10038D38 ; ---------------------------------------------------------------------------
.text:10038D38
.text:10038D38 loc_10038D38: ; DATA XREF: .rdata:stru_10086C44↓o
.text:10038D38 ; catch(ErrorClass) // owned by 10038B34
.text:10038D38 ; catch(ErrorClass) // owned by 10038C55
.text:10038D38 mov esi, [ebp+i]
.text:10038D3B push 10000h ; uType
.text:10038D40 push offset aError ; "Error"
.text:10038D45 push esi ; lpText
.text:10038D46 xor ebx, ebx
.text:10038D48 push ebx ; hWnd
.text:10038D49 call ds:MessageBoxA
.text:10038D4F cmp esi, ebx
.text:10038D51 jz short loc_10038D5F
.text:10038D53 mov edx, ds:void (*MAX_free)(void *)
.text:10038D59 push esi
.text:10038D5A call dword ptr [edx]
.text:10038D5C add esp, 4
.text:10038D5F
.text:10038D5F loc_10038D5F: ; CODE XREF: W3dExportClass__DoExport+281↑j
.text:10038D5F mov eax, offset loc_10038D65
.text:10038D64 retn
.text:10038D65 ; ---------------------------------------------------------------------------
.text:10038D65
.text:10038D65 loc_10038D65: ; CODE XREF: W3dExportClass__DoExport+294↑j
.text:10038D65 ; DATA XREF: W3dExportClass__DoExport:loc_10038D5F↑o
.text:10038D65 mov esi, [ebp+var_220]
.text:10038D6B xor ebx, ebx
.text:10038D6B ; } // starts at 10038D2E
.text:10038D6D
.text:10038D6D loc_10038D6D: ; CODE XREF: W3dExportClass__DoExport+266↑j
.text:10038D6D mov [ebp+var_4], 0FFFFFFFFh
.text:10038D74 call W3dExportClass__PrintTotalVertexCount
.text:10038D79 xor eax, eax
.text:10038D7B mov al, [esi+W3dExportClass.ExportStruct.ReviewLog]
.text:10038D81 push eax ; a1
.text:10038D82 call W3dExportClass__DestroyLogDialog
.text:10038D87 mov ecx, [esi+W3dExportClass.Int] ; this
.text:10038D8D mov edi, [ecx]
.text:10038D8F add esp, 4
.text:10038D92 push ebx
.text:10038D93 push 8
.text:10038D95 call [edi+InterfaceVtable.GetTime]
.text:10038D9B mov ecx, [esi+W3dExportClass.Int] ; Interface *
.text:10038DA1 push eax ; t
.text:10038DA2 call [edi+InterfaceVtable.RedrawViews]
.text:10038DA5
.text:10038DA5 loc_10038DA5: ; CODE XREF: W3dExportClass__DoExport+143↑j
.text:10038DA5 ; W3dExportClass__DoExport+15F↑j ...
.text:10038DA5 mov ecx, [ebp+var_C]
.text:10038DA8 mov large fs:0, ecx
.text:10038DAF mov ecx, [ebp+var_14]
.text:10038DB2 mov eax, 1
.text:10038DB7 call __security_check_cookie(x)
.text:10038DBC pop edi
.text:10038DBD pop esi
.text:10038DBE pop ebx
.text:10038DBF mov esp, ebp
.text:10038DC1 pop ebp
.text:10038DC2 retn 14h
.text:10038DC2 ; } // starts at 10038AD0
.text:10038DC2 W3dExportClass__DoExport endp
.text:10072A0B SEH_10038AD0 proc near ; DATA XREF: W3dExportClass__DoExport+5↑o
.text:10072A0B ; .rdata:1008556C↓o
.text:10072A0B mov eax, offset stru_10086C68
.text:10072A10 jmp ___CxxFrameHandler
.text:10072A10 SEH_10038AD0 endp
.rdata:10086C68 stru_10086C68 FuncInfo_V1 <19930520h, 3, offset stru_10086C2C, 1, \
.rdata:10086C68 ; DATA XREF: SEH_10038AD0↑o
.rdata:10086C68 offset stru_10086C54, 0, 0>
.rdata:10086C2C stru_10086C2C UnwindMapEntry <-1, 0> ; DATA XREF: .rdata:stru_10086C68↓o
.rdata:10086C34 UnwindMapEntry <0, offset loc_10072A00>
.rdata:10086C3C UnwindMapEntry <-1, 0>
.text:10072A00 loc_10072A00: ; DATA XREF: .rdata:10086C34↓o
.text:10072A00 ; __unwind { // SEH_10038AD0 ; this
.text:10072A00 ; cleanup() // owned by 10038C55
.text:10072A00 ; cleanup() // owned by 10038C7E
.text:10072A00 ; cleanup() // owned by 10038D2E
.text:10072A00 lea ecx, [ebp+var_23C]
.text:10072A06 jmp RawFileClass::~RawFileClass()
.text:10072A06 ; } // starts at 10072A00
.rdata:10086C54 stru_10086C54 TryBlockMapEntry <0, 1, 2, 1, offset stru_10086C44>
.rdata:10086C54 ; DATA XREF: .rdata:stru_10086C68↓o
.rdata:10086C44 stru_10086C44 HandlerType <0, offset ErrorClass `RTTI Type Descriptor', 16, \
.rdata:10086C44 ; DATA XREF: .rdata:stru_10086C54↓o
.rdata:10086C44 offset loc_10038D38>
I have a clone of the function (without any try/catch statements in there) as follows:
Code:
int __thiscall W3dExportClass::DoExport(W3dExportClass *this, const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD options)
{
this->ExpInt = ei;
this->Int = i;
this->field_47C = 0;
this->OriginNodeList = NULL;
this->DamageNodeList = NULL;
this->HierarchyStruct = NULL;
this->Time = i->GetTime(i);
this->FrameRate = GetFrameRate();
this->field_478 = 2;
_splitpath(name, (char *)&ei, &Dir, &Caption, NULL);
sprintf(buf, "%s%s", &ei, &Dir);
if ( strlen(&Caption) > 0xF && !suppressPrompts )
MessageBoxA(NULL, "Warning: W3D filenames should be 15 characters or less!", "Warning", 0);
_splitpath((const char *)i->GetCurFilePath(), (char *)&ei, &Dir, NULL, NULL);
sprintf(this->Path, "%s%s", &ei, &Dir);
if ( W3DExportClass::DoExportDialog(this, suppressPrompts)
&& (this->ExportStruct.ExportSkeleton || this->ExportStruct.ExportAnimation || this->ExportStruct.ExportGeometry) )
{
CreateLogDialog(0);
RawFileClass r(name);
if ( r.Open(2) )
{
ChunkSaveClass::ChunkSaveClass(&r);
if ( W3dExportClass::CreateOriginNodeList(this) )
W3dExportClass::ExportData(this, &Caption, (int)&v21);
r.Close();
if ( this->HierarchyStruct )
{
delete this->HierarchyStruct;
this->HierarchyStruct = NULL;
}
if ( this->OriginNodeList )
{
delete this->OriginNodeList;
this->OriginNodeList = NULL;
}
if ( this->DamageNodeList )
{
delete this->DamageNodeList;
this->DamageNodeList = NULL;
}
W3dExportClass::PrintTotalVertexCount();
W3dExportClass::DestroyLogDialog(this->ExportStruct.ReviewLog);
this->Int->RedrawViews(this->Int->GetTime() //not sure of full prototype for this function, may have more arguments);
}
else
{
MessageBoxA(NULL, "Unable to open file.", "Error", MB_SETFOREGROUND);
}
}
return 1;
}
Can anyone tell me based on the ASM and the above clone where the try/catch statements and other EH stuff need to go to complete the clone? (if any further information is needed I can provide that)
|