windows x86系统调用(一)

一、前言

windows和linux这样的现代化操作系统,都是是运行在保护模式下,在保护模式下CPU分为了特权级权限和用户级权限,操作系统根据CPU提供的不同权限将系统分为了内核态和用户态,用户态是不允许直接访问内核态的内存的,那就说明了用户态就不能直接调用内核态提供的函数的,那就引出了本片文章的主题用户态如何调用内核态的函数。
由于系统调用流程比较复杂,涉及内容比较多暂时打算将该内容分为三篇给大家分享,当前篇主要分享用户态进入内核态前的工作。

二、环境

调试机器:windows10
调试工具:windbg、x32dbg
被调试机器:windows 7 sp1 x86

三、词汇说明

由于网上很多使用的是非标准名称,而是使用了一些行业中的名词有些新手恐怕不太明白,我将该文章中使用的行业名词进行说明,方便大家理解。
3环:在windows中泛指用户态。
0环:在windows中泛指内核态。
领空:当前代码执行在什么库中,比如调用ntdll.dll中的函数,并且正在该函数中执行,那么当前的领空就是ntdll.dll。该名称一般用于在动态分析中。

四、调用流程

4.1 调用系统代码

编写一个需要调用0环代码,当前我使用的是OpenProcess来进行跟踪3环的执行流程,大家可以选择其他的函数只要这个函数最终要调用0环都可以。

#include <Windows.h>

int main()
{
	__asm int 3;
	OpenProcess(0, 0, 0);
}

4.2 调用过程

4.2.1 kernel32.dll

在这里插入图片描述
调用OpenProcess最先进入的Kernel32.dll的代码领空,并且在该函数中什么都没有做就跳转了一下。

4.2.2 kernelbase.dll

在这里插入图片描述
当前领空为kernelbase.dll,说明当前执行到了kernelbase.dll中的OpenProces函数,在这个函数的关键点是绿色箭头指向的Call,调用了一个名字为NtOpenProcess的函数。使用蓝色框起来的那些指令的作用就是构建调用NtOpenProcess函数的参数,不是该文章的主线就不进行分析了。

4.2.3 ntdll.dll

在这里插入图片描述
当前领空为ntdll.dll,说明了kernelbase.dll调用的NtOpenProcess函数是ntdll.dll中的函数,这个函数就需要分析一下了。

  • mov eax,BE 将一个立即数存入到eax中。
  • mov edx,7ffe0300 将一个立即数存入到edx中。注意调试将7ffe0300翻译成了KiFastSystemCall.
  • mov dword ptr ds:[edx] 使用call调用了一下这个立即数。
    在这里插入图片描述
    当前领空为ntdll.dll,说明在NtOpenProcess函数中的call又调用了ntdll中的KiFastSystemCall.
调用号

这里又引入了一个概念 调用号 ,其实在上面代码中eax存入是0环NtOpenProcess的调用号,当前大家就先知道它是调用号就可以了,下一篇文章将会说明它的作用。

_KUSER_SHARED_DATA结构
//0x5f0 bytes (sizeof)
struct _KUSER_SHARED_DATA
{
    ULONG TickCountLowDeprecated;                                           //0x0
    ULONG TickCountMultiplier;                                              //0x4
    volatile struct _KSYSTEM_TIME InterruptTime;                            //0x8
    volatile struct _KSYSTEM_TIME SystemTime;                               //0x14
    volatile struct _KSYSTEM_TIME TimeZoneBias;                             //0x20
    USHORT ImageNumberLow;                                                  //0x2c
    USHORT ImageNumberHigh;                                                 //0x2e
    WCHAR NtSystemRoot[260];                                                //0x30
    ULONG MaxStackTraceDepth;                                               //0x238
    ULONG CryptoExponent;                                                   //0x23c
    ULONG TimeZoneId;                                                       //0x240
    ULONG LargePageMinimum;                                                 //0x244
    ULONG Reserved2[7];                                                     //0x248
    enum _NT_PRODUCT_TYPE NtProductType;                                    //0x264
    UCHAR ProductTypeIsValid;                                               //0x268
    ULONG NtMajorVersion;                                                   //0x26c
    ULONG NtMinorVersion;                                                   //0x270
    UCHAR ProcessorFeatures[64];                                            //0x274
    ULONG Reserved1;                                                        //0x2b4
    ULONG Reserved3;                                                        //0x2b8
    volatile ULONG TimeSlip;                                                //0x2bc
    enum _ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture;            //0x2c0
    ULONG AltArchitecturePad[1];                                            //0x2c4
    union _LARGE_INTEGER SystemExpirationDate;                              //0x2c8
    ULONG SuiteMask;                                                        //0x2d0
    UCHAR KdDebuggerEnabled;                                                //0x2d4
    UCHAR NXSupportPolicy;                                                  //0x2d5
    volatile ULONG ActiveConsoleId;                                         //0x2d8
    volatile ULONG DismountCount;                                           //0x2dc
    ULONG ComPlusPackage;                                                   //0x2e0
    ULONG LastSystemRITEventTickCount;                                      //0x2e4
    ULONG NumberOfPhysicalPages;                                            //0x2e8
    UCHAR SafeBootMode;                                                     //0x2ec
    union
    {
        UCHAR TscQpcData;                                                   //0x2ed
        struct
        {
            UCHAR TscQpcEnabled:1;                                          //0x2ed
            UCHAR TscQpcSpareFlag:1;                                        //0x2ed
            UCHAR TscQpcShift:6;                                            //0x2ed
        };
    };
    UCHAR TscQpcPad[2];                                                     //0x2ee
    union
    {
        ULONG SharedDataFlags;                                              //0x2f0
        struct
        {
            ULONG DbgErrorPortPresent:1;                                    //0x2f0
            ULONG DbgElevationEnabled:1;                                    //0x2f0
            ULONG DbgVirtEnabled:1;                                         //0x2f0
            ULONG DbgInstallerDetectEnabled:1;                              //0x2f0
            ULONG DbgSystemDllRelocated:1;                                  //0x2f0
            ULONG DbgDynProcessorEnabled:1;                                 //0x2f0
            ULONG DbgSEHValidationEnabled:1;                                //0x2f0
            ULONG SpareBits:25;                                             //0x2f0
        };
    };
    ULONG DataFlagsPad[1];                                                  //0x2f4
    ULONGLONG TestRetInstruction;                                           //0x2f8
    ULONG SystemCall;                                                       //0x300
    ULONG SystemCallReturn;                                                 //0x304
    ULONGLONG SystemCallPad[3];                                             //0x308
    union
    {
        volatile struct _KSYSTEM_TIME TickCount;                            //0x320
        volatile ULONGLONG TickCountQuad;                                   //0x320
        ULONG ReservedTickCountOverlay[3];                                  //0x320
    };
    ULONG TickCountPad[1];                                                  //0x32c
    ULONG Cookie;                                                           //0x330
    ULONG CookiePad[1];                                                     //0x334
    LONGLONG ConsoleSessionForegroundProcessId;                             //0x338
    ULONG Wow64SharedInformation[16];                                       //0x340
    USHORT UserModeGlobalLogger[16];                                        //0x380
    ULONG ImageFileExecutionOptions;                                        //0x3a0
    ULONG LangGenerationCount;                                              //0x3a4
    ULONGLONG Reserved5;                                                    //0x3a8
    volatile ULONGLONG InterruptTimeBias;                                   //0x3b0
    volatile ULONGLONG TscQpcBias;                                          //0x3b8
    volatile ULONG ActiveProcessorCount;                                    //0x3c0
    volatile USHORT ActiveGroupCount;                                       //0x3c4
    USHORT Reserved4;                                                       //0x3c6
    volatile ULONG AitSamplingValue;                                        //0x3c8
    volatile ULONG AppCompatFlag;                                           //0x3cc
    ULONGLONG SystemDllNativeRelocation;                                    //0x3d0
    ULONG SystemDllWowRelocation;                                           //0x3d8
    ULONG XStatePad[1];                                                     //0x3dc
    struct _XSTATE_CONFIGURATION XState;                                    //0x3e0
}; 

在上述代码中将一个立即数存入到了edx中,其实是将_KUSER_SHARED_DATA结构的SystemCall存入到了edx中,该结构是0环和3环共用的,0环有修改权限而3环只有只读权限,而且这个结构是地址是固定3环在7ffe0000这个位置。
有的朋友会好奇为什么需要将函数地址存储到一个结构中而不直接写到代码中呢?这里就引出一个一个兼容的问题当前分析的流程是使用sysenter进行进入0环的,但是存在一些CPU是不支持这种快速调用就使用了中断的方式进入的0环,在windodws启动的时候会去检查当前CPU是否支持sysenter这种指令来确定该结构中的值。

sysenter指令说明

该指针负责将3环权限提示为0环权限,我们需要知道提权需要执行以下操作:

  • 将cs修改为0环权限
  • 将ss修改为0环权限

sysenter执行流程:

  1. 将msr寄存器的174位存入到cs中
  2. 将msr寄存器的176位存入到eip中
  3. 将cs寄存器的GDT表项加8的位置存入到ss中
  4. 将msr寄存器的175位存入到esp中
  5. 清除eflags寄存器的IF位

五、总结

5.1 调用流程

3环的调用流程相对比较简单,就是构建了以下0环函数需要使用的参数,然后就进入了0环了。

Created with Raphaël 2.3.0 开始 kernel32.dll:OpenProcess kernelbase.dll:OpenProcess ntdll.dll:NtOpenProcess ntdll.dll:KiFastSystemCall 进入0环

5.2 环境

最后需要记录以下三环进入0环的环境状态,我将比较重要的环境进行列出方便进入0环后的分析。

5.2.1 寄存器

  • eax:当前存入的是BE
  • edx:当前存入的是三环的ESP

5.2.2 堆栈

在这里插入图片描述

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值