首页
社区
课程
招聘
[原创]内核APC结合内存加载实现无模块注入
发表于: 2017-11-23 17:46 23350

[原创]内核APC结合内存加载实现无模块注入

2017-11-23 17:46
23350
上一边帖子里回顾了一下内核APC注入,代码有个地方欠妥,就没有选择合适的线程去注入,这里做了如下修改
        if (*(PULONG)((PCHAR)ethreAd + TCB_TEB_OFFSET) != 0 //teb!=0
            && *((PUCHAR)ethreAd + 0x068) == 0x5 //state=5
            && *(PULONG)((PCHAR)ethreAd + 0x06c) == 0 //waitstatus=0
            && (((*(PULONG)((PCHAR)ethreAd + ALERTABLE_OFFSET) >> 5) & 1) == 1)) //alertable=1
        {
            KdPrint(("target ethreAd: 0x%x\n", ethreAd));
            break;
        }
因为我们是在进程已经存在的时候注入的,我们需要选择处于等待状态而且可唤醒的线程,但是我们最好不要手动去设置UserApcPending,这样肯定会有问题
     ....
        else if ((Thread->State == Waiting) &&
                  (Thread->WaitMode == UserMode) &&
                  (Thread->Alertable || Thread->ApcState.UserApcPending)) {

            Thread->ApcState.UserApcPending = TRUE;
            KiUnwaitThread(Thread, STATUS_USER_APC, Increment);
        }
    ...
//计算整个dll映像文件的尺寸
int CalcTotalImageSize()
{
    int nSize = 0;
    if (m_pNTHeader == NULL)
    {
        return 0;
    }
    int nAlign = m_pNTHeader->OptionalHeader.SectionAlignment; //段对齐字节数
    // 计算所有头的尺寸。包括dos, coff, pe头 和 段表的大小
    nSize = GetAlignedSize(m_pNTHeader->OptionalHeader.SizeOfHeaders, nAlign);
    // 计算所有节的大小
    for (int i = 0; i < m_pNTHeader->FileHeader.NumberOfSections; ++i)
    {
        //得到该节的大小
        int nCodeSize = m_pSectionHeader[i].Misc.VirtualSize;
        int nLoadSize = m_pSectionHeader[i].SizeOfRawData;
        int nMaxSize = (nLoadSize > nCodeSize) ? (nLoadSize) : (nCodeSize);
        int nSectionSize = GetAlignedSize(m_pSectionHeader[i].VirtualAddress + nMaxSize, nAlign);
        if (nSize < nSectionSize)
        {
            nSize = nSectionSize;  //Use the Max;
        }
    }
    return nSize;
}
这究竟是为什么要这么做?映像大小不是nt头里SizeOfImage的值么?观察了一下这里的计算结果跟SizeOfImage是一样的啊。。知道的老铁剧透一下吧-,-。PE我还只了解一下基本的知识,这里这样做肯定是有什么玄机!
/************************************************************************
* 文件名称:apc_inject_memLoadDll.h
* 作    者:Justgoon
* 完成日期:
*************************************************************************/

#include <ntifs.h>
#include <wdm.h>

typedef void *LPVOID;
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef unsigned short WORD;

typedef struct _UNICODE_STR
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR pBuffer;
} UNICODE_STR, *PUNICODE_STR;

typedef struct _LDR_DATA_TABLE_ENTRY
{
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STR FullDllName;
    UNICODE_STR BaseDllName;
    ULONG Flags;
    SHORT LoadCount;
    SHORT TlsIndex;
    LIST_ENTRY HashTableEntry;
    ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

typedef struct _PEB_LDR_DATA
{
    DWORD dwLength;
    DWORD dwInitialized;
    LPVOID lpSsHandle;
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    LPVOID lpEntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _PEB_FREE_BLOCK
{
    struct _PEB_FREE_BLOCK * pNext;
    DWORD dwSize;
} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;

typedef struct _RTL_CRITICAL_SECTION_DEBUG {
    WORD   Type;
    WORD   CreatorBackTraceIndex;
    struct _RTL_CRITICAL_SECTION *CriticalSection;
    LIST_ENTRY ProcessLocksList;
    DWORD EntryCount;
    DWORD ContentionCount;
    DWORD Flags;
    WORD   CreatorBackTraceIndexHigh;
    WORD   SpareWORD;
} RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG;

typedef struct _RTL_CRITICAL_SECTION {
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

typedef struct __PEB
{
    BYTE bInheritedAddressSpace;
    BYTE bReadImageFileExecOptions;
    BYTE bBeingDebugged;
    BYTE bSpareBool;
    LPVOID lpMutant;
    LPVOID lpImageBaseAddress;
    PPEB_LDR_DATA pLdr;
    LPVOID lpProcessParameters;
    LPVOID lpSubSystemData;
    LPVOID lpProcessHeap;
    PRTL_CRITICAL_SECTION pFastPebLock;
    LPVOID lpFastPebLockRoutine;
    LPVOID lpFastPebUnlockRoutine;
    DWORD dwEnvironmentUpdateCount;
    LPVOID lpKernelCallbackTable;
    DWORD dwSystemReserved;
    DWORD dwAtlThunkSListPtr32;
    PPEB_FREE_BLOCK pFreeList;
    DWORD dwTlsExpansionCounter;
    LPVOID lpTlsBitmap;
    DWORD dwTlsBitmapBits[2];
    LPVOID lpReadOnlySharedMemoryBase;
    LPVOID lpReadOnlySharedMemoryHeap;
    LPVOID lpReadOnlyStaticServerData;
    LPVOID lpAnsiCodePageData;
    LPVOID lpOemCodePageData;
    LPVOID lpUnicodeCaseTableData;
    DWORD dwNumberOfProcessors;
    DWORD dwNtGlobalFlag;
    LARGE_INTEGER liCriticalSectionTimeout;
    DWORD dwHeapSegmentReserve;
    DWORD dwHeapSegmentCommit;
    DWORD dwHeapDeCommitTotalFreeThreshold;
    DWORD dwHeapDeCommitFreeBlockThreshold;
    DWORD dwNumberOfHeaps;
    DWORD dwMaximumNumberOfHeaps;
    LPVOID lpProcessHeaps;
    LPVOID lpGdiSharedHandleTable;
    LPVOID lpProcessStarterHelper;
    DWORD dwGdiDCAttributeList;
    LPVOID lpLoaderLock;
    DWORD dwOSMajorVersion;
    DWORD dwOSMinorVersion;
    WORD wOSBuildNumber;
    WORD wOSCSDVersion;
    DWORD dwOSPlatformId;
    DWORD dwImageSubsystem;
    DWORD dwImageSubsystemMajorVersion;
    DWORD dwImageSubsystemMinorVersion;
    DWORD dwImageProcessAffinityMask;
    DWORD dwGdiHandleBuffer[34];
    LPVOID lpPostProcessInitRoutine;
    LPVOID lpTlsExpansionBitmap;
    DWORD dwTlsExpansionBitmapBits[32];
    DWORD dwSessionId;
    ULARGE_INTEGER liAppCompatFlags;
    ULARGE_INTEGER liAppCompatFlagsUser;
    LPVOID lppShimData;
    LPVOID lpAppCompatInfo;
    UNICODE_STR usCSDVersion;
    LPVOID lpActivationContextData;
    LPVOID lpProcessAssemblyStorageMap;
    LPVOID lpSystemDefaultActivationContextData;
    LPVOID lpSystemAssemblyStorageMap;
    DWORD dwMinimumStackCommit;
} _PEB, *_PPEB;

typedef struct _LDR_MODULE
{
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID BaseAddress;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    LIST_ENTRY HashTableEntry;
    ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE, *PLML;

typedef enum _KAPC_ENVIRONMENT {
    OriginalApcEnvironment,
    AttachedApcEnvironment,
    CurrentApcEnvironment
} KAPC_ENVIRONMENT;

ULONG THREADLISTHEAD_OFFSET = 0x188;
ULONG THREADLISTENTRY_OFFSET = 0x268;//both ThreAdListEntry in ETHREAD KTHREAD works;
ULONG IMAGEFILENAME_OFFSET = 0x16c;
ULONG ACTIVEPROCESSLINKS_OFFSET = 0x0b8;
ULONG TCB_TEB_OFFSET = 0x088;
ULONG OBJECT_TABLE_OFFSET = 0x0f4;
ULONG ALERTABLE_OFFSET = 0x03c;

#define NAME_BUF_SIZE 256

typedef BOOLEAN(__stdcall *ProcDllMain)(PVOID, ULONG, PVOID);

PVOID g_pImageBase = NULL;
ProcDllMain g_pDllMain = NULL;

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA;

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

#define IMAGE_ORDINAL_FLAG32 0x80000000
#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00
#define IMAGE_FILE_EXECUTABLE_IMAGE         0x0002  // File is executable  (i.e. no unresolved external references).
#define IMAGE_FILE_DLL                      0x2000  // File is a DLL.

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
    // -1 if bound, and real date\time stamp
    //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
    // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;

typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef IMAGE_OPTIONAL_HEADER32                 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32                 PIMAGE_OPTIONAL_HEADER;

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef PIMAGE_NT_HEADERS32                 PIMAGE_NT_HEADERS;

#define IMAGE_SIZEOF_SHORT_NAME              8

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
        DWORD   PhysicalAddress;
        DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

typedef IMAGE_NT_HEADERS32     IMAGE_NT_HEADERS;

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
    //  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table

UserExec(
    PVOID	dllPath,
    PVOID	unused1,
    PVOID	unused2
    );

UserExec_end(
    VOID
    );

VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
);

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);

VOID
KeInitializeApc(
PKAPC Apc,
PKTHREAD Thread,
CCHAR ApcStateIndex,
PKKERNEL_ROUTINE KernelRoutine,
PKRUNDOWN_ROUTINE RundownRoutine,
PKNORMAL_ROUTINE NormalRoutine,
KPROCESSOR_MODE ApcMode,
PVOID NormalContext
);

BOOLEAN
KeInsertQueueApc(
PKAPC Apc,
PVOID SystemArgument1,
PVOID SystemArgument2,
UCHAR unknown
);

/************************************************************************
* 文件名称:apc_inject_memLoadDll.c
* 作    者:Justgoon
* 完成日期:
*************************************************************************/
#include "apc_inject_memLoadDll.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,DriverUnload)
#endif

HANDLE                  g_hProcess = NULL;
ULONG                   g_process = 0;
ULONG                   g_thread = 0;
PIMAGE_DOS_HEADER       g_pDosHeader = NULL;
PIMAGE_NT_HEADERS       g_pNTHeader = NULL;
PIMAGE_SECTION_HEADER   g_pSectionHeader = NULL;

BOOLEAN
SearchTargetThread(
IN  PCHAR processName,
OUT	ULONG *process,
OUT	ULONG *threAd
)
{
    ULONG		    eproc;
    ULONG		    begin_proc;
    ULONG		    ethreAd;
    ULONG		    begin_threAd;
    PLIST_ENTRY		plist_Active_procs;
    PLIST_ENTRY		plist_threAd;

    //遍历进程
    eproc = (ULONG)PsGetCurrentProcess();
    if (!eproc)
    {
        return FALSE;
    }
    begin_proc = eproc;
    while (1)
    {
        //OBJECT_TABLE_OFFSET 没有句柄表就是死的进程
        if (0 == _stricmp((PCHAR)((PCHAR)eproc + IMAGEFILENAME_OFFSET), processName) && (*(PULONG)((CHAR*)eproc + OBJECT_TABLE_OFFSET)) != 0)
        {
            break;
        }
        else
        {
            plist_Active_procs = (PLIST_ENTRY)((PCHAR)eproc + ACTIVEPROCESSLINKS_OFFSET);
            eproc = (ULONG)plist_Active_procs->Flink;
            eproc = (ULONG)((PCHAR)eproc - ACTIVEPROCESSLINKS_OFFSET);
            if (eproc == begin_proc)
            {
                return FALSE;
            }
        }
    }
    plist_threAd = (PLIST_ENTRY)((PCHAR)eproc + THREADLISTHEAD_OFFSET);
    ethreAd = (ULONG)((PCHAR)plist_threAd->Flink - THREADLISTENTRY_OFFSET);
    KdPrint(("ethreAd: 0x%x\n", ethreAd));
    KdPrint(("eproc: 0x%x\n", eproc));
    //遍历线程
    begin_threAd = ethreAd;
    while (1)
    {
        if (*(PULONG)((PCHAR)ethreAd + TCB_TEB_OFFSET) != 0 //teb!=0
            && *((PUCHAR)ethreAd + 0x068) == 0x5 //state=5
            && *(PULONG)((PCHAR)ethreAd + 0x06c) == 0 //waitstatus=0
            && (((*(PULONG)((PCHAR)ethreAd + ALERTABLE_OFFSET) >> 5) & 1) == 1)) //alertable=1
        {
            KdPrint(("target ethreAd: 0x%x\n", ethreAd));
            break;
        }
        else
        {
            plist_threAd = (PLIST_ENTRY)(ethreAd + THREADLISTENTRY_OFFSET);
            ethreAd = (ULONG)((PCHAR)plist_threAd->Flink - THREADLISTENTRY_OFFSET);
            KdPrint(("ethreAd: 0x%x\n", ethreAd));
            if (ethreAd == begin_threAd)
            {
                return FALSE;
            }
        }
    }
    *process = eproc;
    *threAd = ethreAd;
    return TRUE;
}

BOOLEAN
CheckDataValide(
IN PVOID lpFileData,
IN INT nDataLength
)
{
    INT index = 0;
    //检查长度
    if (nDataLength < sizeof(IMAGE_DOS_HEADER))
    {
        return FALSE;
    }
    g_pDosHeader = (PIMAGE_DOS_HEADER)lpFileData;  // DOS头
    //检查dos头的标记
    if (g_pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return FALSE;  //0x5A4D : MZ
    }
    //检查长度
    if ((ULONG)nDataLength < (g_pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)))
    {
        return FALSE;
    }
    //取得pe头
    g_pNTHeader = (PIMAGE_NT_HEADERS)((PCHAR)lpFileData + g_pDosHeader->e_lfanew); // PE头
    //检查pe头的合法性
    if (g_pNTHeader->Signature != IMAGE_NT_SIGNATURE)
    {
        return FALSE;  //0x00004550 : PE00
    }
    if ((g_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) //0x2000  : File is a DLL
    {
        return FALSE;
    }
    if ((g_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) //0x0002 : 指出文件可以运行
    {
        return FALSE;
    }
    if (g_pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
    {
        return FALSE;
    }
    //取得节表(段表)
    g_pSectionHeader = (PIMAGE_SECTION_HEADER)((PCHAR)g_pNTHeader + sizeof(IMAGE_NT_HEADERS));
    //验证每个节表的空间
    for (index = 0; index < g_pNTHeader->FileHeader.NumberOfSections; index++)
    {
        if ((g_pSectionHeader[index].PointerToRawData + g_pSectionHeader[index].SizeOfRawData) > (ULONG)nDataLength)
        {
            return FALSE;
        }
    }
    return TRUE;
}

VOID
CopyDllDatas(
IN VOID* pDest,
IN VOID* pSrc
)
{
    INT     i = 0;
    INT     nHeaderSize = g_pNTHeader->OptionalHeader.SizeOfHeaders;
    INT     nSectionSize = g_pNTHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
    INT     nMoveSize = nHeaderSize + nSectionSize;
    PVOID   pSectionAddress = NULL;
    //复制头和段信息
    memcpy(pDest, pSrc, nMoveSize);
    //复制每个节
    for (i = 0; i < g_pNTHeader->FileHeader.NumberOfSections; ++i)
    {
        if (g_pSectionHeader[i].VirtualAddress == 0 || g_pSectionHeader[i].SizeOfRawData == 0)
        {
            continue;
        }
        // 定位该节在内存中的位置
        pSectionAddress = (VOID *)((PCHAR)pDest + g_pSectionHeader[i].VirtualAddress);
        // 复制段数据到虚拟内存
        memcpy((VOID *)pSectionAddress, (VOID *)((PCHAR)pSrc + g_pSectionHeader[i].PointerToRawData), g_pSectionHeader[i].SizeOfRawData);
    }
    //修正指针,指向新分配的内存
    //新的dos头
    g_pDosHeader = (PIMAGE_DOS_HEADER)pDest;
    //新的pe头地址
    g_pNTHeader = (PIMAGE_NT_HEADERS)((PCHAR)pDest + (g_pDosHeader->e_lfanew));
    //新的节表地址
    g_pSectionHeader = (PIMAGE_SECTION_HEADER)((PCHAR)g_pNTHeader + sizeof(IMAGE_NT_HEADERS));
}

// 重定向PE用到的地址
VOID
DoRelocation(
IN PVOID pNewBase
)
{
    INT                     i = 0;
    INT                     nNumberOfReloc;
    PUSHORT                 pLocData;
    PULONG                  pAddress;
    ULONG                   dwDelta;
    PIMAGE_BASE_RELOCATION  pLoc = (PIMAGE_BASE_RELOCATION)((ULONG)pNewBase + g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

    while ((pLoc->VirtualAddress + pLoc->SizeOfBlock) != 0) //开始扫描重定位表
    {
        pLocData = (USHORT *)((PCHAR)pLoc + sizeof(IMAGE_BASE_RELOCATION));
        //计算本节需要修正的重定位项(地址)的数目
        nNumberOfReloc = (pLoc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
        for (i = 0; i < nNumberOfReloc; i++)
        {
            if ((USHORT)(pLocData[i] & 0x0000F000) == 0x00003000) //这是一个需要修正的地址
            {
                // 32位dll重定位,IMAGE_REL_BASED_HIGHLOW
                // 对于x86的可执行文件,所有的基址重定位都是IMAGE_REL_BASED_HIGHLOW类型的。
                pAddress = (PULONG)((PCHAR)pNewBase + pLoc->VirtualAddress + (pLocData[i] & 0x0FFF));
                dwDelta = (ULONG)pNewBase - g_pNTHeader->OptionalHeader.ImageBase;
                *pAddress += dwDelta;
            }
        }
        //转移到下一个节进行处理
        pLoc = (PIMAGE_BASE_RELOCATION)((PCHAR)pLoc + pLoc->SizeOfBlock);
    }
}

//获取模块基址
ULONG
GetModuleBaseAddress(
IN CHAR* pModuleName
)
{
    _PPEB           pPeb = NULL;
    ULONG           temp;
    ULONG           hModule;
    PLIST_ENTRY     pCurrentList = NULL;
    PLIST_ENTRY     pTempList = NULL;
    PLIST_ENTRY     pLoadOrderModuleList;
    PLIST_ENTRY     list;
    ANSI_STRING     aniModuleName = { 0 };
    UNICODE_STRING  uModuleName = { 0 };

    pPeb = (_PPEB)(*(PULONG)(g_process + 0x1a8));
    RtlInitAnsiString(&aniModuleName, pModuleName);
    RtlAnsiStringToUnicodeString(&uModuleName, &aniModuleName, TRUE);
    if (pPeb != NULL)
    {
        //遍历进程模块
        pLoadOrderModuleList = pPeb->pLdr->InLoadOrderModuleList.Flink;
        list = pLoadOrderModuleList;
        do   // 遍历进程所加载模块中,直到找到EXE模块
        {
            UNICODE_STRING pstrTemp = ((PLDR_MODULE)list)->BaseDllName;
            if (!RtlCompareUnicodeString(&uModuleName, &pstrTemp, TRUE))
            {
                hModule = (ULONG)((PLDR_MODULE)list)->BaseAddress;
                temp = *(PULONG)hModule;
                RtlFreeUnicodeString(&uModuleName);
                return hModule;
            }
            list = list->Flink;
        } while (list != pLoadOrderModuleList);
    }
    return 0;
}

//遍历导出表获取导出函数地址
ULONG
MyGetProcAddress(
IN ULONG hModule,    // handle to DLL module
IN LPCSTR lpProcName   // function name
)
{
    INT                     i = 0;
    PCHAR                   p;
    PCHAR                   pRet = NULL;
    PCHAR                   strFunction;
    CHAR                    pTempDll[100] = { 0 };
    CHAR                    pTempFuction[100] = { 0 };
    ULONG                   moduleBaseAddress;
    ULONG                   dwExportRVA;
    ULONG                   dwExportSize;
    PULONG                  pAddressOfFunction;
    PULONG                  pAddressOfNames;
    ULONG                   dwNumberOfNames;
    ULONG                   dwBase;
    ULONG                   dwName;
    PUSHORT                 pAddressOfNameOrdinals;
    PIMAGE_DOS_HEADER       pImageDosHeader = NULL;
    PIMAGE_NT_HEADERS       pImageNtHeader = NULL;
    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;

    pImageDosHeader = (PIMAGE_DOS_HEADER)hModule;
    pImageNtHeader = (PIMAGE_NT_HEADERS)((ULONG)hModule + pImageDosHeader->e_lfanew);
    pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONG)hModule + pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    dwExportRVA = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    dwExportSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
    pAddressOfFunction = (ULONG*)(pImageExportDirectory->AddressOfFunctions + (ULONG)hModule);
    pAddressOfNames = (ULONG*)(pImageExportDirectory->AddressOfNames + (ULONG)hModule);
    dwNumberOfNames = (ULONG)(pImageExportDirectory->NumberOfNames);
    dwBase = (ULONG)(pImageExportDirectory->Base);
    pAddressOfNameOrdinals = (USHORT*)(pImageExportDirectory->AddressOfNameOrdinals + (ULONG)hModule);

    dwName = (ULONG)lpProcName;
    if ((dwName & 0xFFFF0000) == 0)
    {
        if (dwName < dwBase || dwName > dwBase + pImageExportDirectory->NumberOfFunctions - 1)
        {
            return 0;
        }
        pRet = (CHAR *)(pAddressOfFunction[dwName - dwBase] + (ULONG)hModule);
        return (ULONG)pRet;
    }
    for (i = 0; i < (INT)dwNumberOfNames; i++)
    {
        strFunction = (CHAR *)(pAddressOfNames[i] + (ULONG)hModule);
        if (strcmp(strFunction, (CHAR *)lpProcName) == 0)
        {
            pRet = (CHAR *)(pAddressOfFunction[pAddressOfNameOrdinals[i]] + (ULONG)hModule);
            if ((ULONG)pRet<dwExportRVA + (ULONG)hModule || (ULONG)pRet > dwExportRVA + (ULONG)hModule + dwExportSize)
            {
                return (ULONG)pRet;
            }
            //如果地址在范围内说明这是个字符串而已 user32.MessageBoxA
            else
            {
                strcpy(pTempDll, pRet);
                p = strchr(pTempDll, '.');
                if (!p)
                {
                    return 0;
                }
                *p = 0;
                strcpy(pTempFuction, p + 1);
                strcat(pTempDll, ".dll");
                moduleBaseAddress = GetModuleBaseAddress(pTempDll);
                if (!moduleBaseAddress)
                {
                    return 0;
                }
                return MyGetProcAddress(moduleBaseAddress, pTempFuction);
            }
        }
    }
    return 0;
}

//填充引入地址表
BOOLEAN
FillRavAddress(
IN VOID *pImageBase
)
{
    INT                         i = 0;
    CHAR                        szBuf[NAME_BUF_SIZE] = { 0 }; //dll name;
    PCHAR                       pName;
    ULONG                       hDll;
    ULONG                       lpFunction = 0;
    PIMAGE_IMPORT_BY_NAME       pByName;
    PIMAGE_IMPORT_DESCRIPTOR    pID;
    PIMAGE_THUNK_DATA           pRealIAT;
    PIMAGE_THUNK_DATA           pOriginalIAT;
    ULONG                       nOffset = g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

    if (nOffset == 0)
    {
        return TRUE;//No Import Table
    }
    pID = (PIMAGE_IMPORT_DESCRIPTOR)((PCHAR)pImageBase + nOffset);
    while (pID->Characteristics != 0)
    {
        pRealIAT = (PIMAGE_THUNK_DATA)((PCHAR)pImageBase + pID->FirstThunk);
        pOriginalIAT = (PIMAGE_THUNK_DATA)((PCHAR)pImageBase + pID->OriginalFirstThunk);
        pName = (CHAR*)((ULONG)pImageBase + pID->Name);
        for (i = 0; i < NAME_BUF_SIZE; i++)
        {
            if (pName[i] == 0)
            {
                break;
            }
            szBuf[i] = pName[i];
        }
        if (i >= NAME_BUF_SIZE)
        {
            return FALSE;// bad dll name
        }
        else
        {
            szBuf[i] = 0;
        }
        hDll = GetModuleBaseAddress(szBuf);
        if (!hDll)//这里我们默认需要内存加载的dll的引入表中的dll已经被当前进程加载过了
        {
            return FALSE;
        }
        for (i = 0;; i++)
        {
            if (pOriginalIAT[i].u1.Function == 0)
            {
                break;
            }
            if (pOriginalIAT[i].u1.Ordinal & IMAGE_ORDINAL_FLAG) //这里的值给出的是导出序号
            {
                lpFunction = MyGetProcAddress(hDll, (LPCSTR)(pOriginalIAT[i].u1.Ordinal & 0x0000FFFF));
            }
            else //按照名字导入
            {
                //获取此IAT项所描述的函数名称
                pByName = (PIMAGE_IMPORT_BY_NAME)((ULONG)pImageBase + (ULONG)(pOriginalIAT[i].u1.AddressOfData));
                lpFunction = MyGetProcAddress(hDll, (CHAR *)pByName->Name);
            }
            if (lpFunction)   //找到了!
            {
                pRealIAT[i].u1.Function = (ULONG)lpFunction;
            }
            else
            {
                return FALSE;
            }
        }
        //move to next 
        pID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)pID + sizeof(IMAGE_IMPORT_DESCRIPTOR));
    }
    return TRUE;
}

NTSTATUS
MemLoadLibrary(
IN PVOID lpFileData,
IN INT nDataLength
)
{
    INT         nImageSize = 0;
    PVOID       pMemoryAddress = NULL;
    NTSTATUS    status;
    KAPC_STATE	ApcStAte = { 0 };

    if (g_pImageBase != NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }
    //检查数据有效性,并初始化
    if (!CheckDataValide(lpFileData, nDataLength))
    {
        return STATUS_UNSUCCESSFUL;
    }
    //获取映像大小
    nImageSize = g_pNTHeader->OptionalHeader.SizeOfImage;
    if (nImageSize == 0)
    {
        return STATUS_UNSUCCESSFUL;
    }
    status = ZwAllocateVirtualMemory(g_hProcess, &pMemoryAddress, 0, &nImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwAllocateVirtualMemory false :%x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    KeStackAttachProcess((PEPROCESS)g_process, &ApcStAte);
    //将dll数据复制到指定内存区域,并对齐所有节
    CopyDllDatas(pMemoryAddress, lpFileData);
    if (g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > 0 && g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
    {
        //重定位
        DoRelocation(pMemoryAddress);
    }
    //填充导入表
    if (!FillRavAddress(pMemoryAddress))
    {
        ZwFreeVirtualMemory(g_hProcess, &pMemoryAddress, &nImageSize, MEM_RELEASE);
        KeUnstackDetachProcess(&ApcStAte);
        return STATUS_UNSUCCESSFUL;
    }
    //修正基地址
    g_pNTHeader->OptionalHeader.ImageBase = (ULONG)pMemoryAddress;
    //保存dll基址和dllmain入口地址
    g_pDllMain = (ProcDllMain)(g_pNTHeader->OptionalHeader.AddressOfEntryPoint + (PCHAR)pMemoryAddress);
    g_pImageBase = pMemoryAddress;
    KeUnstackDetachProcess(&ApcStAte);
    return STATUS_SUCCESS;
}

NTSTATUS
ReadFileToTargetProcess(
IN WCHAR *szFile
)
{
    PUCHAR						pBuffer = NULL;
    HANDLE 						hfile = NULL;
    NTSTATUS					ntStatus = 0;
    UNICODE_STRING 				uFile = { 0 };
    IO_STATUS_BLOCK 			iostatus = { 0 };
    OBJECT_ATTRIBUTES 			objectAttributes = { 0 };
    FILE_STANDARD_INFORMATION	fsi = { 0 };

    RtlInitUnicodeString(&uFile, szFile);
    InitializeObjectAttributes(&objectAttributes,
        &uFile,
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
        NULL,
        NULL);
    ntStatus = ZwCreateFile(&hfile,
        GENERIC_READ,
        &objectAttributes,
        &iostatus,
        NULL,
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        FILE_OPEN,
        FILE_SYNCHRONOUS_IO_NONALERT,
        NULL,
        0);
    if (!NT_SUCCESS(ntStatus))
    {
        return ntStatus;
    }
    ntStatus = ZwQueryInformationFile(hfile,
        &iostatus,
        &fsi,
        sizeof(FILE_STANDARD_INFORMATION),
        FileStandardInformation);
    if (!NT_SUCCESS(ntStatus))
    {
        ZwClose(hfile);
        return ntStatus;
    }
    pBuffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool,
        (LONG)fsi.EndOfFile.QuadPart, 'ELIF');
    if (pBuffer == NULL)
    {
        ZwClose(hfile);
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    ntStatus = ZwReadFile(
        hfile,
        NULL,
        NULL,
        NULL,
        &iostatus,
        pBuffer,
        (LONG)fsi.EndOfFile.QuadPart,
        NULL, NULL);
    if (NT_SUCCESS(ntStatus))
    {
        ntStatus = MemLoadLibrary(pBuffer, iostatus.Information);
    }
    ZwClose(hfile);
    ExFreePool(pBuffer);
    return ntStatus;
}

VOID
KernelApcCAllBAck_Exec(
PKAPC Apc,
PKNORMAL_ROUTINE *NormAlRoutine,
IN OUT PVOID *NormAlContext,
IN OUT PVOID *SystemArgument1,
IN OUT PVOID *SystemArgument2
)
{
    if (Apc)
    {
        ExFreePool(Apc);
    }
    KdPrint(("NormAlContext: 0x%x\n", (ULONG)*NormAlContext));
}

NTSTATUS
ApcInject_MemLoadDll(
IN CHAR* processName,
IN WCHAR* dllPath
)
{
    PVOID			param_address = NULL;
    ULONG           param_size = sizeof(ULONG) * 2;//dll地址 + dllMain入口地址
    PKAPC			pkApc;
    PVOID			func_address = NULL;
    ULONG			func_size = 0;
    NTSTATUS        status = 0;
    KAPC_STATE		ApcStAte = { 0 };

    //找到合适的插入目标
    if (!SearchTargetThread(processName, &g_process, &g_thread))
    {
        KdPrint(("SearchTargetThread failed\n"));
        return STATUS_UNSUCCESSFUL;
    }
    status = ObOpenObjectByPointer((PVOID)g_process,
        OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
        NULL,
        GENERIC_ALL,
        *PsProcessType,
        KernelMode,
        &g_hProcess
        );
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ObOpenObjectByPoINTer failed  %x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    //将dll映射进目标地址空间
    status = ReadFileToTargetProcess(dllPath);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ReadFileToTargetProcess failed\n"));
        return STATUS_UNSUCCESSFUL;
    }
    func_size = (UCHAR*)UserExec_end - (UCHAR*)UserExec;
    status = ZwAllocateVirtualMemory(g_hProcess, &func_address, 0, &func_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwAllocateVirtualMemory false :%x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    status = ZwAllocateVirtualMemory(g_hProcess, &param_address, 0, &param_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwAllocateVirtualMemory false :%x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    KeStackAttachProcess((PEPROCESS)g_process, &ApcStAte);
    //拷贝apc函数体到用户地址空间
    RtlZeroMemory(func_address, func_size);
    RtlCopyMemory(func_address, UserExec, func_size);
    //拷贝参数到用户地址空间
    RtlZeroMemory(param_address, param_size);
    RtlCopyMemory(param_address, &g_pImageBase, sizeof(ULONG));
    RtlCopyMemory(((PCHAR)param_address + sizeof(ULONG)), &g_pDllMain, sizeof(ULONG));
    KeUnstackDetachProcess(&ApcStAte);
    pkApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
    if (pkApc == NULL)
    {
        KdPrint(("error:ExAllocAtePool\n"));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    //初始化一个APC
    KeInitializeApc(
        pkApc,
        (PKTHREAD)g_thread,
        OriginalApcEnvironment,
        (PKKERNEL_ROUTINE)KernelApcCAllBAck_Exec,
        NULL,
        (PKNORMAL_ROUTINE)func_address,//UserApcCAllBAck,
        UserMode,	//用户模式
        (PVOID)param_address
        );
    //插入apc
    if (!KeInsertQueueApc(pkApc, 0, 0, 0)){
        KdPrint(("KeInsertQueueApc err\n"));
        return STATUS_UNSUCCESSFUL;
    }
    return STATUS_SUCCESS;
}

__declspec(naked)
UserExec(
PVOID	param,
PVOID	unused1,
PVOID	unused2
)
{
    __asm
    {
        push ebp
        mov  ebp, esp

        pushad
        pushfd

        mov ecx, [ebp + 8]
        mov edx, [ecx]
        mov eax, [ecx + 4]
        push 0      //0
        push 1      //DLL_PROCESS_ATTACH
        push edx    //dllbase
        call eax    //g_pDllMain((PULONG)dllbase, DLL_PROCESS_ATTACH, 0);

        popfd
        popad

        mov esp, ebp
        pop ebp
        ret
    }
}
__declspec(naked)
UserExec_end(VOID)
{

}

VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
    KdPrint(("DriverUnload\r\n"));
}

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath
)
{
    KdPrint(("DriverEntry\r\n"));
    pDriverObject->DriverUnload = DriverUnload;
    return ApcInject_MemLoadDll("explorer.exe", L"\\??\\C:\\dlltest32.dll");
}
        if (*(PULONG)((PCHAR)ethreAd + TCB_TEB_OFFSET) != 0 //teb!=0
            && *((PUCHAR)ethreAd + 0x068) == 0x5 //state=5
            && *(PULONG)((PCHAR)ethreAd + 0x06c) == 0 //waitstatus=0
            && (((*(PULONG)((PCHAR)ethreAd + ALERTABLE_OFFSET) >> 5) & 1) == 1)) //alertable=1
        {
            KdPrint(("target ethreAd: 0x%x\n", ethreAd));
            break;
        }
     ....
        else if ((Thread->State == Waiting) &&
                  (Thread->WaitMode == UserMode) &&
                  (Thread->Alertable || Thread->ApcState.UserApcPending)) {

            Thread->ApcState.UserApcPending = TRUE;
            KiUnwaitThread(Thread, STATUS_USER_APC, Increment);
        }
    ...
//计算整个dll映像文件的尺寸
int CalcTotalImageSize()
{
    int nSize = 0;
    if (m_pNTHeader == NULL)
    {
        return 0;
    }
    int nAlign = m_pNTHeader->OptionalHeader.SectionAlignment; //段对齐字节数
    // 计算所有头的尺寸。包括dos, coff, pe头 和 段表的大小
    nSize = GetAlignedSize(m_pNTHeader->OptionalHeader.SizeOfHeaders, nAlign);
    // 计算所有节的大小
    for (int i = 0; i < m_pNTHeader->FileHeader.NumberOfSections; ++i)
    {
        //得到该节的大小
        int nCodeSize = m_pSectionHeader[i].Misc.VirtualSize;
        int nLoadSize = m_pSectionHeader[i].SizeOfRawData;
        int nMaxSize = (nLoadSize > nCodeSize) ? (nLoadSize) : (nCodeSize);
        int nSectionSize = GetAlignedSize(m_pSectionHeader[i].VirtualAddress + nMaxSize, nAlign);
        if (nSize < nSectionSize)
        {
            nSize = nSectionSize;  //Use the Max;
        }
    }
    return nSize;
}
/************************************************************************
* 文件名称:apc_inject_memLoadDll.h
* 作    者:Justgoon
* 完成日期:
*************************************************************************/

#include <ntifs.h>
#include <wdm.h>

typedef void *LPVOID;
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef unsigned short WORD;

typedef struct _UNICODE_STR
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR pBuffer;
} UNICODE_STR, *PUNICODE_STR;

typedef struct _LDR_DATA_TABLE_ENTRY
{
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STR FullDllName;
    UNICODE_STR BaseDllName;
    ULONG Flags;
    SHORT LoadCount;
    SHORT TlsIndex;
    LIST_ENTRY HashTableEntry;
    ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

typedef struct _PEB_LDR_DATA
{
    DWORD dwLength;
    DWORD dwInitialized;
    LPVOID lpSsHandle;
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    LPVOID lpEntryInProgress;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _PEB_FREE_BLOCK
{
    struct _PEB_FREE_BLOCK * pNext;
    DWORD dwSize;
} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;

typedef struct _RTL_CRITICAL_SECTION_DEBUG {
    WORD   Type;
    WORD   CreatorBackTraceIndex;
    struct _RTL_CRITICAL_SECTION *CriticalSection;
    LIST_ENTRY ProcessLocksList;
    DWORD EntryCount;
    DWORD ContentionCount;
    DWORD Flags;
    WORD   CreatorBackTraceIndexHigh;
    WORD   SpareWORD;
} RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG, RTL_RESOURCE_DEBUG, *PRTL_RESOURCE_DEBUG;

typedef struct _RTL_CRITICAL_SECTION {
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

typedef struct __PEB
{
    BYTE bInheritedAddressSpace;
    BYTE bReadImageFileExecOptions;
    BYTE bBeingDebugged;
    BYTE bSpareBool;
    LPVOID lpMutant;
    LPVOID lpImageBaseAddress;
    PPEB_LDR_DATA pLdr;
    LPVOID lpProcessParameters;
    LPVOID lpSubSystemData;
    LPVOID lpProcessHeap;
    PRTL_CRITICAL_SECTION pFastPebLock;
    LPVOID lpFastPebLockRoutine;
    LPVOID lpFastPebUnlockRoutine;
    DWORD dwEnvironmentUpdateCount;
    LPVOID lpKernelCallbackTable;
    DWORD dwSystemReserved;
    DWORD dwAtlThunkSListPtr32;
    PPEB_FREE_BLOCK pFreeList;
    DWORD dwTlsExpansionCounter;
    LPVOID lpTlsBitmap;
    DWORD dwTlsBitmapBits[2];
    LPVOID lpReadOnlySharedMemoryBase;
    LPVOID lpReadOnlySharedMemoryHeap;
    LPVOID lpReadOnlyStaticServerData;
    LPVOID lpAnsiCodePageData;
    LPVOID lpOemCodePageData;
    LPVOID lpUnicodeCaseTableData;
    DWORD dwNumberOfProcessors;
    DWORD dwNtGlobalFlag;
    LARGE_INTEGER liCriticalSectionTimeout;
    DWORD dwHeapSegmentReserve;
    DWORD dwHeapSegmentCommit;
    DWORD dwHeapDeCommitTotalFreeThreshold;
    DWORD dwHeapDeCommitFreeBlockThreshold;
    DWORD dwNumberOfHeaps;
    DWORD dwMaximumNumberOfHeaps;
    LPVOID lpProcessHeaps;
    LPVOID lpGdiSharedHandleTable;
    LPVOID lpProcessStarterHelper;
    DWORD dwGdiDCAttributeList;
    LPVOID lpLoaderLock;
    DWORD dwOSMajorVersion;
    DWORD dwOSMinorVersion;
    WORD wOSBuildNumber;
    WORD wOSCSDVersion;
    DWORD dwOSPlatformId;
    DWORD dwImageSubsystem;
    DWORD dwImageSubsystemMajorVersion;
    DWORD dwImageSubsystemMinorVersion;
    DWORD dwImageProcessAffinityMask;
    DWORD dwGdiHandleBuffer[34];
    LPVOID lpPostProcessInitRoutine;
    LPVOID lpTlsExpansionBitmap;
    DWORD dwTlsExpansionBitmapBits[32];
    DWORD dwSessionId;
    ULARGE_INTEGER liAppCompatFlags;
    ULARGE_INTEGER liAppCompatFlagsUser;
    LPVOID lppShimData;
    LPVOID lpAppCompatInfo;
    UNICODE_STR usCSDVersion;
    LPVOID lpActivationContextData;
    LPVOID lpProcessAssemblyStorageMap;
    LPVOID lpSystemDefaultActivationContextData;
    LPVOID lpSystemAssemblyStorageMap;
    DWORD dwMinimumStackCommit;
} _PEB, *_PPEB;

typedef struct _LDR_MODULE
{
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
    PVOID BaseAddress;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    LIST_ENTRY HashTableEntry;
    ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE, *PLML;

typedef enum _KAPC_ENVIRONMENT {
    OriginalApcEnvironment,
    AttachedApcEnvironment,
    CurrentApcEnvironment
} KAPC_ENVIRONMENT;

ULONG THREADLISTHEAD_OFFSET = 0x188;
ULONG THREADLISTENTRY_OFFSET = 0x268;//both ThreAdListEntry in ETHREAD KTHREAD works;
ULONG IMAGEFILENAME_OFFSET = 0x16c;
ULONG ACTIVEPROCESSLINKS_OFFSET = 0x0b8;
ULONG TCB_TEB_OFFSET = 0x088;
ULONG OBJECT_TABLE_OFFSET = 0x0f4;
ULONG ALERTABLE_OFFSET = 0x03c;

#define NAME_BUF_SIZE 256

typedef BOOLEAN(__stdcall *ProcDllMain)(PVOID, ULONG, PVOID);

PVOID g_pImageBase = NULL;
ProcDllMain g_pDllMain = NULL;

typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE 
        DWORD Function;             // PDWORD
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
    } u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA;

typedef struct _IMAGE_IMPORT_BY_NAME {
    WORD    Hint;
    CHAR   Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;

#define IMAGE_ORDINAL_FLAG32 0x80000000
#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ
#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00
#define IMAGE_FILE_EXECUTABLE_IMAGE         0x0002  // File is executable  (i.e. no unresolved external references).
#define IMAGE_FILE_DLL                      0x2000  // File is a DLL.

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;                  // 0 if not bound,
    // -1 if bound, and real date\time stamp
    //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
    // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;

typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES    16

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef IMAGE_OPTIONAL_HEADER32                 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32                 PIMAGE_OPTIONAL_HEADER;

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef PIMAGE_NT_HEADERS32                 PIMAGE_NT_HEADERS;

#define IMAGE_SIZEOF_SHORT_NAME              8

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
        DWORD   PhysicalAddress;
        DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

typedef IMAGE_NT_HEADERS32     IMAGE_NT_HEADERS;

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
    //  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table

UserExec(
    PVOID	dllPath,
    PVOID	unused1,
    PVOID	unused2
    );

UserExec_end(
    VOID
    );

VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
);

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);

VOID
KeInitializeApc(
PKAPC Apc,
PKTHREAD Thread,
CCHAR ApcStateIndex,
PKKERNEL_ROUTINE KernelRoutine,
PKRUNDOWN_ROUTINE RundownRoutine,
PKNORMAL_ROUTINE NormalRoutine,
KPROCESSOR_MODE ApcMode,
PVOID NormalContext
);

BOOLEAN
KeInsertQueueApc(
PKAPC Apc,
PVOID SystemArgument1,
PVOID SystemArgument2,
UCHAR unknown
);
/************************************************************************
* 文件名称:apc_inject_memLoadDll.c
* 作    者:Justgoon
* 完成日期:
*************************************************************************/
#include "apc_inject_memLoadDll.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,DriverUnload)
#endif

HANDLE                  g_hProcess = NULL;
ULONG                   g_process = 0;
ULONG                   g_thread = 0;
PIMAGE_DOS_HEADER       g_pDosHeader = NULL;
PIMAGE_NT_HEADERS       g_pNTHeader = NULL;
PIMAGE_SECTION_HEADER   g_pSectionHeader = NULL;

BOOLEAN
SearchTargetThread(
IN  PCHAR processName,
OUT	ULONG *process,
OUT	ULONG *threAd
)
{
    ULONG		    eproc;
    ULONG		    begin_proc;
    ULONG		    ethreAd;
    ULONG		    begin_threAd;
    PLIST_ENTRY		plist_Active_procs;
    PLIST_ENTRY		plist_threAd;

    //遍历进程
    eproc = (ULONG)PsGetCurrentProcess();
    if (!eproc)
    {
        return FALSE;
    }
    begin_proc = eproc;
    while (1)
    {
        //OBJECT_TABLE_OFFSET 没有句柄表就是死的进程
        if (0 == _stricmp((PCHAR)((PCHAR)eproc + IMAGEFILENAME_OFFSET), processName) && (*(PULONG)((CHAR*)eproc + OBJECT_TABLE_OFFSET)) != 0)
        {
            break;
        }
        else
        {
            plist_Active_procs = (PLIST_ENTRY)((PCHAR)eproc + ACTIVEPROCESSLINKS_OFFSET);
            eproc = (ULONG)plist_Active_procs->Flink;
            eproc = (ULONG)((PCHAR)eproc - ACTIVEPROCESSLINKS_OFFSET);
            if (eproc == begin_proc)
            {
                return FALSE;
            }
        }
    }
    plist_threAd = (PLIST_ENTRY)((PCHAR)eproc + THREADLISTHEAD_OFFSET);
    ethreAd = (ULONG)((PCHAR)plist_threAd->Flink - THREADLISTENTRY_OFFSET);
    KdPrint(("ethreAd: 0x%x\n", ethreAd));
    KdPrint(("eproc: 0x%x\n", eproc));
    //遍历线程
    begin_threAd = ethreAd;
    while (1)
    {
        if (*(PULONG)((PCHAR)ethreAd + TCB_TEB_OFFSET) != 0 //teb!=0
            && *((PUCHAR)ethreAd + 0x068) == 0x5 //state=5
            && *(PULONG)((PCHAR)ethreAd + 0x06c) == 0 //waitstatus=0
            && (((*(PULONG)((PCHAR)ethreAd + ALERTABLE_OFFSET) >> 5) & 1) == 1)) //alertable=1
        {
            KdPrint(("target ethreAd: 0x%x\n", ethreAd));
            break;
        }
        else
        {
            plist_threAd = (PLIST_ENTRY)(ethreAd + THREADLISTENTRY_OFFSET);
            ethreAd = (ULONG)((PCHAR)plist_threAd->Flink - THREADLISTENTRY_OFFSET);
            KdPrint(("ethreAd: 0x%x\n", ethreAd));
            if (ethreAd == begin_threAd)
            {
                return FALSE;
            }
        }
    }
    *process = eproc;
    *threAd = ethreAd;
    return TRUE;
}

BOOLEAN
CheckDataValide(
IN PVOID lpFileData,
IN INT nDataLength
)
{
    INT index = 0;
    //检查长度
    if (nDataLength < sizeof(IMAGE_DOS_HEADER))
    {
        return FALSE;
    }
    g_pDosHeader = (PIMAGE_DOS_HEADER)lpFileData;  // DOS头
    //检查dos头的标记
    if (g_pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
        return FALSE;  //0x5A4D : MZ
    }
    //检查长度
    if ((ULONG)nDataLength < (g_pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)))
    {
        return FALSE;
    }
    //取得pe头
    g_pNTHeader = (PIMAGE_NT_HEADERS)((PCHAR)lpFileData + g_pDosHeader->e_lfanew); // PE头
    //检查pe头的合法性
    if (g_pNTHeader->Signature != IMAGE_NT_SIGNATURE)
    {
        return FALSE;  //0x00004550 : PE00
    }
    if ((g_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) //0x2000  : File is a DLL
    {
        return FALSE;
    }
    if ((g_pNTHeader->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) //0x0002 : 指出文件可以运行
    {
        return FALSE;
    }
    if (g_pNTHeader->FileHeader.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER))
    {
        return FALSE;
    }
    //取得节表(段表)
    g_pSectionHeader = (PIMAGE_SECTION_HEADER)((PCHAR)g_pNTHeader + sizeof(IMAGE_NT_HEADERS));
    //验证每个节表的空间
    for (index = 0; index < g_pNTHeader->FileHeader.NumberOfSections; index++)
    {
        if ((g_pSectionHeader[index].PointerToRawData + g_pSectionHeader[index].SizeOfRawData) > (ULONG)nDataLength)
        {
            return FALSE;
        }
    }
    return TRUE;
}

VOID
CopyDllDatas(
IN VOID* pDest,
IN VOID* pSrc
)
{
    INT     i = 0;
    INT     nHeaderSize = g_pNTHeader->OptionalHeader.SizeOfHeaders;
    INT     nSectionSize = g_pNTHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
    INT     nMoveSize = nHeaderSize + nSectionSize;
    PVOID   pSectionAddress = NULL;
    //复制头和段信息
    memcpy(pDest, pSrc, nMoveSize);
    //复制每个节
    for (i = 0; i < g_pNTHeader->FileHeader.NumberOfSections; ++i)
    {
        if (g_pSectionHeader[i].VirtualAddress == 0 || g_pSectionHeader[i].SizeOfRawData == 0)
        {
            continue;
        }
        // 定位该节在内存中的位置
        pSectionAddress = (VOID *)((PCHAR)pDest + g_pSectionHeader[i].VirtualAddress);
        // 复制段数据到虚拟内存
        memcpy((VOID *)pSectionAddress, (VOID *)((PCHAR)pSrc + g_pSectionHeader[i].PointerToRawData), g_pSectionHeader[i].SizeOfRawData);
    }
    //修正指针,指向新分配的内存
    //新的dos头
    g_pDosHeader = (PIMAGE_DOS_HEADER)pDest;
    //新的pe头地址
    g_pNTHeader = (PIMAGE_NT_HEADERS)((PCHAR)pDest + (g_pDosHeader->e_lfanew));
    //新的节表地址
    g_pSectionHeader = (PIMAGE_SECTION_HEADER)((PCHAR)g_pNTHeader + sizeof(IMAGE_NT_HEADERS));
}

// 重定向PE用到的地址
VOID
DoRelocation(
IN PVOID pNewBase
)
{
    INT                     i = 0;
    INT                     nNumberOfReloc;
    PUSHORT                 pLocData;
    PULONG                  pAddress;
    ULONG                   dwDelta;
    PIMAGE_BASE_RELOCATION  pLoc = (PIMAGE_BASE_RELOCATION)((ULONG)pNewBase + g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

    while ((pLoc->VirtualAddress + pLoc->SizeOfBlock) != 0) //开始扫描重定位表
    {
        pLocData = (USHORT *)((PCHAR)pLoc + sizeof(IMAGE_BASE_RELOCATION));
        //计算本节需要修正的重定位项(地址)的数目
        nNumberOfReloc = (pLoc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
        for (i = 0; i < nNumberOfReloc; i++)
        {
            if ((USHORT)(pLocData[i] & 0x0000F000) == 0x00003000) //这是一个需要修正的地址
            {
                // 32位dll重定位,IMAGE_REL_BASED_HIGHLOW
                // 对于x86的可执行文件,所有的基址重定位都是IMAGE_REL_BASED_HIGHLOW类型的。
                pAddress = (PULONG)((PCHAR)pNewBase + pLoc->VirtualAddress + (pLocData[i] & 0x0FFF));
                dwDelta = (ULONG)pNewBase - g_pNTHeader->OptionalHeader.ImageBase;
                *pAddress += dwDelta;
            }
        }
        //转移到下一个节进行处理
        pLoc = (PIMAGE_BASE_RELOCATION)((PCHAR)pLoc + pLoc->SizeOfBlock);
    }
}

//获取模块基址
ULONG
GetModuleBaseAddress(
IN CHAR* pModuleName
)
{
    _PPEB           pPeb = NULL;
    ULONG           temp;
    ULONG           hModule;
    PLIST_ENTRY     pCurrentList = NULL;
    PLIST_ENTRY     pTempList = NULL;
    PLIST_ENTRY     pLoadOrderModuleList;
    PLIST_ENTRY     list;
    ANSI_STRING     aniModuleName = { 0 };
    UNICODE_STRING  uModuleName = { 0 };

    pPeb = (_PPEB)(*(PULONG)(g_process + 0x1a8));
    RtlInitAnsiString(&aniModuleName, pModuleName);
    RtlAnsiStringToUnicodeString(&uModuleName, &aniModuleName, TRUE);
    if (pPeb != NULL)
    {
        //遍历进程模块
        pLoadOrderModuleList = pPeb->pLdr->InLoadOrderModuleList.Flink;
        list = pLoadOrderModuleList;
        do   // 遍历进程所加载模块中,直到找到EXE模块
        {
            UNICODE_STRING pstrTemp = ((PLDR_MODULE)list)->BaseDllName;
            if (!RtlCompareUnicodeString(&uModuleName, &pstrTemp, TRUE))
            {
                hModule = (ULONG)((PLDR_MODULE)list)->BaseAddress;
                temp = *(PULONG)hModule;
                RtlFreeUnicodeString(&uModuleName);
                return hModule;
            }
            list = list->Flink;
        } while (list != pLoadOrderModuleList);
    }
    return 0;
}

//遍历导出表获取导出函数地址
ULONG
MyGetProcAddress(
IN ULONG hModule,    // handle to DLL module
IN LPCSTR lpProcName   // function name
)
{
    INT                     i = 0;
    PCHAR                   p;
    PCHAR                   pRet = NULL;
    PCHAR                   strFunction;
    CHAR                    pTempDll[100] = { 0 };
    CHAR                    pTempFuction[100] = { 0 };
    ULONG                   moduleBaseAddress;
    ULONG                   dwExportRVA;
    ULONG                   dwExportSize;
    PULONG                  pAddressOfFunction;
    PULONG                  pAddressOfNames;
    ULONG                   dwNumberOfNames;
    ULONG                   dwBase;
    ULONG                   dwName;
    PUSHORT                 pAddressOfNameOrdinals;
    PIMAGE_DOS_HEADER       pImageDosHeader = NULL;
    PIMAGE_NT_HEADERS       pImageNtHeader = NULL;
    PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL;

    pImageDosHeader = (PIMAGE_DOS_HEADER)hModule;
    pImageNtHeader = (PIMAGE_NT_HEADERS)((ULONG)hModule + pImageDosHeader->e_lfanew);
    pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONG)hModule + pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    dwExportRVA = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    dwExportSize = pImageNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
    pAddressOfFunction = (ULONG*)(pImageExportDirectory->AddressOfFunctions + (ULONG)hModule);
    pAddressOfNames = (ULONG*)(pImageExportDirectory->AddressOfNames + (ULONG)hModule);
    dwNumberOfNames = (ULONG)(pImageExportDirectory->NumberOfNames);
    dwBase = (ULONG)(pImageExportDirectory->Base);
    pAddressOfNameOrdinals = (USHORT*)(pImageExportDirectory->AddressOfNameOrdinals + (ULONG)hModule);

    dwName = (ULONG)lpProcName;
    if ((dwName & 0xFFFF0000) == 0)
    {
        if (dwName < dwBase || dwName > dwBase + pImageExportDirectory->NumberOfFunctions - 1)
        {
            return 0;
        }
        pRet = (CHAR *)(pAddressOfFunction[dwName - dwBase] + (ULONG)hModule);
        return (ULONG)pRet;
    }
    for (i = 0; i < (INT)dwNumberOfNames; i++)
    {
        strFunction = (CHAR *)(pAddressOfNames[i] + (ULONG)hModule);
        if (strcmp(strFunction, (CHAR *)lpProcName) == 0)
        {
            pRet = (CHAR *)(pAddressOfFunction[pAddressOfNameOrdinals[i]] + (ULONG)hModule);
            if ((ULONG)pRet<dwExportRVA + (ULONG)hModule || (ULONG)pRet > dwExportRVA + (ULONG)hModule + dwExportSize)
            {
                return (ULONG)pRet;
            }
            //如果地址在范围内说明这是个字符串而已 user32.MessageBoxA
            else
            {
                strcpy(pTempDll, pRet);
                p = strchr(pTempDll, '.');
                if (!p)
                {
                    return 0;
                }
                *p = 0;
                strcpy(pTempFuction, p + 1);
                strcat(pTempDll, ".dll");
                moduleBaseAddress = GetModuleBaseAddress(pTempDll);
                if (!moduleBaseAddress)
                {
                    return 0;
                }
                return MyGetProcAddress(moduleBaseAddress, pTempFuction);
            }
        }
    }
    return 0;
}

//填充引入地址表
BOOLEAN
FillRavAddress(
IN VOID *pImageBase
)
{
    INT                         i = 0;
    CHAR                        szBuf[NAME_BUF_SIZE] = { 0 }; //dll name;
    PCHAR                       pName;
    ULONG                       hDll;
    ULONG                       lpFunction = 0;
    PIMAGE_IMPORT_BY_NAME       pByName;
    PIMAGE_IMPORT_DESCRIPTOR    pID;
    PIMAGE_THUNK_DATA           pRealIAT;
    PIMAGE_THUNK_DATA           pOriginalIAT;
    ULONG                       nOffset = g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

    if (nOffset == 0)
    {
        return TRUE;//No Import Table
    }
    pID = (PIMAGE_IMPORT_DESCRIPTOR)((PCHAR)pImageBase + nOffset);
    while (pID->Characteristics != 0)
    {
        pRealIAT = (PIMAGE_THUNK_DATA)((PCHAR)pImageBase + pID->FirstThunk);
        pOriginalIAT = (PIMAGE_THUNK_DATA)((PCHAR)pImageBase + pID->OriginalFirstThunk);
        pName = (CHAR*)((ULONG)pImageBase + pID->Name);
        for (i = 0; i < NAME_BUF_SIZE; i++)
        {
            if (pName[i] == 0)
            {
                break;
            }
            szBuf[i] = pName[i];
        }
        if (i >= NAME_BUF_SIZE)
        {
            return FALSE;// bad dll name
        }
        else
        {
            szBuf[i] = 0;
        }
        hDll = GetModuleBaseAddress(szBuf);
        if (!hDll)//这里我们默认需要内存加载的dll的引入表中的dll已经被当前进程加载过了
        {
            return FALSE;
        }
        for (i = 0;; i++)
        {
            if (pOriginalIAT[i].u1.Function == 0)
            {
                break;
            }
            if (pOriginalIAT[i].u1.Ordinal & IMAGE_ORDINAL_FLAG) //这里的值给出的是导出序号
            {
                lpFunction = MyGetProcAddress(hDll, (LPCSTR)(pOriginalIAT[i].u1.Ordinal & 0x0000FFFF));
            }
            else //按照名字导入
            {
                //获取此IAT项所描述的函数名称
                pByName = (PIMAGE_IMPORT_BY_NAME)((ULONG)pImageBase + (ULONG)(pOriginalIAT[i].u1.AddressOfData));
                lpFunction = MyGetProcAddress(hDll, (CHAR *)pByName->Name);
            }
            if (lpFunction)   //找到了!
            {
                pRealIAT[i].u1.Function = (ULONG)lpFunction;
            }
            else
            {
                return FALSE;
            }
        }
        //move to next 
        pID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)pID + sizeof(IMAGE_IMPORT_DESCRIPTOR));
    }
    return TRUE;
}

NTSTATUS
MemLoadLibrary(
IN PVOID lpFileData,
IN INT nDataLength
)
{
    INT         nImageSize = 0;
    PVOID       pMemoryAddress = NULL;
    NTSTATUS    status;
    KAPC_STATE	ApcStAte = { 0 };

    if (g_pImageBase != NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }
    //检查数据有效性,并初始化
    if (!CheckDataValide(lpFileData, nDataLength))
    {
        return STATUS_UNSUCCESSFUL;
    }
    //获取映像大小
    nImageSize = g_pNTHeader->OptionalHeader.SizeOfImage;
    if (nImageSize == 0)
    {
        return STATUS_UNSUCCESSFUL;
    }
    status = ZwAllocateVirtualMemory(g_hProcess, &pMemoryAddress, 0, &nImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwAllocateVirtualMemory false :%x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    KeStackAttachProcess((PEPROCESS)g_process, &ApcStAte);
    //将dll数据复制到指定内存区域,并对齐所有节
    CopyDllDatas(pMemoryAddress, lpFileData);
    if (g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > 0 && g_pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0)
    {
        //重定位
        DoRelocation(pMemoryAddress);
    }
    //填充导入表
    if (!FillRavAddress(pMemoryAddress))
    {
        ZwFreeVirtualMemory(g_hProcess, &pMemoryAddress, &nImageSize, MEM_RELEASE);
        KeUnstackDetachProcess(&ApcStAte);
        return STATUS_UNSUCCESSFUL;
    }
    //修正基地址
    g_pNTHeader->OptionalHeader.ImageBase = (ULONG)pMemoryAddress;
    //保存dll基址和dllmain入口地址
    g_pDllMain = (ProcDllMain)(g_pNTHeader->OptionalHeader.AddressOfEntryPoint + (PCHAR)pMemoryAddress);
    g_pImageBase = pMemoryAddress;
    KeUnstackDetachProcess(&ApcStAte);
    return STATUS_SUCCESS;
}

NTSTATUS
ReadFileToTargetProcess(
IN WCHAR *szFile
)
{
    PUCHAR						pBuffer = NULL;
    HANDLE 						hfile = NULL;
    NTSTATUS					ntStatus = 0;
    UNICODE_STRING 				uFile = { 0 };
    IO_STATUS_BLOCK 			iostatus = { 0 };
    OBJECT_ATTRIBUTES 			objectAttributes = { 0 };
    FILE_STANDARD_INFORMATION	fsi = { 0 };

    RtlInitUnicodeString(&uFile, szFile);
    InitializeObjectAttributes(&objectAttributes,
        &uFile,
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
        NULL,
        NULL);
    ntStatus = ZwCreateFile(&hfile,
        GENERIC_READ,
        &objectAttributes,
        &iostatus,
        NULL,
        FILE_ATTRIBUTE_NORMAL,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        FILE_OPEN,
        FILE_SYNCHRONOUS_IO_NONALERT,
        NULL,
        0);
    if (!NT_SUCCESS(ntStatus))
    {
        return ntStatus;
    }
    ntStatus = ZwQueryInformationFile(hfile,
        &iostatus,
        &fsi,
        sizeof(FILE_STANDARD_INFORMATION),
        FileStandardInformation);
    if (!NT_SUCCESS(ntStatus))
    {
        ZwClose(hfile);
        return ntStatus;
    }
    pBuffer = (PUCHAR)ExAllocatePoolWithTag(PagedPool,
        (LONG)fsi.EndOfFile.QuadPart, 'ELIF');
    if (pBuffer == NULL)
    {
        ZwClose(hfile);
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    ntStatus = ZwReadFile(
        hfile,
        NULL,
        NULL,
        NULL,
        &iostatus,
        pBuffer,
        (LONG)fsi.EndOfFile.QuadPart,
        NULL, NULL);
    if (NT_SUCCESS(ntStatus))
    {
        ntStatus = MemLoadLibrary(pBuffer, iostatus.Information);
    }
    ZwClose(hfile);
    ExFreePool(pBuffer);
    return ntStatus;
}

VOID
KernelApcCAllBAck_Exec(
PKAPC Apc,
PKNORMAL_ROUTINE *NormAlRoutine,
IN OUT PVOID *NormAlContext,
IN OUT PVOID *SystemArgument1,
IN OUT PVOID *SystemArgument2
)
{
    if (Apc)
    {
        ExFreePool(Apc);
    }
    KdPrint(("NormAlContext: 0x%x\n", (ULONG)*NormAlContext));
}

NTSTATUS
ApcInject_MemLoadDll(
IN CHAR* processName,
IN WCHAR* dllPath
)
{
    PVOID			param_address = NULL;
    ULONG           param_size = sizeof(ULONG) * 2;//dll地址 + dllMain入口地址
    PKAPC			pkApc;
    PVOID			func_address = NULL;
    ULONG			func_size = 0;
    NTSTATUS        status = 0;
    KAPC_STATE		ApcStAte = { 0 };

    //找到合适的插入目标
    if (!SearchTargetThread(processName, &g_process, &g_thread))
    {
        KdPrint(("SearchTargetThread failed\n"));
        return STATUS_UNSUCCESSFUL;
    }
    status = ObOpenObjectByPointer((PVOID)g_process,
        OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
        NULL,
        GENERIC_ALL,
        *PsProcessType,
        KernelMode,
        &g_hProcess
        );
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ObOpenObjectByPoINTer failed  %x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    //将dll映射进目标地址空间
    status = ReadFileToTargetProcess(dllPath);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ReadFileToTargetProcess failed\n"));
        return STATUS_UNSUCCESSFUL;
    }
    func_size = (UCHAR*)UserExec_end - (UCHAR*)UserExec;
    status = ZwAllocateVirtualMemory(g_hProcess, &func_address, 0, &func_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwAllocateVirtualMemory false :%x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    status = ZwAllocateVirtualMemory(g_hProcess, &param_address, 0, &param_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (!NT_SUCCESS(status))
    {
        KdPrint(("ZwAllocateVirtualMemory false :%x\n", status));
        return STATUS_UNSUCCESSFUL;
    }
    KeStackAttachProcess((PEPROCESS)g_process, &ApcStAte);
    //拷贝apc函数体到用户地址空间
    RtlZeroMemory(func_address, func_size);
    RtlCopyMemory(func_address, UserExec, func_size);
    //拷贝参数到用户地址空间
    RtlZeroMemory(param_address, param_size);
    RtlCopyMemory(param_address, &g_pImageBase, sizeof(ULONG));
    RtlCopyMemory(((PCHAR)param_address + sizeof(ULONG)), &g_pDllMain, sizeof(ULONG));
    KeUnstackDetachProcess(&ApcStAte);
    pkApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
    if (pkApc == NULL)
    {
        KdPrint(("error:ExAllocAtePool\n"));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    //初始化一个APC
    KeInitializeApc(
        pkApc,
        (PKTHREAD)g_thread,
        OriginalApcEnvironment,
        (PKKERNEL_ROUTINE)KernelApcCAllBAck_Exec,
        NULL,
        (PKNORMAL_ROUTINE)func_address,//UserApcCAllBAck,
        UserMode,	//用户模式
        (PVOID)param_address
        );
    //插入apc
    if (!KeInsertQueueApc(pkApc, 0, 0, 0)){
        KdPrint(("KeInsertQueueApc err\n"));
        return STATUS_UNSUCCESSFUL;
    }
    return STATUS_SUCCESS;
}

__declspec(naked)
UserExec(
PVOID	param,
PVOID	unused1,
PVOID	unused2
)
{
    __asm
    {
        push ebp
        mov  ebp, esp

        pushad
        pushfd

        mov ecx, [ebp + 8]
        mov edx, [ecx]
        mov eax, [ecx + 4]
        push 0      //0
        push 1      //DLL_PROCESS_ATTACH
        push edx    //dllbase
        call eax    //g_pDllMain((PULONG)dllbase, DLL_PROCESS_ATTACH, 0);

        popfd
        popad

        mov esp, ebp
        pop ebp
        ret
    }
}
__declspec(naked)
UserExec_end(VOID)
{

}

VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
    KdPrint(("DriverUnload\r\n"));
}

NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath
)
{
    KdPrint(("DriverEntry\r\n"));
    pDriverObject->DriverUnload = DriverUnload;
    return ApcInject_MemLoadDll("explorer.exe", L"\\??\\C:\\dlltest32.dll");
}
上一边帖子里回顾了一下内核APC注入,代码有个地方欠妥,就没有选择合适的线程去注入,这里做了如下修改
        if (*(PULONG)((PCHAR)ethreAd + TCB_TEB_OFFSET) != 0 //teb!=0
            && *((PUCHAR)ethreAd + 0x068) == 0x5 //state=5
            && *(PULONG)((PCHAR)ethreAd + 0x06c) == 0 //waitstatus=0
            && (((*(PULONG)((PCHAR)ethreAd + ALERTABLE_OFFSET) >> 5) & 1) == 1)) //alertable=1
        {
            KdPrint(("target ethreAd: 0x%x\n", ethreAd));
            break;
        }
因为我们是在进程已经存在的时候注入的,我们需要选择处于等待状态而且可唤醒的线程,但是我们最好不要手动去设置UserApcPending,这样肯定会有问题
     ....
        else if ((Thread->State == Waiting) &&
                  (Thread->WaitMode == UserMode) &&
                  (Thread->Alertable || Thread->ApcState.UserApcPending)) {

            Thread->ApcState.UserApcPending = TRUE;
            KiUnwaitThread(Thread, STATUS_USER_APC, Increment);
        }
    ...
这一段是wrk里一部分插入用户apc的代码,可以看到如过我们找到的线程合适,这里系统会自动设置这个值,而线程返回用户层时在KiServiceExit中系统会检查这个 UserApcPending,如果true才会执行用户apc。如果我们强行吧 UserApcPending置为true线程将会被强制唤醒,唤醒的原因就是STATUS_USER_APC,那么如果这个线程是不能被唤醒的,比方说他在等待另一个线程执行某个操作后才能走下去,那么此时他肯定会崩溃,就是一开始玩apc的时候经常把进程插崩掉的原因之一。另外就是这个waitstatus=0,应该是代表等待成功?这里我也没摸清具体是啥意思,只是在测试的时候这个状态为0的时候注入就没问题,各位老铁知道的话跟我讲讲啊0,0。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 5
支持
分享
最新回复 (11)
雪    币: 300
活跃值: (2452)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
mark
2017-11-23 23:41
0
雪    币: 1319
活跃值: (1945)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
不是警醒的线程插两条APC,一条设置标志位为警醒,另一条为注入dll的shellcode,然后就可以随时注入了=-=
2017-11-24 09:03
0
雪    币: 635
活跃值: (1011)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
4
库尔 不是警醒的线程插两条APC,一条设置标志位为警醒,另一条为注入dll的shellcode,然后就可以随时注入了=-=
不警惕的万一他一直都不唤醒呢,,两个apc都没得机会执行
2017-11-24 09:11
0
雪    币: 1319
活跃值: (1945)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
Justgoon 不警惕的万一他一直都不唤醒呢,,两个apc都没得机会执行[em_41]
啥意思?内核线程回到用户线程先遍历检查一下,符合条件执行usaapc,这个时候有很多机会执行的。第一条先插KeDelayExecutionThread内核模块的apc,警接着插用户模块的apc,线程会立马执行。
2017-11-24 09:23
0
雪    币: 635
活跃值: (1011)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
6
库尔 啥意思?内核线程回到用户线程先遍历检查一下,符合条件执行usaapc,这个时候有很多机会执行的。第一条先插KeDelayExecutionThread内核模块的apc,警接着插用户模块的apc,线程会 ...
Got  it!!!我晚上试一下去
2017-11-24 09:41
0
雪    币: 1319
活跃值: (1945)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
Justgoon Got it!!![em_63]我晚上试一下去
说反了,先插用户在插内核-  -*
2017-11-24 10:42
0
雪    币: 5734
活跃值: (1737)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
创建用户线程吧  APC  执行完全靠等
2017-11-25 11:41
0
雪    币: 190
活跃值: (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我要64位的
2017-11-29 15:21
0
雪    币: 202
活跃值: (428)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
感谢分享
2020-9-1 12:07
0
雪    币: 14
活跃值: (948)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
感谢分享.
你这份代码我改了下能在64位系统运行了,但是那个UserExec代码用apc执行会导致被注入程序崩溃,直接创建用户线程不会,或者把参数直接写到里面不传参数也行,不知道为什么
2021-6-20 09:05
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
库尔 说反了,先插用户在插内核- -*
没必要吧 如果是内核APC执行很快不用管 如果是用户APC你插内核APC又不影响
2022-11-29 01:31
0
游客
登录 | 注册 方可回帖
返回
//