上一边帖子里回顾了一下内核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, ¶m_address, 0, ¶m_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, ¶m_address, 0, ¶m_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直播授课