首页
社区
课程
招聘
[原创]南极动物厂 游戏安全2024决赛 PC
发表于: 2024-4-22 00:24 10282

[原创]南极动物厂 游戏安全2024决赛 PC

2024-4-22 00:24
10282

感谢宝子们对我的帮助!
特别感谢!存宝!翔哥!呜呜呜呜!
WP是简单的版本,因为做题的时候是远程好盆友的电脑,自己没有windows环境,所以代码和截图说明就没有那么多了,就简单版本!希望大家不要喷我!我就是记录一下!存个档!

题目解读后,可以分为两个块,一个是写注册机,一个是分析内核shellcode的位置和干了什么

在进行这个题目的时候,发现双机调试不能使用,分析的ark工具也不能使用,基本上这种方式不太行了,但是仍然比不了自己手速!哈哈哈哈!在没有蓝屏的时候用ark dump了一份load.dump.bin,哈哈哈哈

因为题目要求将card.txt放置到C盘根目录:这个时候发现一个现象,如果我不放到根目录下,或者如果我card.txt里面的值被我随便修改的情况下可以进行双机调试不会被检测,这个时候自己有了一点想法,(但是还是先做这个问为主),因为这个时候可以进行双机调试所以自己用双机调试做的USERKEY分析的东西

load.dump.bin中,可以看到路径的名称为:\\??\\C:\\card.txt,但是回溯不了很烦

还根据ZwCreateFile入手

直接看一下ObjectAttributes里面的ObjectName的名字

一般来说如果读取文件来说,用的是ZwCreateFile,进行栈回溯一直跟一直跟,因为在vm中一定要回到text段,这个时候我认为的方式是:参数写入后,进行call

但是感觉栈回溯太多了不太行,然后想了一下看了一下这个地址的address模块在这个loader.sys中,计算一下offset = 0x675e20,然后交叉引用回去即可

这个的路径是xor 0xace做到的,我这边直接解密,也可以看到code References的地址

直接windbg分析后,这个位置不难,很好的可以分析user算法的位置:

key的算法位置:

这两个位置我是动态调试出来的,大概算法的表示为-进行分割后,user计算后的值转化为10进制,就是key的值

注册机:

第一问:administrator-4007951923

第二问:如上

第三问:编写一个exp,在exp程序运行后,对于任意的用户名-key,Loader.sys均能正确启动

只需要把jne -> nop即可,因为我们不需要对al进行处理了

目前是前三问都OK了,这个时候会出现双机调试的问题,根本调试不了,因为在没有双机调试的环境下进行分析的时候发现不会蓝屏,但是当驱动正常加载后,进行打开ark这种工具,几秒后还是会蓝屏

想了一下还是在内核当中起了线程(因为第四问也说了:在Load驱动运行后找到内核内存空间中的shellcode),因为一定是线程在做的检测的事情导致的蓝屏,尝试断PsCreateSystemThread没有发现什么重要的信息,但是一定是有线程跑不然为什么会蓝屏?

所以注册进程回调看有什么异常的,打印ProcessIdThreadId

主要观察processid = 4的,因为初赛也是这样,所以主要观察点在这个位置,发现确实创建了两条很可疑的线程,但是自己在观察这些线程地址的时候,确实没有很奇怪的地址存在,那么很有可能,在线程地址那里做了个跳板,之后进行了恢复所以看到的所有的线程都是很正常的地址

直接使用PsLookupThreadByThreadId通过threadId,找到startAddress

然后直接dump,看一下里面做了什么

发现这里就是一个push mov ret返回真正的地址位置,这两个都是这种形式

现在可以确定线程的入口是伪造的,当线程启动后会还原入口,所以这就是为什么看的线程的这些都没有啥问题的原因,这个时候猜测的这两个线程肯定是有一个做了检测的工作,另一个做了真正的事情,不然没必要创建两条

所以直接修改入口为ret,这个时候可以发现可以双机调试了,也可以打开ark工具,其中的另一个很奇怪的shellcode如下

这里做了很多xmm的操作,大概看了一下这个xmm操作都是混淆,分析的时候直接跳过了这些分析的

现在可以确定的是百分百分确定了线程会被创建,一定会用到PsCreateSystemThread,但是bp不到,直接去看一下函数的实现

直接下断PsCreateSystemThreadEx

这里可以获取函数的入口点

但是按照道理来说如果直接ret的话,不应该会做shellcode的事情,但是现象是:断下后,瞬间入口还原了,并且蓝屏了,说明有个地方启动了,这里就猜测是插了APC

插入APC:使用KeInsertQueueApc函数来插入APC到目标线程的APC队列中,直接断KeInsertQueueApc

查看一下KPAC结构

可以查看到APC的内容在loader.sys

可以看到这里进行了cmp ,直接修改了je -> jmp 就不会蓝屏了

第二次APC的位置

第二次的时候发现都是xmm的操作,很难去分析,所以没有管第二次的问题,但是由于题目上说:分析shellcode反复在读取哪个内存地址,可以确定这里一定是一个while 1一直在循环操作,为了降低CPU的利用率,猜测会用延时函数,最有可能的就是KeDelayExecutionThread

可以看到找到了这个shellcode的位置,可以看到是根据rax来的,往上跟一下

可以看到表的解密方式是xor acacacacacacac

解密出的函数列表:

这样就比较好看了,直接hook所有的函数,发现一直在循环的遍历进程,感觉有点问题存在,直接过去分析看看做了什么,如果是一直循环遍历进程,自己猜测肯定是在准备比对什么东西,但是没有比对到,直接去分析vm中的东西

下读断点,断下后,进行分析,发现时逐字节比对,比对是不是GameSec.exe

这个GameSec.exe需要自己创建这个进程,然后继续分析,直接写了一个helloworld改个名字丢进去看看做啥了,这个时候不难想到是在读R3进程的东西

这个时候可以看到了MmCopyVirtualMemoryPsGetProcessPeb在一直做事情

直接跟PsGetProcessPeb回溯

直接对rsp+40h下访问断点

所以第四问:PsGetProcessPeb + 0xACE

第五问:编写一个search程序,在Load驱动运行后找到内核内存空间中的shellcode,输出shellcode范围内的任意地址 (NMI即可)

NTSYSAPI NTSTATUS ZwCreateFile(
  [out]          PHANDLE            FileHandle,
  [in]           ACCESS_MASK        DesiredAccess,
  [in]           POBJECT_ATTRIBUTES ObjectAttributes,
  [out]          PIO_STATUS_BLOCK   IoStatusBlock,
  [in, optional] PLARGE_INTEGER     AllocationSize,
  [in]           ULONG              FileAttributes,
  [in]           ULONG              ShareAccess,
  [in]           ULONG              CreateDisposition,
  [in]           ULONG              CreateOptions,
  [in, optional] PVOID              EaBuffer,
  [in]           ULONG              EaLength
);
NTSYSAPI NTSTATUS ZwCreateFile(
  [out]          PHANDLE            FileHandle,
  [in]           ACCESS_MASK        DesiredAccess,
  [in]           POBJECT_ATTRIBUTES ObjectAttributes,
  [out]          PIO_STATUS_BLOCK   IoStatusBlock,
  [in, optional] PLARGE_INTEGER     AllocationSize,
  [in]           ULONG              FileAttributes,
  [in]           ULONG              ShareAccess,
  [in]           ULONG              CreateDisposition,
  [in]           ULONG              CreateOptions,
  [in, optional] PVOID              EaBuffer,
  [in]           ULONG              EaLength
);
#include <iostream>
using namespace std;
 
uint64_t getkey(string user)
{
    uint32_t encuser = 0;
    for(int i : user)
    {
        encuser = (i + encuser)*0x1003f;
    }
    return encuser;
}
 
int main()
{
    string user;
    cout << "input your user: " << endl;
    cin >> user;
    cout << "your key : " << getkey(user) << endl;
    return 0;
}
#include <iostream>
using namespace std;
 
uint64_t getkey(string user)
{
    uint32_t encuser = 0;
    for(int i : user)
    {
        encuser = (i + encuser)*0x1003f;
    }
    return encuser;
}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-4-22 00:25 被L0x1c编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (2)
雪    币: 10636
活跃值: (5769)
能力值: ( LV15,RANK:523 )
在线值:
发帖
回帖
粉丝
2
源神nb
2024-4-22 00:33
0
雪    币: 1918
活跃值: (6250)
能力值: ( LV7,RANK:118 )
在线值:
发帖
回帖
粉丝
3
源神!
2024-4-22 12:49
0
游客
登录 | 注册 方可回帖
返回
//