首页
论坛
课程
招聘
[原创] 祥云杯2021 Windows R0题 Rev_APC
2021-8-23 19:16 8229

[原创] 祥云杯2021 Windows R0题 Rev_APC

2021-8-23 19:16
8229

祥云杯2021 Rev_APC

差点拿一血,可惜了

 

 

一看题目给出的sys文件,可以确定是本人最擅长的Windows内核和注入相关题目,必须要把这个驱动安排的明明白白的

附件已上传对应的i64文件

把驱动拖入IDA分析,发现创建了通信设备

 

 

解密加密的dll文件数据,释放到C:\WINDOWS\TEMP\InjectDLL.dll

 

注册了minifilter,暂时没有发现这个minifilter有什么用,可能是配合LoadImage回调里的计算文件名用的

 

 

还另外创建了LPC端口用来与r3通信

 

 

创建一个SystemThread监听LPC端口

 

 

创建了进程通知回调和LoadImage回调

 

 

先来看进程通知回调

 

 

insert_contextlist这边取了一波进程映像名字符串的hash,如果是explorer.exe,就设置context+301的flag,其实就是指定注入explorer.exe

 

 

来看LoadImage回调

 

如果当前执行该回调的进程是explorer.exe,则插入一个内核模式apc

 

 

 

fntable[0x100]的地方是执行注入r3的函数,所以文件名算出来的合必须为0x100

 

 

注入shellcode的过程是用ZwMapViewOfSection来申请R3注入代码所需的RWX内存,然后插入用户模式APC,异步执行R3注入代码

 

 

 

R3 shellcode:

 

 

至此,该驱动的基本功能已分析完毕

构建调试环境条件

因为要求注入的是explorer.exe,但是注入系统的explorer.exe会导致进程崩溃,所以我自己编译了一份与explorer.exe映像名称相同的exe来调试InjectDLL.dll

 

我这里预先计算出来了一个文件名来绕过Load
Image回调的限制

分析InjectDLL.dll

先Load了一个不存在的dll,调用了里面的"GetContentHash"函数

 

l

 

字符串"test"对应的hash为36F028580BB02CC8272A9A020F4200E346E276AE664E45EE80745574E2F5AB80,经过一番搜索后,可知这是SHA3-256算法

 

在线计算得出字符串'AkiraDDL'的SHA3-256值为9d5f741799d7e62274f01963516316d2eb6888b737bab0a2b0e1774e3b7389e5

 

手动编写一个dll,导出GetContentHash函数,粗略cmp一下就行

 

 

创建设备与R0通信,然后再使用lpc和r0通信

 

这里的数据都是固定的,动态调试dump下来就行

 

 

这里的rand没有设定随机数种子,所以可以模拟出来每次的返回值

 

 

case里面是与驱动通信来加密buf的

 

将各个加密函数求出逆运算即可解密flag

 

flag : flag{Kmode_Umode_Communication!}

 

解密代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include <iostream>
#include "windows.h"
#include "intrin.h"
 
void re_dec1(PCHAR b1, PCHAR b2) {
    char v9;
    char v8;
    for (int i = 0x1F; i >= 0; i--) {
        v9 = i;
        v8 = b1[i];
        b2[i] ^= v8;
        b1[i] -= 0x10;
    }
 
}
void re_dec2(PCHAR b1, PCHAR b2) {
    char v8 = 0;
    for (int i = 0x1F; i >= 0; i--) {
        char b1v = b1[i];
        _asm mov al, b1v;
        _asm ror al, 4;
        _asm mov v8, al;
        b2[i] ^= v8;
    }
    for (int i = 0x1F; i >= 0; i--) {
        b1[i] += 80;
    }
 
}
void re_dec3(PCHAR b1, PCHAR b2) {
    for (int i = 0x1F; i >= 0; i--) {
        b2[i] ^= b1[i];
    }
}
void re_dec4(PCHAR b1, PCHAR b2) {
    /*for (int i = 0xF; i >= 0; i--) {
        char v = b1[i * 2];
        b2[i * 2 + 1] ^= v >> 4;
        b2[i * 2] ^= v * 16;
 
    }*/
    BYTE* v8; // r8
    BYTE* fu_sz; // r10
    unsigned __int64 v10; // r9
    unsigned __int8 v_pbuf1; // cl
    v8 = (BYTE*)(b2 + 1);
    fu_sz = (BYTE*)-0x20;
    v10 = 0x10;// 0x10
    do
    {
        v_pbuf1 = v8[(DWORD64)fu_sz - 1];
        *v8 ^= v_pbuf1 >> 4;
        v8 += 2;
        *(v8 - 3) ^= 16 * v_pbuf1;
        --v10;
    } while (v10);
    for (int i = 0x1F; i >= 0; i--) {
        b1[i] += 80;
    }
}
void re_dec5(PCHAR b1, PCHAR b2) {
    for (int i = 0x1F; i >= 0; i--) {
        b2[i] ^= b1[i];
    }
    char* buf1_right = &b1[0x10];
    char* buf1_left = &b1[0x10 - 1];
    for (int i = 0xF; i >= 0; i--) {
        char temp = 0;
        temp = *buf1_right;
        *buf1_right = *buf1_left;
        *buf1_left = temp;
        buf1_left--;
        buf1_right++;
    }
 
    char* buf1_start = b1;
    char* buf1_end = &b1[0x20 - 1];
    for (int i = 0xF; i >= 0; i--) {
        char temp = 0;
        temp = *buf1_start;
        *buf1_start = *buf1_end;
        *buf1_end = temp;
        buf1_start++;
        buf1_end--;
    }
 
}
void re_dec6(PUCHAR b1, PUCHAR b2) {
    unsigned char v8 = 0;
    unsigned char v7 = 0;
    unsigned char v6 = 0;
    for (int i = 0x1F; i >= 0; i--) {
        if (b1[i] == 0x50)
            continue;
        if (b1[i] == 0x80)
            __debugbreak();
        if (b1[i] > 0x50 && b1[i] <= 0xCF) {
            v8 = b1[i];
            b1[i] += 0x30;
            b2[i] += v8;
        }
        else if (b1[i] > 0x20 && b1[i] <= 0x4F) {
            v7 = b1[i];
            b1[i] += 0x30;
            b2[i] ^= v7 >> 4;
        }
        else if (b1[i] > 0xD0 && b1[i] <= 0xFF) {
            v6 = b1[i];
            b1[i] += 0x50;
            b2[i] -= v6;
        }
 
    }
}
 
int main()
{
    unsigned char pstatic[] = { 0xF5, 0x9A, 0xF7, 0xA1, 0xC4, 0xA7, 0xD6, 0x23, 0xE1, 0x28, 0xEF, 0xB8, 0xDE, 0x23, 0xE7, 0x2F };
    unsigned char pebuf[] = { 0xDC, 0xA7, 0xCA, 0x92, 0xFE, 0x9D, 0xED, 0xB8, 0x70, 0x29, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5 };
 
    unsigned char use_buf1[0x20] = { 0 };
    memcpy(use_buf1, pstatic, 0x10);
    memcpy(use_buf1 + 0x10, pebuf, 0x10);
 
    unsigned char use_buf2[0x20] = { 0 };
    *(ULONG64*)use_buf2 = 0x2F34A83A1B38C557;
    *(ULONG64*)(use_buf2 + 0x8) = 0xEE8F2F04E4C69739;
    *(ULONG*)(use_buf2 + 0x10) = 0x6780515E;
    *(ULONG*)(use_buf2 + 0x14) = 0x486FC924;
    *(ULONG*)(use_buf2 + 0x18) = 0xC7BD7F5B;
    *(ULONG*)(use_buf2 + 0x1C) = 0xEBC2C2B0;
    unsigned char all_buf[0x40] = { 0 };
    memcpy(all_buf, use_buf1, 0x20);
    memcpy(all_buf + 0x20, use_buf2, 0x20);
 
    char* pbuf1 = (char*)all_buf;
    char* pbuf2 = (char*)(all_buf + 0x20);
 
 
    int reverseidx[32] = { 0 };
    HMODULE hmod = LoadLibraryA("ucrtbase.dll");
    typedef int (*fnrand)();
    fnrand prand = (fnrand)GetProcAddress(hmod, "rand");
    for (int i = 0; i < 32; i++) {
        int v = prand() % 6;
        reverseidx[i] = v;
        printf("%d\n", v);
    }
    for (int j = 31; j >= 0; j--) {
        int i = reverseidx[j];
        switch (i)
        {
        case 0:
            re_dec1(pbuf1, pbuf2);
            break;
        case 1:
            re_dec2(pbuf1, pbuf2);
            break;
        case 2:
            re_dec3(pbuf1, pbuf2);
            break;
        case 3:
            re_dec4(pbuf1, pbuf2);
            break;
        case 4:
            re_dec5(pbuf1, pbuf2);
            break;
        case 5:
            re_dec6((PUCHAR)pbuf1, (PUCHAR)pbuf2);
            break;
        default:
            break;
        }
    }
 
}

2021 KCTF 秋季赛 防守篇-征题倒计时(11月14日截止)!

最后于 2021-8-24 16:54 被cslime编辑 ,原因:
上传的附件:
收藏
点赞3
打赏
分享
最新回复 (7)
雪    币: 776
活跃值: 活跃值 (554)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
烟花易冷丶 活跃值 2021-8-23 21:01
2
0
感谢分享,玩一玩 hhh
雪    币: 2425
活跃值: 活跃值 (1539)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
sunfishi 活跃值 1 2021-8-23 21:29
3
0
mark!学习下内核驱动的逆向
雪    币: 2930
活跃值: 活跃值 (3196)
能力值: ( LV15,RANK:685 )
在线值:
发帖
回帖
粉丝
无名侠 活跃值 11 2021-8-24 02:39
4
0
不会内核的靠静态怼完了
雪    币: 2261
活跃值: 活跃值 (1070)
能力值: ( LV6,RANK:95 )
在线值:
发帖
回帖
粉丝
cslime 活跃值 2 2021-8-24 17:00
5
0
无名侠 不会内核的靠静态怼完了
无名侠大佬!!
雪    币: 210
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_rtshsaxv 活跃值 2021-9-6 21:55
6
0
请教一下师傅是怎么调试起来sys文件的/怎么动态调试拿到IOCTL的结果的?菜鸡调了很久也没调起来...
雪    币: 2261
活跃值: 活跃值 (1070)
能力值: ( LV6,RANK:95 )
在线值:
发帖
回帖
粉丝
cslime 活跃值 2 2021-9-13 14:59
7
0
mb_rtshsaxv 请教一下师傅是怎么调试起来sys文件的/怎么动态调试拿到IOCTL的结果的?菜鸡调了很久也没调起来...
调试sys可以用vmmon+windbg调试vmware里的Windows系统,很方便
雪    币: 210
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_rtshsaxv 活跃值 2021-9-26 15:23
8
0
cslime 调试sys可以用vmmon+windbg调试vmware里的Windows系统,很方便
感谢!
游客
登录 | 注册 方可回帖
返回