还有一个礼拜就要开学了...
开学了就要军训了, 军训完就要忙了, 可能也就没时间写程序了.
考虑了一下, 还是用最后一个礼拜把 PN 完善一下吧.
顺便公布一下某原创定位内核函数的方法 (PN1 开始采用):
--- dispatch.c (part) ---
/*++
Routine description:
Detour KeInsertQueueApc to locate PsExitSpecialApc, PspExitApcRundown
and PspExitNormalApc.
Input:
0x0 - Supplies the ID of the temporary thread to be terminated
Output:
0x0 - Status of call
--*/
ULONG PN3InitializeApc(PULONG inPlain, ULONG inPlainLength, PULONG outPlain, ULONG outPlainLength)
{
HANDLE hThread = 0;
OBJECT_ATTRIBUTES oa = {0};
CLIENT_ID cli;
NTSTATUS Status;
PETHREAD Thread;
KIRQL OldIrql;
KPROCESSOR_MODE PreviousMode;
if (inPlainLength < 4 || outPlainLength < 4) return 0;
// Temporarily disable the process protect
Status = PsLookupThreadByThreadId((HANDLE)inPlain[0], &VictimThread);
if (!NT_SUCCESS(Status)) {
*outPlain = 0;
return 4;
}
ObDereferenceObject(VictimThread);
// Open the thread
Status = ObOpenObjectByPointer(VictimThread,
0,
NULL,
0,
NULL,
KernelMode,
&hThread);
if (!NT_SUCCESS(Status) || hThread == 0) {
VictimThread = 0;
*outPlain = 0;
return 4;
}
// Terminate the thread with detour of KeInsertQueueApc
PreviousMode = SetCurrentThreadProcessorMode(KernelMode);
KeAcquireSpinLock(&HookApcSpinLock, &OldIrql);
EnableKeInsertQueueApcHook(TRUE);
NtTerminateThread(hThread, 0);
EnableKeInsertQueueApcHook(FALSE);
KeReleaseSpinLock(&HookApcSpinLock, OldIrql);
NtClose(hThread);
SetCurrentThreadProcessorMode(PreviousMode);
// Enable the process protect
VictimThread = NULL;
// Test if our special apcs are presented
if (PsExitSpecialApc == NULL) {
*outPlain = 0;
} else {
*outPlain = 1;
}
return 4;
}
--- hookapc.c ---
#include <ntddk.h>
#include <pn3hook.h>
#include <pn3imp.h>
#include <pn3misc.h>
ULONG ApcHookLen = 0;
BOOLEAN ApcFoundNop = FALSE;
PETHREAD VictimThread = NULL;
PVOID PsExitSpecialApc = NULL, PspExitApcRundown = NULL, PspExitNormalApc = NULL;
UCHAR BackupKeInsertQueueApc[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
UCHAR RealKeInsertQueueApc[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
VOID KeInsertQueueApcNotify(PETHREAD Thread, PVOID KernelRoutine, PVOID RundownRoutine, PVOID NormalRoutine)
{
if (Thread == VictimThread &&
KernelRoutine != NULL &&
NormalRoutine != NULL &&
PsExitSpecialApc == NULL &&
(ULONG)KernelBase < (ULONG)KernelRoutine &&
(ULONG)KernelBase + KernelSize > (ULONG)KernelRoutine) {
PsExitSpecialApc = KernelRoutine;
PspExitApcRundown = RundownRoutine;
PspExitNormalApc = NormalRoutine;
}
}
BOOLEAN __stdcall HookedKeInsertQueueApc(IN PKAPC Apc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2,
IN KPRIORITY Increment) {
KeInsertQueueApcNotify((PETHREAD)Apc->Thread,
Apc->KernelRoutine,
Apc->RundownRoutine,
Apc->NormalRoutine);
return ((KEINSERTQUEUEAPC)RealKeInsertQueueApc)(Apc,
SystemArgument1,
SystemArgument2,
Increment);
}
VOID EnableKeInsertQueueApcHook(BOOLEAN Enable)
{
PUCHAR Ptr = (PUCHAR)KeInsertQueueApc;
KIRQL OldIrql;
// Unhook, no matter what we're gonna do
if (ApcHookLen != 0) {
if (ApcFoundNop) Ptr += 2;
OldIrql = KeRaiseIrqlToDpcLevel();
CliAndDisableWP();
RtlMoveMemory(Ptr, BackupKeInsertQueueApc, ApcHookLen);
EnableWPAndSti();
KeLowerIrql(OldIrql);
ApcHookLen = 0;
}
if (Enable) {
// Test if there's any NOPs
// It's important for keeping compatibility with KV2008
if (*(PUSHORT)Ptr == 0xff8b) {
ApcFoundNop = TRUE;
Ptr += 2;
} else {
ApcFoundNop = FALSE;
}
// Measure the code length to be copied
ApcHookLen = MeasureCodeLength(Ptr, 5);
if (ApcHookLen == 0 || ApcHookLen > 11) {
ApcHookLen = 0;
return;
}
// Copy the code
RtlMoveMemory(BackupKeInsertQueueApc, Ptr, ApcHookLen);
RtlMoveMemory(RealKeInsertQueueApc, Ptr, ApcHookLen);
// Relocate jmps and calls
if (!RelocateJumps(RealKeInsertQueueApc, (ULONG)RealKeInsertQueueApc - (ULONG)Ptr, ApcHookLen)) {
ApcHookLen = 0;
return;
}
// Write jumps
WriteJump(&RealKeInsertQueueApc[ApcHookLen], (PVOID)((ULONG)Ptr + ApcHookLen));
WriteJump(Ptr, HookedKeInsertQueueApc);
}
}