首页
社区
课程
招聘
[求助] 关于内核APC注入32位进程的shellcode崩溃问题
发表于: 2021-4-4 14:24 6033

[求助] 关于内核APC注入32位进程的shellcode崩溃问题

2021-4-4 14:24
6033

对于注入64位进程,我可以直接写一个函数,然后注入时直接把汇编代码拷贝到用户层就行了

1
2
3
4
5
6
7
8
9
10
11
12
EXTERN_C typedef struct _KINJECT {
    ULONG64 routine;
    ULONG64 UserContext;
}KINJECT, * PKINJECT;
 
EXTERN_C VOID UserModeApc64(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) {
    PKINJECT context = (PKINJECT)(NormalContext);
    UserModeAPCRoutine routine = reinterpret_cast<UserModeAPCRoutine>(context->routine);
    routine(context->UserContext);
}
ShellCodeSize = CalcFuncSize(UserModeApc64);
memcpy((PVOID)ShellCodeBuffer, UserModeApc64, ShellCodeSize);

但是对于注入32位进程,没办法直接拷贝函数,我在应用层随便写了个控制台程序编译出来把shellcode拿到,准备注入shellcode,但是目标程序崩溃了

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
/*
    EXTERN_C VOID UserModeApc32(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) {
    005715D0 55                   push        ebp 
    005715D1 8B EC                mov         ebp,esp 
        PKINJECT context = (PKINJECT)(NormalContext);
        UserModeAPCRoutine routine = reinterpret_cast<UserModeAPCRoutine>(context->routine);
        routine(context->UserContext);
    005715D3 8B 45 08             mov         eax,dword ptr [NormalContext] 
    005715D6 FF 70 0C             push        dword ptr [eax+0Ch
    005715D9 FF 70 08             push        dword ptr [eax+8
    005715DC 8B 00                mov         eax,dword ptr [eax] 
    005715DE FF D0                call        eax 
    }
    005715E0 5D                   pop         ebp 
    005715E1 C3                   ret 
 
    55                            push    ebp
    8B EC                         mov     ebp, esp
    8B 45 08                      mov     eax, [ebp+NormalContext]
    FF 70 0C                      push    dword ptr [eax+0Ch]
    FF 70 08                      push    dword ptr [eax+8]
    8B 00                         mov     eax, [eax]
    FF D0                         call    eax
    5D                            pop     ebp
    C3                            retn
*/
 
 
EXTERN_C char UserModeApc32[] = { 0x55 ,0x8B ,0xEC ,0x8B ,0x45 ,0x08 ,0xFF ,0x70 ,0x0C ,0xFF ,0x70 ,0x08 ,0x8B ,0x00 ,0xFF ,0xD0 ,0x5D ,0xC3 };

目测是shellcode问题,捕获到的异常是shellcode执行完返回上一层堆栈的时候抛出的

 

不知道问题出在哪里,希望各位大佬赐教

 

总代码:

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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#include <ntifs.h>
#include <windef.h>
#include "public.h"
#include "struct10.h"
 
 
 
typedef enum _KAPC_ENVIRONMENT {
    OriginalApcEnvironment, //原始的进程环境
    AttachedApcEnvironment, //挂靠后的进程环境
    CurrentApcEnvironment, //当前的环境
    InsertApcEnvironment  //被插入时的环境
} KAPC_ENVIRONMENT;
 
typedef
VOID
(*PKNORMAL_ROUTINE) (
    IN PVOID NormalContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    );
 
typedef
VOID
(*PKKERNEL_ROUTINE) (
    IN struct _KAPC* Apc,
    IN OUT PKNORMAL_ROUTINE* NormalRoutine,
    IN OUT PVOID* NormalContext,
    IN OUT PVOID* SystemArgument1,
    IN OUT PVOID* SystemArgument2
    );
 
typedef
VOID
(*PKRUNDOWN_ROUTINE) (
    IN struct _KAPC* Apc
    );
 
EXTERN_C NTKERNELAPI
VOID
KeInitializeApc(
    __out PRKAPC Apc,
    __in PRKTHREAD Thread,
    __in KAPC_ENVIRONMENT Environment,
    __in PKKERNEL_ROUTINE KernelRoutine,
    __in_opt PKRUNDOWN_ROUTINE RundownRoutine,
    __in_opt PKNORMAL_ROUTINE NormalRoutine,
    __in_opt KPROCESSOR_MODE ProcessorMode,
    __in_opt PVOID NormalContext
);
 
EXTERN_C NTSYSAPI
BOOLEAN
NTAPI
KeInsertQueueApc(
    IN PRKAPC Apc,
    IN PVOID SystemArgument1 OPTIONAL,
    IN PVOID SystemArgument2 OPTIONAL,
    IN KPRIORITY Increment
);
 
EXTERN_C PETHREAD LookupThread(HANDLE handle)
{
    NTSTATUS status;
    PETHREAD PThread;
    status = PsLookupThreadByThreadId(handle, &PThread);
    if (status == STATUS_SUCCESS)
    {
        return PThread;
    }
    else
    {
        return NULL;
    }
}
 
EXTERN_C NTSTATUS GetProcessAvailableThread(PEPROCESS process, PETHREAD *res) {
    *res = NULL;
    for (int i = 8; i < 1000000; i = i + 4)
    {
        PETHREAD ethrd = LookupThread((HANDLE)i);
        if (ethrd != NULL)
        {
            PEPROCESS eproc = IoThreadToProcess(ethrd);
            ObDereferenceObject(ethrd);
            if (eproc == process)
            {
                if (*(ULONG*)((ULONG64)ethrd + hardOffset.KTHREAD_WaitStatus) == 0)
                {
                    if (((*(ULONG*)((ULONG64)ethrd + hardOffset.KTHREAD_Alertable) >> 4) & 1) == 1)
                    {
                        *res = ethrd;
                        return STATUS_SUCCESS;
                    }
                }
            }
        }
    }
    return STATUS_UNSUCCESSFUL;
}
 
EXTERN_C typedef ULONG64(WINAPI* UserModeAPCRoutine)(ULONG64 userContext);
 
EXTERN_C typedef struct _KINJECT {
    ULONG64 routine;
    ULONG64 UserContext;
}KINJECT, * PKINJECT;
 
EXTERN_C ULONG64 AllocateVirtualMemory(SIZE_T length) {
    ULONG64 ret = 0;
    ZwAllocateVirtualMemory((HANDLE)-1, (PVOID*)&ret, 0, &length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    return ret;
}
 
/*
    EXTERN_C VOID UserModeApc32(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) {
    005715D0 55                   push        ebp 
    005715D1 8B EC                mov         ebp,esp 
        PKINJECT context = (PKINJECT)(NormalContext);
        UserModeAPCRoutine routine = reinterpret_cast<UserModeAPCRoutine>(context->routine);
        routine(context->UserContext);
    005715D3 8B 45 08             mov         eax,dword ptr [NormalContext] 
    005715D6 FF 70 0C             push        dword ptr [eax+0Ch
    005715D9 FF 70 08             push        dword ptr [eax+8
    005715DC 8B 00                mov         eax,dword ptr [eax] 
    005715DE FF D0                call        eax 
    }
    005715E0 5D                   pop         ebp 
    005715E1 C3                   ret 
 
    55                            push    ebp
    8B EC                         mov     ebp, esp
    8B 45 08                      mov     eax, [ebp+NormalContext]
    FF 70 0C                      push    dword ptr [eax+0Ch]
    FF 70 08                      push    dword ptr [eax+8]
    8B 00                         mov     eax, [eax]
    FF D0                         call    eax
    5D                            pop     ebp
    C3                            retn
*/
 
//0x55 ,0x8B ,0xEC ,0x8B ,0x45 ,0x08 ,0xFF ,0x70 ,0x0C ,0xFF ,0x70 ,0x08 ,0x8B ,0x00 ,0xFF ,0xD0 ,0x5D ,0xC3
 
EXTERN_C char UserModeApc32[] = { 0x55 ,0x8B ,0xEC ,0x8B ,0x45 ,0x08 ,0xFF ,0x70 ,0x0C ,0xFF ,0x70 ,0x08 ,0x8B ,0x00 ,0xFF ,0xD0 ,0x5D ,0xC3 };
 
EXTERN_C VOID UserModeApc64(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) {
    PKINJECT context = (PKINJECT)(NormalContext);
    UserModeAPCRoutine routine = reinterpret_cast<UserModeAPCRoutine>(context->routine);
    routine(context->UserContext);
}
 
ULONG64 CalcFuncSize(PVOID FuncAddr) {
    ULONG64 ret = 0;
    __try {
        while (*(unsigned char*)((ULONG64)FuncAddr + ret) != 0xcc) {
            ret++;
            if (ret > 1000) return ret;
        }
    }
    __except (1) {
        return 0;
    }
    return ret + 1;
}
 
EXTERN_C void NTAPI KernelRoutine(PKAPC apc, PKNORMAL_ROUTINE* NormalRoutine, PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArgument2)
{
 
}
 
extern BOOL IsProcessX86(PEPROCESS Process);
 
EXTERN_C VOID InjectApcRoutine(PEPROCESS pProcess, PETHREAD pThread, ULONG64 routineAddr, ULONG64 userContext) {
    SIZE_T size = 0;
    ULONG64 ShellCodeBuffer = 0;
    BOOL Wow64Process = IsProcessX86(pProcess);
    ULONG64 ShellCodeSize;
    if (Wow64Process) {
        ShellCodeSize = sizeof(UserModeApc32);
    }
    else {
        ShellCodeSize = CalcFuncSize(UserModeApc64);
    }
    KAPC_STATE apc_state = { 0 };
    LARGE_INTEGER interval = { 0 };
    PRKAPC apc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
    RtlZeroMemory(apc, sizeof(KAPC));
    KeStackAttachProcess(pProcess, &apc_state);
    ShellCodeBuffer = AllocateVirtualMemory(0x1000);
    ShellCodeBuffer = routineAddr + 0x20;
    PKINJECT data = (PKINJECT)AllocateVirtualMemory(sizeof(KINJECT));
    PrintLog("ShellCodeBuf: %llX; ShellcodeSize: %llX; data: %llX \r\n", ShellCodeBuffer, ShellCodeSize, data);
    if (ShellCodeBuffer && ShellCodeSize) {
        if (Wow64Process) {
            memcpy((PVOID)ShellCodeBuffer, UserModeApc32, ShellCodeSize);
        }
        else {
            memcpy((PVOID)ShellCodeBuffer, UserModeApc64, ShellCodeSize);
        }
        data->routine = routineAddr;
        data->UserContext = userContext;
        PrintLog("data->routine = %llX \n", data->routine);
        PrintLog("data->UserContext = %llX \n", data->UserContext);
        PKAPC_STATE ApcState = (PKAPC_STATE)((PUCHAR)pThread + hardOffset.KTHREAD_ApcState);
        ApcState->UserApcPending = TRUE;
        if (Wow64Process) {
            PrintLog("Inject to 32 process! OriginShellcodeBuf = %llX ! \n", ShellCodeBuffer);
            ShellCodeBuffer = ((LONG_PTR)ShellCodeBuffer * (-4));
            PrintLog("Inject to 32 process! CalcShellcodeBuf = %llX ! \n", ShellCodeBuffer);
        }
        KeInitializeApc(apc, pThread, OriginalApcEnvironment, KernelRoutine, NULL, (PKNORMAL_ROUTINE)ShellCodeBuffer, UserMode, data);
        if (!KeInsertQueueApc(apc, 0, 0, IO_NO_INCREMENT))
        {
            PrintLog("KeInsertQueueApc err\n");
        }
    }
    end:
    KeUnstackDetachProcess(&apc_state);
    ExFreePool(apc);
}
 
EXTERN_C NTSTATUS QueueUserApcRoutine(struct IoQueueUserApcPack param) {
    PEPROCESS Process;
    NTSTATUS status = PsLookupProcessByProcessId((HANDLE)param.pid, &Process);
    if (!NT_SUCCESS(status)) {
        PrintLog("%s : Unable to lookup the process!\r\n", __FUNCTION__);
        return status;
    }
    PETHREAD pThread = NULL;
    status = GetProcessAvailableThread(Process, &pThread);
    if (!NT_SUCCESS(status)) {
        PrintLog("%s : Unable to lookup the suitable thread to inject!\r\n", __FUNCTION__);
        return status;
    }
    PrintLog("[PID = %d] pThread = %llX \r\n", param.pid, pThread);
    InjectApcRoutine(Process, pThread, param.routine, param.userContext);
    PrintLog("Inject APC success! \r\n");
    return STATUS_SUCCESS;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 1
支持
分享
最新回复 (3)
雪    币: 181
活跃值: (131)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

参考一下BlackBone库

2021-4-6 16:06
0
雪    币: 458
活跃值: (1882)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
Private丶 参考一下BlackBone库
谢谢大哥!
2021-4-7 23:17
0
雪    币: 458
活跃值: (1882)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4

问题解决了,也谢谢 Private丶 大哥的建议,不过问题不是那个问题,因为PsWrapApcWow64Thread这个函数就只是单纯的变换了一下函数的地址,和我原代码的208行

```cpp

ShellCodeBuffer =((LONG_PTR)ShellCodeBuffer *(-4));

```

是一致的


出问题的是我shellcode,调用约定搞错了,不过还是谢谢大哥了!

2021-4-10 21:52
0
游客
登录 | 注册 方可回帖
返回
//