Results 1 to 9 of 9

Thread: Questions about SysAllocString functions in VB6

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Questions about SysAllocString functions in VB6

    The three functions SysAllocString, SysAllocStringByteLen, and SysAllocStringLen all allocate a BSTR and initialize it with a copy of another string. When such a BSTR is done being used, the program that called the allocation function is expected to call a deallocation function (SysFreeString) to get rid of the BSTR. Otherwise it can lead to memory leaks. So how does that work in VB6? I know VB6 already internally allocates strings (and VB6 uses BSTR as the type of string it uses), and deallocates them when they are no longer needed. So if I follow protocol and free a string previously allocated with one of the SysAllocString functions will I crash my program when I call SysFreeString, because it will get freed twice, once when VB6 frees it, and once when I call SysFreeString? Or am I more likely to cause a problem by not freeing it, and getting a memory leak, because VB6 is only aware of strings allocated by VB6 and not when the program calls SysAllocString (or SysAllocStringLen or SysAllocStringByteLen)?

  2. #2
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: Questions about SysAllocString functions in VB6

    Hi Ben,

    The only one of the three that I've routinely used is the SysAllocStringByteLen. But it's always been my understanding that SysFreeString and VB6 are going to de-allocate a string in exactly the same way, so don't do it twice. If you insist on calling SysFreeString, then you should use VarPtr and PutMem4 to put a 0& into the string's pointer to manually "de-reference" it for VB6.

    Here's some code where I use SysAllocStringByteLen:

    Code:
    
    Private Function GetUniCaption() As String ' Get Unicode string from caption.
        Const WM_GETTEXT As Long = &HD
        Const WM_GETTEXTLENGTH As Long = &HE
        Dim lLen As Long
        Dim lPtr As Long
        lLen = DefWindowProcW(opt.hWnd, WM_GETTEXTLENGTH, 0&, ByVal 0&) ' Get length of caption.
        If lLen Then ' Must have length.
            lPtr = SysAllocStringLen(0&, lLen) ' Create a BSTR of that length.
            PutMem4 ByVal VarPtr(GetUniCaption), ByVal lPtr ' Make the property return the BSTR.
            DefWindowProcW opt.hWnd, WM_GETTEXT, lLen + 1&, ByVal lPtr ' Call the default Unicode window procedure to fill the BSTR.
        End If
    End Function
    
    
    As you can see, I let VB6 deal with un-allocating the GetUniCaption string.

    Good Luck,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  3. #3
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Questions about SysAllocString functions in VB6

    I tend to use them this way:

    Code:
    Option Explicit
    
    'Requires: Edanmo's OLE interfaces & functions v1.81
    
    Private Sub Form_Load()
        Dim S1 As String
        Dim S2 As String
    
        S1 = "abc"
        S2 = olelib.SysAllocString(StrPtr(S1))
        Debug.Print S2
        'Safe if not linked LARGEADDRESSAWARE:
        S2 = olelib.SysAllocStringLen(StrPtr(S1) + 2, 1)
        Debug.Print S2
    End Sub
    Less fiddling around.

  4. #4

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    Re: Questions about SysAllocString functions in VB6

    Quote Originally Posted by Elroy View Post
    Hi Ben,

    The only one of the three that I've routinely used is the SysAllocStringByteLen. But it's always been my understanding that SysFreeString and VB6 are going to de-allocate a string in exactly the same way, so don't do it twice. If you insist on calling SysFreeString, then you should use VarPtr and PutMem4 to put a 0& into the string's pointer to manually "de-reference" it for VB6.

    Here's some code where I use SysAllocStringByteLen:

    Code:
    
    Private Function GetUniCaption() As String ' Get Unicode string from caption.
        Const WM_GETTEXT As Long = &HD
        Const WM_GETTEXTLENGTH As Long = &HE
        Dim lLen As Long
        Dim lPtr As Long
        lLen = DefWindowProcW(opt.hWnd, WM_GETTEXTLENGTH, 0&, ByVal 0&) ' Get length of caption.
        If lLen Then ' Must have length.
            lPtr = SysAllocStringLen(0&, lLen) ' Create a BSTR of that length.
            PutMem4 ByVal VarPtr(GetUniCaption), ByVal lPtr ' Make the property return the BSTR.
            DefWindowProcW opt.hWnd, WM_GETTEXT, lLen + 1&, ByVal lPtr ' Call the default Unicode window procedure to fill the BSTR.
        End If
    End Function
    
    
    As you can see, I let VB6 deal with un-allocating the GetUniCaption string.

    Good Luck,
    Elroy
    I just compiled an EXE from my test program that uses SysAllocStringByteLen, and looked at it in a debugger (OllyDbg). When I got to the CALL to SysAllocStringByteLen, I noted what the address was and used OllyDbg's memory viewer to verify that the string was there. Then I stepped until I got to VB's own internal function that free's strings that it always calls at the end of a Sub or Function, called __vbaFreeStrList. I stepped into that function and watched what happened. It loops through every string created previously, that is no longer used, and in each iteration of the loop it calls SysFreeString on the corresponding string pointer. I noticed that one of the pointers it used in this process was the one previously returned by SysAllocStringByteLen. And this makes sense. When a function (such as SysAllocStringByteLen) has a return type of String, if that function was an a Windows API function (or any other DLL function declared with a Declare statement) then VB6 assumes that it was an ASCII string that was returned, and automatically converts it to Unicode, meaning that the original ASCII string is no longer used, so VB6 adds it to the list of strings that get freed (deallocated) at the end of whatever VB Sub or Function had called the API/DLL function in question. Because VB6 takes care of calling SysFreeString on the string returned from any DLL function who's return type is String, that means there is never any need to manually call SysFreeString in a VB6 program. That only is required in programming languages that don't automatically free strings, such as C++.

    Another interesting thing I noticed is that when a string is freed that doesn't mean that the memory region for that string automatically gets zeroed. After the string was freed, I used OllyDbg's memory viewer to see if the string was still present at the address that it was at prior to freeing, and it turns out that yes it is still there. So this could be a security hole when typing a password in a password field. Freeing a BSTR from memory does not automatically clear the contents of the BSTR, it just marks it as not currently used, so it's ok for the system to reallocate in the future. If I were to type a password in a program in VB6, and then copied it into a section of memory I set up to be secure (a region I would manually clear when not in use), the original string (which is a BSTR) associated with the text box I typed the password into would still contain the password, even after VB6 freed it. This potentially would give a hacker a way to use malware to dump a process's memory (via the ReadProcessMemory API call), and after searching through the memory dump they could get my password.

    This also means that VB6 calls to Windows API functions aren't secure, because every time an API is called with type String as either an argument or return value, VB6 automatically does Unicode to ASCII conversions and ASCII to Unicode conversions, and every single one of those conversions allocates an additional BSTR to hold the output of the conversion. So if you use Windows API calls or any other calls to external DLL functions to process a password, there will be multiple copies of your password (as both Unicode and ASCII strings) laying around in that process's address space, just waiting for a malware program to call ReadProcessMemory to dump your password. Because VB6 does not reveal the locations of these internal copies of strings to the programmer, there is no way for me to just call ZeroMemory on one of these string pointers to clear the memory. So they stay in memory until that program closes. And they might (under some conditions) even get saved to the harddrive, in the Windows paging file, such as if you have a lot of programs running and there's not enough physical memory in your computer's RAM chips to hold all of the contents of all of the running programs.
    Last edited by Ben321; Dec 12th, 2017 at 02:59 PM.

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Questions about SysAllocString functions in VB6

    You might find this article interesting?
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: Questions about SysAllocString functions in VB6

    Hi Ben,

    Gosh, you're competing with me for the word-length of posts. However, I did read it.

    Yes, you're correct about lots of string copying going on when you use the ...A version of API calls. However, if you use the ...W version along with StrPtr(), you circumvent most (if not all) of this. Who knows what an API call does with data, but I'd suspect they're pretty efficient, and don't make copies of strings unless there's a compelling reason.

    Also, regarding a de-allocated string, I don't even have to check, and I just feel certain that you're correct (i.e., that the original string is left in un-allocated memory). What comes to mind for me is to use some left-hand-Mid$() to take care of that. Possibly something like:

    Code:
    
    Option Explicit
    
    Private Sub Form_Load()
        Dim sPass As String
    
        sPass = "MyPassword"
    
        Mid$(sPass, 1, Len(sPass)) = Space$(Len(sPass))
    
        MsgBox sPass
    
    
    End Sub
    
    Now, in my example, you've still got the problem of the literal-constant being in memory, but you typically won't have that problem. However, I'm not entirely clear on the internal workings of a TextBox, and clearing that out of all memory may be another issue.

    Best Regards,
    Elroy
    Last edited by Elroy; Dec 13th, 2017 at 10:35 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Questions about SysAllocString functions in VB6

    Quote Originally Posted by Ben321 View Post
    This also means that VB6 calls to Windows API functions aren't secure, because every time an API is called with type String as either an argument or return value, VB6 automatically does Unicode to ASCII conversions and ASCII to Unicode conversions, and every single one of those conversions allocates an additional BSTR to hold the output of the conversion. So if you use Windows API calls or any other calls to external DLL functions to process a password, there will be multiple copies of your password (as both Unicode and ASCII strings) laying around in that process's address space, just waiting for a malware program to call ReadProcessMemory to dump your password. Because VB6 does not reveal the locations of these internal copies of strings to the programmer, there is no way for me to just call ZeroMemory on one of these string pointers to clear the memory. So they stay in memory until that program closes. And they might (under some conditions) even get saved to the harddrive, in the Windows paging file, such as if you have a lot of programs running and there's not enough physical memory in your computer's RAM chips to hold all of the contents of all of the running programs.
    This pretty much holds true when working with whatever security library -- e.g. openssl.

    When you set a password char to a textbox, its contents hopefully is stored w/ some form of encryption. Calling `GetWindowText` potentially reveals the password but this output buffer (string) becomes your responsibility. Try not copy it too much, don't concat it left and right or even better -- keep it encrypted.

    Elroy already mentioned what you can do with the string variable at the end of it's short-lived lifecycle -- lets call the function `WipeString`
    vb Code:
    1. Public Sub WipeString(sText As String)
    2.     If Len(sText) <> 0 Then
    3.         Mid$(sText, 1, Len(sText)) = Space$(Len(sText))
    4.     End If
    5. End Sub
    cheers,
    </wqw>

  8. #8
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,852

    Re: Questions about SysAllocString functions in VB6

    Yeah, I like wqweto's WipeString function. Just be careful to not put a ByVal on the "sText As String" or you'll make a copy.

    Just thought that was worth saying, for someone who is really trying to wipe memory.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  9. #9
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Questions about SysAllocString functions in VB6

    Better yet, make use of the Data Protection API (DPAPI). See Windows Data Protection.

    The idea here is that as soon as you accept and process things like credential data you encrypt it, and only decrypt it when you need to look at it again, after which you re-encrypt it or wipe it. Since this does not "encrypt in place" you still have to call RtlZeroMemory to "wipe" the plain-text buffer before returning it to the String pool or heap for re-use.

    This way you don't leave sensitive data lying around unecrypted even while you have it in active memory. The bonus is you can also persist the encrypted data to an INI file other other long term storage.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width