Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attach feature on Windows #725

Closed
derekbruening opened this issue Nov 28, 2014 · 13 comments · Fixed by #6244
Closed

attach feature on Windows #725

derekbruening opened this issue Nov 28, 2014 · 13 comments · Fixed by #6244

Comments

@derekbruening
Copy link
Contributor

From [email protected] on April 09, 2012 14:58:26

xref issue #38 : attach injection on Linux
xref issue #722 : internally-triggered attach

the problem with attach on windows of course is the inability to
maintain control across a callback return when the callback
occurred prior to attaching.

idea: have thin_client presence up front that hooks all alertable
syscalls. risk: there are many alertable syscalls and maybe we
don't really know all of them. probably best to hook all the
file i/o calls even though their alertability depends on their
args.

in absence of control up front, we could go ahead and try on windows and lose control briefly, counting on native_exec_syscalls like we do when we lose control on AppInit (though here there are multiple threads), and
just document the limitations to any users

Original issue: http://code.google.com/p/dynamorio/issues/detail?id=725

@derekbruening
Copy link
Contributor Author

From [email protected] on May 08, 2012 10:42:26

some ideas I've entertained:

** TODO how regain control?
*** TODO idea: have thin_client presence up front that hooks all alertable syscalls
*** TODO idea: just lose control briefly
*** TODO idea: use kernel driver
*** TODO idea: walk stack to find resumption point
*** TODO idea: on cbret w/ unknown return point: suspend world and make system libs unreadable
*** TODO idea: at cbret, hook post-syscall point of all possibly-alertable syscalls

however, some experiments show that cbs are delivered at probably
all NtUser* syscalls, which are not exported. thus they are a
pain for core DR to hook, in addition to there being quite a few
of them. so the ideas involving hooking all interruptible
syscalls aren't looking so hot.

@derekbruening
Copy link
Contributor Author

From [email protected] on May 08, 2012 10:42:38

Owner: [email protected]

@derekbruening
Copy link
Contributor Author

From [email protected] on May 09, 2012 07:37:55

*** TODO idea: set trap flag and single-step

while this works great across normal syscalls, it fails to work across int2b or cbret syscall (debugger must use some other mechanism). it also has complications on wow64: would have to have some x64 stubs in 32-bit DR.

@derekbruening
Copy link
Contributor Author

9c95ba5 added enumeration and takeover of unknown threads, invoked by default on regular startup

@OrBenPorath
Copy link
Contributor

Added in #5075.
Test still requires works, and to be removed from the flaky list.

Test occasionally failing in one of two ways:

  1. Nothing happens until the test times out.
    Unclear how that could happen, as one of the first things the target does is print something.
    Maybe it doesn't even start?

  2. Test output missing 'MessageBox closed' before 'done':
    Unclear how the target terminates, as there is no FATAL_ERROR reported, and all normal termination paths have another print before "done".

derekbruening pushed a commit that referenced this issue Sep 23, 2021
Adds an attach feature for Windows, marked as experimental.

Builds on the unsubmitted PR #3328.
One difference from the original PR, is not taking over threads that are terminating (otherwise attach always fails).
Added the possibility to sleep 1 millisecond between takeover attempts, and controlling the number of attempts.

Attach fails when the main thread (to which we are injecting) is blocking.  To solve this, we create a new suspended thread that sleeps indefinitely and we inject into it.  As part of pointing this thread at a Sleep function, generalizes  find_remote_ntdll_base() to find_remote_dll_base(), and solves an infinite loop there coming from strange kernel behavior.

Adds attach documentation to the section on how to deploy an application under DR.

Adds a new test client.attach.  It uses a new target rather than the existing infloop due to differences in staging the output checking steps.  Unfortunately there are still some flaky failures, so the test is added to the ignore list for now in order to make progress and get this key feature into DR.

Co-authored-by: Yibai Zhang <[email protected]>
Co-authored-by: orbp <[email protected]>

Issue: #725
@derekbruening
Copy link
Contributor Author

I thought the Windows detach via nudge was exposed today but it's not:

The existing Windows detach nudge feature is internal to DR and does not go
through a client. It looks like it is not exposed in drconfig and the old
tests for it are not all enabled; the old way to trigger it is in the
no-longer-supported "drcontrol" front-end, but it's just a different nudge
type so it should be feasible to tweak drconfig to enable it to try it out.
You can see the code paths in libutil/detach.c triggering the nudge to be
sent and handling it in core/nudge.c "TEST(NUDGE_GENERIC(detach),
nudge_action_mask)" calling detach_helper() which calls the
shared-with-all-detach-types detach_on_permanent_stack().

So that is a remaining action item as well. Xref adding a nudge detach
for Linux #95 where we have to create a new stack.

@derekbruening
Copy link
Contributor Author

derekbruening commented Jul 19, 2023

Still remaining:

  • We want to get an automated test of detach in place
  • We should update the documentation to include how to detach

Once we have those 2 things we should be able to close this issue (with any future problems being opened as new bugs).

@derekbruening
Copy link
Contributor Author

For the test, pasting from PR #6209

See e.g. client.attach_test which has support in multiple places to accomplish an attach from another process: see git grep '<attach'.

github-merge-queue bot pushed a commit that referenced this issue Jul 19, 2023
The old way to trigger detach on the Windows platform is the
no-longer-supported "drcontrol" front-end.
Re-exposing the detach feature in drconfig front-end on the Windows
platform.

The following briefly describes my manual testing process, and I'll
continue to submit an automated testing tool in a new PR soon.


I wrote my own continuously running example as a manual test case for
DynamoRIO, which counts the time of summing the first 1 billion numbers
in real time. I'd like to use the real-time output of the test case to
present the running state of the program.
```
#include <iostream>
#include <chrono>
#define LOOPCOUNT 100000;
// Function to perform a computationally intensive task
void performTask()
{
    //calculate the sum of the first 1 billion numbers
    long long unsigned sum = 0;
    for (int i = 1; i <= 1000000000; ++i)
    {
            sum += i;
    }
    std::cout << "The sum of the first 1 billion numbers: " << sum << std::endl;
}
void single_loop() {
    // Start the timer
    auto start = std::chrono::high_resolution_clock::now();
    // Perform the computationally intensive task
    performTask();
    // Stop the timer
    auto end = std::chrono::high_resolution_clock::now();
    // Calculate the elapsed time
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    // Print the elapsed time
    std::cout << "Elapsed time: " << duration.count() << " milliseconds" << std::endl;
}
int main()
{
    int counts = LOOPCOUNT;
    for (int i = 0; i < counts;i++)
    {
        single_loop();
    }
    return 0;
}
```
Here are the steps to perform a manual test:

1. Execute our test case: ./SumOneBillion.exe
2. Use the "ps" command to get the target process ID: ps | grep
SumOneBillion
3. Use "-attach" option to instrument the target process ID: .\drrun.exe
-attach pid -c64 D:\dynamorio\build_debug\api\bin\inscount.dll
4. Use "-detach" option to stop the instrumentation:.\drconfig.exe
-detach pid

The output of the test case and the DynamoRIO in debug version is like
following.


> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 192 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 191 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 191 milliseconds
**> <Starting application
D:\vs_demos_repos\SumOneBillion\x64\Release\SumOneBillion.exe (16300)>
> <cannot remove dll from rbtree: at root/min + can't find real tree>
> <Running on newer-than-this-build "Microsoft Windows 10-2009 x64">
> <Early threads found>
> <Initial options = -no_dynamic_options -client_lib
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -client_lib64
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -code_api -probe_api
-stack_size 56K -max_elide_jmp 0 -max_elide_call 0
-no_inline_ignored_syscalls -native_exec_default_list ''
-no_native_exec_managed_code -skip_terminating_threads
-no_indcall2direct >
> Client inscount is running**
> <CURIOSITY : instr_get_opcode(instr_new) !=
instr_get_opcode(instr_old) in file
D:\DynamoRIODetach\dynamorio-master\core\win32\callback.c line 2079
> version 9.93.19549, custom build
> -no_dynamic_options -client_lib
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -client_lib64
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -code_api -probe_api
-stack_size 56K -max_elide_jmp 0 -max_elide_call 0
-no_inline_ignored_syscalls -native_exec_default_list ''
> D:\dynamorio\build_debug\lib64\debug\dynamorio.dll=0x0000000015000000
> D:\dynamorio\build_debug\api\bin\inscount.dll=0x00007ff721f90000
> C:\WINDOWS/system32/KERNEL32.dll=0x0000026257e00000
> C:\WINDOWS/system32/KERNELBASE.dll=0x0000026257f40000
> D:\dynamorio\build_debug\ext\lib64\debug/drmgr.dll=0x00007ff721ff0000>
> <CURIOSITY : instr_new == instrlist_first(ilist) || instr_new ==
instr_get_next(instrlist_first(ilist)) in file
D:\dynamorio\core\win32\callback.c line 2082
> version 9.93.19549, custom build
> -no_dynamic_options -client_lib
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -client_lib64
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -code_api -probe_api
-stack_size 56K -max_elide_jmp 0 -max_elide_call 0
-no_inline_ignored_syscalls -native_exec_default_list ''
> D:\dynamorio\build_debug\lib64\debug\dynamorio.dll=0x0000000015000000
> D:\dynamorio\build_debug\api\bin\inscount.dll=0x00007ff721f90000
> C:\WINDOWS/system32/KERNEL32.dll=0x0000026257e00000
> C:\WINDOWS/system32/KERNELBASE.dll=0x0000026257f40000
> D:\dynamorio\build_debug\ext\lib64\debug/drmgr.dll=0x00007ff721ff0000>
> <Cleaning hooked Nt wrapper @0x00007ffeba790800 sysnum=0x1c2>
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 417 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 552 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 545 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 537 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 543 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 539 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 538 milliseconds
**> <curiosity: rex.w on OPSZ_6_irex10_short4!>
> <received nudge mask=0x4 id=0x00000000 arg=0x0000000000000000>
> <Detaching from application
D:\vs_demos_repos\SumOneBillion\x64\Release\SumOneBillion.exe (16300)>
> <Detaching from process, entering final cleanup>
> Instrumentation results: 20766267822 instructions executed**
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 194 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 194 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 194 milliseconds
> 

Issue: [#725](#725)
@onroadmuwl
Copy link
Contributor

The automated test of detach and detach documentation have been fixed, although the detach test for vs2019-32 may complain timeout like the attach test.

derekbruening pushed a commit that referenced this issue Jul 24, 2023
…6222)

Updates the usage docs to include an example of `drcontrol -detach`.

Issue: [#725](#725)
@derekbruening
Copy link
Contributor Author

Looks like the attach_test is still listed on the ignore-failures list. That should be fixed before this issue is closed.
Looks like it might be easy: it just has the wrong order of two lines:

126/257 Test #125: code_api|client.attach_test ..................................***Failed  Required regular expression not found. Regex=[^starting attachee
thank you for testing attach
thread init
event_post_attach
MessageBox closed
done$] 61.93 sec

Vs the actual output

starting attachee
thank you for testing attach
event_post_attach
thread init
MessageBox closed
done

@onroadmuwl
Copy link
Contributor

onroadmuwl commented Jul 25, 2023

Even if I swap the order of the two lines, there are still some tests that don't pass, it may require a clear macro definition rule.
#6227

@derekbruening
Copy link
Contributor Author

Even if I swap the order of the two lines, there are still some tests that don't pass, it may require a clear macro definition rule. #6227

You mean Linux has one order and Windows another? We can use #ifdef WINDOWS..#else in the match file.

github-merge-queue bot pushed a commit that referenced this issue Jul 26, 2023
Fixes incorrect output ordering for the client.attach_test.
Removes the client.attach_test from the ignore-failure list in the
wrapper script as it now passes for 32-bit and 64-bit Windows.

Issue: [#725](#725)

---------

Co-authored-by: Derek Bruening <[email protected]>
github-merge-queue bot pushed a commit that referenced this issue Jul 27, 2023
This patch adds an automated test of detach on Windows platform. The
test start a target program and attach to the process firstly, then use
the drconfig front-end to detach from the process.
As shown in the .template file, the detach mechanism lets the target
process be detached before stopping it.

Issue: [#725](#725)

---------

Co-authored-by: Derek Bruening <[email protected]>
ivankyluk pushed a commit to ivankyluk/dynamorio that referenced this issue Jul 28, 2023
The old way to trigger detach on the Windows platform is the
no-longer-supported "drcontrol" front-end.
Re-exposing the detach feature in drconfig front-end on the Windows
platform.

The following briefly describes my manual testing process, and I'll
continue to submit an automated testing tool in a new PR soon.


I wrote my own continuously running example as a manual test case for
DynamoRIO, which counts the time of summing the first 1 billion numbers
in real time. I'd like to use the real-time output of the test case to
present the running state of the program.
```
#include <iostream>
#include <chrono>
#define LOOPCOUNT 100000;
// Function to perform a computationally intensive task
void performTask()
{
    //calculate the sum of the first 1 billion numbers
    long long unsigned sum = 0;
    for (int i = 1; i <= 1000000000; ++i)
    {
            sum += i;
    }
    std::cout << "The sum of the first 1 billion numbers: " << sum << std::endl;
}
void single_loop() {
    // Start the timer
    auto start = std::chrono::high_resolution_clock::now();
    // Perform the computationally intensive task
    performTask();
    // Stop the timer
    auto end = std::chrono::high_resolution_clock::now();
    // Calculate the elapsed time
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    // Print the elapsed time
    std::cout << "Elapsed time: " << duration.count() << " milliseconds" << std::endl;
}
int main()
{
    int counts = LOOPCOUNT;
    for (int i = 0; i < counts;i++)
    {
        single_loop();
    }
    return 0;
}
```
Here are the steps to perform a manual test:

1. Execute our test case: ./SumOneBillion.exe
2. Use the "ps" command to get the target process ID: ps | grep
SumOneBillion
3. Use "-attach" option to instrument the target process ID: .\drrun.exe
-attach pid -c64 D:\dynamorio\build_debug\api\bin\inscount.dll
4. Use "-detach" option to stop the instrumentation:.\drconfig.exe
-detach pid

The output of the test case and the DynamoRIO in debug version is like
following.


> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 192 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 191 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 191 milliseconds
**> <Starting application
D:\vs_demos_repos\SumOneBillion\x64\Release\SumOneBillion.exe (16300)>
> <cannot remove dll from rbtree: at root/min + can't find real tree>
> <Running on newer-than-this-build "Microsoft Windows 10-2009 x64">
> <Early threads found>
> <Initial options = -no_dynamic_options -client_lib
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -client_lib64
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -code_api -probe_api
-stack_size 56K -max_elide_jmp 0 -max_elide_call 0
-no_inline_ignored_syscalls -native_exec_default_list ''
-no_native_exec_managed_code -skip_terminating_threads
-no_indcall2direct >
> Client inscount is running**
> <CURIOSITY : instr_get_opcode(instr_new) !=
instr_get_opcode(instr_old) in file
D:\DynamoRIODetach\dynamorio-master\core\win32\callback.c line 2079
> version 9.93.19549, custom build
> -no_dynamic_options -client_lib
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -client_lib64
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -code_api -probe_api
-stack_size 56K -max_elide_jmp 0 -max_elide_call 0
-no_inline_ignored_syscalls -native_exec_default_list ''
> D:\dynamorio\build_debug\lib64\debug\dynamorio.dll=0x0000000015000000
> D:\dynamorio\build_debug\api\bin\inscount.dll=0x00007ff721f90000
> C:\WINDOWS/system32/KERNEL32.dll=0x0000026257e00000
> C:\WINDOWS/system32/KERNELBASE.dll=0x0000026257f40000
> D:\dynamorio\build_debug\ext\lib64\debug/drmgr.dll=0x00007ff721ff0000>
> <CURIOSITY : instr_new == instrlist_first(ilist) || instr_new ==
instr_get_next(instrlist_first(ilist)) in file
D:\dynamorio\core\win32\callback.c line 2082
> version 9.93.19549, custom build
> -no_dynamic_options -client_lib
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -client_lib64
'D:\dynamorio\build_debug\api\bin\inscount.dll;0;' -code_api -probe_api
-stack_size 56K -max_elide_jmp 0 -max_elide_call 0
-no_inline_ignored_syscalls -native_exec_default_list ''
> D:\dynamorio\build_debug\lib64\debug\dynamorio.dll=0x0000000015000000
> D:\dynamorio\build_debug\api\bin\inscount.dll=0x00007ff721f90000
> C:\WINDOWS/system32/KERNEL32.dll=0x0000026257e00000
> C:\WINDOWS/system32/KERNELBASE.dll=0x0000026257f40000
> D:\dynamorio\build_debug\ext\lib64\debug/drmgr.dll=0x00007ff721ff0000>
> <Cleaning hooked Nt wrapper @0x00007ffeba790800 sysnum=0x1c2>
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 417 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 552 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 545 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 537 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 543 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 539 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 538 milliseconds
**> <curiosity: rex.w on OPSZ_6_irex10_short4!>
> <received nudge mask=0x4 id=0x00000000 arg=0x0000000000000000>
> <Detaching from application
D:\vs_demos_repos\SumOneBillion\x64\Release\SumOneBillion.exe (16300)>
> <Detaching from process, entering final cleanup>
> Instrumentation results: 20766267822 instructions executed**
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 194 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 194 milliseconds
> The sum of the first 1 billion numbers: 500000000500000000
> Elapsed time: 194 milliseconds
> 

Issue: [DynamoRIO#725](DynamoRIO#725)
ivankyluk pushed a commit to ivankyluk/dynamorio that referenced this issue Jul 28, 2023
…ynamoRIO#6222)

Updates the usage docs to include an example of `drcontrol -detach`.

Issue: [DynamoRIO#725](DynamoRIO#725)
ivankyluk pushed a commit to ivankyluk/dynamorio that referenced this issue Jul 28, 2023
…moRIO#6227)

Fixes incorrect output ordering for the client.attach_test.
Removes the client.attach_test from the ignore-failure list in the
wrapper script as it now passes for 32-bit and 64-bit Windows.

Issue: [DynamoRIO#725](DynamoRIO#725)

---------

Co-authored-by: Derek Bruening <[email protected]>
ivankyluk pushed a commit to ivankyluk/dynamorio that referenced this issue Jul 28, 2023
This patch adds an automated test of detach on Windows platform. The
test start a target program and attach to the process firstly, then use
the drconfig front-end to detach from the process.
As shown in the .template file, the detach mechanism lets the target
process be detached before stopping it.

Issue: [DynamoRIO#725](DynamoRIO#725)

---------

Co-authored-by: Derek Bruening <[email protected]>
@derekbruening
Copy link
Contributor Author

Looks like there is non-determinism as this win32 run has "thread_init" before "event_post_attach": https://github.com/DynamoRIO/dynamorio/actions/runs/5764745468/job/15629345646?pr=6241

derekbruening added a commit that referenced this issue Aug 4, 2023
Removes the printing of "event_post_attach" in the client.attach test,
as it had non-deterministic ordering versus the "thread init" printing
(and runall.cmake requires "thread init").  Replaces with a boolean
check and error print at exit to ensure we saw the attach event.

This completes the base attach feature.  Future problems should open new issues.

Fixes #725
derekbruening added a commit that referenced this issue Aug 5, 2023
Removes the printing of "event_post_attach" in the client.attach test,
as it had non-deterministic ordering versus the "thread init" printing
(and runall.cmake requires "thread init"). Replaces with a boolean check
and error print at exit to ensure we saw the attach event.

This completes the base attach feature. Future problems should open new
issues.

Fixes #725
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants