0x01 写在前面

决赛果然是被大佬教做人.png

ring0好像需要大量的动调还有断链操作emmmmmm

然鹅窝的双机调试还没搞好。。。。

先去把 Linux Kernel的东西搞好再回来深究吧(望天)

Writeup中所示内容均为比赛期间临场学习得到的成果,没有分析出的部分在大佬写了相关内容后将会以友链的方式更新到文章里~

0x02 ring3 程序分析

题目描述

winmine.exe是一个扫雷游戏程序,winmine.dmp是该程序的一份进程dump, 在这份dump中,有一个DLL作弊程序。

1, 请找到该作弊程序,给出模块名(1分)

2, 并分析它所包含的4个作弊功能,给出实现作弊功能的函数的偏移,并说明其作弊功能是什么(4分)

题目分析

定位并提取dump中的内存映像

使用工具:WinDbg Preview 1.0.2001.02001CFF Explorer 2012

  1. 首先使用WinDbg Preview加载程序,使用lm命令列出所有加载的模块列表

    image-20200410221132955

    image-20200410221217018

  2. 通过.writemem C:\Users\error404\Desktop\CheatTools.dll 0x6e220000 (0x6e266000-0x1)命令将其中的模块存成文件。

    image-20200410221432413

  3. 接下来需要做一下这个文件的修复,因为我们这样提取必然已经破坏了文件内部的段首部信息。

    因此我们需要将Raw AddressVirtual Address校准。

    image-20200410224443633

IDA分析该程序

使用工具:IDA Pro For Mac v7.0Resource Hacker v5.1.7

  1. 首先,我们查看字符串列表。

    image-20200410224757888

    我们发现了重要的头文件标识,这里出现了MFC文件常用的头文件,于是怀疑程序中极有可能存在资源文件,于是使用Resource Hacker查看其内部资源文件。

  2. 可以发现,程序给出了主窗体代码。

    image-20200410225123024

    于是我们可以确认四个作弊模块分别是:

    1. 暂停时间
    2. 遇雷不报
    3. 一键游戏
    4. 地雷分布(透视)

逐作弊模块分析——暂停时间

  1. 我们在初赛中其实已经发现在扫雷程序中,.text:01002FF5 inc dword_100579C处的代码是计时器递增逻辑,于是我们只需要查找这个程序中哪里进行了类似修改即可,这里我们选择直接查找这个立即数。

    image-20200410233304956

  2. 通过反汇编,我们确认了这个函数就是负责暂停计时的函数。

    image-20200410233405431

逐作弊模块分析——遇雷不报

  1. 我们在初赛中其实已经发现在扫雷程序中,0x1003591处的代码是遇雷不报逻辑,于是我们只需要查找这个程序中哪里进行了类似修改即可,这里我们选择直接查找这个立即数。

    image-20200410233745139

  2. 通过反汇编,我们确认了这个函数就是负责忽略踩雷逻辑的函数。

    此处会将源程序中push 0这个压参操作转换为了jmp short loc_10035B0

    image-20200410233853150

逐作弊模块分析——一键游戏

  1. 这里我们首先要确定,一键游戏这个功能一定是要调用扫雷中的点击操作的,即,用户点击格子后的处理程序,这个函数在扫雷程序中的sub_1003512

    image-20200410234619475

    可以看到函数中有明显的取坐标的操作v2 = &byte_1005340[32 * a2 + a1];,于是v2就是我们”点击”的格子。

    之后也有对于是否踩雷的判断

    image-20200410235034993

  2. 于是直接查找0x1003512是否在作弊模块中产生了调用。

    image-20200410235221398

    image-20200410235304298

    于是成功定位。

逐作弊模块分析——地雷分布(透视)

  1. 对于透视功能,可以在字符串窗口发现一个行:%d,列:%d

    image-20200411000851214

  2. 于是推测此函数就是透视函数。

    image-20200411001041667

题目总结

  1. 作弊程序模块名为:CheatTools.dll

  2. 四个作弊功能如下:

    1. 暂停时间

      偏移:0x1660

    2. 遇雷不报

      偏移:0x16D0

    3. 一键游戏

      偏移:0x1F00

    4. 地雷分布(透视)

      偏移:0x1AC0

0x03 ring0 程序分析 —— Part1

题目描述

(1) 成功加载Driver.drv至驱动模块链表(0.5分)

(2) 自编写驱动加载程序,使用非服务方式加载Driver.drv驱动,加载后需要保证驱动路径为C:\Driver.drv(0.5分)

(3) 分析驱动接口,给出每个功能的调用控制码,输入,输出数据的结构(0.5分)

(4) 分析驱动接口,分析每个接口的作用(0.5分)

(5) 调用驱动接口,使Driver.drv在驱动模块中断链隐藏(只允许在应用层调用Driver.drv接口实现)(2分)

(6) 从Flag.fg中分析出Flag,此flag用于解密Part2.7z(1分)

题目分析

以服务方式加载驱动

  1. 为了加载该驱动程序,需要手动编写一个INF文件。
    [Version]
    Signature   = "$CHICAGO$" 
    Provider    = ERROR404
    DriverVer   = 8/21/2002,3.0.0.3               
    Class       = DisplayCodec
    ClassGUID   = {E6ABB47D-8339-4c60-BE92-E9045FF5A33D}                                   
    
    [DestinationDirs]
    DefaultDestDir               = 12
    DriverDemo.DriverFiles      = 12
    
    [SourceDisksNames] 
    1 = "DriverDemo",Disk1,,
    
    [SourceDisksFiles]
    DriverDemo.sys = 1,objfre\i386,
    
    [DefaultInstall]
    OptionDesc  = %DriverDemoServiceDesc%
    CopyFiles   = DriverDemo.DriverFiles
    AddReg      = DriverDemo.AddRegistry
    
    [DefaultInstall.Services]
    AddService          = %DriverDemoServiceName%,,DriverDemo.Service
    
    [DefaultUninstall]
    DelFiles   = DriverDemo.DriverFiles
    DelReg     = DriverDemo.DelRegistry
    
    [DefaultUninstall.Services]
    DelService = DriverDemo,0x200    
    
    [DriverDemo.Service]
    DisplayName      = %DriverDemoServiceName%      
    Description      = %DriverDemoServiceDesc%      
    ServiceBinary    = %12%\DriverDemo.drv
    ServiceType      = 1      
    StartType        = 3      
    ErrorControl     = 1   
    LoadOrderGroup   = "DriverDemo"
    
    
    [DriverDemo.DriverFiles]
    DriverDemo.drv
    
    [DriverDemo.AddRegistry]
    HKLM,%DriverDemoRegistry%,%DriverDemoKey%,0x00010001,1
    
    [DriverDemo.DelRegistry]
    HKLM,%DriverDemoRegistry%,%DriverDemoKey%
    
    ;;
    ;; String Section
    ;;
    
    [Strings]
    DriverDemoServiceDesc = "DriverDemo.Inf"
    DriverDemoServiceName = "DriverDemo"
    DriverDemoRegistry    = "SOFTWARE\AppDataLow\Tencent\{61B942F7-A946-4585-B624-B2C0228FFEBC}"
    DriverDemoKey         = "key"
    Disk1                 = "DriverDemo Source Media"
    
  2. 然后在Windows中右击安装此inf文件即可,通过查阅系统日志,发现此驱动程序已被成功加载。

    image-20200411103454697

    image-20200411103522011

  3. 接下来尝试通过sc start DriverDemo启动,发现失败

    image-20200411103410676

    于是选择静态分析文件。

  4. 从发现在内核入口的主函数处最终返回的是一个错误码!

    image-20200411104237860

    于是我们对其进行Patch操作

    image-20200411104647298

  5. 然后加载并运行

    image-20200411104901196

非服务方式加载驱动

  1. 经过查阅相关资料,此处选择使用ZwSetSystemInformation方式加载驱动。

  2. 关键点有两个,一个是要求加载后驱动的路径恒为C:/Driver_test.drv,另一个就是成功加载驱动,这里我们选择选择使用MoveFile这个API函数来完成移动驱动的目的。

  3. 最终加载代码如下:

    #include <Windows.h>
    #include <stdio.h>
    #include <atlconv.h>
    #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
    const INT SystemLoadAndCallImage = 38;
    typedef struct  _UNICODE_STRING {
    
    USHORT Length;
    USHORT MaximumLength;
    PWCH   Buffer;
    } UNICODE_STRING, * PUNICODE_STRING;
    
    typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE {
    UNICODE_STRING ModuleName;
    } SYSTEM_LOAD_AND_CALL_IMAGE, * PSYSTEM_LOAD_AND_CALL_IMAGE;
    
    typedef void(*RTLINITUNICODESTRING)(
    PUNICODE_STRING DestinationString,
    PCWSTR          SourceString
    );
    
    typedef NTSTATUS(__stdcall* ZwSetSystemInformation)(
    IN DWORD SystemInformationClass,
    IN OUT PVOID SystemInformation,
    IN ULONG SystemInformationLength
    );
    
    int main(int argc, char* argv)
    {
    SYSTEM_LOAD_AND_CALL_IMAGE Images;
    RTLINITUNICODESTRING RtlInitUnicodeString;
    ZwSetSystemInformation fZwSetSystemInformation;
    
    char szDrvFullPath[256] = "C:\\Users\\error404\\Desktop\\Driver_test.drv";
    
    if (!(RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "RtlInitUnicodeString"))) {
        printf("GetProcAddrss error:%d\n", GetLastError());
        exit(-1);
    }
    if (!(fZwSetSystemInformation = (ZwSetSystemInformation)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "ZwSetSystemInformation"))) {
        printf("GetProcAddrss error:%d\n", GetLastError());
        exit(-1);
    }
    MoveFileA(szDrvFullPath, "C:\\Driver.drv");
    USES_CONVERSION;
    PWCHAR path = A2W("\\??\\C:\\Driver.drv");
    RtlInitUnicodeString(&(Images.ModuleName), path);
    
    if (!NT_SUCCESS(fZwSetSystemInformation(SystemLoadAndCallImage, &Images, sizeof(SYSTEM_LOAD_AND_CALL_IMAGE))))
    {
        printf("drive %s was loaded....", szDrvFullPath);
    }
    else
    {
        printf("dirve load error...");
    }
    getchar();
    return 1;
    }
    

    image-20200411141940331

    image-20200411142016081

分析驱动接口

  1. 首先,驱动和用户层交互的时候必然调用的是I/O相关的操作内容,那么首先定位到sub_140001ED0

    image-20200411151852273

  2. 然后我们进行函数跟进。

    image-20200411151937994

    发现了四个功能模块函数,那么我们逐个分析。

  3. 第一个功能模块位于sub_1400023F0

    image-20200411152215181

    可以看出调用控制码为0x400000010,输入结构为一个函数指针和一个QWORD型的变量

  4. 第二个功能模块位于sub_1400022A0

    image-20200411155011133

    可以看出调用控制码为0x800000008,输入结构为一个数值, 8和0x1E8A0C。

  5. 第三个功能模块位于sub_140002310

    image-20200411161338146

    没有给出调用控制码,输入结构为一个数值, 8和0x237BB3。

  6. 第四个功能模块位于sub_140002380

    image-20200411161443722

    没有给出调用控制码,输入结构为一个数值, 8和0x237BB3。

  7. 由于没有明确的思路做后续分析,于是不再分析具体功能。推测功能模块已经被做了混淆和花指令处理,功能应该是和Windows内存隐藏技术相关。

  8. Flag.fg可以判断出是一个shellcode:

    image-20200411161822742

    但是分析flag字符串失败,因此没有开启Part2的题目。

    附一个大佬的分析博客:https://bbs.pediy.com/thread-258803.htm

分类: CTF

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注