Giter VIP home page Giter VIP logo

injdrv's Introduction

injdrv

injdrv is a proof-of-concept Windows Driver for injecting DLL into user-mode processes using APC.

Motivation

Even though APCs are undocumented to decent extent, the technique of using them to inject a DLL into a user-mode process is not new and has been talked through many times. Such APC can be queued from regular user-mode process (seen in Cuckoo) as well as from kernel-mode driver (seen in Blackbone).

Despite its popularity, finding small, easy-to-understand and actually working projects demonstrating usage of this technique isn't very easy. This project tries to fill this gap.

Features

  • Support for Windows 7 up to Windows 10
  • Support for x86, x64, ARM32 & ARM64 architectures
  • Ability to inject Wow64 processes
    • With DLL of the same architecture as the injected process (e.g. x86 DLL into x86 Wow64 process)
    • With DLL of the same architecture as the OS (e.g. x64 DLL into Wow64 process on Windows x64)
  • DLL is injected in very early process initialization stage
    • Injection is performed from the PsSetLoadImageNotifyRoutine callback
    • Native processes (e.g. x86 on Windows x86, x64 on Windows x64, ...) are injected on next load of DLL after ntdll.dll
    • Wow64 processes are injected on next load of DLL after the Wow64-DLLs are loaded
  • Because of that, injected DLL must depend only on ntdll.dll
  • Demonstrative DLL performs hooking of few ntdll.dll functions
  • Detoured functions use ETW to trace hooked function calls

Compilation

Because DetoursNT project is attached as a git submodule, which itself carries the Detours git submodule, you must not forget to fetch them:

git clone --recurse-submodules [email protected]:wbenny/injdrv.git

After that, compile this project using Visual Studio 2017. Solution file is included. The only required dependency is WDK.

Implementation

When the driver is loaded, it'll register two callbacks:

When a new process is created, the driver allocates small structure, which will hold information relevant to the process injection, such as:

  • Which DLLs are already loaded in the process
  • Addresses of important functions (such as LdrLoadDll in ntdll.dll)

Start of a new Windows process is followed by mapping ntdll.dll into its address space and then ongoing load of DLLs from the process's import table. In case of Wow64 processes on Windows x64, the following libraries are loaded immediately after native ntdll.dll: wow64.dll, wow64cpu.dll, wow64win.dll and second (Wow64) ntdll.dll. The driver is notified about load of these DLLs and marks down this information.

When these DLLs are loaded, it is safe for the driver to queue the user-mode APC to the process, which will load our DLL into the process.

Challenges

Although such project might seem trivial to implement, there are some obstacles you might be facing along the way. Here I will try to summarize some of them:

"Thunk"-method

This method injects DLL of the same architecture as the process. This method is available on all architectures.

Injection of DLL requires a small allocation inside of the user-mode address space. This allocation holds path to the DLL to be injected and a small thunk (shellcode), which basically calls LdrLoadDll with the DLL path as a parameter. It is obvious that this memory requires PAGE_EXECUTE_READ protection, but the driver has to fill this memory somehow - and PAGE_EXECUTE_READWRITE is unacceptable security concern.

It might be tempting to use ZwAllocateVirtualMemory and ZwProtectVirtualMemory but unfortunatelly, the second function is exported only since Windows 8.1.

The solution used in this driver is to create section (ZwCreateSection), map it (ZwMapViewOfSection) with PAGE_READWRITE protection, write the data, unmap it (ZwUnmapViewOfSection) and then map it again with PAGE_EXECUTE_READ protection.

With usage of sections another problem arises. Since this driver performs injection from the image load notification callback - which is often called from the NtMapViewOfSection function - we'd be calling MapViewOfSection recursively. This wouldn't be a problem, if mapping of the section wouldn't lock the EPROCESS->AddressCreationLock. Because of that, we would end up in deadlock.

The solution used in this driver is to inject kernel-mode APC first, from which the ZwMapViewOfSection is called. This kernel-mode APC is triggered right before the kernel-to-user-mode transition, so the internal NtMapViewOfSection call won't be on the callstack anymore (and therefore, AddressCreationLock will be unlocked).

Injection of our DLL is triggered on first load of DLL which happens after all important system DLLs (mentioned above) are already loaded.

In case of native processes, the codeflow is following:

  • process.exe is created (process create notification)
  • process.exe is loaded (image load notification)
  • ntdll.dll is loaded (image load notification)
  • kernel32.dll is loaded (image load notification + injection happens here)

In case of Wow64 processes, the codeflow is following:

  • process.exe is created (process create notification)
  • process.exe is loaded (image load notification)
  • ntdll.dll is loaded (image load notification)
  • wow64.dll is loaded (image load notification)
  • wow64cpu.dll is loaded (image load notification)
  • wow64win.dll is loaded (image load notification)
  • ntdll.dll is loaded (image load notification - note, this is 32-bit ntdll.dll)
  • kernel32.dll is loaded (image load notification + injection happens here)

NOTE: Load of the kernel32.dll was used as an example. In fact, load of any DLL will trigger the injection. But in practice, kernel32.dll is loaded into every Windows process, even if:

  • it has no import table
  • it doesn't depend on kernel32.dll
  • it does depend only on ntdll.dll (covered in previous point, I just wanted to make that crystal-clear)
  • it is a console application

Also note that the order of loaded DLLs mentioned above might not reflect the exact order the OS is performing.

The only processes that won't be injected by this method are:

Injection of these processes is not in the scope of this project.

NOTE: On Windows 7, the Wow64 loads kernel32.dll and user32.dll (both native and Wow64) into the process. Unfortunatelly, this load is performed in the initialization of Wow64 (by wow64!ProcessInit), therefore on Windows 7 we have to wait until these DLLs are loaded as well before injecting a Wow64 process.

The injected user-mode APC is then force-delivered by calling KeTestAlertThread(UserMode). This call internally checks if any user-mode APCs are queued and if so, sets the Thread->ApcState.UserApcPending variable to TRUE. Because of this, the kernel immediately delivers this user-mode APC (by KiDeliverApc) on next transition from kernel-mode to user-mode.

If we happened to not force the delivery of the APC, the APC would've been delivered when the thread would be in the alertable state. (There are two alertable states per each thread, one for kernel-mode, one for user-mode; this paragraph is talking about Thread->Alerted[UserMode] == TRUE.) Luckily, this happens when the Windows loader in the ntdll.dll finishes its job and gives control to the application - particularly by calling NtAlertThread in the LdrpInitialize (or _LdrpInitialize) function. So even if we happened to not force the APC, our DLL would still be injected before the main execution would take place.

NOTE: This means that if we wouldn't force delivery of the APC on our own, the APC would be delivered BEFORE the main/WinMain is executed, but AFTER all TLS callbacks are executed. This is because TLS callbacks are executed also in the early process initialization stage, within the LdrpInitialize function.

This behavior is configurable in this project by the ForceUserApc variable (by default it's TRUE).

NOTE: Some badly written drivers try to inject DLL into processes by queuing APC at wrong time. For example:

  • Queuing an APC for injecting DLL that doesn't depend only on ntdll.dll right when ntdll.dll is mapped
  • Queuing an APC for injecting DLL that depends on kernel32.dll right when kernel32.dll is mapped (but not loaded!)

Such injection will actually work as long as someone won't try to forcefully deliver user-mode APCs. Because this driver triggers immediate deliver of user-mode APCs (all of them, you can't pick which should be delivered), it might happen that APC of other driver will be triggered. If such APC consisted, let's say, of calling LoadLibraryA from kernel32.dll and the kernel32.dll won't be fully loaded (just mapped), such APC would fail. And because this injection happens in early process initialization stage, this error would be considered critical and the process start would fail. Also because basically every process is being injected, if start of every process would fail, it would make the system very unusable.

The reason why our DLL is not injected immediately from the ntdll.dll image load callback is simple: the image load callback is called when the DLL is mapped into the process - and at this stage, the DLL is not fully initialized. The initialization takes place after this callback (in user-mode, obviously). If we would happen to inject LdrLoadDll call before ntdll.dll is initialized, the call would fail somewhere in that function, because some variable it relies on would not be initialized.

Injection of Wow64 processes is handled via PsWrapApcWow64Thread(&NormalContext, &NormalRoutine) call. This function essentially alters provided arguments in a way (not covered here) that KiUserApcDispatcher in native ntdll.dll is able to recognize and handle such APCs differently. Handling of such APCs is internally resolved by calling Wow64ApcRoutine (from wow64.dll). This function then emulates queuing of "32-bit APC" and resumes its execution in KiUserApcDispatcher in the Wow64 ntdll.dll.

"Thunkless"-method

This method injects x64 DLL into both x64 (native) and x86 (Wow64) processes. This method is available only on Windows x64.

Injection of x64 DLL into Wow64 processes is tricky on its own, and SentinelOne wrote an excellent 3-part blogpost series on how to achieve that:

In short, if you try to use the same approach as with "thunk"-method for injecting x64 DLL into Wow64 process, you will run into problems with Control Flow Guard on Windows 10.

  • On x64 system, CFG maintains 2 bitmaps for Wow64 processes
    • One for "x86 address space" (used when checking execution of < 4GB memory)
    • One for "x64 address space" (used when checking execution of >= 4 GB memory)
  • You cannot allocate memory in > 4GB range (even from the kernel-mode), because of VAD that reserves this memory range
    • You can theoretically unlink such VAD from EPROCESS->VadRoot and decrement EPROCESS->VadCount, but that's highly unrecommended
  • That means, when you allocate memory inside of Wow64 process (even from the kernel-mode) or change its protection, the x86 CFG bitmap is used.
  • x64 ntdll.dll is mapped above 4GB, therefore, the KiUserApcDispatcher function is also located in > 4GB address.
  • Before KiUserApcDispatcher calls (indirectly) the NormalRoutine provided to the KeInitializeApc function, it checks whether NormalRoutine can be executed via CFG
  • Because KiUserApcDispatcher is called from > 4GB address, this CFG check is performed on x64 CFG bitmap, but this check will fail, because the allocated memory of ours is in < 4GB memory
    • You can theoreticaly work around this by disabling the CFG with various hacks, but that's also highly unrecommended
  • ZwProtectVirtualMemory and even ZwSetInformationVirtualMemory won't help you, because these APIs will operate on x86 CFG bitmap as well, if you feed them with < 4GB address

The solution outlined in the SentinelOne blogpost rests in calling LdrLoadDll of x64 ntdll.dll directly from the user APC dispatcher - effectively, making NormalRoutine point to the address of the LdrLoadDll. The issue here is that PKNORMAL_ROUTINE takes only 3 parameters, while LdrLoadDll takes 4.

typedef
VOID
(NTAPI *PKNORMAL_ROUTINE) (
  _In_ PVOID NormalContext,
  _In_ PVOID SystemArgument1,
  _In_ PVOID SystemArgument2
  );

NTSTATUS
NTAPI
LdrLoadDll (
  _In_opt_ PWSTR SearchPath,
  _In_opt_ PULONG DllCharacteristics,
  _In_ PUNICODE_STRING DllName,
  _Out_ PVOID *BaseAddress
  );

Note that 4th parameter of the LdrLoadDll must point to some valid address, where the BaseAddress will be stored. The devil is always in the details - the solution takes advance of "couple of lucky coincidences":

  • KiUserApcDispatcher is a function expecting RSP to point to the CONTEXT structure

  • From this structure, values P1Home ... P4Home are fetched:

    • P1Home (moved to RCX) represent NormalContext
    • P2Home (moved to RDX) represent SystemArgument1
    • P3Home (moved to R8) represent SystemArgument2
    • P4Home (moved to RAX) represent NormalRoutine
    • Also, R9 is set to point to the RSP (the CONTEXT structure)
    • Note that RCX, RDX, R8 and R9 are used as first four function parameters in Microsoft x64 calling convention

  • KiUserApcDispatcher calls KiUserCallForwarder

    • KiUserCallForwarder checks whether RAX points to valid execution target (in x64 CFG bitmap)
    • KiUserCallForwarder calls function pointed by RAX with parameters RCX, RDX, R8 and R9
    • This is basically equivalent of calling APC's PKNORMAL_ROUTINE
      • NormalRoutine(NormalContext, SystemArgument1, SystemArgument2)
    • ...except that, because R9 is set, it is in fact called like this:
      • NormalRoutine(NormalContext, SystemArgument1, SystemArgument2, ContinueContext)

  • Therefore, if we queue the user-mode APC like this:

    • NormalRoutine = address of LdrLoadDll in 64-bit ntdll.dll
    • NormalContext = NULL (translates to 1st param. of LdrLoadDll (SearchPath))
    • SystemArgument1 = NULL (translates to 2nd param. of LdrLoadDll (DllCharacteristics))
    • SystemArgument2 = pointer to UNICODE_STRING DllName (translates to 3rd param. of LdrLoadDll (DllName))
    • (as mentioned above, the 4th parameter (BaseAddress) will be provided automatically by the KiUserApcDispatcher)
  • ...it will effectively result in the following call: LdrLoadDll(NULL, 0, &DllName, &ContinueContext)

  • LdrLoadDll overwrites first 8 bytes of the CONTEXT structure, which happens to be its P1Home field

  • It doesn't break anything, because this field has been already used (when fetching NormalContext) and is no longer accessed (not even by ZwContinue)

NOTE: Not all function calls from x86 NTDLL end up in x64 NTDLL. This is because some functions are fully implemented on its own in both x86 and x64 NTDLL. This applies mainly on functions that does not require any syscall - i.e. Rtl* functions. For example, if you wanted to hook RtlDecompressBuffer in Wow64 process, hooking that function in x64 NTDLL wouldn't have any effect and such hooked function would be never called.

NOTE: Because of differences in APC-dispatching mechanism, this method is not possible to use on x86 or ARM64 Windows.

"wow64log.dll reparse"-method

This method injects native DLL into all processes. This method is available on all architectures.

When Wow64 process is starting, the wow64.dll tries to load wow64log.dll. This DLL is never present in regular Windows installation (it's probably used internally by Microsoft for debugging of the Wow64 subsystem). Therefore, load of this DLL will normally fail. This isn't problem, though, because no critical functionality of the Wow64 subsystem depends on it. If the load actually succeeds, it tries to find following exported functions in the DLL:

  • Wow64LogInitialize
  • Wow64LogMessageArgList
  • Wow64LogSystemService
  • Wow64LogTerminate

If one of these functions is not exported by the DLL, the DLL is immediately unloaded.

If we drop custom wow64log.dll (which exports functions mentioned above) into the %SystemRoot%\System32 directory, it gets loaded into every Wow64 process.

For more details, this method is greatly described by Walied Assar

The actual injection of Wow64 processes by injdrv is handled via redirection of wow64log.dll path to the path of our native DLL. This redirection is solved via filter driver, which registers IRP_MJ_CREATE pre-callback. When this pre-callback detects that the wow64log.dll file is being opened, it replaces the path in the FILE_OBJECT by using IoReplaceFileObjectName function and returning STATUS_REPARSE in the IO_STATUS_BLOCK. The code of the filter driver is entirely based on SimRep example found in Microsoft's WDK examples.

NOTE: Because native processes do not load wow64.dll, injdrv injects them using "thunk"-method when "wow64log.dll reparse"-method is selected.

NOTE: Because wow64.dll itself is compiled for native architecture, the wow64log.dll must be also native.

Protected processes

Injection of protected processes is simply skipped, as it triggers code-integrity errors. Such processes are detected by the PsIsProtectedProcess function. If you're curious about workaround of this issue (by temporarily unprotecting these processes), you can peek into Blackbone source code. Keep in mind that unprotecting protected processes requires manipulation with undocumented structures, which change dramatically between Windows versions.

ETW logging

Finally, as mentioned in the beginning, the injected DLL performs logging of hooked functions with ETW. Because functions such as EventRegister, EventWriteString, ... are located in the advapi32.dll, we can't use them from our NTDLL-only dependent DLL. Luckily, ETW support is hardwired in the ntdll.dll too. In fact, most of the Event* functions in the advapi32.dll are simply redirected to the EtwEvent* functions in ntdll.dll without any change to the arguments! Therefore, we can simply mock the Event* functions and just include the <evntprov.h> header:

//
// Include support for ETW logging.
// Note that following functions are mocked, because they're
// located in advapi32.dll.  Fortunatelly, advapi32.dll simply
// redirects calls to these functions to the ntdll.dll.
//

#define EventActivityIdControl  EtwEventActivityIdControl
#define EventEnabled            EtwEventEnabled
#define EventProviderEnabled    EtwEventProviderEnabled
#define EventRegister           EtwEventRegister
#define EventSetInformation     EtwEventSetInformation
#define EventUnregister         EtwEventUnregister
#define EventWrite              EtwEventWrite
#define EventWriteEndScenario   EtwEventWriteEndScenario
#define EventWriteEx            EtwEventWriteEx
#define EventWriteStartScenario EtwEventWriteStartScenario
#define EventWriteString        EtwEventWriteString
#define EventWriteTransfer      EtwEventWriteTransfer

#include <evntprov.h>

...easy, wasn't it?

Usage

Following example is performed on Windows 10 x64

Enable Test-Signing boot configuration option (note that you'll need administrative privileges to use bcdedit) and reboot the machine:

bcdedit /set testsigning on
shutdown /r /t 0

Now open administrator command line and run following command:

injldr -i

The -i option installs the driver. After the driver is installed, it waits for newly created processes. When a new process is created, it is hooked. Prepare some x86 application, for example, PuTTY and run it. With Process Explorer we can check that indeed, our x64 DLL is injected in this x86 application.

Also, immediately after injldr is started, it starts an ETW tracing session and prints out information about called hooked functions:

You can exit injldr by pressing Ctrl+C. Now you can run injldr without any parameters to just start the tracing session. If you wish to uninstall the driver, run injldr -u.

This driver by default uses following injection methods:

  • InjMethodThunk on Windows x86
  • InjMethodThunkless on Windows x64
  • InjMethodWow64LogReparse on Windows ARM64

Therefore, it always tries to inject native DLL into all processes, including Wow64 processes. If you wish to change this behavior and e.g. inject x86 DLL into x86 Wow64 process, set injection method to InjMethodThunk. Also, do not forget to compile injdll for the corresponding architectures and place it in the same directory as injldr.exe.

License

This software is open-source under the MIT license. See the LICENSE.txt file in this repository.

Dependencies are licensed by their own licenses.

If you find this project interesting, you can buy me a coffee

  BTC 3GwZMNGvLCZMi7mjL8K6iyj6qGbhkVMNMF
  LTC MQn5YC7bZd4KSsaj8snSg4TetmdKDkeCYk

injdrv's People

Contributors

wbenny avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

injdrv's Issues

0x139_3_CORRUPT_LIST_ENTRY_injdrv in InjCreateInjectionInfo while call InsertTailList


                    Bugcheck Analysis 

KERNEL_SECURITY_CHECK_FAILURE (139)
A kernel component has corrupted a critical data structure. The corruption
could potentially allow a malicious user to gain control of this machine.
Arguments:
Arg1: 0000000000000003, A LIST_ENTRY has been corrupted (i.e. double remove).
Arg2: fffff208510c9970, Address of the trap frame for the exception that caused the BugCheck
Arg3: fffff208510c98c8, Address of the exception record for the exception that caused the BugCheck
Arg4: 0000000000000000, Reserved

Debugging Details:

"C:\Windows\System32\KERNELBASE.dll" was not found in the image list.
Debugger will attempt to load "C:\Windows\System32\KERNELBASE.dll" at given base 00000000`00000000.

Please provide the full image name, including the extension (i.e. kernel32.dll)
for more reliable results.Base address and size overrides can be given as
.reload <image.ext>=<base>,<size>.
Unable to add module at 00000000`00000000

KEY_VALUES_STRING: 1

Key  : Analysis.CPU.mSec
Value: 2171

Key  : Analysis.DebugAnalysisManager
Value: Create

Key  : Analysis.Elapsed.mSec
Value: 693889

Key  : Analysis.IO.Other.Mb
Value: 15

Key  : Analysis.IO.Read.Mb
Value: 4

Key  : Analysis.IO.Write.Mb
Value: 27

Key  : Analysis.Init.CPU.mSec
Value: 1734

Key  : Analysis.Init.Elapsed.mSec
Value: 11687220

Key  : Analysis.Memory.CommitPeak.Mb
Value: 97

Key  : Bugcheck.Code.DumpHeader
Value: 0x139

Key  : Bugcheck.Code.KiBugCheckData
Value: 0x139

Key  : Bugcheck.Code.Register
Value: 0x3

Key  : FailFast.Name
Value: CORRUPT_LIST_ENTRY

Key  : FailFast.Type
Value: 3

Key  : WER.OS.Branch
Value: 19h1_release

Key  : WER.OS.Timestamp
Value: 2019-03-18T12:02:00Z

Key  : WER.OS.Version
Value: 10.0.18362.1

BUGCHECK_CODE: 139

BUGCHECK_P1: 3

BUGCHECK_P2: fffff208510c9970

BUGCHECK_P3: fffff208510c98c8

BUGCHECK_P4: 0

TRAP_FRAME: fffff208510c9970 -- (.trap 0xfffff208510c9970)
NOTE: The trap frame does not contain all registers.

Some register values may be zeroed or incorrect. rax=ffffda084ac90b90 rbx=0000000000000000 rcx=0000000000000003 rdx=fffff804756b6370 rsi=0000000000000000 rdi=0000000000000000 rip=fffff804756b1772 rsp=fffff208510c9b08 rbp=fffff208510c9c89 r8=0000000000000000 r9=0000000000000fff r10=ffffa20003219000 r11=fffff208510c9b30 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei ng nz na pe nc injdrv+0x1772: fffff804`756b1772 cd29 int 29h Resetting default scope

EXCEPTION_RECORD: fffff208510c98c8 -- (.exr 0xfffff208510c98c8)
ExceptionAddress: fffff804756b1772 (injdrv+0x0000000000001772)
ExceptionCode: c0000409 (Security check failure or stack buffer overrun)
ExceptionFlags: 00000001
NumberParameters: 1
Parameter[0]: 0000000000000003
Subcode: 0x3 FAST_FAIL_CORRUPT_LIST_ENTRY

PROCESS_NAME: ngentask.exe

ERROR_CODE: (NTSTATUS) 0xc0000409 - <Unable to get error code text>

EXCEPTION_CODE_STR: c0000409

EXCEPTION_PARAMETER1: 0000000000000003

EXCEPTION_STR: 0xc0000409

STACK_TEXT:
fffff208510c8ea8 fffff804720a9522 : 0000000000000003 0000000000000003 fffff208510c9010 fffff80471f1db90 : nt!DbgBreakPointWithStatus
fffff208510c8eb0 fffff804720a8c12 : 0000000000000003 fffff208510c9010 fffff80471fd5b60 0000000000000139 : nt!KiBugCheckDebugBreak+0x12
fffff208510c8f10 fffff80471fc15e7 : ffffda084a8f6ae0 fffff80471e40b8a fffff208510c9c60 00000000ffff7fff : nt!KeBugCheck2+0x952
fffff208510c9610 fffff80471fd32e9 : 0000000000000139 0000000000000003 fffff208510c9970 fffff208510c98c8 : nt!KeBugCheckEx+0x107
fffff208510c9650 fffff80471fd3710 : 0000000000000000 0000000000000000 ffffb28a8afb1730 fffff208510c9840 : nt!KiBugCheckDispatch+0x69
fffff208510c9790 fffff80471fd1aa5 : ffffda083f267300 fffff80472460351 0000000000000000 0000000000000000 : nt!KiFastFailDispatch+0xd0
fffff208510c9970 fffff804756b1772 : fffff804756b182d 0000000000000000 0000000000000000 00000000000000c8 : nt!KiRaiseSecurityCheckFailure+0x325
fffff208510c9b08 fffff804756b182d : 0000000000000000 0000000000000000 00000000000000c8 fffff80471f9fb13 : injdrv+0x1772
fffff208510c9b10 fffff804756b2a61 : fffff804756b6370 fffff804756b6370 0000000000000000 fffff8047216f06d : injdrv+0x182d
fffff208510c9b40 fffff804756b28d8 : fffff804756b6370 0000000000000030 ffffda0800000000 fffff80474dea5a0 : injdrv+0x2a61
fffff208510c9b70 fffff804756b19b7 : fffff804756b6370 ffffda084ac90b90 ffffda0843c089a0 ffffda0800000000 : injdrv+0x28d8
fffff208510c9bb0 fffff804756b19e7 : 0000000000000000 0000000000000380 ffffda0843c08970 ffffda084a0d72c0 : injdrv+0x19b7
fffff208510c9bf0 fffff804723cd996 : ffffda084a0d72c0 0000000000000380 fffff208510c9c60 0000000000000000 : injdrv+0x19e7
fffff208510c9c20 fffff8047245da9c : ffffffff00000000 fffff208510caa10 fffff208510ca301 ffffda084b41d120 : nt!PspCallProcessNotifyRoutines+0x212
fffff208510c9cf0 fffff8047242fba4 : ffffda084aec60c0 ffffda084a0d72c0 fffff208510ca4b0 fffff208510ca370 : nt!PspInsertThread+0x5e8
fffff208510c9de0 fffff80471fd2d18 : 00000000004ffda0 0000000000774000 0000000000000000 0000000000000000 : nt!NtCreateUserProcess+0x964
fffff208510caa90 00007ffd54ddd934 : 00007ffd52fa04f8 00007ffd00580058 0000000000a901dc 00000000004fe050 : nt!KiSystemServiceCopyEnd+0x28
00000000004fdd28 00007ffd52fa04f8 : 00007ffd00580058 0000000000a901dc 00000000004fe050 0000000000a901c0 : ntdll!NtCreateUserProcess+0x14
00000000004fdd30 00007ffd52f9fce0 : 00000000004fe050 00000000004fdef8 0000000002000000 0000000002000000 : wow64!Wow64NtCreateUserProcess+0xe4
00000000004fde10 00007ffd52f97123 : 00000000005fea01 0000000000774000 00007ffd52f9f790 0000000000000000 : wow64!whNtCreateUserProcess+0x550
00000000004fe0f0 00000000777f1783 : 0000002377871e7c 00007ffd54d90023 0000000000000000 00000000005fdf4c : wow64!Wow64SystemServiceEx+0x153
00000000004fe9b0 00000000777f1199 : 00000000005ff61c 00007ffd52f9c864 00000000004fea80 00007ffd52f9bf58 : wow64cpu!ServiceNoTurbo+0xb
00000000004fea60 00007ffd52f9c77a : 0000000000773000 0000000000450080 0000000000000000 00000000004ff2e0 : wow64cpu!BTCpuSimulate+0x9
00000000004feaa0 00007ffd52f9c637 : 0000000000000000 0000000000912178 0000000000000000 0000000000000000 : wow64!RunCpuSimulation+0xa
00000000004fead0 00007ffd54e13fb3 : 0000000000772000 0000000000772000 00007ffd54e6d4c0 0000000000000010 : wow64!Wow64LdrpInitialize+0x127
00000000004fed80 00007ffd54e01db5 : 0000000000000001 0000000000000000 0000000000000000 0000000000000001 : ntdll!LdrpInitializeProcess+0x186b
00000000004ff1c0 00007ffd54db1853 : 0000000000000000 00007ffd54d40000 0000000000000000 0000000000774000 : ntdll!_LdrpInitialize+0x50549
00000000004ff260 00007ffd54db17fe : 00000000004ff2e0 0000000000000000 0000000000000000 0000000000000000 : ntdll!LdrpInitialize+0x3b
00000000004ff290 0000000000000000 : 0000000000000000 0000000000000000 0000000000000000 0000000000000000 : ntdll!LdrInitializeThunk+0xe

SYMBOL_NAME: injdrv+1772

MODULE_NAME: injdrv

IMAGE_NAME: injdrv.sys

STACK_COMMAND: .cxr; .ecxr ; kb

BUCKET_ID_FUNC_OFFSET: 1772

FAILURE_BUCKET_ID: 0x139_3_CORRUPT_LIST_ENTRY_injdrv!unknown_function

OS_VERSION: 10.0.18362.1

BUILDLAB_STR: 19h1_release

OSPLATFORM_TYPE: x64

OSNAME: Windows 10

FAILURE_ID_HASH: {b45b9d7e-89f1-dfe2-8192-89894ee49511}

Followup: MachineOwner

7: kd> .trap 0xfffff208510c9970
NOTE: The trap frame does not contain all registers.

Some register values may be zeroed or incorrect. rax=ffffda084ac90b90 rbx=0000000000000000 rcx=0000000000000003 rdx=fffff804756b6370 rsi=0000000000000000 rdi=0000000000000000 rip=fffff804756b1772 rsp=fffff208510c9b08 rbp=fffff208510c9c89 r8=0000000000000000 r9=0000000000000fff r10=ffffa20003219000 r11=fffff208510c9b30 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei ng nz na pe nc injdrv+0x1772: fffff804`756b1772 cd29 int 29h

k
*** Stack trace for last set context - .thread/.cxr resets it

Child-SP RetAddr Call Site

00 fffff208510c9b08 fffff804756b182d injdrv+0x1772
01 fffff208510c9b10 fffff804756b2a61 injdrv+0x182d
02 fffff208510c9b40 fffff804756b28d8 injdrv+0x2a61
03 fffff208510c9b70 fffff804756b19b7 injdrv+0x28d8
04 fffff208510c9bb0 fffff804756b19e7 injdrv+0x19b7
05 fffff208510c9bf0 fffff804723cd996 injdrv+0x19e7
06 fffff208510c9c20 fffff8047245da9c nt!PspCallProcessNotifyRoutines+0x212
07 fffff208510c9cf0 fffff8047242fba4 nt!PspInsertThread+0x5e8
08 fffff208510c9de0 fffff80471fd2d18 nt!NtCreateUserProcess+0x964
09 fffff208510caa90 00007ffd54ddd934 nt!KiSystemServiceCopyEnd+0x28
0a 00000000004fdd28 00007ffd52fa04f8 ntdll!NtCreateUserProcess+0x14
0b 00000000004fdd30 00007ffd52f9fce0 wow64!Wow64NtCreateUserProcess+0xe4
0c 00000000004fde10 00007ffd52f97123 wow64!whNtCreateUserProcess+0x550
0d 00000000004fe0f0 00000000777f1783 wow64!Wow64SystemServiceEx+0x153
0e 00000000004fe9b0 00000000777f1199 wow64cpu!ServiceNoTurbo+0xb
0f 00000000004fea60 00007ffd52f9c77a wow64cpu!BTCpuSimulate+0x9
10 00000000004feaa0 00007ffd52f9c637 wow64!RunCpuSimulation+0xa
11 00000000004fead0 00007ffd54e13fb3 wow64!Wow64LdrpInitialize+0x127
12 00000000004fed80 00007ffd54e01db5 ntdll!LdrpInitializeProcess+0x186b
13 00000000004ff1c0 00007ffd54db1853 ntdll!_LdrpInitialize+0x50549
14 00000000004ff260 00007ffd54db17fe ntdll!LdrpInitialize+0x3b
15 00000000004ff290 0000000000000000 ntdll!LdrInitializeThunk+0xe

MSB3191: Unable to create director

The command I have used to build was:
msbuild injldr.vcxproj /p:Configuration=Release /p:Platform=x64

Error

Build FAILED.

"C:\Users\Username\injdrv\src\injldr\injldr.vcxproj" (default target) (1) ->
(MakeDirsForCl target) ->
  C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppBuild.targets(1016,5): error MSB3191: Unable to create director
y "C:\Users\Username\injdrv\src\injldr\bin\obj\x64\Release\injldr\C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.36.32532\modules". The g
iven path's format is not supported. [C:\Users\Username\injdrv\src\injldr\injldr.vcxproj]

What did I do as a solution
I have changed
<ObjectFileName>$(IntDir)%(RelativeDir)%(Filename)%(Extension).obj</ObjectFileName>
in line 70 to
<ObjectFileName>$(IntDir)%(Directory)%(Filename)%(Extension).obj</ObjectFileName>

bypass ProcessDynamicCodePolicy mitigation policy flagged processes.

Unprotected processes may set the ProcessDynamicCodePolicy flag on, which prevents the driver from allocate new executable memory on their virtual memory space and fail injDrv.

I guess that the intention was that no user-space program may alter this settings, but there must be a way from driver to avoid this bit, since it has more privileges.

I know that there are methods to detect mitigation policy flags such as NtQueryInformationProcess and set them using SetProcessMitigationPolicy(), but they all uses undocumented structures. I wonder if there's an alternative way to do so from driver...

Is there any way to avert this bit from driver once process has started, or allocate the memory for injected code before this policy is being enforced ?

thanks

Infection successful but dll is not loaded

I complied the driver and created 2 x64/x86 dlls that just call to OutputDebugString on process attach.
I get injection successful message in DebugView but nothing is printed in the DebugView that indicates that the dll was loaded to the process. I also used procexp and I don't see the injdllx64 in the dll list. This behavior is on all the processes!

This is the message I'm getting for example from DebugView:
[injlib]: Injecting (PID: 15608, Wow64: FALSE, Name: 'ftp.exe')
[injlib]: InjpQueueApc successfull
[injlib]: Mark process: 15608 is injected

What could be the reason that it does not load the dll?

Thanks,
Rony.

PsWrapApcWow64Thread cause normalRoutine to become invalid.

Hi,

I've got a question regarding the usage of the undocumented method PsWrapApcWow64Thread
that is used to support regular 32bits normalRoutines to wow64 processes.

Basically i've used your project with replacing the section memory allocation with ZwProtectVirtualMemory for user-space memory allocation on the context of the process I wish to inject to. I'm using VM of windows 10 RS5.

reading the memory from winDbg, the candidate NormalRoutine function looked pretty much like a normal function in assembly code :

0: kd> u 0x00000000`00880000

00000000`00880000 55              push    rbp
00000000`00880001 8bec            mov     ebp,esp
00000000`00880003 83ec1c          sub     esp,1Ch

However, after calling the method PsWrapApcWow64Thread with this function I got the following wrapping :

0: kd> u 0x00000000`00880000

00000000`00880000 ac              lods    byte ptr [rsi]
00000000`00880001 d24df0          ror     byte ptr [rbp-10h],cl
00000000`00880004 4d8ce3          mov     r11,fs
00000000`00880007 e8fc000000      call    00000000`00880108
00000000`0088000c 00c7            add     bh,al
00000000`0088000e 45ec            in      al,dx
00000000`00880010 0000            add     byte ptr [rax],al

First, i thought that the original function was relocated to address 00880108, but when i read this section in memory i got all zeros

0: kd> dd 00000000`00880108
00000000`00880108  00000000 00000000 00000000 00000000
00000000`00880118  00000000 00000000 00000000 00000000
00000000`00880128  00000000 00000000 00000000 00000000
00000000`00880138  00000000 00000000 00000000 00000000
...

So it seems that the wrapping cause the code to jump to "zeroes" code.
Any idea what went wrong ?

don`t compiling

I compile the project in visual studio 2019 and get the following:
Error C1083 Cannot open the inclusion file: phnt / phnt_windows.h: No such file or directory, injdll C: \ Users \ Alexander \ Desktop \ injdrv-master \ include \ ntdll.h 19
Error LNK1104 cannot open the file "LIBCMT.lib" injldr C: \ Users \ Alexander \ Desktop \ injdrv-master \ src \ injldr \ LINK 1

Inject to Running processes (with no altertable threads)

Hi,

I was wonder if it's optional to using APC to inject into already running processes that doesn't necessarily have alertable threads.

According to APC doc :

When a user-mode APC is queued, the thread to which it is queued is not directed to call the APC function unless it is in an alertable state. (I assume kernel-mode APC work the same way)

Is there a way to change thread state so it will accept APC calls, or any other alternative ?

thanks

BSOD Windows 10

Hi & Tnx for your code

After a few hours running in system, We've got a BSOD. Can you guide me to how to fix it plz ?!
this is the result of !analyze -v

BUGCODE_NDIS_DRIVER (7c)
The operating system detected an error in a networking driver.
The BUGCODE_NDIS_DRIVER bugcheck identifies problems in network drivers.
Often, the defect is caused by a NDIS miniport driver. You can get a complete
list of NDIS miniport drivers using !ndiskd.netadapter. You can get a
big-picture overview of the network stack with !ndiskd.netreport.
Arguments:
Arg1: 0000000000000025, NDIS_BUGCHECK_WATCHDOG
An attempt to manage the network stack has taken too
long. When NDIS calls out into other drivers, NDIS
starts a watchdog timer to ensure the call completes
promptly. If the call takes too long, NDIS injects a
bugcheck.
This can be caused by a simple deadlock -- look with
"!stacks 2 ndis!" or similar to see if any threads
look suspicious. Pay special attention to the
PrimaryThread from the NDIS_WATCHDOG_TRIAGE_BLOCK.
This can be caused by lost NBLs, in which case
!ndiskd.pendingnbls may help. Check for OIDs that are
stuck using !ndiskd.oid.
Arg2: 0000000000000011, NDIS_BUGCHECK_WATCHDOG_FILTER_PAUSE
There was a timeout while pausing a filter driver.
Arg3: ffffd78e90fb4fa8, Cast to ndis!_NDIS_WATCHDOG_TRIAGE_BLOCK. Interesting fields:
* StartTime shows what time the operation started,
in 100ns units, as returned by KeQueryInterruptTime.
* TimeoutMilliseconds shows how long NDIS waited, at a
minimum, before triggering this bugcheck.
Measured in milliseconds.
* TargetObject is a handle to the protocol, filter,
or miniport that NDIS is waiting on. Use with
!ndiskd.protocol, !ndiskd.filter, or !ndiskd.miniport.
* PrimaryThread is the thread on which NDIS initiated
the operation. Usually this is the first place to
look, although the thread may have gone elsewhere
if the operation is being handled asynchronously.
Arg4: 0000000000000000

Debugging Details:

KEY_VALUES_STRING: 1

PROCESSES_ANALYSIS: 1

SERVICE_ANALYSIS: 1

STACKHASH_ANALYSIS: 1

TIMELINE_ANALYSIS: 1

DUMP_CLASS: 1

DUMP_QUALIFIER: 0

BUILD_VERSION_STRING: 18362.1.amd64fre.19h1_release.190318-1202

DUMP_TYPE: 0

BUGCHECK_P1: 25

BUGCHECK_P2: 11

BUGCHECK_P3: ffffd78e90fb4fa8

BUGCHECK_P4: 0

MODULE_NAME: wfplwfs

FAULTING_IP:
wfplwfs!LwfLowerPause+0
fffff805`081a61f0 48895c2408 mov qword ptr [rsp+8],rbx

CPU_COUNT: 4

CPU_MHZ: a22

CPU_VENDOR: GenuineIntel

CPU_FAMILY: 6

CPU_MODEL: 3e

CPU_STEPPING: 4

CPU_MICROCODE: 6,3e,4,0 (F,M,S,R) SIG: 427'00000000 (cache) 427'00000000 (init)

DEFAULT_BUCKET_ID: WIN8_DRIVER_FAULT

BUGCHECK_STR: 0x7C

PROCESS_NAME: System

CURRENT_IRQL: 0

ANALYSIS_SESSION_TIME: 12-14-2020 12:28:48.0744

ANALYSIS_VERSION: 10.0.18362.1 amd64fre

STACK_TEXT:
ffff9f88ad213c38 fffff80505aba942 : 0000000000000025 0000000000000003 ffff9f88ad213da0 fffff805058709f0 : nt!DbgBreakPointWithStatus
ffff9f88ad213c40 fffff80505aba032 : 0000000000000003 ffff9f88ad213da0 fffff805059e7a60 000000000000007c : nt!KiBugCheckDebugBreak+0x12
ffff9f88ad213ca0 fffff805059d3487 : 0000000000000000 0000000000000007 ffffd78e8a80c1a0 fffff80505b3af6b : nt!KeBugCheck2+0x952
ffff9f88ad2143a0 fffff80507c4e27e : 000000000000007c 0000000000000025 0000000000000011 ffffd78e90fb4fa8 : nt!KeBugCheckEx+0x107
ffff9f88ad2143e0 fffff80507cf4121 : 0000000000000000 fffff8050618b3f0 ffffd78e90fb4ee0 00000000000000a8 : ndis!ndisBugCheckEx+0x1e
ffff9f88ad214420 fffff80507cf3ff1 : 0000000003bfefbf ffffd78e90fb4ee0 fffff80507cb6918 0000000000000000 : ndis!ndisReportTimeoutWaitingForExternalDriver+0xd5
ffff9f88ad214460 fffff80507cf43e9 : 0000000000040b28 ffffd78e90fb4fa8 0000000000000011 ffff9f88ad214558 : ndis!ndisFindSomeoneToBlame+0x125
ffff9f88ad2144d0 fffff80507cf3e6e : ffffd78e90fb4ee0 ffff9f88ad2145d9 ffffd78e8b6b2d30 0000000000010286 : ndis!ndisWaitForExternalDriver+0x75
ffff9f88ad214500 fffff80507cf4342 : ffffd78e90fb4ee0 fffff80507cf4314 0000000000000010 0000000000010246 : ndis!NdisWatchdogState::WaitSynchronously+0x6e
ffff9f88ad214540 fffff80507d06a23 : ffffd78e90fb4ee0 ffff9f88ad2145d9 ffffd78e8b6b2d30 ffffd78e8b6b2ca0 : ndis!ndisWaitForEventThenDisarmWatchdog+0x2e
ffff9f88ad214580 fffff80507cdb830 : ffffe78746c4efa0 ffffe78746c4efa0 ffffd78e8a80d5a8 ffffd78e8b6b2ca0 : ndis!ndisPauseFilterInner+0x573b
ffff9f88ad214640 fffff80507cd166a : 0000000000000000 ffff9f88ad214790 ffffd78e8a80d590 0000000000000000 : ndis!ndisPauseFilter+0xb4
ffff9f88ad214690 fffff80507cd13c0 : ffffd78e8a80c1a0 ffffd78e8a80c1a0 ffffd78e8a80d608 ffffd78e8a80d590 : ndis!Ndis::BindEngine::Iterate+0x202
ffff9f88ad214810 fffff80507ccc409 : ffffd78e8a80d590 0000000000000000 0000000000000000 0000000000000000 : ndis!Ndis::BindEngine::UpdateBindings+0x98
ffff9f88ad214860 fffff80507ccc2c8 : ffffd78e8a80d590 0000000000000000 ffffd78e8a80d590 fffff80507ccc8e6 : ndis!Ndis::BindEngine::DispatchPendingWork+0x75
ffff9f88ad214890 fffff80507c24728 : ffffd78e8a80c1a0 0000000000000002 0000000000000020 0000000000000000 : ndis!Ndis::BindEngine::ApplyBindChanges+0x54
ffff9f88ad2148e0 fffff80507be280d : ffffd78e8a80c1a0 0000000000000000 ffffd78e8a80cd48 ffffd78e8a80c1a0 : ndis!ndisPrepForLowPowerCommon+0x41eec
ffff9f88ad2149d0 fffff80507be3246 : ffffd78e8a80c1a0 0000000000000000 ffffd78e970f4e10 fffff80507bd6755 : ndis!ndisPrepForLowPower+0x1d
ffff9f88ad214a20 fffff80507be3931 : 0000000000000000 ffffd78e00000004 ffffd78e970f4e10 ffffd78e8a80c1a0 : ndis!ndisSetSystemPower+0x19e
ffff9f88ad214aa0 fffff80507be9e84 : ffffd78e970f4e10 ffffd78e8690ed30 ffffd78e970f4f28 ffffd78e8a80c1a0 : ndis!ndisSetPower+0x109
ffff9f88ad214b00 fffff8050598b02f : ffffd78e8a80c050 ffff9f88ad214be0 0000000000000000 ffffd78e970f4e10 : ndis!ndisPowerDispatch+0x114
ffff9f88ad214b60 fffff8050587cce5 : 0000000000000000 ffffd78e86939080 fffff8050598ae50 0000000000000000 : nt!PopIrpWorker+0x1df
ffff9f88ad214c10 fffff805059da9ca : ffffa38117580180 ffffd78e86939080 fffff8050587cc90 0000000000000000 : nt!PspSystemThreadStartup+0x55
ffff9f88ad214c60 0000000000000000 : ffff9f88ad215000 ffff9f88ad20f000 0000000000000000 0000000000000000 : nt!KiStartSystemThread+0x2a

THREAD_SHA1_HASH_MOD_FUNC: fb82d6835acc43782ce2d8cc87312c71a062da7a

THREAD_SHA1_HASH_MOD_FUNC_OFFSET: e9f541403998cd88a52fb202de8d71d9d54c78c0

THREAD_SHA1_HASH_MOD: ee7c730e4531afb6d09bc1abcea8a663b1fba34b

FOLLOWUP_IP:
wfplwfs!LwfLowerPause+0
fffff805`081a61f0 48895c2408 mov qword ptr [rsp+8],rbx

FAULT_INSTR_CODE: 245c8948

SYMBOL_NAME: wfplwfs!LwfLowerPause+0

FOLLOWUP_NAME: MachineOwner

IMAGE_NAME: wfplwfs.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 60902cbb

STACK_COMMAND: .thread ; .cxr ; kb

BUCKET_ID_FUNC_OFFSET: 0

FAILURE_BUCKET_ID: 0x7C_VRF_FILT_Pause_wfplwfs!LwfLowerPause

BUCKET_ID: 0x7C_VRF_FILT_Pause_wfplwfs!LwfLowerPause

PRIMARY_PROBLEM_CLASS: 0x7C_VRF_FILT_Pause_wfplwfs!LwfLowerPause

TARGET_TIME: 2020-12-14T08:55:59.000Z

OSBUILD: 18362

OSSERVICEPACK: 0

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

SUITE_MASK: 272

PRODUCT_TYPE: 1

OSPLATFORM_TYPE: x64

OSNAME: Windows 10

OSEDITION: Windows 10 WinNt TerminalServer SingleUserTS

OS_LOCALE:

USER_LCID: 0

OSBUILD_TIMESTAMP: unknown_date

BUILDDATESTAMP_STR: 190318-1202

BUILDLAB_STR: 19h1_release

BUILDOSVER_STR: 10.0.18362.1.amd64fre.19h1_release.190318-1202

ANALYSIS_SESSION_ELAPSED_TIME: d54

ANALYSIS_SOURCE: KM

FAILURE_ID_HASH_STRING: km:0x7c_vrf_filt_pause_wfplwfs!lwflowerpause

FAILURE_ID_HASH: {fef43b4d-fb67-4c46-c742-ecef5a38ee06}

Followup: MachineOwner

Windows 7 x64 - InjMethodThunk method failing in ntdll!RtlEqualUnicodeString due to AV

Hello,

The InjMethodThunk method is failing on Win7 x64 (both updated 6.1.7601.24387 ntdll.dll and non updated 6.1.7601.17514) when loading a wow64 process. All native x64 processes are loaded and injected fine.
This leads to an access violation error.

Some debug output:
The original shellcode looks broken for me. I've updated it with the following one (but still failing):
0x83, 0xec, 0x0c, // sub esp,0xc
0x0f, 0xb7, 0x44, 0x24, 0x18, // movzx eax,[esp + 0x18]
0x66, 0x89, 0x04, 0x24, // mov [esp],ax
0x66, 0x89, 0x44, 0x24, 0x02, // mov [esp + 0x2],ax
0x8b, 0x44, 0x24, 0x14, // mov eax,[esp + 0x14]
0x89, 0x44, 0x24, 0x04, // mov [esp + 0x4],eax
0x8d, 0x44, 0x24, 0x08, // lea eax,[esp + 0x8]
0x50, // push eax
0x8d, 0x44, 0x24, 0x04, // lea eax,[esp + 0x04]
0x50, // push eax
0x6a, 0x00, // push 0x0
0x6a, 0x00, // push 0x0
0xff, 0x54, 0x24, 0x20, // call [esp + 0x20]
0x83, 0xc4, 0x0c, // add esp,0xc
0xc2, 0x0c, 0x00, // ret 0xc

0:000> g
ModLoad: 0000000077a10000 0000000077b2f000 WOW64_IMAGE_SECTION
ModLoad: 0000000076190000 00000000762a0000 WOW64_IMAGE_SECTION
ModLoad: 0000000077a10000 0000000077b2f000 NOT_AN_IMAGE
ModLoad: 0000000077910000 0000000077a0a000 NOT_AN_IMAGE
(b6c.eb4): WOW64 breakpoint - code 4000001f (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
00010000 cc int 3
0:000:x86> u
00010000 cc int 3
00010001 83ec0c sub esp,0Ch
00010004 0fb7442418 movzx eax,word ptr [esp+18h]
00010009 66890424 mov word ptr [esp],ax
0001000d 6689442402 mov word ptr [esp+2],ax
00010012 8b442414 mov eax,dword ptr [esp+14h]
00010016 89442404 mov dword ptr [esp+4],eax
0001001a 8d442408 lea eax,[esp+8]
0:000:x86> dd esp L8
0018fd08 77d0007d 77d2eaea 00010032 00000062
0018fd18 00010003 00000000 00000000 00000000
0:000:x86> ln poi(esp)
(77d00058) ntdll32!KiUserApcDispatcher+0x25 | (77d000a0) ntdll32!KiUserCallbackExceptionHandler
0:000:x86> du poi(esp+8)
00010032 "C:\Users\tant\Desktop\bin\x64\De"
00010072 "bug\injdllx86.dll"

Before calling LdrLoadDll, the stack seems having the correct arguments:
00010028 ff542420 call dword ptr [esp+20h] ss:002b:0018fd0c={ntdll32!LdrLoadDll (77d2eaea)}
0:000:x86> dd esp LC
0018fcec 00000000 00000000 0018fcfc 0018fd04
0018fcfc 00620062 00010032 00000000 77d0007d
0018fd0c 77d2eaea 00010032 00000062 00010003

Where:
PVOID BaseAddress == 0x0018fd04;
DllName.Length = (USHORT)SystemArgument2 = 0x0062;
DllName.MaximumLength = (USHORT)SystemArgument2 = 0x0062;
DllName.Buffer = (PWSTR) SystemArgument1 = 0x0018fcfc;

Then an access violation occurs in RtlEqualUnicodeString
0:000:x86> g
(b6c.eb4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
ntdll32!RtlEqualUnicodeString+0x10:
77d1e8cb 0fb732 movzx esi,word ptr [edx] ds:002b:00000024=????

With the following call stack:
0:000:x86> kp
ChildEBP RetAddr
0018fa14 77d2bc57 ntdll32!RtlEqualUnicodeString+0x10
0018fa34 77d2e737 ntdll32!LdrpFindLoadedDllByName+0x9d
0018fb1c 77d2e946 ntdll32!LdrpFindOrMapDll+0x1e5
0018fca8 77d6d3df ntdll32!LdrpLoadDll+0x2d6
0018fce4 0001002c ntdll32!LdrLoadDll+0xc7
WARNING: Frame IP not in any known module. Following frames may be wrong.
00000000 00000000 0x1002c

It seems that RtlEqualUnicodeString is getting invalid arguments:
0:000:x86> dd ebp L8
0018fa14 0018fa34 77d2bc57 0018fb70 00000024
0018fa24 00000001 00000000 00000002 00000000
0:000:x86> dd poi(ebp+8) L2
0018fb70 00620062 00010032 <== this is our DllName struct
0:000:x86> dd poi(ebp+c) L2
00000024 ???????? ???????? <== this is a broken UNICODE_STRING, coming from somewhere.

Thread create messages?

So I would like to know if there is a way (as a driver) to see and detect when another process creates a thread in my process. This is for a notification to my process to update it’s internal thread counter that I put in place for the fun of it (or to tell the process to exit upon the call to CreateRemoteThread to my process).

I also would like to figure out to have my program init, and unit my driver upon closing and to feed data to/from it. If anyone here knows how that is done and how some well know online game anti-hacks do it with a dll and a device driver to detect suspicious programs running, debuggers, etc.

Cannot inject dll due to signing issue

I've encounter in image validation error while trying to inject dll from slightly different version of injdrv where the injection timing is on creation of new thread (so that processes that existed before the driver is loaded could be injected as well - assuming new alertable threads will be created on them).

Anyhow, it seems that although the dll is signed, it fails on signing issue (perhaps mismatch between processes executable file and dll signatures)

here's the stack trace from the context of the injected processes after initial injected code tried to call ldrloaddll

[0x0]   CI!CipReportAndReprieveUMCIFailure + 0x563   
[0x1]   CI!CiValidateImageHeader + 0xbdb   
[0x2]   nt!SeValidateImageHeader + 0xd6   
[0x3]   nt!MiValidateSectionCreate + 0x436   
[0x4]   nt!MiValidateSectionSigningPolicy + 0xa6   
[0x5]   nt!MiValidateExistingImage + 0x12e   
[0x6]   nt!MiShareExistingControlArea + 0xc2   
[0x7]   nt!MiCreateImageOrDataSection + 0x1a3   
[0x8]   nt!MiCreateSection + 0xf4   
[0x9]   nt!MiCreateSectionCommon + 0x1ff   
[0xa]   nt!NtCreateSection + 0x60   
[0xb]   nt!KiSystemServiceCopyEnd + 0x25   
[0xc]   ntdll!NtCreateSection + 0x14   
[0xd]   ntdll!LdrpMapDllNtFileName + 0x136   
[0xe]   ntdll!LdrpMapDllFullPath + 0xe0   
[0xf]   ntdll!LdrpProcessWork + 0x74   
[0x10]   ntdll!LdrpLoadDllInternal + 0x13e   
[0x11]   ntdll!LdrpLoadDll + 0xa8   
[0x12]   ntdll!LdrLoadDll + 0xe4   

the process is image is spawned from dllhost.exe and it's not revealed as protected as one might thing ...

Any idea what can lead to this error ?

thanks

IoAllocateMdl

how to use IoAllocateMdl in injdllx64.dll?thank you again.

BSOD on Windows 10

Hi,
I got BSOD on Windows 10.

SYSTEM_SERVICE_EXCEPTION (3b)
An exception happened while executing a system service routine.
Arguments:
Arg1: 00000000c0000005, Exception code that caused the bugcheck
Arg2: fffff802bc932524, Address of the instruction which caused the bugcheck
Arg3: ffffe08f1ba66ae0, Address of the context record for the exception that caused the bugcheck
Arg4: 0000000000000000, zero.

FAULTING_IP:
injdrv+2524
fffff802`bc932524 48394110 cmp qword ptr [rcx+10h],rax

MODULE_NAME: injdrv

IMAGE_NAME: injdrv.sys

This is the callstack:
0: kd> kp

Child-SP RetAddr Call Site
00 ffffe08f1ba66208 fffff802bd45b669 nt!KeBugCheckEx
01 ffffe08f1ba66210 fffff802bd45abbc nt!KiBugCheckDispatch+0x69
02 ffffe08f1ba66350 fffff802bd4533ad nt!KiSystemServiceHandler+0x7c
03 ffffe08f1ba66390 fffff802bd35b126 nt!RtlpExecuteHandlerForException+0xd
04 ffffe08f1ba663c0 fffff802bd35cc23 nt!RtlDispatchException+0x416
05 ffffe08f1ba66ab0 fffff802bd45b742 nt!KiDispatchException+0x1f3
06 ffffe08f1ba67160 fffff802bd4582c5 nt!KiExceptionDispatch+0xc2
07 ffffe08f1ba67340 fffff802bc932524 nt!KiPageFault+0x405
*** WARNING: Unable to verify timestamp for injdrv.sys
08 ffffe08f1ba674d0 fffff802bc9327f3 injdrv!InjFindInjectionInfo(void * ProcessId = 0x00000000000020ac)+0x34 [c:\working\injdrv\injlib.c @ 1093] 09 ffffe08f1ba674f0 fffff802bd7f2efe injdrv!InjLoadImageNotifyRoutine(struct _UNICODE_STRING * FullImageName = 0xffff91889adea688 "\Windows\System32\msvcrt.dll", void * ProcessId = 0x00000000000020ac, struct _IMAGE_INFO * ImageInfo = 0xffffe08f1ba676c0)+0x23 [c:\working\injdrv\injlib.c @ 1340]
0a ffffe08f1ba675b0 fffff802bd7f19f4 nt!PsCallImageNotifyRoutines+0x12e
0b ffffe08f1ba67610 fffff802bd7a1721 nt!MiMapViewOfImageSection+0x734
0c ffffe08f1ba67790 fffff802bd7a0e7b nt!MiMapViewOfSection+0x3c1
0d ffffe08f1ba678e0 fffff802bd45b143 nt!NtMapViewOfSection+0x12b
0e ffffe08f1ba67a10 00007ff9f867aea4 nt!KiSystemServiceCopyEnd+0x13
0f 00000070e8c7e6e8 0000000000000000 0x00007ff9`f867aea4

Checking the source code I found that it is in:
PINJ_INJECTION_INFO
NTAPI
InjFindInjectionInfo(
In HANDLE ProcessId
)
{
PLIST_ENTRY NextEntry = InjInfoListHead.Flink;

while (NextEntry != &InjInfoListHead)
{
PINJ_INJECTION_INFO InjectionInfo = CONTAINING_RECORD(NextEntry,
INJ_INJECTION_INFO,
ListEntry);

if (InjectionInfo->ProcessId == ProcessId)
{
return InjectionInfo;
}

NextEntry = NextEntry->Flink;
}

return NULL;
}

It only happened once.
What could be the cause of the problem?
Maybe the page fault while in the function for memory that should not be paged?

Random crash for wow64 process in win10 X64 1809

Hi wbenny,

Thanks for your work. I test injdrv in Win7, it works perfectly. However, in win10, it will cause some wow64 process crash. For example, the "cl.exe" comes from visual studio 2013. It will crash at launch, the dll didn't load into the process space.

ModLoad: 74ce0000 74d05000 C:\WINDOWS\SysWOW64\IMM32.DLL
(4c4.3608): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00010000 ebx=00a89000 ecx=00010000 edx=77312790 esi=00000001 edi=0105f8dc
eip=00010000 esp=0105f8c8 ebp=0105fc04 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010202
00010000 0000 add byte ptr [eax],al ds:002b:00010000=00

It seems it crashes in the first line of the shellcode. Any ideas? Thanks.

inject any dll

Is it possible to inject any dll? I try to inject my dll and gives an error: "the entry point to the interlockedincrement procedure was not found"

Issue after hooking MicrosoftEdgeCP.exe

Running InjDrv successfully hooks all process once its' loaded.

But after injection on MicrosoftEdgeCP.exe the Edge browser stalls, and errors thrown at EventLogs. [After loading the driver, close all edge browser windows and open a new edge browser window ]

My Scenario:
I want to know all the processes that are opened and want to elegate/delegate some process specifically. InjDrv satisifies the need and it works perfect, except it stalls MicrosoftEdge browser. I have tried by modifying forceUserAPC but still its not working.

Kindly show the way to overcome it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.