问题记录:
根据g_IndexNtResumeThread 中查询到的对于NtResumeThread的hook来完成的,
这里推测当前eax的作为线程入口的状态是这里保证的,但是为什么是eax呢,这个还没有查询到具体的原因,
记录问题,
[next ] 考虑应该看一下NtResumeThread调用后,对目的进程的修改和完成情况来评估这个eax的原因 。
问题来源:
P476
12.1.2 改变程序运行流程使用主动加载目标DLL 中的
5. 内核中通过 Hook/Notify 干预执行流程法的 code read 中注释 提示
“此时,eax 指向线程中的真正的起点 ” 的 问题记录和下一步开始位置
补充内容:
code list:
原始方法,
NTSTATUS
NTAPI
DetourNtResumeThread (
IN HANDLE ThreadHandle,
OUT PULONG PreviousSuspendCount
)
{
char *szCurProc = NULL;
char *szTargetProc = NULL;
NTSTATUS status = STATUS_SUCCESS;
PEPROCESS pTargetProc = NULL ;
PETHREAD pTargetThread = NULL ;
HANDLE hThreadID = 0 ; //[popexizhi: 原书没有的code]
SIZE_T MemSize = 0x1000;
PCONTEXT pContext = NULL ;
szCurProc = PsGetProcessImageFileName(PsGetCurrentProcess()); //[popexizhi: szCurProc保存的是当前进程的任务管理器中看到的名字]
status = ObReferenceObjectByHandle(ThreadHandle,THREAD_ALL_ACCESS,PsThreadType,KernelMode,&pTargetThread,NULL);
if (NT_SUCCESS(status))
{
//取得线程对应的进程
pTargetProc = IoThreadToProcess(pTargetThread);
szTargetProc = PsGetProcessImageFileName(pTargetProc);
hThreadID = PsGetThreadId(pTargetThread);
DbgPrint("%s is Resuming Thread (ThreadId = %d) in Process %s\n",
szCurProc,hThreadID,szTargetProc);
//启动notepad时
//explorer.exe is Resuming Thread (ThreadId = 2724) in Process notepad.exe
if ((PsGetCurrentProcess() != pTargetProc) //当前进程与目标进程不同,说明是在创建新进程,而不是进程内自己创建线程
&& (_stricmp(szTargetProc,g_szProcNameToInject) == 0)) //判断目标进程是不是notepad
{
KeAttachProcess(pTargetProc);
//先申请内存
status = ZwAllocateVirtualMemory(NtCurrentProcess(),
&pContext,0,&MemSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if (NT_SUCCESS(status))//alloc mem
{
DbgPrint("Alloc Memory for Context = 0x%p\n",pContext);
RtlZeroMemory(pContext,sizeof(CONTEXT));
pContext->ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
status = PsGetContextThread(pTargetThread,pContext,UserMode);
if (NT_SUCCESS(status))//GetContext
{
DbgPrint("EIP = 0x%p EAX = 0x%p\n",pContext->Eip , pContext->Eax);
//此时eax指向线程的真正起点,对于进程的第一个线程来说,它就是入口点 -- [?]
//注入ShellCode并修改Context.Eax
status = InjectShellCodeToProcessByModifyContext(pContext,g_DllPathToInject);
if (NT_SUCCESS(status))
{
DbgPrint("现在修改线程的Context!\n");
pContext->ContextFlags = CONTEXT_INTEGER ;
status = PsSetContextThread(pTargetThread,pContext,UserMode);
if (NT_SUCCESS(status))
{
DbgPrint("修改线程的Context成功!\n");
//释放内存
ZwFreeVirtualMemory(NtCurrentProcess(),&pContext,&MemSize,MEM_RELEASE);
}
else
{
DbgPrint("修改线程的Context失败! status = 0x%08X\n",status);
}
}
else
{
DbgPrint("向进程中插入ShellCode失败! status = 0x%08X\n",status);
}
}
else
{
DbgPrint("获取线程的Context失败! status = 0x%08X\n",status);
}
}
else
{
DbgPrint("申请内存失败! status = 0x%08X\n",status);
}
KeDetachProcess();
}
ObDereferenceObject(pTargetThread);
}
status = OriginalNtResumeThread(ThreadHandle,PreviousSuspendCount);
return status;
}
NTSTATUS InjectShellCodeToProcessByModi
此方法的调用相关位置:
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = KernelresumeinjectDispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KernelresumeinjectDispatchClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KernelresumeinjectDispatchDeviceControl;
DriverObject->DriverUnload = KernelresumeinjectUnload;
if (InitGlobalVars()==FALSE)
{
DbgPrint("[DriverEntry] InitGlobalVars Failed!\n");
goto __failed;
}
OriginalNtResumeThread=(PFN_NtResumeThread)HookSSDTServiceByIndex(g_IndexNtResumeThread,(ULONG_PTR)DetourNtResumeThread);
if (OriginalNtResumeThread==0)
{
DbgPrint("[DriverEntry] HookSSDTServiceByIndex Failed!\n");
goto __failed;
}
入参的定义位置:
BOOL InitServiceIndex()
{
NTSTATUS status;
MAP_IMAGE_INFO NtdllInfo = {0};
ULONG ServiceIndex=0;
ULONG_PTR FnAddr=0;
ULONG_PTR MapedNtdllBase=0;
char szNtdllPath[MAX_PATH] = "\\SystemRoot\\system32\\ntdll.dll";
status = MapImageFile(szNtdllPath,&NtdllInfo);
if (!NT_SUCCESS(status))
{
dprintf("[GetServiceIndex] Map Ntdll.dll Failed!\n");
return FALSE;
}
MapedNtdllBase = (ULONG_PTR)NtdllInfo.MappedBase;
g_IndexNtResumeThread = GetServiceIndexByName(MapedNtdllBase,"NtResumeThread");
UnMapImageFile(&NtdllInfo);
return TRUE;
}
其他补充:[?] why eax 是线程的入口地址?
-
猜测: 与keAttachProcess有关
no
根据keAttachProcess的调用过程分析,此方法使用前pTargetProc 的eax的值应该是第一线程入口了
猜测 DetourNtResumeThread 调用时刻,eax的是线程入口地址吗?
- analysis
-
[next]
当前pTargetProc是入参threadHandle的地址
,而此入参threadHandle的调用来自于
OriginalNtResumeThread=(PFN_NtResumeThread)HookSSDTServiceByIndex(g_IndexNtResumeThread,(ULONG_PTR)DetourNtResumeThread);
[next] 这个g_IndexNtResumeThread的赋值位置查找,和HookSSDTServiceByIndex的使用说明查找
- g_IndexNtResumeThread
- HookSSDTServiceByIndex
根据g_IndexNtResumeThread 中查询到的对于NtResumeThread的hook来完成的,
这里推测当前eax的作为线程入口的状态是这里保证的,但是为什么是eax呢,这个还没有查询到具体的原因
记录问题,[next ] 考虑应该看一下NtResumeThread调用后,对目的进程的修改和完成情况来评估这个eax的原因 。
-
- g_IndexNtResumeThread
-
[next]
定义在BOOL InitServiceIndex()中如下:
g_IndexNtResumeThread = GetServiceIndexByName(MapedNtdllBase,"NtResumeThread");
这里的"NtResumeThread" 介绍为
大概流程如下:
Kernel32!CreateProcessW
Kernel32!CreateProcessInternalW
ntdll!NtCreateProcessEx
ntdll!NtCreateThread
ntdll!NtResumeThread
因为进程创建后,Windows 必须为它创建一个主线程,然后等待操作系统调度它。所以调用NtResumeThread的时候,就是我们Hook的最佳时机,因为此时创建进程的主要工作已经完成,
但是进程并没有调度起来,呵呵,方便干坏事啊。
[thinking 这里应该是eax的位置为第一个线程入口的原因吧?但是NtResumeThread 的具体内容go一下,确定一下]
参考: https://blog.csdn.net/zhou191954/article/details/10164459
- HookSSDTServiceByIndex
-
[next]
- analysis
没有评论:
发表评论