## ADDED Requirements ### Requirement: InjectAndExecuteEx creates remote thread without waiting `BlackMagic.InjectAndExecuteEx(IntPtr startAddress, IntPtr parameter)` injects code at `startAddress` into the opened process, creates a remote thread with `parameter`, and returns the thread handle immediately without waiting for the thread to exit. #### Scenario: successful non-blocking execution - **WHEN** a process is open and `InjectAndExecuteEx(addr, param)` is called with a valid code address - **THEN** a remote thread is created in the target process and a valid `SafeMemoryHandle` is returned #### Scenario: no process open - **WHEN** no process is open and `InjectAndExecuteEx(addr, param)` is called - **THEN** `null` is returned ### Requirement: InjectAndExecuteEx single-parameter overload `BlackMagic.InjectAndExecuteEx(IntPtr startAddress)` calls `InjectAndExecuteEx(startAddress, IntPtr.Zero)`. #### Scenario: parameter-less non-blocking execution - **WHEN** `InjectAndExecuteEx(addr)` is called with a valid address - **THEN** the thread is created with parameter `IntPtr.Zero` ### Requirement: InjectAndExecuteEx from assembly text `BlackMagic.InjectAndExecuteEx(string asm)` assembles the text via `AsmBuilder`, allocates remote memory, writes the bytes, calls `InjectAndExecuteEx` on the allocated address, and returns the thread handle. #### Scenario: execute assembly text non-blocking - **WHEN** `InjectAndExecuteEx("nop")` is called with a process open - **THEN** the text is assembled to bytes, written to remote memory, a thread is started, and the handle is returned #### Scenario: assembly failure - **WHEN** `InjectAndExecuteEx("invalidinstruction")` is called - **THEN** `ArgumentException` is thrown with the assembly error ### Requirement: InjectAndExecute from assembly text (blocking convenience) `BlackMagic.InjectAndExecute(string asm)` assembles the text, allocates remote memory, writes the bytes, calls `Execute` (blocking, 10s timeout), and returns the exit code. #### Scenario: execute assembly text blocking - **WHEN** `InjectAndExecute("mov eax, 42\nret")` is called with a process open - **THEN** the text is assembled, injected, executed, and the thread exit code is returned