VB6 VTable Layout


Author: David Zimmer
Date: 09.26.22 - 10:06pm



to see the vtable layout of a vb6 COM object compile a native exe with debug symbols, in form load do something like
    Dim c As New Class1
    InputBox "", "", Hex(ObjPtr(c))
    End
attach ollydbg, in the bottom dump window right click view Long - as address then ctrl-g to go to the address copied from the inputbox. for me it was 4EB260
offset          value @ address       symbols resolved as 
-------------------------------------------------------
004EB260       00403354              OFFSET Project1.___vba@07F1B854
004EB264       00000000             (class based variables can be stored in memory below here)
follow that pointer to get to the vtable
00403354  6F2A306E  MSVBVM60.BASIC_CLASS_QueryInterface
00403358  6F2A2F45  MSVBVM60.Zombie_AddRef
0040335C  6F2A2D18  MSVBVM60.Zombie_Release
00403360  6F352FE1  MSVBVM60.BASIC_DISPINTERFACE_GetTICount
00403364  6F2E3ADC  MSVBVM60.BASIC_DISPINTERFACE_GetTypeInfo
00403368  6F2AF26C  MSVBVM60.BASIC_CLASS_GetIDsOfNames
0040336C  6F2AF141  MSVBVM60.BASIC_CLASS_Invoke
00403370  00401484  Project1.00401484             ;first user function on class (+0x1c)
00403374  00000000
00403378  00000000
403370 holds a pointer to code
offset          instruction byte dump        disassembly
--------------------------------------------------------
00401484   . E9 A7090000                   JMP Project1.Class1::x  (resolves to 0x401E30 could patch to hook here..)
actual function body
00401E30     55             PUSH EBP
00401E31   . 8BEC           MOV EBP,ESP
00401E33   . 83EC 0C        SUB ESP,0C
00401E36   . 68 F6104000    PUSH Project1.___vbaExceptHandler      
...
For a form the vtable is different such as:
Public a As Long

Private Sub Form_Load()
    a = &H11223344
    InputBox "", "", Hex(ObjPtr(Me))
    End
End Sub

Function x(a)
    DoEvents
End Function
ObjPtr(form)
$ ==>    >004032E4  OFFSET Project1.___vba@0763FC74
$+4      >00000000
$+8      >00689784
$+C      >02C0CA34
$+10     >02C0C9BC
$+14     >00000000
$+18     >00000000
$+1C     >6F2BAE80  MSVBVM60.6F2BAE80
$+20     >00000007
$+24     >00000001
$+28     >00000000
$+2C     >0000100F
$+30     >00000000
$+34     >11223344   <-- variable a

Code:

$4032E4 6F2A306E  MSVBVM60.BASIC_CLASS_QueryInterface
$+4      >6F2A2F45  MSVBVM60.Zombie_AddRef
$+8      >6F2A2D18  MSVBVM60.Zombie_Release
$+C      >6F352FE1  MSVBVM60.BASIC_DISPINTERFACE_GetTICount
$+10     >6F2E3ADC  MSVBVM60.BASIC_DISPINTERFACE_GetTypeInfo
$+14     >6F2AF26C  MSVBVM60.BASIC_CLASS_GetIDsOfNames
$+18     >6F2AF141  MSVBVM60.BASIC_CLASS_Invoke
$+1C     >6F3A6C14  MSVBVM60.6F3A6C14
...
$+6F8    >00401508  Project1.095D7F30    \__ get / let for public a as long 
$+6FC    >00401517  Project1.00401517    /
$+700    >0040153B  Project1.0040153B      ; 0040153B   . E9 40070000     JMP Project1.Form1::x
$+704    >0040152E  Project1.0040152E      ; 0040152E   . E9 4D050000     JMP Project1.Form1::Form_Load
$+708    >00000000
$+70C    >00000000
so vtable changes based on what kind of object it is with housekeeping stuff. (form vrs class) and what public variables you have plus methods implemented.

If you have a private variable in a form or class, and set its value in native code, the compiler will generate this:
0040199B  |. C746 34 443322>MOV DWORD PTR DS:[ESI+34],11223344
Where esi is the this pointer and local instance variables are stored at this+x with first slot being +34

If you instead declare the variable as
Public a As Long
a = &H11223344
You get the same thing in asm..However if you do
Public a As Long
me.a = &H11223344
Now COM comes into play and you get this..
00401A1B  |. 8B16           MOV EDX,DWORD PTR DS:[ESI]
00401A1D  |. 68 44332211    PUSH 11223344
00401A22  |. 56             PUSH ESI
00401A23  |. FF92 FC060000  CALL DWORD PTR DS:[EDX+6FC]  ;in a form so huge default vtable

0040149F   . 814424 04 3400>ADD DWORD PTR SS:[ESP+4],34  ;offset of instance var this+34 as above..
004014A7   . B9 60114000    MOV ECX,
004014AC   . FFE1           JMP ECX

00401160   .-FF25 2C104000  JMP DWORD PTR DS:[<&MSVBVM60.#307>]  ;  MSVBVM60.PutMem4

PutMem4
6F32EC11 > 8B4C24 04        MOV ECX,DWORD PTR SS:[ESP+4]
6F32EC15   8B4424 08        MOV EAX,DWORD PTR SS:[ESP+8]
6F32EC19   8901             MOV DWORD PTR DS:[ECX],EAX
6F32EC1B   33C0             XOR EAX,EAX
6F32EC1D   C2 0800          RETN 8

And the abbreviated vtable for the form
$ ==>    >6F23306E  MSVBVM60.BASIC_CLASS_QueryInterface
$+4      >6F232F45  MSVBVM60.Zombie_AddRef
$+8      >6F232D18  MSVBVM60.Zombie_Release
$+C      >6F2E2FE1  MSVBVM60.BASIC_DISPINTERFACE_GetTICount
$+10     >6F273ADC  MSVBVM60.BASIC_DISPINTERFACE_GetTypeInfo
$+14     >6F23F26C  MSVBVM60.BASIC_CLASS_GetIDsOfNames
$+18     >6F23F141  MSVBVM60.BASIC_CLASS_Invoke
$+1C     >6F336C14  MSVBVM60.6F336C14
...
$+6F8    >00401490  Project1.00401490  ;get a using GetMem4
$+6FC    >0040149F  Project1.0040149F  ;let a using PutMem4
$+700    >004014B6  Project1.004014B6  ;form_load
$+704    >00000000
And just to clarify objptr(me)
$ ==>    >004022F0  Project1.004022F0 ;points to vtable
$+4      >00000000
$+8      >005B5B0C  ;points to $+1C
$+C      >0227C9EC  -> 66068960  MSVBVM60.??_7CUnkDesk@@6B@
$+10     >0227C974  -> 0224C170 -> obj3
$+14     >00000000
$+18     >00000000
$+1C     >660682E0  MSVBVM60.??_7PRIVATE_UNKNOWN@BASIC_CLASS@@6B@
$+20     >00000006  ; com obj reference count (AddRef@CEnumConPnts)
$+24     >00000001
$+28     >00000000
$+2C     >0000100F
$+30     >00000000
$+34     >00000000  ;first user variable data slot

660682E0  >66007ED0  MSVBVM60.?QueryInterface@PRIVATE_UNKNOWN@BASIC_CLASS@@UAGJABU_GUID@@PAPAX@Z
$+4      >66001B4B  MSVBVM60.?AddRef@CEnumConPnts@@UAGKXZ
$+8      >66002F60  MSVBVM60.?Release@PRIVATE_UNKNOWN@BASIC_CLASS@@UAGKXZ
$+C      >660E2930  MSVBVM60.?GetClassInfoA@PRIVATE_UNKNOWN@BASIC_CLASS@@UAGJPAPAUITypeInfo@@@Z


obj3: 0224C170 66057CDE MSVBVM60.?QueryInterface@DESK@@UAGJABU_GUID@@PAPAX@Z 0224C174 66001B35 MSVBVM60.?AddRef@DESK@@UAGKXZ 0224C178 66001B1A MSVBVM60.?Release@DESK@@UAGKXZ 0224C17C 660E26F7 MSVBVM60.BASIC_DISPINTERFACE_GetTICount 0224C180 660B36C3 MSVBVM60.?GetTypeInfo@DESK@@UAGJIKPAPAUITypeInfo@@@Z 0224C184 6605E448 MSVBVM60.?GetIDsOfNames@DESK@@UAGJABU_GUID@@PAPAGIKPAJ@Z 0224C188 660579F3 MSVBVM60.?Invoke@DESK@@UAGJJABU_GUID@@KGPAUtagDISPPARAMS@@PAUtagVARIANT@@PAUtagEXCEPINFO@@PAI@Z 0224C18C 66019A57 MSVBVM60.?HctlDemandLoad@DESK@@UAEJPAPAUCTL@@@Z 0224C190 6609CF0C MSVBVM60.?SetPropA@CVBControlDefNoRefCount@@EAEJHTtagDATA@@@Z 0224C194 6609CF0C MSVBVM60.?SetPropA@CVBControlDefNoRefCount@@EAEJHTtagDATA@@@Z 0224C198 6609CF0C MSVBVM60.?SetPropA@CVBControlDefNoRefCount@@EAEJHTtagDATA@@@Z 0224C19C 6609CF0C MSVBVM60.?SetPropA@CVBControlDefNoRefCount@@EAEJHTtagDATA@@@Z 0224C1A0 6609CF0C MSVBVM60.?SetPropA@CVBControlDefNoRefCount@@EAEJHTtagDATA@@@Z 0224C1A4 6609CF0C MSVBVM60.?SetPropA@CVBControlDefNoRefCount@@EAEJHTtagDATA@@@Z 0224C1A8 660637C8 MSVBVM60.?GetPalette@CVBControlDefNoRefCount@@EAEPAUHPALETTE__@@XZ 0224C1AC 66048AC4 MSVBVM60.EbLibraryUnload 0224C1B0 007A5168 0224C1B4 007A5198 0224C1B8 007A51C8

So the objptr is a data block that actually contains pointers to several COM interfaces, along with the reference count and then local class variables, each stored per instance. The vtable itself is stored independently of the instance data makes sense.




Comments: (0)

 
Leave Comment:
Name:
Email: (not shown)
Message: (Required)
Math Question: 27 + 13 = ? followed by the letter: U 



About Me
More Blogs
Main Site
Posts: (year)
2023 (3)
     PublicBytes struct
     DispCallFunc
     VB6 Class Instances
2022 (6)
     VB6 Implements
     vbdec remote scripting
     VB6 Stubs BS
     VB6 TypeInfo
     VB6 VTable Layout
     Yara isPCode rule
2021 (4)
     VB6 Hijacking
     rtcTypeName
     VB6 Gosub
     VB App object
2020 (6)
     AutoIT versions
     IDA JScript 2
     Using VB6 Obj files from C
     Vb6 PCode Internals
     Yara Corrupt Imports
     Yara Undefined values
2019 (6)
     Yara WorkBench
     SafeArrayGetVartype
     vb6 API and call backs
     PrintFile
     ImpAdCallNonVirt
     UConnect Disable Cell Modem
2017 (5)
     IDA python over IPC
     dns wildcard blocking
     64bit IDA Plugins
     anterior lines
     misc news/updates
2016 (4)
     KANAL Mod
     Decoders again
     CDO.Message Breakpoints
     SysAnalyzer Updates
2015 (6)
     SysAnalyzer and Site Updates
     crazy decoder
     ida js w/dbg
     flash patching #2
     JS Graphing
     packet reassembly
2014 (5)
     Delphi IDA Plugin
     scdbg IDA integration
     API Hash Database
     Winmerge plugin
     IDACompare Updates
2013 (9)
     Guest Post @ hexblog
     TCP Stream Reassembly
     SysAnalyzer Updates
     Apilogger Video
     Shellcode2Exe trainer
     scdbg updates
     IDA Javascript w/IDE
     Rop Analysis II
     scdbg vrs ROP
2012 (13)
     flash patching
     x64 Hooks
     micro hook
     jmp api+5 *2
     SysAnalyzer Updates
     InjDll runtime config
     C# Asm/Dsm Library
     Shellcode Hook Detection
     Updates II
     findDll
     Java Hacking
     Windows 8
     Win7 x64
2011 (19)
     Graphing ideas
     .Net Hacking
     Old iDefense Releases
     BootLoaders
     hll shellcode
     ActionScript Tips
     -patch fu
     scdbg ordinal lookup
     scdbg -api mode
     Peb Module Lists
     scdbg vrs Process Injection
     GetProcAddress Scanner
     scdbg fopen mode
     scdbg findsc mode
     scdbg MemMonitor
     demo shellcodes
     scdbg download
     api hashs redux
     Api hash gen
2010 (11)
     Retro XSS Chat Codes
     Exe as DLL
     Olly Plugins
     Debugging Explorer
     Attach to hidden process
     JS Refactoring
     Asm and Shellcode in CSharp
     Fancy Return Address
     PDF Stream Dumper
     Malcode Call API by Hash
     WinDbg Cheat Sheet
2009 (1)
     GPG Automation