PublicBytes struct


Author: David Zimmer
Date: 01.28.23 - 9:49pm



So i am looking at the Object.aPublicBytes structure. It contains type data that is used during tear down to free resources (ie prevent memory leaks)

The types of some kinds of (public and private) variables can be inferred from its information. bytes and longs etc will not have entries. Strings, objects, and arrays will have embedded information however.

Consider the following (in a module)

Private s As String
Private d As Long
Private c As New Collection

Sub sets()
    s = "tesT"
    d = 3
    c.Add s
End Sub

4017B8  008   aPublicBytes     401914
4017C0  010   aModulePublic    402024 - data section

00402024 (+0)  004FF90C  UNICODE "tesT"
00402028 (+4)  00000003
0040202C (+8)  004FF930 -> vtable for collection object

.text:00401914                 dw 14h |--;total data size - header
.text:00401916                 dd 10h |  ;size in mem of live vars?
.text:0040191A                 dd 2   |  ;entries
.text:0040191E                 dw 0   |__;requires alloc 660625AD 
.text:00401920                 dw 0   ;data offset - variable data
.text:00401922                 dw 1   ;string
.text:00401924                 dw 8   ;data offset
.text:00401926                 dw 3   ;object
So (for a module) aModulePublic points to the address in the data section where the private variables will be stored. aPublicBytes points to the structure describing the type bytes for the private vars.

Only 2 entries are represented because only two require cleanup.

We can infer there are intrinsic types since the data offset for object 2 is +8 bytes in.

type bytes:
    1 = string
    3 = object
    2 = variant
    0x105 = array type follows
Things get complicated once you get into an array, and crazy if you get an array of UDT types.
Private Type x
    a As Long
    b As String
End Type

Dim o() As x

.text:00401694 word_401694     dw 10h                 
.text:00401696                 dw 8
.text:00401698                 dw 0
.text:0040169A                 dw 1
.text:0040169C                 dw 8
.text:0040169E                 dw 2C04h
.text:004016A0                 dw 4
.text:004016A2                 dw 1
.text:004016A4 Module1_PubBytes dw 2Ch
.text:004016A6                 dw 8
.text:004016A8                 dw 0
.text:004016AA                 dw 1
.text:004016AC                 dw 0
.text:004016AE                 dw 1000h
.text:004016B0                 dw 0
.text:004016B2                 dw 2105h
.text:004016B4                 dw 0
.text:004016B6                 dw 0FFFFh
.text:004016B8                 dw 2069h
.text:004016BA                 db 0
.text:004016BB                 db    0
.text:004016BC                 dd offset word_401694 IRecordInfo Desc?
.text:004016C0                 db 0
.text:004016C1                 db    0
.text:004016C2                 db    0
.text:004016C3                 db    0
.text:004016C4                 db    0
.text:004016C5                 db    0
.text:004016C6                 db    0
.text:004016C7                 db    0
.text:004016C8                 db    0
.text:004016C9                 db    0
.text:004016CA                 db    0
.text:004016CB                 db    0
.text:004016CC                 db    0
.text:004016CD                 db    0
.text:004016CE                 db    0
.text:004016CF                 db    0
I did some debugging on this just to verify its usage. For more refer to
'RESDESCTB - Resource Descriptor Table?
.text:66061E42 ; void __thiscall RESDESCTBL::DestructItem(
   RESDESCTBL *this, 
   void *aModulePublic, 
   struct RESDESC *a3, 
   unsigned int *a4
)
There is also a RESDESCTBL::ConstructItem which is probably used for initialization and allocation of some types such as say Private x(5) As Long. So there will be rich type information in there which makes this more delicious

Right now I am mostly looking at data variations from compiling different combinations and looking for data patterns since its quicker. An array of UDT where the UDT does not require any cleanup of its own is easy
Private Type x
    a As Long
    b As Long
End Type

Dim o() As x

.text:004016A0                 dw 16h
.text:004016A2                 dw 8
.text:004016A4                 dw 0
.text:004016A6                 dw 1
.text:004016A8                 dw 0
.text:004016AA                 dw 0
.text:004016AC                 dw 0
.text:004016AE                 dw 105h
.text:004016B0                 dw 0
.text:004016B2                 dw 0
.text:004016B4                 dw 0
.text:004016B6                 dw 0
We already list public variables from entries from the IDispatch implementation, so we would have to ignore some of these selectively as duplicates as well...

It is enticing though to extract var types and data offsets for listing in the UI and potentially extracting for the live class instances form. We can not know the scoping (private/public/global) since the compiler enforces that. If we have a live instance running, I can call TypeName() remotely for object types.

Not sure if I care enough to handle the crazy UDT cases but it looks like I already have enough info to extract the other bits reliably...

I know I should probably pick a more relevant target for research, I am basically an archaeologist at this point. But there are still some interesting things to squeeze out of the runtime and it is a good puzzle so...I basically wanted this for 20yrs and once I move on to the next project this info will go stale in my mind so I guess its now or never.

Another example of an array to construct:

Dim x(&H11223344 To &H22334455) As Integer '11111112 elements

.text:0040165C                 dw 38h
.text:0040165E                 dw 20h
.text:00401660                 dw 1  ; 660625AD cmp [esi+6], ax
.text:00401662                 dw 1  
.text:00401664                 dw 0
.text:00401666                 dw 0  ; RescDesctbl ends here
.text:00401668                 dw 4  ; 660625B1 lea edi, [esi+0Ch]
.text:0040166A                 dw 5  ; 6605606D MOV AX,WORD PTR DS:[ESI+2]
.text:0040166C                 dw 0
.text:0040166E                 dw 0
.text:00401670                 dw 0  ; 660560F2  TEST BYTE PTR DS:[ECX+8],60
.text:00401672                 dw 0
.text:00401674                 dw 0
.text:00401676                 dw 0  ;end of struct 2 (based on ..x670 flag)
.text:00401678                 dw 1   dims - raw safe array struct
.text:0040167A                 dw 92h features? FADF_HAVEVARTYPE | FADF_FIXEDSIZE | FADF_STATIC ? 660560B2 MOV AX,WORD PTR DS:[EDI+2]
.text:0040167C                 dw 2 \_ element size - 4 for long
.text:0040167E                 dw 0 /
.text:00401680                 dw 0 \_locks
.text:00401682                 dw 0 /
.text:00401684                 dw 0 \_pvdata
.text:00401686                 dw 0 /
.text:00401688                 dd 11111112h ;Elements count (SafeArrayBound struct)
.text:0040168C                 dd 11223344h ;lbound
.text:00401690                 dw 2 VT_i2 - 3: VT_i4 if long
.text:00401692                 dw 0

Private Type SafeArray
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    cLocks As Long
    pvData As Long
End Type

Private Type SAFEARRAYBOUND 'directly follows SafeArray struct, one per dimension
  cElements As Long
  lLbound As Long
End Type

https://learn.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-safearray






Comments: (0)

 
Leave Comment:
Name:
Email: (not shown)
Message: (Required)
Math Question: 29 + 54 = ? followed by the letter: V 



About Me
More Blogs
Main Site
Posts: (All)
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 )
2019 ( 6 )
2017 ( 5 )
2016 ( 4 )
2015 ( 6 )
2014 ( 5 )
2013 ( 9 )
2012 ( 13 )
2011 ( 19 )
2010 ( 11 )
2009 ( 1 )