Re: Pre-execution callback as a certain API and post as another one when wrapping

37 views
Skip to first unread message
Message has been deleted

assad.hashm...@gmail.com

unread,
Jul 27, 2021, 6:49:30 AM7/27/21
to DynamoRIO Users
Hi Nicola,

Does this behaviour only happen for GetUserName(A/W) and GetAdapterAddresses()?

If you can test with different Windows API functions and it's the same
behaviour as for GetUserName(A/W) and GetAdapterAddresses() then it's more
likely an issue with the client rather than something related to the particular
Windows API functions you are wrapping.

At this stage I can only suggest that you check a few things and do some
dr_printf() debugging/tracing in the client to make sure the name is as you
expect, e.g.
- The symbol from the iterator loop has the name you expect.
- Make sure check_names() does not alter the sym pointer.
- The bool return from drwrap_wrap_ex() is true to confirm the wrap registration was successful.

If the behaviour only happens for GetUserName(A/W) and GetAdapterAddresses()
then it's worth checking what these functions could be doing e.g. with memory
and pointers, as compared to Windows API functions which wrap as expected.

On Monday, July 26, 2021 at 8:45:35 PM UTC+1 Nicola Bottura wrote:
Hi all,

I'm writing a DR client that wraps some specific Microsoft APIs but I have encountered a problem with some of them.
In particular, with GetUserName(A/W) and GetAdapterAddresses.
What happens is that I see these APIs in the pre-execution callback(I pass the name of the symbol as user_data with drwrap_wrap_ex, and so I can check it) but in the post-execution callback I see a different API with respect to the one that was in the pre-phase and so I never execute the post-phase of certain APIs.

For example, in the case of GetUserName I have noticed that if I also wrap GlobalMemoryStatusEx, I enter as it in the post phase instead of GetUserName(for GetAdapterAddresses I enter the post as _wcsicmp).
The problem is that each API in which I'm interested in wrapping in the post phase is managed by my client in different ways and in this case, since GetUserName go in post as GlobalMemoryStatusEx, instead of performing, for example, the changes on the buffer that is one of its arguments(of GetUserName), it perform different changes that I have written for the post phase of GlobalMemoryStatusEx and in this way my client reports incorrect results.

The code for wrapping I use is the following:
dr_symbol_export_iterator_t *exp_iter = dr_symbol_export_iterator_start(mod->handle);
while (dr_symbol_export_iterator_hasnext(exp_iter))
{
dr_symbol_export_t *sym = dr_symbol_export_iterator_next(exp_iter);
app_pc towrap = (app_pc)dr_get_proc_address(mod->handle, sym->name);

char *the_name = _strdup(sym->name);

if (towrap != NULL && check_names(sym))
{
drwrap_wrap_ex(towrap, wrap_pre, wrap_post, (void *) the_name, 0);
 }

"check_name" simply check if sym->name is equal to some API names like GetUserName, GlobalMemoryStatusEx, GetModuleFileName and many others for which I'm interested in wrapping.

I checked with Ida and drltrace the program I'm testing with my client to see if GetUserName calls GlobalMemoryStatusEx, but it does not.
I also tried to copy the examples(adapted for my case) that are on Github, wrap.c and sslijack.c but it gives the same resutls.

I don't understand what I did wrong, maybe I'm managing badly the wrapping or the checks for the name of the API that I want to wrap, I don't know.
This behavior is pretty strange because obviously if I don't wrap GlobalMemoryStatusEx then I enter the post callback of GetUserName.
The name of the API is in a c struct allocated and registered with TLS using the DR APIs in this way I can get it anywhere:
hooked_func *current_func = (hooked_func *)drmgr_get_tls_field(drcontext, tls_idx);

I hope I was clear, sorry for bothering you and thanks for your patience, best regards,
Nicola

Nicola Bottura

unread,
Jul 31, 2021, 5:11:48 AM7/31/21
to DynamoRIO Users
Hi Assad,

thanks for replying, I guess I found the problem.
Trying your suggestions I decided to print also the module from which every API that is successfully wrapped is loaded, and I found out that most of the APIs are loaded from more than a dll, causing them to be wrapped more than just one time.
As an example, the API that "steal" the post phase of GetUserName(A/W) is GlobalMemoryStatusEx, that is wrapped for kernel32.dll and kernelbase.dll.
This API in kernel32.dll is a stub exported and the real implementation is in kernelbase.dll, but if I wrap the version of this dll happens the problem, but if I wrap only the version of kernel32.dll my client behave correctly.
My guess about this is related to the fact that the programs I test imports this API from kernel32.dll, so now the question is, how can I understand if an module is imported by the program I test with DR? 
Because checking with Ida I have seen that the program never imports something from kernelbase obviously, but I want to understand this at run time and exclude the dlls that I don't need if possible.

Thanks again, best regards,
Nicola

Reply all
Reply to author
Forward
0 new messages