DynamoRIO / dynamorio

Dynamic Instrumentation Tool Platform
Other
2.64k stars 560 forks source link

Signal delivery to windows application not working in Powershell #3843

Open fmoessbauer opened 5 years ago

fmoessbauer commented 5 years ago

When running a windows application in Powershell with DynamoRIO + client, signals like "Ctrl-c" (issued from the terminal) are not delivered to the application. However, when running without a client (just DR), the signal handling works as expected. In other shells like MinGW bash, the signal delivery works as expected.

I tested with: DynamoRIO: 7.91.18137 Windows: Version 10.0.17134 Build 17134 Client: bbcount (applies to all other tested clients as well) Shell: PowerShell

As recommended on the mailing-list, I also run with -loglevel 2. There the shutdown thread bb's are not visible. In a pure DR run, I see lines like the following. In a DR+client run, they do not appear:

d_r_dispatch: target = 0x00007ffc7c803683
Fragment 2, tag 0x00007ffc7c803683, flags 0x1000630, shared, size 70:
    [ntdll.dll~RtlUserThreadStart+0x13,~RtlExitUserThread-0x3d]
Entry into F2(0x00007ffc7c803683).0x00007ff705b51034 (shared)
Exit from sourceless ibl: bb call*  []
 (target 0x00007ffc7c82e350 not in cache)

In both executions, two threads are detected by DR.

Sample test code:

#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <csignal>

std::atomic<bool> running{ true };

void sig_handler(int signal)
{
    if (signal == SIGINT) {
        running.store(false, std::memory_order_relaxed);
    }
    std::cout << "Got signal" << std::endl;
}

int main(int argc, char ** argv) {
    std::cout << "Start application, hit ctrl-c to quit" << std::endl;

    std::signal(SIGINT, sig_handler);

    while (running.load(std::memory_order_relaxed))
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
    std::cout << "quit!" << std::endl;
}
derekbruening commented 5 years ago

Link to users list thread: https://groups.google.com/forum/#!topic/DynamoRIO-Users/zB6omls3sk

In both executions, two threads are detected by DR.

And just one thread if you never hit ^C?

What about with an empty client (empty.dll)?

If an empty client with no events causes the problem, I would look at the runtime option differences: a client triggers some changes in enabled options. Maybe enabling those same options without a client will also reproduce and will point toward the problem area.

fmoessbauer commented 5 years ago

And just one thread if you never hit ^C?

Yes!

What about with an empty client (empty.dll)?

Exactly the same behaviour

If an empty client with no events causes the problem, I would look at the runtime option differences: a client triggers some changes in enabled options. Maybe enabling those same options without a client will also reproduce and will point toward the problem area.

When running DR without a client, but with the same options, the signal is delivered correctly. The options are: -no_dynamic_options -code_api -probe_api -stack_size 56K -max_elide_jmpp 0 -max_elide_call 0 -no_inline_ignored_syscalls -n ative_exec_default_list '' -no_native_exec_managed_code -no_indcall2direct -pad_jmps_mark_no_trace

I had a look into the logfile of the signal-thread. It seems that it entered an infinite loop after a syscall (all consecutive lines are exactly like the last block of the following log):

d_r_dispatch: target = 0x00007ffc7c82b202
Fragment 1821, tag 0x00007ffc7c82b202, flags 0x1801030, shared, size 5, must end trace:
    [ntdll.dll~ZwContinue+0x12,~ZwQueryDefaultUILanguage-0xe]
Entry into F1821(0x00007ffc7c82b202).0x00007ff5b4584e38 (shared)
Exit from F1821(0x00007ffc7c82b202).0x00007ff5b4584e38 (shared) 
 (block ends with syscall)
Entry into do_syscall to execute a non-ignorable system call
system call: sysnum = 0x0000000000000043, param_base = 0x000000a99b4ff490
priv_mcontext_t @0x00000239d7da5e00
    xax = 0x0000000000000043
    xbx = 0x000000a99b4ff4e0
    xcx = 0x000000a99b4ff4e0
    xdx = 0x0000000000000001
    xsi = 0x0000000000000000
    xdi = 0x0000000000000000
    xbp = 0x0000000000000000
    xsp = 0x000000a99b4ff488
    r8  = 0x000000a99b4ff3b8
    r9  = 0x0000000000000000
    r10 = 0x000000a99b4ff4e0
    r11 = 0x0000000000000246
    r12 = 0x0000000000000000
    r13 = 0x0000000000000000
    r14 = 0x0000000000000000
    r15 = 0x0000000000000000
    ymm0= 0x0000000000000000000000000000000000000000000000000000000000000000
    ymm1= 0x0000000000000000000000000000000000000000000000000000000000000000
    ymm2= 0x0000000000000000000000000000000000000000000000000000000000000000
    ymm3= 0x0000000000000000000000000000000000000000000000000000000000000000
    ymm4= 0x0000000000000000000000000000000000000000000000000000000000000000
    ymm5= 0x0000000000000000000000000000000000000000000000000000000000000000
    mxcsr=0x00001f80
    eflags = 0x0000000000000246
    pc     = 0x00007ffc7c82b204
syscall: NtContinue cxt->Xip=0x00007ffc7c803670 flag=0x000000a900000001
ASYNCH intercept_nt_continue in thread 2808, xip=0x00007ffc7c803670
    xip=0x00007ffc7c803670 not in fcache, intercepting at 0x000000001533d5ef
nt_continue_setup: target is 0x00007ffc7c803670
set teb->peb to 0x00000239d7cd12a8
Exit from asynch event

d_r_dispatch: target = 0x00007ffc7c803670
Entry into F1(0x00007ffc7c803670).0x00007ff5b44e1008 (shared)
Exit from sourceless ibl: bb call*  []
 (target 0x00007ffc7c82e350 in cache but not lookup table)

d_r_dispatch: target = 0x00007ffc7c82e350
Entry into F3(0x00007ffc7c82e350).0x00007ff5b44e1084 (shared)
Exit from sourceless ibl: bb jmp*   []
 (target 0x00007ffc7b594020 in cache but not lookup table)

d_r_dispatch: target = 0x00007ffc7b594020
Entry into F4(0x00007ffc7b594020).0x00007ff5b44e10a0 (shared)
Exit from sourceless ibl: bb call*  []
 (target 0x00007ffc7b5a22d0 in cache but not lookup table)

d_r_dispatch: target = 0x00007ffc7b5a22d0
Entry into F6(0x00007ffc7b5a22d0).0x00007ff5b44e1108 (shared)
Exit from sourceless ibl: bb jmp*   []
 (target 0x0000023a57d85660 not in cache)

d_r_dispatch: target = 0x0000023a57d85660
transfer_to_dispatch: pc=0x57d85660, xsp=0x000000a99b4ff938, on-initstack=0
Exit from sourceless ibl: bb ret    []
 (target 0x0000023a57d85660 not in cache)
derekbruening commented 5 years ago

OK, so the new thread finished its standard thread initialization and did an NtContinue to the library layer which will send it to its targeted code for the SIGINT handler. Seems reasonable.

What does DR think is the "Win32 start address", i.e., where it should go instead of an infinite loop? That string should be in the log, back when the init APC was intercepted. What does that symbolize to?

You're saying it runs an infinite loop using return instructions?? What is the disassembly of the block at 0x0000023a57d85660? What is the symbolization of that address? Is that inside a library/executable? That's a strange address for a library or the executable.