VB6 Implements


Author: David Zimmer
Date: 12.03.22 - 5:48am



So how does VB6 handle the Implements keyword?

The VTable and PrivObjs both take on changes first off.

'cPrintSample.cls
'Implements IVBPrint
'Private Property Let IVBPrint_Column(ByVal RHS As Long)
'Private Property Get IVBPrint_Column() As Long
'Private Sub IVBPrint_WriteText(ByVal strText As String)
'Private Sub mytest(x As String)

'$ ==>    >7013306E  MSVBVM60.BASIC_CLASS_QueryInterface
'$+4      >70132F45  MSVBVM60.Zombie_AddRef
'$+8      >70132D18  MSVBVM60.Zombie_Release
'$+C      >701E2FE1  MSVBVM60.BASIC_DISPINTERFACE_GetTICount
'$+10     >70173ADC  MSVBVM60.BASIC_DISPINTERFACE_GetTypeInfo
'$+14     >7013F26C  MSVBVM60.BASIC_CLASS_GetIDsOfNames
'$+18     >7013F141  MSVBVM60.BASIC_CLASS_Invoke
'$+1C     >00000000
'$+20     >00000000
'$+24     >00000000
'$+28     >00401614  Project1.00401614
'$+2C     >00401621  Project1.00401621
'$+30     >0040162E  Project1.0040162E
'$+34     >004030D0  Project1.004030D0

VTable Dump: (Beta)
	[0] IUnknown.QueryInterface
	[4] IUnknown.AddRef
	[8] IUnknown.Release
	[C] IDispatch.GetTypeInfoCount
	[10] IDispatch.GetTypeInfo
	[14] IDispatch.GetIDsOfNamese
	[18] IDispatch.Invoke
	[Get/Let/Set Null Entries] Implements IVBPrint{000204F0-0000-0000-C000-000000000046}   
	[28] - MemID:68030000 - Public Property Let IVBPrint_Column(ByVal RHS As Long) 
	[2c] - MemID:68030000 - Public Property Get IVBPrint_Column()  As Long
	[30] - MemID:60030002 - Public Sub IVBPrint_WriteText(ByVal strText As String) 
	[34] - cPrintSample.proc_4030D0
	
Structure dump of Public VarTypes: 
	VA       Off   Name    = Value
	402464   000   lpName = 402674 -> Implements IVBPrint {000204F0-0000-0000-C000-000000000046}
	402468   004   nul1 = 0
	40246C   008   nul2 = FFFFFFFF
	402470   00C   index = FFFF
	402472   00E   unk1 = FF
	402473   00F   unk2 = FF
	402474   010   unk3 = 2
	402476   012   vOff = FFFF    [Get/Let/Set Null Entries]
	402478   014   dataOffset = FFFFFFFF


So a fake public var with no vtable offsets was added (although it does inject 3 null entries in the actual vtable) and all of the private methods were converted to public and had type info added to teh PrivObj IDispatch type info.

I still need to see if the GUID was somehow added to the QueryInterface lookup list. They must have shoe horned this in as a special case to have created the fake public variable with the type information.

If you add another implements it will add another block of nulls in where other public prop get/let/set would usually be.

VTable Layout is:
  • IUnknown
  • IDispatch
  • Form/UserCtl related stuff
  • Public Variable Get/Let/maybe Set
  • Public functions
  • private functions
(I have added a vtable dump to the output if you click on the main Form/Class entry)

So actually the vtable layout rules get complicated with implements involved.

The interface functions are laid out according to the private object rules. IE sequential order in the source. If you interleave a regular private function in between, it will retain that vtable slot and the interface functions are not sequential. So even though they are listed in the type info as pub functions..they are not moved to the front of the vtable like actual public functions are.

Additionally if you
Public I as long
Implements IVBPrint
Private Sub mytest(x As String)
Private Property Let IVBPrint_Column(ByVal RHS As Long)
Private Property Get IVBPrint_Column() As Long
Private Sub IVBPrint_WriteText(ByVal strText As String)
Then the vtable will be in the same order as defined.
$+18     >7013F141  MSVBVM60.BASIC_CLASS_Invoke
$+1C     >00401728  Project1.0401728   ;get i as long 
$+20     >00401737  Project1.00401737  ;let i as long 
$+24     >00000000
$+28     >00000000
$+2C     >00000000
$+30     >0040174E  Project1.0040174E   ;JMP Project1.cPrintSample::mytest
$+34     >0040175B  Project1.0040175B
$+38     >00401768  Project1.00401768
$+3C     >00401775  Project1.00401775
And a final example of the reshuffling:
Source order:
Public i As Long
Implements IVBPrint
Private Property Let IVBPrint_Column(ByVal RHS As Long)
Public Function myPubFunc(x As Long)
Private Sub mytest(x As String)
Private Property Get IVBPrint_Column() As Long
Private Sub IVBPrint_WriteText(ByVal strText As String)

Actual VTable:
$ ==>    >7013306E  MSVBVM60.BASIC_CLASS_QueryInterface
$+4      >70132F45  MSVBVM60.Zombie_AddRef
$+8      >70132D18  MSVBVM60.Zombie_Release
$+C      >701E2FE1  MSVBVM60.BASIC_DISPINTERFACE_GetTICount
$+10     >70173ADC  MSVBVM60.BASIC_DISPINTERFACE_GetTypeInfo
$+14     >7013F26C  MSVBVM60.BASIC_CLASS_GetIDsOfNames
$+18     >7013F141  MSVBVM60.BASIC_CLASS_Invoke
$+1C     >00401740  Project1.00401740  ; get i
$+20     >0040174F  Project1.0040174F  ; let i
$+24     >00000000                     ; 3 null for Implements "pubVar"
$+28     >00000000
$+2C     >00000000
$+30     >00401773  Project1.00401773 JMP cPrintSample::myPubFunc
$+34     >00401766  Project1.00401766 JMP cPrintSample::IVBPrint_Column__Let
$+38     >00401780  Project1.00401780 JMP cPrintSample::mytest
$+3C     >0040178D  Project1.0040178D JMP cPrintSample::IVBPrint_Column__Get
$+40     >0040179A  Project1.0040179A JMP cPrintSample::IVBPrint_WriteText
If we only cared about the vtable offsets for public members its fine since they are given to us. But I kinda want to be able to accurately predict the full vtable including the entries for the private members.

Also note that the pubFunc entries, IVBPrint_Column will appear before myPubFunc. Which screws up the display anyway.
	VTable Dump: (Beta)
	[0] IUnknown.QueryInterface
	[4] IUnknown.AddRef
	[8] IUnknown.Release
	[C] IDispatch.GetTypeInfoCount
	[10] IDispatch.GetTypeInfo
	[14] IDispatch.GetIDsOfNamese
	[18] IDispatch.Invoke
	[Get 1C] Public i As Long  [+34] 
	[Let 20] Public i As Long  [+34] 
	[Get/Let/Set Null Entries] Implements IVBPrint{000204F0-0000-0000-C000-000000000046}  [+FFFFFFFF] 
	[34] - MemID:68030000 - Public Property Let IVBPrint_Column(ByVal RHS As Long) 
	[30] - MemID:60030001 - Public Function myPubFunc(x As Long)  As Variant -- out of order
	[3C] - MemID:68030000 - Public Property Get IVBPrint_Column()  As Long
	[40] - MemID:60030003 - Public Sub IVBPrint_WriteText(ByVal strText As String) 
	[40] - cPrintSample.proc_402E20 -- wrong should be 38
And Private Sub mytest is showing up in the wrong slot in my calculated dump. (mixing known offsets with calculated offsets..beta feature indeed...

This is painful..



I will update this post as I learn more about how the QueryInterface lookup on it was modified...

Damn it, so one more interesting thing. So if you implement an interface, you can access that interface directly and are handed a small mini interface of just that and IUnknown.

Dim p As IVBPrint
Set c = New cPrintSample
Set p = c 
debug.print Hex(ObjPtr(c)) 59B210
debug.print Hex(ObjPtr(p)) 59B250
	
$59B210  >00404424  OFFSET Project1.404424  = ObjPtr(c) main class
$+4      >00000000
$+8      >0059B22C
$+C      >02AE2E64
$+10     >02AE2E4C
$+14     >00000000
$+18     >00000000
$+1C     >7014AE80  MSVBVM60.7014AE80
$+20     >00000004
$+24     >00000000
$+28     >00000000
$+2C     >0000100F
$+30     >00000000
$+34     >00000000
$+38     >0040172C  Project1.0040172C
$+3C     >00000000
$+40     >00401764  Project1.00401764 (ObjPtr(p) = va:59B250) <-- IVBPrint interface

00404424 >7013306E  MSVBVM60.BASIC_CLASS_QueryInterface
...
0040445C  004017AF  Project1.004017AF JMP Project1.cPrintSample::IVBPrint_Column__Let
00404464  004017D6  Project1.004017D6 JMP Project1.cPrintSample::IVBPrint_Column__Get
00404468  004017E3  Project1.004017E3 JMP Project1.cPrintSample::IVBPrint_WriteText

00401764  004012CC  JMP to MSVBVM60.EVENT_SINK_QueryInterface
00401768  004012DE  JMP.&MSVBVM60.EVENT_SINK2_AddRef
0040176C  004012E4  JMP.&MSVBVM60.EVENT_SINK2_Release
00401770  004017DB  Project1.004017DB
00401774  004017A7  Project1.004017A7
00401778  004017CE  Project1.004017CE

 ;org esp+4 was 59B250 (this for IVbPrint) final is 59B211 why +1 from parent this?
004017DB   816C24 04 3F0000>SUB DWORD PTR SS:[ESP+4],3F
004017E3   E9 58190000      JMP Project1.cPrintSample::IVBPrint_WriteText

004017A7   816C24 04 3F0000>SUB DWORD PTR SS:[ESP+4],3F
004017AF   E9 7C160000      JMP Project1.cPrintSample::IVBPrint_Column__Let

004017CE   816C24 04 3F0000>SUB DWORD PTR SS:[ESP+4],3F
004017D6   E9 55180000      JMP Project1.cPrintSample::IVBPrint_Column__Get





Comments: (0)

 
Leave Comment:
Name:
Email: (not shown)
Message: (Required)
Math Question: 10 + 17 = ? followed by the letter: Y 



About Me
More Blogs
Main Site
Posts: (All)
2023 ( 4 )
2022 (5)
     VB6 Implements
     VB6 Stubs BS
     VB6 TypeInfo
     VB6 VTable Layout
     Yara isPCode rule
2021 (2)
     rtcTypeName
     VB6 Gosub
2020 (5)
     AutoIT versions
     IDA JScript 2
     Using VB6 Obj files from C
     Yara Corrupt Imports
     Yara Undefined values
2019 ( 6 )
2017 ( 5 )
2016 ( 4 )
2015 ( 5 )
2014 ( 5 )
2013 ( 9 )
2012 ( 13 )
2011 ( 19 )
2010 ( 11 )
2009 ( 1 )