`
java-mans
  • 浏览: 11391972 次
文章分类
社区版块
存档分类
最新评论

windows创建进程的用户态和内核态交互----小话windows(1)

 
阅读更多
作者:陈曦

日期:2012-6-19 12:28:30

环境:[win7旗舰版 SP1 ; Intel i3 x86, 支持64位 ;vs2010 ; wrk-v1.2 ; Virtual PC 2007 windows 2003 server sp1 standard edition镜像 ;WinDbg 6.11.0001.404(x86) ]

转载请注明出处


Q:在windows下,调用CreateProcess这个API来创建进程,它内部究竟做了什么?

A:对于操作系统,一般肯定是分层的。内核将处理最终的创建进程操作,但是它的上层可能有一些模块,进行一些参数合法性判断或者为了可移植考虑的判断。windows同样不例外。看看windows下面内核上面的模块:


不妨先写一个CreateProcess的程序,通过逆向工程得到内部调用的东西。


Q:如下代码:

#include <windows.h>
#include <stdio.h>

int main()
{
    PROCESS_INFORMATION processInfo;
    STARTUPINFOA	startupInfo;
    ZeroMemory(&processInfo, sizeof(processInfo));
    ZeroMemory(&startupInfo, sizeof(startupInfo));
    startupInfo.cb = sizeof(startupInfo);

    BOOL ret = CreateProcessA(NULL, "c:\\windows\\system32\\cmd.exe", NULL, NULL, false, 
				0, NULL, NULL, &startupInfo, &processInfo);
    if(ret)
	printf("create process ok...\n");
    else
    {
	printf("create process failed...\n");
	printf("error is %d", GetLastError());
    }

    return 0;
}

编译成CreateProcessDemo.exe, 运行:

可以看出,它正确地创建了进程。


A: 下面我们将找出哪个模块包含CreateProcessA函数。进入VS的命令行工具,

使用如下命令dumpbin.exe /all CreateProcessDemo.exe > d:\dumpbin_createprocessdemo.txt得到所有dump的信息,找到如下信息:

 KERNEL32.dll
                41819C Import Address Table
                41803C Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                   A4 CreateProcessA
                  1C0 GetCurrentProcess
                  4C0 TerminateProcess
                  162 FreeLibrary
                  4F1 VirtualQuery
                  214 GetModuleFileNameW
                  24A GetProcessHeap
                  2CB HeapAlloc
                  2CF HeapFree
                  279 GetSystemTimeAsFileTime
                  1C1 GetCurrentProcessId
                  1C5 GetCurrentThreadId
                  293 GetTickCount
                  3A7 QueryPerformanceCounter
                   CA DecodePointer
                  4A5 SetUnhandledExceptionFilter

可以看出,CreateProcessA是在KERNEL32.DLL中被引用的。


Q:现在我们可以在kernel32.dll中查看CreateProcessA的调用关系了?

A:是的。使用ida,打开系统目录下面的kernel32.dll,并查找CreateProcessA函数的位置:


可以在靠近最后的时候发现调用CreateProcessInternalA例程。


Q:继续查找CreateProcessInternalA例程的内部实现,它最终会调用CreateProcessInternalW来实现。继续查找CreateProcessInternalW的实现,发现它最终会调用NtCreateUserProcess例程(在xp或者server 2003下,会调用NtCreateProcessEx).此例程不在kernel32.dll中,它在哪里?

A:正如上面的图示描述,它以nt开头,它在ntdll.dll中。同样适用ida打开ntdll.dll,找到NtCreateUserProcess的实现:



Q: ZwCreateUserProcess是什么,好像和NtCreateUserProcess是一样的?

A:仅仅在ntdll.dll中来说,依照上面的截图,它们是一致的;可是在内核中,它们不完全一致。Nt开头的例程会进行访问权限和参数合法性判断,而Zw不会,Zw它可以由内核模式代码直接使用;同时,调用Zw开头的例程会将先前的模式改变为内核模式,而使用Nt开头的例程不能。

这里,可以看下xp或2003 server下的nt内核对应的代码:

//
//NtCreateProcess函数是调用它 的。
//此函数调用PspCreateProcess函数。
//

NTSTATUS              // typedef  ULONG  NTSTATUS;
NtCreateProcessEx(
    __out PHANDLE ProcessHandle,
    __in ACCESS_MASK DesiredAccess,
    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
    __in HANDLE ParentProcess,
    __in ULONG Flags,        //创建标志
    __in_opt HANDLE SectionHandle,
    __in_opt HANDLE DebugPort,
    __in_opt HANDLE ExceptionPort,
    __in ULONG JobMemberLevel
    )

/*++ 

Routine Description: //例程描述

    This routine creates a process object.    //创建一个进程对象

Arguments:   //参数

    ProcessHandle - Returns the handle for the new process. //返回新进程的句柄指针

    DesiredAccess - Supplies the desired access modes to the new process. //提供新进程的访问权限

    ObjectAttributes - Supplies the object attributes of the new process. //提供新进程的对象属性
    .
    .
    .

--*/

{
    NTSTATUS Status;

	//
	//  在调试模式下才有用;否则,被定义为空语句
	//

    PAGED_CODE();   

	//如果线程之前执行的模式不是内核模式
    if (KeGetPreviousMode() != KernelMode) { 

        //
        // Probe all arguments    //检查所有的参数
        //

        try {
            ProbeForWriteHandle (ProcessHandle); //ProbeForWriteHandle宏在ex.h文件中定义
        } except (EXCEPTION_EXECUTE_HANDLER) {
            return GetExceptionCode ();
        }
    }

    if (ARGUMENT_PRESENT (ParentProcess)) {  //如果参数--父进程句柄存在
        Status = PspCreateProcess (ProcessHandle, //调用PspCreateProcess函数
                                   DesiredAccess,
                                   ObjectAttributes,
                                   ParentProcess,
                                   Flags,
                                   SectionHandle,
                                   DebugPort,
                                   ExceptionPort,
                                   JobMemberLevel);
    } else {    //否则,返回参数不合法的错误
        Status = STATUS_INVALID_PARAMETER;
    }

    return Status;
}


Q:刚刚所说的用户模式是如何进入内核模式的?

A:上面的ntdll.dll中执行依然是用户模式,NtCreateUserProcess通过向eax传入中断号, edx传入7FFE0300H为参数地址来进行系统调用,进入内核模式。它的内部实现为:

NTSTATUS
NtCreateProcess(  //创建进程
    __out PHANDLE ProcessHandle,   //进程句柄的指针
    __in ACCESS_MASK DesiredAccess,
    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
    __in HANDLE ParentProcess,    //父进程句柄
    __in BOOLEAN InheritObjectTable,  //是否继承句柄表
    __in_opt HANDLE SectionHandle,
    __in_opt HANDLE DebugPort,         //调试端口
    __in_opt HANDLE ExceptionPort     //异常端口
    )
{
    ULONG Flags = 0;

    if ((ULONG_PTR)SectionHandle & 1) {
        Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
    }

    if ((ULONG_PTR) DebugPort & 1) {
        Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
    }

    if (InheritObjectTable) {  //是否继承句柄表
        Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
    }

	//调用NtCreateProcessEx函数
    return NtCreateProcessEx (ProcessHandle,
                              DesiredAccess,
                              ObjectAttributes OPTIONAL, //OPTIONAL只是表示可选参数的意思,并不会对编译造成影响
                              ParentProcess,
                              Flags,   //上面计算得到的Flags
                              SectionHandle,
                              DebugPort,
                              ExceptionPort,
                              0);
}

因为未找到win7的WRK源代码信息,上面为nt内核的实现。注意,如上程序执行是在win7系统下的执行。


Q:为了更清楚地得到内部调用细节,是否可以使用虚拟机来测试一下?

A: 可以,使用虚拟机进行内核模式调试,来验证上面的整个过程;当然,因为使用的虚拟机系统是2003 server sp1,它的内核和win7内核是不同的,所以会有不一致的地方。


Q:当虚拟机和调试器启动后(此具体过程略,关于wrk的配置可以在网上搜索),然后做什么?

A:先在win7下面编写一个可以在虚拟机系统2003 server sp1下可以跑的程序.可以是任意的了。


Q:如下代码:

#include <stdio.h>

int main()
{
    printf("hello\n");

    return 0;
}
为了保证在低版本下可运行,编译时将使用的库设置成使用静态库。

编译成hello.exe.放到虚拟机系统桌面上。此时让hello.exe运行吗?

A:不要着急,我们先在NtCreateProcessEx开始处加断点。如下:


如上图红色地方。接着让虚拟机继续运行,在虚拟机的桌面双击hello.exe运行起来。


Q:双击后,调试器遇到断点停顿下来:

如上,紫色位置为windbg跑到断点时的截图。此时,是否就可以看看调用堆栈了?

A:是的。使用在kd提示符后输入k命令得到堆栈信息:

可以看出从kernel32中的CreateProcessW,到CreateProcessInternalW,又到ntdll中的NtCreateProcessEx,接着调入陷入内核例程KiFastSystemCallRet进入nt模块(即为内核模块)。在内核中,它调用NtCreateProcessEx函数来完成具体的工作。


Q:ntdll中的NtCreateProcessEx与nt中的NtCreateProcessEx名称一样,会有冲突吗?

A:它们不是简单的上层和下层的模块,中间又有了一些模块,所以名称一样不会直接造成冲突;并且ntdll调用内核例程也肯定不是把函数名称传进去的; 编译器是可以正确地找到了地址,运行时也不会混淆。


Q:在内核中,NtCreateProcessEx和ZwCreateProcessEx有什么区别?

A:使用x nt!ZwCreateProcessEx先看看内核中是否存在ZwCreateProcessEx:

由上可以看出确实存在。

接着反汇编:

可以看出,它的实现很直接,调用系统调用具体处理。它和之前看到的NtCreateProcessEx显然不一样,NtCreateProcessEx先进行了一些参数和模式的判断。所以说,ZwCreateProcessEx会将运行的模式转变成内核模式,因为它通过系统调用被迫陷入内核模式。不过,NtCreateProcessEx内部的处理依然是它实际的实现。


Q:那么,调用结束时如何返回呢?

A:如下,

在base\ntos\ke\i386\trap.asm中包含了返回时的处理:

kss61:

;
; Upon return, (eax)= status code. This code may also be entered from a failed
; KiCallbackReturn call.
;

        mov     esp, ebp                ; deallocate stack space for arguments

;
; Restore old trap frame address from the current trap frame.
;

kss70:  mov     ecx, PCR[PcPrcbData+PbCurrentThread] ; get current thread address
        mov     edx, [ebp].TsEdx        ; restore previous trap frame address
        mov     [ecx].ThTrapFrame, edx  ;

;
;   System service's private version of KiExceptionExit
;   (Also used by KiDebugService)
;
;   Check for pending APC interrupts, if found, dispatch to them
;   (saving eax in frame first).
;
        public  _KiServiceExit
_KiServiceExit:

        cli                                         ; disable interrupts
        DISPATCH_USER_APC   ebp, ReturnCurrentEax

;
; Exit from SystemService
;

        EXIT_ALL    NoRestoreSegs, NoRestoreVolatile

主要就是恢复调用时的信息,继续执行。


作者:陈曦

日期:2012-6-19 12:28:30

环境:[win7旗舰版 SP1 ; Intel i3 x86, 支持64位 ;vs2010 ; wrk-v1.2 ; Virtual PC 2007 windows 2003 server sp1 standard edition镜像 ;WinDbg 6.11.0001.404(x86) ]

转载请注明出处



分享到:
评论

相关推荐

    windows驱动开发技术详解-part2

     5.1.4 Windows驱动程序和进程的关系  5.1.5 分页与非分页内存  5.1.6 分配内核内存  5.2 在驱动中使用链表  5.2.1 链表结构  5.2.2 链表初始化  5.2.3 从首部插入链表  5.2.4 从尾部插入链表  ...

    Windows内部原理(十一):存储和文件系统

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    windows 内部原理(一)

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    WINDOWS 内部原理 (八)

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    WINDOWS 内部原理(九)

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    WINDOWS 内部原理(四)

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    Windows程序设计(第2版)王艳_源代码

    书籍目录: 第1章 Windows程序设计基础   1.1 必须了解的内容   1.2 VC++的基本使用  1.3 本书推荐的编程环境  1.4 代码的风格  第2章 Win32程序运行原理   2.1 CPU的保护模式和Windows系统  2.2 ...

    Windows驱动开发技术详解的光盘-part1

    本书是作者结合教学和科研实践经验编写而成的,不仅详细介绍了Windows内核原理,而且介绍了编程技巧和应用实例,兼顾了在校研究生和工程技术人员的实际需求,对教学、生产和科研有现实的指导意义,是一本值得推荐的...

    WINDOWS 内部原理(十)驱动和硬件的管理

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    WINDOWS 内部原理 (三)

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    WINDOWS 内部原理(五)

    Windows的启动是一个复杂的过程,从加载器(NTLDR或WinLoad)开始工作到Windows子系统准备就绪,中间经历了若干个复杂的步骤,包括内核和执行体的初始化,创建系统进程和线程,对象管理器初始化基本对象,I/O管理器...

    新版Android开发教程.rar

    ANDROID 的推出后可能影响的产业包括移动电信业,软件开发业,手机制造业,在以消费者为核心的状 态 。 对消费者的影响 � 高档手机选择面增加。 � A ndroid 在设计初期就考虑了与现其有业务的融合,改变以往从...

    入门学习Linux常用必会60个命令实例详解doc/txt

    因为Linux与Windows不同,其后台运行着许多进程,所以强制关机可能会导致进程的数据丢失,使系统处于不稳定的状态,甚至在有的系统中会损坏硬件设备(硬盘)。在系统关机前使用 shutdown命令,系统管理员会通知所有...

    Advanced Windows Debugging 英文原版

    13.1.3.内核态转储文件的创建 421 13.2.转储文件的使用 423 13.2.1.转储文件的分析:访问违例 424 13.2.2.转储文件的分析:句柄泄漏 425 13.3.Windows错误报告 429 13.3.1.Dr.Watson 429 13.3.2.Windows错误报告的...

    Google Android SDK开发范例大全(完整版)

    每个 Android 应用程序都在 Dalvik VM 的一个实例中运行,这个实例驻留在一个由 Linux 内核管理的进程中,如下图所示。 图 2. Dalvik VM Android 应用程序由一个或多个组件组成: 活动 具有可视 UI 的应用...

    RED HAT LINUX 6大全

    第1章 Red Hat Linux和UNIX简介 1 1.1 Linux的优点 2 1.2 版权和保证 3 1.3 在哪里可以获取Red Hat Linux 3 1.4 系统需求 3 1.5 小结 4 第2章 Red Hat系统的安装 5 2.1 准备,认真准备 5 2.2 安装Red Hat Linux 6 ...

    vc++ 开发实例源码包

    如题,此实例非常适合学习,重载并自绘了Wnd类,效果是上下文字、图片、文字由大到小和星星闪烁等滚动效果。实例使用了加载类似xml文件读取信息,然后显示。 COM_ATL_Tutorial 简单的atl控件演示 COM接口挂钩及其...

    黑客反汇编揭秘(第二版).part1.rar

    版次:2-1 所属分类: 计算机 &gt; 软件与程序设计 &gt; 汇编语言/编译原理 &gt; 汇编语言程序设计 编辑推荐 俄罗斯著名的安全技术专家Kris Kaspersky力作 横跨Windows和UNIX两大主流操作系统 全面介绍多种调试工具和方法 ...

    AIX基础PPT

    内核提供以下功能 ● 多用户、多进程的调度● I/O设备的接口● 管理磁盘上的文件● AIX内核主要用C语言编写、少量用汇编语言 文件系统 AIX提供三种类型的文件,普通文件,设备文件和命令文件 Shell ● 是系统于...

    Android高级编程--源代码

     ◆如何使用布局和定制view创建用户界面  ◆存储和共享应用程序数据的技术  ◆如何创建基于地图的应用程序,如何使用gps和地理编码位置等基于位置的服务  ◆如何创建和使用后台服务及notification  ◆使用加速...

Global site tag (gtag.js) - Google Analytics