ฉันสามารถส่ง ctrl-C (SIGINT) ไปยังแอปพลิเคชันบน Windows ได้หรือไม่


91

ฉันได้ (ในอดีต) เขียนข้ามแพลตฟอร์ม (Windows / Unix) การใช้งานซึ่งเมื่อเริ่มต้นจากบรรทัดคำสั่งการจัดการผู้ใช้พิมพ์Ctrl- Cรวมกันในลักษณะเดียวกัน (เช่นการยกเลิกการสมัครเรียบร้อย)

เป็นไปได้ไหมใน Windows ที่จะส่งCtrl- C/ SIGINT / เทียบเท่ากับกระบวนการจากกระบวนการอื่น (ที่ไม่เกี่ยวข้อง) เพื่อขอให้ยุติอย่างหมดจด (ให้โอกาสในการจัดระเบียบทรัพยากร ฯลฯ )


1
ฉันสนใจที่จะส่ง Ctrl-C ไปยังกระบวนการบริการ java เพื่อรับ threaddumps ปรากฏว่าjstackสามารถใช้แทนเรื่องนี้ได้อย่างน่าเชื่อถือ: stackoverflow.com/a/47723393/603516
Vadzim

คำตอบ:


31

สิ่งที่ใกล้เคียงที่สุดที่ฉันได้พบคือแอปSendSignalของบุคคลที่สาม ผู้เขียนแสดงรายการซอร์สโค้ดและไฟล์ปฏิบัติการ ฉันได้ตรวจสอบแล้วว่าทำงานภายใต้หน้าต่าง 64 บิต (ทำงานเป็นโปรแกรม 32 บิตฆ่าโปรแกรม 32 บิตอื่น) แต่ฉันไม่พบวิธีฝังโค้ดลงในโปรแกรม windows (ทั้ง 32 บิต หรือ 64 บิต)

มันทำงานอย่างไร:

หลังจากขุดรอบดีบักเกอร์หลายครั้งฉันพบว่าจุดเข้าที่ทำพฤติกรรมที่เกี่ยวข้องกับสัญญาณเช่น ctrl-break คือ kernel32! CtrlRoutine ฟังก์ชันนี้มีต้นแบบเดียวกับ ThreadProc ดังนั้นจึงสามารถใช้กับ CreateRemoteThread ได้โดยตรงโดยไม่ต้องฉีดโค้ด อย่างไรก็ตามนั่นไม่ใช่สัญลักษณ์ที่ส่งออก! ซึ่งอยู่คนละที่อยู่ (และยังมีชื่อต่างกัน) ใน Windows เวอร์ชันต่างๆ จะทำอย่างไร?

นี่คือวิธีแก้ปัญหาในที่สุดที่ฉันคิดขึ้นมา ฉันติดตั้งตัวจัดการ ctrl คอนโซลสำหรับแอปของฉันจากนั้นสร้างสัญญาณตัวแบ่ง ctrl สำหรับแอปของฉัน เมื่อตัวจัดการของฉันถูกเรียกฉันมองย้อนกลับไปที่ด้านบนสุดของสแต็กเพื่อค้นหาพารามิเตอร์ที่ส่งไปยัง kernel32! BaseThreadStart ฉันคว้าพารามิเตอร์แรกซึ่งเป็นที่อยู่เริ่มต้นที่ต้องการของเธรดซึ่งเป็นที่อยู่ของ kernel32! CtrlRoutine จากนั้นฉันก็กลับจากตัวจัดการของฉันแสดงว่าฉันจัดการสัญญาณแล้วและแอพของฉันไม่ควรถูกยกเลิก กลับไปที่เธรดหลักฉันรอจนกว่าที่อยู่ของ kernel32! CtrlRoutine จะถูกดึงออกมา เมื่อฉันได้รับแล้วฉันจะสร้างเธรดระยะไกลในกระบวนการเป้าหมายด้วยที่อยู่เริ่มต้นที่ค้นพบ สิ่งนี้ทำให้ตัวจัดการ ctrl ในกระบวนการเป้าหมายได้รับการประเมินราวกับว่ามีการกด ctrl-break!

สิ่งที่ดีคือเฉพาะกระบวนการเป้าหมายเท่านั้นที่ได้รับผลกระทบและกระบวนการใด ๆ (แม้แต่กระบวนการที่มีหน้าต่าง) สามารถกำหนดเป้าหมายได้ ข้อเสียอย่างหนึ่งคือแอปเล็ก ๆ ของฉันไม่สามารถใช้ในไฟล์แบตช์ได้เนื่องจากมันจะฆ่ามันเมื่อส่งเหตุการณ์ ctrl-break เพื่อค้นหาที่อยู่ของ kernel32! CtrlRoutine

(นำหน้าด้วยstartถ้าเรียกใช้ในไฟล์แบตช์)


2
+1 - โค้ดที่เชื่อมโยงใช้ Ctrl-Break แทนที่จะเป็น Ctrl-C แต่อยู่ที่ด้านหน้าของมัน (ดูเอกสารสำหรับ GenerateConsoleCtrlEvent) สามารถปรับให้เหมาะกับ Ctrl-C
Matthew Murdoch

8
มีฟังก์ชั่นให้ทำสำหรับคุณจริงๆฮ่า ๆ "GenerateConsoleCtrlEvent" ดู: msdn.microsoft.com/en-us/library/ms683155(v=vs.85).aspx ดูคำตอบของฉันที่นี่: serverfault.com/a/501045/10023
Triynko

1
ลิงก์ Github ที่เกี่ยวข้องกับคำตอบด้านบน: github.com/walware/statet/tree/master/…
meawoppl

3
มันทำให้เข้าใจว่า Windows นั้นเก่าเหมือนเดิม แต่ Microsoft ยังไม่ได้จัดเตรียมกลไกสำหรับแอปพลิเคชันคอนโซล A เพื่อฟังสัญญาณจากแอปพลิเคชันคอนโซล B เพื่อให้แอปพลิเคชันคอนโซล B สามารถบอกให้แอปพลิเคชันคอนโซล A ปิดได้อย่างหมดจด ไม่ว่าในกรณีใด ๆ MS-bashing กันฉันได้ลอง SendSignal และได้รับ "CreateRemoteThread ล้มเหลวด้วย 0x00000005" ความคิดอื่น ๆ เกี่ยวกับวิธีการโค้ดแอปพลิเคชัน A เพื่อฟังสัญญาณ (สัญญาณใด ๆ ที่สะดวก) แล้วจะส่งสัญญาณได้อย่างไร
David I. McIntosh

3
@ DavidI.McIntosh ดูเหมือนว่าคุณต้องการสร้างเหตุการณ์ที่มีชื่อในทั้งสองกระบวนการ จากนั้นคุณจะสามารถส่งสัญญาณจากอีกเครื่องหนึ่งได้ ตรวจสอบเอกสารสำหรับ CreateEvent
arolson101

58

ฉันได้ทำการวิจัยเกี่ยวกับหัวข้อนี้ซึ่งได้รับความนิยมมากกว่าที่ฉันคาดไว้ คำตอบของ KindDragon เป็นหนึ่งในจุดสำคัญ

ฉันเขียนบล็อกโพสต์ที่ยาวขึ้นในหัวข้อนี้และสร้างโปรแกรมสาธิตที่ใช้งานได้ซึ่งแสดงให้เห็นถึงการใช้ระบบประเภทนี้เพื่อปิดแอปพลิเคชันบรรทัดคำสั่งในแฟชั่นที่ดีสองสามอย่าง โพสต์นั้นยังแสดงลิงก์ภายนอกที่ฉันใช้ในการวิจัยของฉัน

ในระยะสั้นโปรแกรมสาธิตเหล่านั้นทำสิ่งต่อไปนี้:

  • เริ่มโปรแกรมด้วยหน้าต่างที่มองเห็นได้โดยใช้. Net ซ่อนด้วย pinvoke รัน 6 วินาทีแสดงด้วย pinvoke หยุดด้วย. Net
  • เริ่มโปรแกรมโดยไม่มีหน้าต่างโดยใช้. Net รันเป็นเวลา 6 วินาทีหยุดโดยการติดคอนโซลและออก ConsoleCtrlEvent

แก้ไข:โซลูชันที่ได้รับการแก้ไขจาก KindDragon สำหรับผู้ที่สนใจรหัสที่นี่และตอนนี้ หากคุณวางแผนที่จะเริ่มโปรแกรมอื่นหลังจากหยุดโปรแกรมแรกคุณควรเปิดใช้งานการจัดการ Ctrl-C อีกครั้งมิฉะนั้นกระบวนการถัดไปจะสืบทอดสถานะปิดใช้งานของผู้ปกครองและจะไม่ตอบสนองต่อ Ctrl-C

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();

[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);

delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);

// Enumerated type for the control messages sent to the handler routine
enum CtrlTypes : uint
{
  CTRL_C_EVENT = 0,
  CTRL_BREAK_EVENT,
  CTRL_CLOSE_EVENT,
  CTRL_LOGOFF_EVENT = 5,
  CTRL_SHUTDOWN_EVENT
}

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);

public void StopProgram(Process proc)
{
  //This does not require the console window to be visible.
  if (AttachConsole((uint)proc.Id))
  {
    // Disable Ctrl-C handling for our program
    SetConsoleCtrlHandler(null, true); 
    GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);

    //Moved this command up on suggestion from Timothy Jannace (see comments below)
    FreeConsole();

    // Must wait here. If we don't and re-enable Ctrl-C
    // handling below too fast, we might terminate ourselves.
    proc.WaitForExit(2000);

    //Re-enable Ctrl-C handling or any subsequently started
    //programs will inherit the disabled state.
    SetConsoleCtrlHandler(null, false); 
  }
}

นอกจากนี้ให้วางแผนสำหรับวิธีแก้ปัญหาฉุกเฉินหากAttachConsole()หรือสัญญาณที่ส่งไปล้มเหลวเช่นกำลังนอนหลับแล้วสิ่งนี้:

if (!proc.HasExited)
{
  try
  {
    proc.Kill();
  }
  catch (InvalidOperationException e){}
}

4
ด้วยแรงบันดาลใจจากสิ่งนี้ฉันจึงสร้างแอป cpp แบบ "สแตนด์อโลน" ขึ้นมา: gist.github.com/rdp/f51fb274d69c5c31b6beเผื่อว่าจะมีประโยชน์ และใช่วิธีนี้สามารถส่ง ctrl + c หรือ ctrl + break ไปยัง pid "any" ได้
rogerdpack

ไม่มีหนึ่งในการนำเข้า DLL "SetConsoleCtrlHandler" แต่วิธีนี้ได้ผล
Derf Skren

โพสต์ที่ยอดเยี่ยม บล็อกที่ยอดเยี่ยม ฉันขอแนะนำให้จบฟังก์ชัน StopProgramWithInvisibleWindowUsingPinvoke ในโปรแกรมการทดลองของคุณ ฉันเกือบจะละทิ้งความคิดที่คิดว่าคุณไม่พบวิธีแก้ปัญหา
Wilmer Saint

เพื่อหลีกเลี่ยงไม่ให้wait()ฉันลบRe-enable Ctrl-C ( SetConsoleCtrlHandler(null, false);) ฉันทำการทดสอบสองสามครั้ง (การโทรหลายครั้งรวมถึงกระบวนการที่ยุติไปแล้ว) และฉันไม่พบผลข้างเคียงใด ๆ (ยัง?)
56ka

FreeConsole ควรถูกเรียกทันทีหลังจากส่ง GenerateConsoleCtrlEvent แอปพลิเคชันของคุณจะถูกแนบไปกับคอนโซลอื่นจนกว่าจะมีการเรียก หากคอนโซลอื่นถูกฆ่าก่อนที่จะเสร็จสิ้นการปิดแอปพลิเคชันของคุณจะถูกยกเลิกเช่นกัน!
Timothy Jannace

17

ฉันเดาว่าฉันตอบคำถามนี้ช้าไปหน่อย แต่ฉันจะเขียนอะไรบางอย่างสำหรับทุกคนที่มีปัญหาเดียวกัน นี่คือคำตอบเช่นเดียวกับผมมอบให้นี้คำถาม

ปัญหาของฉันคือฉันต้องการให้แอปพลิเคชันของฉันเป็นแอปพลิเคชัน GUI แต่กระบวนการที่ดำเนินการควรทำงานในพื้นหลังโดยไม่ต้องติดหน้าต่างคอนโซลแบบโต้ตอบใด ๆ ฉันคิดว่าโซลูชันนี้ควรใช้งานได้เมื่อกระบวนการหลักเป็นกระบวนการคอนโซล คุณอาจต้องลบแฟล็ก "CREATE_NO_WINDOW" ออก

ฉันจัดการเพื่อแก้ปัญหานี้โดยใช้GenerateConsoleCtrlEvent () ด้วยแอป wrapper ส่วนที่ยุ่งยากก็คือเอกสารยังไม่ชัดเจนว่าจะใช้งานได้อย่างไรและมีข้อผิดพลาดอย่างไร

ทางออกของฉันจะขึ้นอยู่กับสิ่งที่อธิบายที่นี่ แต่นั่นไม่ได้อธิบายรายละเอียดทั้งหมดอย่างแท้จริงและมีข้อผิดพลาดดังนั้นนี่คือรายละเอียดเกี่ยวกับวิธีการทำงาน

สร้างแอปพลิเคชันตัวช่วยใหม่ "Helper.exe" แอปพลิเคชันนี้จะอยู่ระหว่างแอปพลิเคชันของคุณ (ผู้ปกครอง) และกระบวนการย่อยที่คุณต้องการให้ปิดได้ นอกจากนี้ยังจะสร้างกระบวนการลูกที่แท้จริง คุณต้องมีกระบวนการ "คนกลาง" นี้มิฉะนั้น GenerateConsoleCtrlEvent () จะล้มเหลว

ใช้กลไก IPC บางประเภทเพื่อสื่อสารจากพาเรนต์ไปยังกระบวนการตัวช่วยที่ผู้ช่วยเหลือควรปิดโปรเซสลูก เมื่อผู้ช่วยเหลือได้รับเหตุการณ์นี้จะเรียกว่า "GenerateConsoleCtrlEvent (CTRL_BREAK, 0)" ซึ่งจะปิดตัวเองและกระบวนการย่อย ฉันใช้ออบเจ็กต์เหตุการณ์สำหรับสิ่งนี้เองซึ่งพาเรนต์ทำสำเร็จเมื่อต้องการยกเลิกกระบวนการย่อย

ในการสร้าง Helper.exe ของคุณให้สร้างด้วย CREATE_NO_WINDOW และ CREATE_NEW_PROCESS_GROUP และเมื่อสร้างกระบวนการลูกให้สร้างโดยไม่มีแฟล็ก (0) หมายความว่าจะได้รับคอนโซลมาจากพาเรนต์ หากไม่ทำเช่นนี้จะทำให้ไม่สนใจเหตุการณ์นั้น

เป็นสิ่งสำคัญมากที่แต่ละขั้นตอนจะทำเช่นนี้ ฉันลองใช้ชุดค่าผสมต่างๆมาแล้ว แต่ชุดนี้เป็นชุดเดียวที่ใช้ได้ คุณไม่สามารถส่ง CTRL_C เหตุการณ์ มันจะกลับมาประสบความสำเร็จ แต่จะถูกละเลยโดยกระบวนการ CTRL_BREAK เป็นหนึ่งเดียวที่ใช้ได้ผล ไม่สำคัญจริงๆเนื่องจากทั้งคู่จะเรียก ExitProcess () ในท้ายที่สุด

คุณยังไม่สามารถเรียก GenerateConsoleCtrlEvent () ด้วยรหัสกลุ่มกระบวนการของ id กระบวนการลูกโดยตรงเพื่อให้กระบวนการช่วยเหลือดำเนินต่อไปได้ สิ่งนี้จะล้มเหลวเช่นกัน

ฉันใช้เวลาทั้งวันในการพยายามทำงานนี้ วิธีนี้ใช้ได้กับฉัน แต่ถ้าใครมีอะไรจะเพิ่มกรุณาทำ ฉันไปทั่วเน็ตเพื่อค้นหาผู้คนมากมายที่มีปัญหาคล้าย ๆ กัน แต่ไม่มีวิธีแก้ปัญหาที่ชัดเจน GenerateConsoleCtrlEvent () ทำงานอย่างไรก็ค่อนข้างแปลกดังนั้นหากใครรู้รายละเอียดเพิ่มเติมโปรดแบ่งปัน


6
ขอบคุณสำหรับการแก้ปัญหา! นี่เป็นอีกตัวอย่างหนึ่งของ Windows API ที่เป็นระเบียบมาก
vitaut

8

แก้ไข:

สำหรับแอป GUI วิธี "ปกติ" ในการจัดการสิ่งนี้ในการพัฒนา Windows คือการส่งข้อความ WM_CLOSE ไปที่หน้าต่างหลักของกระบวนการ

สำหรับแอปคอนโซลคุณต้องใช้SetConsoleCtrlHandlerเพื่อเพิ่มไฟล์CTRL_C_EVENT.

หากโปรแกรมประยุกต์ที่ไม่ให้เกียรติที่คุณสามารถเรียกTerminateProcess


ฉันต้องการทำสิ่งนี้ในแอพบรรทัดคำสั่ง (ไม่มีหน้าต่าง) TerminateProcess เป็นกลไก Force kill (คล้ายกับ SIGKILL) ดังนั้นจึงไม่เปิดโอกาสให้แอปพลิเคชันยุติการล้างข้อมูลใด ๆ
Matthew Murdoch

@Matthew Murdoch: อัปเดตเพื่อรวมข้อมูลเกี่ยวกับวิธีจัดการสิ่งนี้ในแอปคอนโซล คุณยังสามารถตรวจจับเหตุการณ์อื่น ๆ ได้เช่นการปิดหน้าต่างหรือคอนโซลปิด ฯลฯ ผ่านกลไกเดียวกัน ดู MSDN สำหรับรายละเอียดทั้งหมด
Reed Copsey

@Reed Copsey: แต่ฉันต้องการเริ่มต้นจากกระบวนการแยกต่างหาก ฉันได้ดู GenerateConsoleCtrlEvent (อ้างอิงจาก SetConsoleCtrlHandler) แต่ดูเหมือนว่าจะใช้ได้ผลก็ต่อเมื่อกระบวนการที่ถูกยุติอยู่ใน 'กลุ่มกระบวนการ' เดียวกันกับกระบวนการที่กำลังยุติ ... ความคิดใด ๆ ?
Matthew Murdoch

1
Matthew: ความคิดเดียวที่ฉันมีคือค้นหากระบวนการค้นหาว่าเป็นพาเรนต์ (คอนโซล) รับที่จับหน้าต่างหลักของผู้ปกครอง (คอนโซล) และใช้ SendKeys เพื่อส่ง Ctrl + C ไปยังมันโดยตรง นั่นควรทำให้กระบวนการคอนโซลของคุณได้รับ CTRL_C_EVENT ยังไม่ได้ลอง - ไม่แน่ใจว่าจะใช้ได้ดีแค่ไหน
Reed Copsey

นี่คือ c ++ ที่เทียบเท่ากับ SendKeys stackoverflow.com/questions/6838363/…ดูที่stackoverflow.com/questions/10407769/…แม้ว่าจะไม่รับประกันว่าจะใช้งานได้ในขณะนั้นก็ตาม ...
rogerdpack

7

GenerateConsoleCtrlEvent()ส่งคืนข้อผิดพลาดอย่างใดหากคุณเรียกใช้สำหรับกระบวนการอื่น แต่คุณสามารถแนบกับแอปพลิเคชันคอนโซลอื่นและส่งเหตุการณ์ไปยังกระบวนการย่อยทั้งหมด

void SendControlC(int pid)
{
    AttachConsole(pid); // attach to process console
    SetConsoleCtrlHandler(NULL, TRUE); // disable Control+C handling for our app
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // generate Control+C event
}

และจะกลับมาควบคุมได้อย่างไร? จากนั้นฉันก็ส่ง control-c, stopar program แต่ฉันไม่สามารถทำอะไรได้ด้วยมือของเขา
Yaroslav L.

จะคืนการควบคุมได้ที่ไหน?
KindDragon

ฉันคิดว่าคุณเรียก SetConsoleCtrlHandler (NULL, FALSE) เพื่อลบตัวจัดการของคุณดูการตอบสนองอื่น ๆ
rogerdpack

6

นี่คือรหัสที่ฉันใช้ในแอป C ++

จุดบวก:

  • ทำงานจากแอปคอนโซล
  • ทำงานจากบริการ Windows
  • ไม่จำเป็นต้องล่าช้า
  • ไม่ปิดแอปปัจจุบัน

จุดลบ:

  • คอนโซลหลักสูญหายและมีการสร้างคอนโซลใหม่ (ดูFreeConsole )
  • การสลับคอนโซลให้ผลลัพธ์ที่แปลก ...

// Inspired from http://stackoverflow.com/a/15281070/1529139
// and http://stackoverflow.com/q/40059902/1529139
bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent)
{
    bool success = false;
    DWORD thisConsoleId = GetCurrentProcessId();
    // Leave current console if it exists
    // (otherwise AttachConsole will return ERROR_ACCESS_DENIED)
    bool consoleDetached = (FreeConsole() != FALSE);

    if (AttachConsole(dwProcessId) != FALSE)
    {
        // Add a fake Ctrl-C handler for avoid instant kill is this console
        // WARNING: do not revert it or current program will be also killed
        SetConsoleCtrlHandler(nullptr, true);
        success = (GenerateConsoleCtrlEvent(dwCtrlEvent, 0) != FALSE);
        FreeConsole();
    }

    if (consoleDetached)
    {
        // Create a new console if previous was deleted by OS
        if (AttachConsole(thisConsoleId) == FALSE)
        {
            int errorCode = GetLastError();
            if (errorCode == 31) // 31=ERROR_GEN_FAILURE
            {
                AllocConsole();
            }
        }
    }
    return success;
}

ตัวอย่างการใช้งาน:

DWORD dwProcessId = ...;
if (signalCtrl(dwProcessId, CTRL_C_EVENT))
{
    cout << "Signal sent" << endl;
}

4
        void SendSIGINT( HANDLE hProcess )
        {
            DWORD pid = GetProcessId(hProcess);
            FreeConsole();
            if (AttachConsole(pid))
            {
                // Disable Ctrl-C handling for our program
                SetConsoleCtrlHandler(NULL, true);

                GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // SIGINT

                //Re-enable Ctrl-C handling or any subsequently started
                //programs will inherit the disabled state.
                SetConsoleCtrlHandler(NULL, false);

                WaitForSingleObject(hProcess, 10000);
            }
        }

2

ควรทำให้ใสเพราะในขณะนี้ไม่ใช่ มี SendSignal เวอร์ชันแก้ไขและคอมไพล์เพื่อส่ง Ctrl-C (โดยค่าเริ่มต้นจะส่งเฉพาะ Ctrl + Break) นี่คือไบนารีบางส่วน:

(2014-3-7): ฉันสร้างทั้งเวอร์ชัน 32 บิตและ 64 บิตด้วย Ctrl-C เรียกว่า SendSignalCtrlC.exe และคุณสามารถดาวน์โหลดได้ที่: https://dl.dropboxusercontent.com/u/49065779/ sentignalctrlc / x86 / SendSignalCtrlC.exe https://dl.dropboxusercontent.com/u/49065779/sendsignalctrlc/x86_64/SendSignalCtrlC.exe - Juraj Michalak

ฉันยังทำมิเรอร์ไฟล์เหล่านั้นในกรณี:
เวอร์ชัน 32 บิต: https://www.dropbox.com/s/r96jxglhkm4sjz2/SendSignalCtrlC.exe?dl=0 เวอร์ชัน
64 บิต: https://www.dropbox.com /s/hhe0io7mcgcle1c/SendSignalCtrlC64.exe?dl=0

ข้อจำกัดความรับผิดชอบ: ฉันไม่ได้สร้างไฟล์เหล่านั้น ไม่มีการแก้ไขไฟล์ต้นฉบับที่คอมไพล์แล้ว แพลตฟอร์มเดียวที่ทดสอบคือ Windows 7 64 บิตขอแนะนำให้ปรับเปลี่ยนแหล่งข้อมูลที่มีอยู่ที่http://www.latenighthacking.com/projects/2003/sendSignal/และรวบรวมด้วยตัวเอง


2

ใน Java ใช้ JNA กับไลบรารี Kernel32.dll คล้ายกับโซลูชัน C ++ รันเมธอดหลักของ CtrlCSender เป็นกระบวนการซึ่งเพิ่งได้รับคอนโซลของกระบวนการเพื่อส่งเหตุการณ์ Ctrl + C ไปและสร้างเหตุการณ์ เนื่องจากทำงานแยกกันโดยไม่มีคอนโซลเหตุการณ์ Ctrl + C จึงไม่จำเป็นต้องปิดใช้งานและเปิดใช้งานอีกครั้ง

CtrlCSender.java - ขึ้นอยู่กับNemo1024 ของและKindDragon ของคำตอบ

ด้วยรหัสกระบวนการที่รู้จักแอปพลิเคชันที่ไม่ใช้ความปลอดภัยนี้จะแนบคอนโซลของกระบวนการที่กำหนดเป้าหมายและสร้างเหตุการณ์ CTRL + C ขึ้นมา

import com.sun.jna.platform.win32.Kernel32;    

public class CtrlCSender {

    public static void main(String args[]) {
        int processId = Integer.parseInt(args[0]);
        Kernel32.INSTANCE.AttachConsole(processId);
        Kernel32.INSTANCE.GenerateConsoleCtrlEvent(Kernel32.CTRL_C_EVENT, 0);
    }
}

แอปพลิเคชันหลัก - รัน CtrlCSender เป็นกระบวนการแยกต่างหาก

ProcessBuilder pb = new ProcessBuilder();
pb.command("javaw", "-cp", System.getProperty("java.class.path", "."), CtrlCSender.class.getName(), processId);
pb.redirectErrorStream();
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Process ctrlCProcess = pb.start();
ctrlCProcess.waitFor();

อืมถ้าฉันเรียกใช้สิ่งนี้กับกระบวนการ powershell กระบวนการจะยังคงมีชีวิตอยู่ ในทางกลับกันสิ่งที่น่าสนใจคือการรันในกระบวนการบน JVM ทำให้ VM ลดลงอย่างแน่นอน! คุณมีความคิดว่าทำไมกระบวนการ PowerShell ไม่ตอบสนองต่อเทคนิคนี้?
Groostav


1

วิธีแก้ปัญหาที่ฉันพบจากที่นี่ค่อนข้างง่ายถ้าคุณมี python 3.x อยู่ในบรรทัดคำสั่งของคุณ ขั้นแรกบันทึกไฟล์ (ctrl_c.py) ที่มีเนื้อหา:

import ctypes
import sys

kernel = ctypes.windll.kernel32

pid = int(sys.argv[1])
kernel.FreeConsole()
kernel.AttachConsole(pid)
kernel.SetConsoleCtrlHandler(None, 1)
kernel.GenerateConsoleCtrlEvent(0, 0)
sys.exit(0)

จากนั้นโทร:

python ctrl_c.py 12345

หากไม่ได้ผลฉันขอแนะนำให้ลองใช้โครงการ windows-kill: https://github.com/alirdn/windows-kill


1

ขอบคุณคำตอบของ jimharkและคำตอบอื่น ๆ ที่นี่ฉันพบวิธีทำใน PowerShell:

$ProcessID = 1234
$MemberDefinition = '
    [DllImport("kernel32.dll")]public static extern bool FreeConsole();
    [DllImport("kernel32.dll")]public static extern bool AttachConsole(uint p);
    [DllImport("kernel32.dll")]public static extern bool GenerateConsoleCtrlEvent(uint e, uint p);
    public static void SendCtrlC(uint p) {
        FreeConsole();
        if (AttachConsole(p)) {
            GenerateConsoleCtrlEvent(0, p);
            FreeConsole();
        }
        AttachConsole(uint.MaxValue);
    }'
Add-Type -Name 'dummyName' -Namespace 'dummyNamespace' -MemberDefinition $MemberDefinition
[dummyNamespace.dummyName]::SendCtrlC($ProcessID) }

อะไรที่ทำให้สิ่งที่ทำงานถูกส่งGenerateConsoleCtrlEventกับกลุ่มกระบวนการที่ต้องการแทนall processes that share the console of the calling processและAttachConsolethe console of the parent of the current processกลับไป


0

เพื่อนของฉันแนะนำวิธีการแก้ปัญหาที่แตกต่างออกไปโดยสิ้นเชิงและได้ผลสำหรับฉัน ใช้ vbscript ดังด้านล่าง มันเริ่มต้นและการประยุกต์ใช้ให้มันทำงาน 7 วินาทีและปิดได้โดยใช้CTRL + C

'ตัวอย่าง VBScript

Set WshShell = WScript.CreateObject("WScript.Shell")

WshShell.Run "notepad.exe"

WshShell.AppActivate "notepad"

WScript.Sleep 7000

WshShell.SendKeys "^C"

วิธีนี้ใช้ได้ผลหากแอปพลิเคชันมีหน้าต่างคุณสามารถ AppActive (นำไปไว้ที่พื้นหน้า)
rogerdpack

0

ฉันพบว่าทั้งหมดนี้ซับซ้อนเกินไปและใช้SendKeysเพื่อส่งCTRL- การCกดแป้นพิมพ์ไปยังหน้าต่างบรรทัดคำสั่ง (เช่นหน้าต่าง cmd.exe) เป็นวิธีแก้ปัญหา


0
// Send [CTRL-C] to interrupt a batch file running in a Command Prompt window, even if the Command Prompt window is not visible,
// without bringing the Command Prompt window into focus.
// [CTRL-C] will have an effect on the batch file, but not on the Command Prompt  window itself -- in other words,
// [CTRL-C] will not have the same visible effect on a Command Prompt window that isn't running a batch file at the moment
// as bringing a Command Prompt window that isn't running a batch file into focus and pressing [CTRL-C] on the keyboard.
ulong ulProcessId = 0UL;
// hwC = Find Command Prompt window HWND
GetWindowThreadProcessId (hwC, (LPDWORD) &ulProcessId);
AttachConsole ((DWORD) ulProcessId);
SetConsoleCtrlHandler (NULL, TRUE);
GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0UL);
SetConsoleCtrlHandler (NULL, FALSE);
FreeConsole ();

0

SIGINT จะสามารถส่งไปยังโปรแกรมโดยใช้หน้าต่างฆ่าโดยไวยากรณ์windows-kill -SIGINT PIDที่PIDสามารถรับได้โดยไมโครซอฟท์pslist

เกี่ยวกับการจับ SIGINT หากโปรแกรมของคุณอยู่ใน Python คุณสามารถใช้การประมวลผล / การจับ SIGINT ในโซลูชันนี้


-1

ตามรหัสกระบวนการเราสามารถส่งสัญญาณไปประมวลผลเพื่อยุติการบังคับหรืออย่างสง่างามหรือสัญญาณอื่น ๆ

แสดงรายการกระบวนการทั้งหมด:

C:\>tasklist

เพื่อฆ่ากระบวนการ:

C:\>Taskkill /IM firefox.exe /F
or
C:\>Taskkill /PID 26356 /F

รายละเอียด:

http://tweaks.com/windows/39559/kill-processes-from-command-prompt/


สันนิษฐานว่าสิ่งนี้ส่งซิกเทอร์ม?
teknopaul

Taskkill ไม่ส่ง CTRL-C ตรวจสอบสัญญาณ Windows
Josi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.