html tool

2019年5月23日星期四

问题记录: 12.1.2 改变程序运行流程使用主动加载目标DLL 中的 5. 内核中通过 Hook/Notify 干预执行流程法的 code read 中注释 提示 “此时,eax 指向线程中的真正的起点 ” 的 问题记录和下一步开始位置


问题记录:

       根据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

没有评论:

发表评论