首页
社区
课程
招聘
1
[原创] 用户APC远程CALL 解决不执行,无法插入32位进程,无法释放内存,无法获取返回值问题
发表于: 2024-6-12 15:08 4230

[原创] 用户APC远程CALL 解决不执行,无法插入32位进程,无法释放内存,无法获取返回值问题

2024-6-12 15:08
4230

问题1.插入用户APC成功后无法得到执行

问题2.如何在64位系统中向32位程序插入APC

问题3.如何获取远程CALL的返回值

问题4.如何释放给对方进程申请的内存


1.接下来我们来看看插入用户APC成功后无法得到执行的问题

原因是在执行用户APC的时候有判断UserApcPending是否为1,但是在插入的时候因条件未满足而没有设置UserApcPending=1

下面的截图来自于KiDeliverApc函数

设置UserApcPending=1的条件是KernelRoutine == PsExitSpecialApc (很明显我们是不能满足这个条件的)

下面的代码截图来自于KiInsertQueueApc函数

设置UserApcPending=1的第二个条件是Thread->State==5,Thread->WaitMode==1,MiscFlags==Alertable

这里就是在判断线程为等待状态并且可唤醒的时候把UserApcPending=1 (很明显我们是不能满足这个条件的)

下面的代码截图来自于KiInsertQueueApc函数

解决方法在APC插入完毕之后 自己设置 UserApcPending = 1

2.如何在64位系统中向32位程序插入APC

当插入到32位进程的时候会崩溃,原因是在Wow64.dll中的whNtQueueApcThread函数里面对ApcRoutine做了转换

解决方法,进行挂靠调用PsWrapApcWow64Thread函数即可

问题3.如何获取远程CALL的返回值

问题4.如何释放给对方进程申请的内存

我的解决方法就是让Shellcode自己写入到自己的末尾8个字节中,其中4个字节是状态,4个字节是返回值

通过创建一个线程一直读取状态来判断shellcode是否执行完毕,如果执行完毕就证明返回值也写入成功了

这个时候就可以调用VirtualFree进行释放内存 (如果没有看懂Shellcode的写法可以去看看动态重定位Call Next)

下面是微软的官方文档对QueueUserAPC函数进行解释 

微软告诉我们,他不建议把APC插入到其他进程当中,在64位进程插入到32位进程的时候会崩溃

插入用户APC之后并不会立刻执行,如果要立刻执行,必须是可警告状态,线程处于挂起状态,线程处于等待状态

调用SleepEx,WaitForSingleObjectEx这种函数的时候

微软还告诉我们在ReadFileEx这种支持异步操作的函数内部使用了APC

下面是用户APC远程CALL的驱动部分关键代码

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
NTSTATUS UserAPCCallFun(PUSER_APC_DATA Info)
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PETHREAD pThread = NULL;
    PEPROCESS pProcess = NULL;
    ntStatus = PsLookupProcessByProcessId((HANDLE)Info->inProcessID,&pProcess);    //通过ID获取对象
    if (!NT_SUCCESS(ntStatus)){
        goto UserAPCCallFunEixt;
    }
    if (PsGetProcessExitStatus(pProcess) != STATUS_PENDING){             //判断进程是不是存在
        ntStatus = STATUS_UNSUCCESSFUL;
        goto UserAPCCallFunEixt;
    }
    ntStatus = PsLookupThreadByThreadId((HANDLE)Info->inThreadID,&pThread);    //通过ID获取对象
    if (!NT_SUCCESS(ntStatus)) {
        goto UserAPCCallFunEixt;
    }
    PVOID pBaseAddress = NULL;
    size_t inShellCodeSize = Info->inShellCodeSize;
    char uShellCode1[256] = { 0 };
    RtlCopyMemory(uShellCode1,Info->inShellCode,inShellCodeSize);    //中转内存
 
    //**************************************************************************************************************
    KAPC_STATE kApcState = { 0 };
    KeStackAttachProcess(pProcess,&kApcState);          //挂靠
    ULONG64 pBase = NULL;
    size_t size1 = 0x1000;
    ntStatus = ZwAllocateVirtualMemory(-1,&pBase,NULL,&size1,MEM_COMMIT,PAGE_EXECUTE_READWRITE); //申请内存
    if (!NT_SUCCESS(ntStatus))
    {
        KeUnstackDetachProcess(&kApcState);         //解除挂靠
        goto UserAPCCallFunEixt;
    }
    RtlCopyMemory(pBase,uShellCode1,inShellCodeSize);           //拷贝内存
    pBaseAddress = pBase;
    PsWrapApcWow64Thread(0,&pBase);                 //兼容32位程序
    KeUnstackDetachProcess(&kApcState);                         //解除挂靠
    //**************************************************************************************************************
 
    PKAPC pApc = ExAllocatePool(NonPagedPool,sizeof(KAPC));             
    KeInitializeApc(pApc,pThread,OriginalApcEnvironment,KrlRoutine,NULL,pBase,UserMode,NULL);    //初始化APC 
    KeInsertQueueApc(pApc,NULL,NULL,NULL);                      //插入APC                                        
 
    //让用户APC执行的快一些
    *(PUCHAR)((PUCHAR)pThread + UserApcPending) = 1;
 
    *(DWORD64*)&Info->retShellAddress = pBaseAddress;      //返回申请的内存地址 让R3进行释放
UserAPCCallFunEixt:
    if(pThread != NULL) ObDereferenceObject(pThread);
    if(pProcess != NULL) ObDereferenceObject(pProcess);
    return ntStatus;
}

代码的MFCApplication是MFC工程,MyDriver1是驱动工程,我的测试环境是在WIn7 SP1 64位,使用x64 debug模式进行编译,下面的驱动路径需要自己更改,MessAgeBox的地址需要自己更改














[注意]看雪招聘,专注安全领域的专业人才平台!

最后于 2024-6-12 15:57 被旺仔_小可爱编辑 ,原因:
上传的附件:
收藏
免费 1
支持
分享
赞赏记录
参与人
雪币
留言
时间
值得怀疑
+1
为你点赞~
2024-6-13 11:38
最新回复 (3)
雪    币: 131
活跃值: (705)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
如果频繁调用call,会导致目标进程未响应,这个怎么解决?
2024-6-14 14:41
0
雪    币: 1845
活跃值: (2853)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
小豆丁CE 如果频繁调用call,会导致目标进程未响应,这个怎么解决?
非必要,不要插在UI线程
2024-6-15 09:57
0
雪    币: 729
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
win10好像不能这么干
    //让用户APC执行的快一些
    *(PUCHAR)((PUCHAR)pThread + UserApcPending) = 1;
2024-11-18 15:55
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册