在科锐学习的第4阶段, 保护模式课后作业,跨进程内存读写的小工具.
第一次内核编程,代码写的比较乱,不免也有些错误.各位牛哥们,见笑乐,!时间仓促,也没对代码进程封装,和界面相关太多.
1. 切换目标进程的CR3
通常,跨进程读写内存,用到ReadProcessMemory, WriteProcessMemory, 但需要进程句柄,如果目标进程受到保护,可能获得进程句柄会失败.
ReadProcessMemory最后会调用到KeStackAttachProcess附加到目标进程上切换进程环境进行拷贝的, 所以想到拿到目标进程的虚拟内存内容,可以将目标进程的页目录基地址放入CR3中即可.
首先要获得目标进程的cr3寄存器,即页目录基地址(开启PAE, 页目录指针表),
每个进程在内核里都有一个EPROCESS结构.
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
…….
nt!_KPROCESS
+0x000 Header : _DISPATCHER_HEADER
+0x010 ProfileListHead : _LIST_ENTRY
+0x018 DirectoryTableBase : [2] Uint4B
+0x020 LdtDescriptor : _KGDTENTRY
+0x028 Int21Descriptor : _KIDTENTRY
………
// 获得当前进程EPROCESS信息
ULONG uEprocess = 0;
__asm
{
mov eax, fs:[0x124] // _ethread
mov eax, [eax+0x44] // _kprocess
mov uEprocess, eax
}
KdPrint(("EPROCESS: 0x%08x\n", uEprocess));
LIST_ENTRY ListHead;
InitializeListHead(&ListHead);
ULONG uFirstEprocess = uEprocess;
ULONG uCount = 0;
PLIST_ENTRY pActiveProcessLinks;
ProcessInfoList *pProcssList = NULL;
ULONG uNameOffset = GetPlantformDependentInfo(FILE_NAME_OFFSET);
ULONG uPidOffset = GetPlantformDependentInfo(PROCESS_ID_OFFSET);
ULONG uLinkOffset = GetPlantformDependentInfo(PROCESS_LINK_OFFSET);
ULONG uExitTime = GetPlantformDependentInfo(EXIT_TIME_OFFSET);
// 遍历链表获得进程信息
do
{
pProcssList=
(ProcessInfoList *)ExAllocatePool(PagedPool, sizeof(ProcessInfoList));
if (pProcssList == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
PLARGE_INTEGER ExitTime;
ExitTime = (PLARGE_INTEGER)(uEprocess + uExitTime);
if (ExitTime->QuadPart == 0)
{
if (*(int *)(uEprocess + uPidOffset) <= 0)
{
pProcssList->ProcInfo.uProcessId = 0;
pProcssList->ProcInfo.uEprocess = uEprocess;
pProcssList->ProcInfo.uCR3 = *(PULONG)(uEprocess + 0x18);
RtlCopyMemory(pProcssList->ProcInfo.pszImageFileName, "Idle", 16);
InsertHeadList(&ListHead, &pProcssList->ListEntry);
KdPrint(("PID: %d, EPROCESS: 0x%08x, FileName: %s, CR3: 0x%08x\n",
pProcssList->ProcInfo.uProcessId,
pProcssList->ProcInfo.uEprocess,
pProcssList->ProcInfo.pszImageFileName,
pProcssList->ProcInfo.uCR3));
}
else
{
pProcssList->ProcInfo.uEprocess = uEprocess;
pProcssList->ProcInfo.uCR3 = *(PULONG)(uEprocess + 0x18);
pProcssList->ProcInfo.uProcessId = *(PULONG)(uEprocess + uPidOffset);
RtlCopyMemory(pProcssList->ProcInfo.pszImageFileName,
(PVOID)(uEprocess + uNameOffset),
16);
InsertHeadList(&ListHead, &pProcssList->ListEntry);
KdPrint(("PID: %d, EPROCESS: 0x%08x, FileName: %s, CR3: 0x%08x\n",
pProcssList->ProcInfo.uProcessId,
pProcssList->ProcInfo.uEprocess,
pProcssList->ProcInfo.pszImageFileName,
pProcssList->ProcInfo.uCR3));
}
uCount++;
}
pActiveProcessLinks = (PLIST_ENTRY)(uEprocess + uLinkOffset);
uEprocess = (ULONG)pActiveProcessLinks->Blink - uLinkOffset;
if (uEprocess == uFirstEprocess)
{
break;
}
} while (uEprocess != 0);
_try
{
WriteMemoryInfo *pInfo =
(WriteMemoryInfo *)ExAllocatePool(PagedPool, sizeof(WriteMemoryInfo));
RtlCopyMemory(pInfo, pIoBuffer, sizeof(WriteMemoryInfo));
PVOID pWrite = ExAllocatePool(PagedPool, pInfo->nWriteSize);
RtlCopyMemory(pWrite, pInfo->pData, pInfo->nWriteSize);
//pInfo->pData = (PBYTE)ExAllocatePool(PagedPool, pInfo->nWriteSize);
ULONG uOldCr3 = 0;
ULONG uCurrentCr3 = *(PULONG)(pInfo->nEprocess + 0x18);
if (pInfo->nMemoryAddr == 0)
{
status = STATUS_UNSUCCESSFUL;
break;
}
__asm
{
mov eax, cr3
mov uOldCr3, eax
mov eax, uCurrentCr3
mov cr3, eax
}
__asm
{
cli
push eax
mov eax, cr0
and eax, not 10000h
mov cr0, eax
}
RtlCopyMemory((PVOID)pInfo->nMemoryAddr,
pWrite, pInfo->nWriteSize);
__asm
{
mov eax, CR0
or eax, 10000h
mov cr0,eax
pop eax
sti
}
__asm
{
mov eax, uOldCr3
mov cr3, eax
}
uOutSize = pInfo->nWriteSize;
if (pInfo != NULL)
{
ExFreePool(pInfo);
pInfo = NULL;
}
// Return success
status = STATUS_SUCCESS;
}
__except(1)
{
status = STATUS_UNSUCCESSFUL;
}
__try
{
ReadMemoryInfo *pInfo =
(ReadMemoryInfo *)ExAllocatePool(PagedPool, sizeof(ReadMemoryInfo));
RtlCopyMemory(pInfo, pIoBuffer, sizeof(ReadMemoryInfo));
ULONG uOldCr3 = 0;
ULONG uCurrentCr3 = *(PULONG)(pInfo->nEprocess + 0x18);
if (pInfo->nMemoryAddr == 0)
{
status = STATUS_UNSUCCESSFUL;
break;
}
__asm
{
mov eax, cr3
mov uOldCr3, eax
mov eax, uCurrentCr3
mov cr3, eax
}
RtlCopyMemory(pIoBuffer,
(PVOID)pInfo->nMemoryAddr ,pInfo->nReadSize);
uOutSize = pInfo->nReadSize;
__asm
{
mov eax, uOldCr3
mov cr3, eax
}
if (pInfo != NULL)
{
ExFreePool(pInfo);
pInfo = NULL;
}
// Return success
status = STATUS_SUCCESS;
}
__except(1)
{
status = STATUS_UNSUCCESSFUL;
}
// 获得CR4的值
__asm
{
_emit 0x0F
_emit 0x20
_emit 0xE0
mov uCR4, eax
}
// 获得页目录表项(PDE)
dwPageDirIndex = (dwVirtualAddr & 0xffc00000) >> 22;
DWORD dwPageDirEntry = ReadPageDirEntryNoPAE(dwPageDirIndex);
if (dwPageDirEntry == 0)
{
return;
}
// 获得页大小
DWORD CReadMemoryDlg::GetPageSizeNoPAE(DWORD dwAddr)
{
if ((dwAddr & 0x00000080) == 0x00000080)
{
return MBSIZE;
}
else
{
return KBSIZE;
}
}
dwPageTableIndex = (dwVirtualAddr & 0x0003ff000) >> 12;
DWORD dwPageTableBaseAddr = dwPageDirEntry & 0xfffff000;
// 获得页表
DWORD dwPageTable = ReadPageTableNoPAE(dwPageTableBaseAddr,
dwPageTableIndex);
if (dwPageTable == 0)
{
return;
}
if (IsPresentNoPAE(dwPageTable) == FALSE)
{
return;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课