-
July 14th, 2019, 01:12 PM
#1
[RESOLVED] EnumServicesStatusEx and Process Walking - How to allocate and free memory?
Got another question:
About Memory Management in EnumServicesStatusEx().
What's the best way to capture the amount of memory needed from the first call to EnumServicesStatusEx() (where the 5th and 6th arguments are NULL and 0 respectively)?
How should I allocate that memory to get around the if(GetLastError() == ERROR_MORE_DATA) scenario?
How can I safely and reliably free that allocated memory when I'm done parsing the Process struct and want to discard it?
-
July 14th, 2019, 02:05 PM
#2
EnumServicesStatusEx and Process Walking - How to allocate and free memory?
This is in C/C++:
I'm doing Process Walking ( https://docs.microsoft.com/en-us/win...rocess-walking ) through a PROCESSENTRY32 struct made with CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL).
Whenever we come across a process with the entry pEntry.szExeFile containing "SVCHost.exe" we call
EnumServicesStatusEx() twice, as shown in the below guide:
https://docs.microsoft.com/en-us/win...vicesstatusexa
Once with the 5th and 6th arguments set to NULL and 0 respectively.
How do I allocate memory to the LPENUM_SERVICE_STATUS_PROCESS struct so it's the right size to receive all the services each instance of SVCHost.exe might be hosting?
How do I destroy the LPENUM_SERVICE_STATUS_PROCESS struct when I'm done with it... OR how do I free the memory allocated to it so if the user repeats the above actions they aren't leaking memory?
Last edited by Arianax; July 14th, 2019 at 02:10 PM.
-
July 14th, 2019, 02:20 PM
#3
Re: [RESOLVED] CreateToolHelp32Snapshot and listing Services under Svchost.exe... How
From MSDN:
To determine the required size, specify NULL for this parameter and 0 for the cbBufSize parameter. The function will fail and GetLastError will return ERROR_MORE_DATA. The pcbBytesNeeded parameter will receive the required size.
It doesn't matter how you allocate. It may be malloc()/calloc() or LocalAlloc() or new(), whatever you want. What does matter is deallocation. It must correspond to the way of allocation, i.e. free() must go along with malloc(), delete with new, etc.
First you make a call with zero size to get the pcbBytesNeeded. Then you allocate the required memory block and repeat the call with actual buffer and its size. Then you make use of the returned data. Finally you deallocate.
An alternative approach may be to allocate only once, say 64kB, and iterate with this exact buffer until no more data reported. And only then you deallocate.
Last edited by Igor Vartanov; July 14th, 2019 at 02:37 PM.
Best regards,
Igor
-
July 14th, 2019, 03:01 PM
#4
Re: [RESOLVED] CreateToolHelp32Snapshot and listing Services under Svchost.exe... How
Could you provide sample allocation code?
I think I might be getting it wrong since I use the name of my LPENUM_SERVICE_STATUS_PROCESS struct as the handle to the memory allocation:
Code:
nameOfStruct = (LPENUM_SERVICE_STATUS_PROCESS) GlobalAlloc(GMEM_FIXED, cbBufSize);
calling GlobalFree(nameOfStruct) seems to result in somewhat random exceptions all over the program. Am I calling it in the wrong place, maybe?
Also: I only need to call EnumServicesStatusEx() with the NULL and 0 parameters ONCE in the whole loop, correct? Seems if I call it every loop then the size of nameOfStruct becomes very huge (like 5-10 megabytes).
Last edited by Arianax; July 14th, 2019 at 03:04 PM.
-
July 14th, 2019, 03:17 PM
#5
Re: EnumServicesStatusEx and Process Walking - How to allocate and free memory?
 Originally Posted by Arianax
...
How do I allocate memory to the LPENUM_SERVICE_STATUS_PROCESS struct so it's the right size to receive all the services each instance of SVCHost.exe might be hosting?
Well, you could set any size of the buffer, but if it would be less than required then look at the MSDN:
ERROR_MORE_DATA
The buffer is too small. Not all data in the active database could be returned. The pcbBytesNeeded parameter contains the number of bytes required to receive the remaining entries.
Victor Nijegorodov
-
July 14th, 2019, 04:31 PM
#6
Re: EnumServicesStatusEx and Process Walking - How to allocate and free memory?
Yes, I know.
Code:
EnumServicesStatusEx(SCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_ACTIVE, NULL, 0, &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle, NULL);
if(GetLastError() == ERROR_MORE_DATA)
{
cbBufSize = pcbBytesNeeded;
serviceStateList = (LPENUM_SERVICE_STATUS_PROCESS) GlobalAlloc(GMEM_FIXED, cbBufSize);
}
EnumServicesStatusEx(SCM, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_ACTIVE, (LPBYTE)serviceStateList, cbBufSize, &pcbBytesNeeded, &lpServicesReturned, &lpResumeHandle, NULL);
How do I empty serviceStateList and free the memory so the next time I start the loop the memory will be freed and LPENUM_SERVICE_STATUS_PROCESS will not contain any data?
-
July 14th, 2019, 11:21 PM
#7
Re: [RESOLVED] CreateToolHelp32Snapshot and listing Services under Svchost.exe... How
Why use globalalloc? Just use new/delete and check for ERROR_MORE_DATA and keep doubling the allocated size until it succeeds. Using pcbBytesNeeded doesn't guarantee success because the memory need may have changed before the api is called again.
-
July 15th, 2019, 01:50 AM
#8
Re: EnumServicesStatusEx and Process Walking - How to allocate and free memory?
Well, if you allocate memory with GlobalAlloc then you will reallocate it with GlobalReAlloc or free it with GlobalFree.
Besides, you could have a look at this code sample: https://github.com/microsoft/Windows...rviceProcess.c
Victor Nijegorodov
-
July 19th, 2019, 10:22 AM
#9
Re: EnumServicesStatusEx and Process Walking - How to allocate and free memory?
Found a fairly comprehensive set of functions() to do the requested operations now... especially thanks to your input @VictorN and @IgorVartanov :
Code:
if(handleName != INVALID_HANDLE_VALUE && handleName != 0
{
CloseHandle(handleName);
}
Also, in the special case of the Service Control Manager handle opened with OpenSCManager() function...:
Code:
if(scHandle != INVALID_HANDLE_VALUE && scHandle != 0)
{
CloseServiceHandle(scHandle);
}
We receive runtime Exception errors if the handles are already invalid or if we use CloseHandle()/FindClose() with the Service Control Manager handle...
Last edited by Arianax; July 19th, 2019 at 10:25 AM.
-
July 19th, 2019, 01:44 PM
#10
Re: [RESOLVED] EnumServicesStatusEx and Process Walking - How to allocate and free me
You can simplify your code by not checking for INVALID_HANDLE_VALUE or NULL before calling the appropriate close handle api.
If the value is INVALID_HANDLE_VALUE or NULL, the close handle family of APIs simply perform a no-op.
You can verify this by calling CloseHandle (or any if the other CloseXXX APIs) with NULL. To check INVALID_HANDLE_VALUE, call CloseHandle on a valid handle twice (as on the 2nd close, the handle will be INVALID_HANDLE_VALUE).
Not a big deal, but not having to do those checks keeps the code cleaner.
-
July 20th, 2019, 05:32 AM
#11
Re: [RESOLVED] EnumServicesStatusEx and Process Walking - How to allocate and free me
The code is still triggering a range of Exception Errors if it is run more than once during the same execution...
When I close the window that outputs the data from GetProcessNext() and EnumServicesStatusEx() I'm trying to free ALL structs/memory associated with those functions.
When I re-open that window it should re-execute the code to populate those structs/heap memory again for a fresh, updated set of Process information and Services information.
However, the second or subsequent times it is run it is VERY prone to triggering Exceptions all over the place (though not necessarily always).
Any idea what is causing this? I'm using VS2017 in Debug Mode.
Also, @Arjay, if I don't check for Invalid or NULL handles then Close Handle returns an Exception Error 'Invalid Handle'. That's also in VS2017 in Debug Mode. That's why I'm checking for Invalid/empty handles...
-
July 20th, 2019, 01:31 PM
#12
Re: [RESOLVED] EnumServicesStatusEx and Process Walking - How to allocate and free me
Set the handle to NULL after closing it.
If you cant run this code more than once, it probably means something isn't getting cleaned up (as you know). To this end, my approach is to leverage C++ and wrap the needed functionality inside a class and perform cleanup in the class destructor (with all variables initialized in the ctor).
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|