首页
社区
课程
招聘
[原创]64位CreateProcess逆向:(七)APC交付、错误处理、以及资源释放
发表于: 2016-5-7 21:51 10731

[原创]64位CreateProcess逆向:(七)APC交付、错误处理、以及资源释放

2016-5-7 21:51
10731

点击下面进入总目录:
64位Windows创建64位进程逆向分析(总目录)

这篇文章是我们整个系列的最后一篇,因为剩下的内容比较多(杂),都集中在这里了,先向大家介绍下这篇文章的分块:
  APC交付部分--涉及到Windows的异步过程调用机制,理解了该机制后,可进行APC注入,相关例子论坛有朋友已经写过,这里就不重复工作了,附上链接http://bbs.pediy.com/showthread.php?t=186631
  错误处理部分--出错后0环怎么进行处理,感兴趣的朋友可以从错误处理中追溯到各种关键的数据结构。
  资源释放部分--这个相对简单,不过同样可以在函数内部跟踪到各种内核数据结构。

  因为之前一起在科锐学习的兄弟们都奔赴各自的工作岗位了,资料的整理、成文只能业余时间做,所以这个系列用了这么久的时间才陆续发布完,与我们开篇时说的一样“有些工作还比较粗糙”,但是“若能给大家提供一些有价值的参考,甚至吸引到爱好者将我们的结果做得更深刻、透彻,那就再好不过了”。

APC交付
  APC交互主要通过KiDeliverApc函数完成,但多数时候不直接调用该函数,而是先通过KiCheckForKernelApcDelivery来检测当前的中断级别,如果当前中断级别不为PASSIVE_LEVEL,则调用HalRequestSoftwareInterrupt请求软中断间接调用KiDeliverApc。
  对于不熟悉的朋友,先简单介绍下APC(异步过程调用)是干什么的。通过apc,windows可以在一个线程中异步执行代码。
  先假设这样的情景,线程A需要调用一个耗时很长的功能,此时它有以下几种选择。
第一种选择:直接调用,且等待调用完成。这样的话,等待过程中线程A将不能进行其他操作,这就是同步调用,可能造成“卡死”的假象。
第二种选择:将调用过程交给另一个单独的线程去完成(线程B),线程A可以继续干自己的事情。这个时候如果线程A需要知道调用的功能什么时候完成,是件很麻烦的事。一般的做法是定义一个全局标识符,线程B在完成功能调用时设置这个标识符的值,以便线程A在需要的时候去检测这个全局标识符。这种情况下代码将比较复杂,不利于维护。
第三种选择:将调用完成后的代码封装到一个函数里面,将函数地址传给线程B,线程B在完成功能调用后调用这个函数。
以上的第三种选择,就是APC的设计思路,虽然实际情况会复杂很多。
KiCheckForKernelApcDelivery的原型为:

void KiCheckForKernelApcDelivery();
.text:0000000140021932                 sub     rsp, 20h
//判断当前IRQL级别是否为PASSIVE_LEVEL
.text:0000000140021936                 mov     rax, cr8        ; KeGetCurrentIrql
.text:000000014002193A                 mov     ecx, 1
.text:000000014002193F                 test    al, al          ; if(KeGetCurrentIrql==PASSIVE_LEVEL)
.text:0000000140021941                 jnz     short loc_14002195F ; //调用KiDeliverApc交付APC
.text:0000000140021943                 xor     ebx, ebx
.text:0000000140021945                 mov     cr8, rcx        ; KfRaiseIrql(APC_LEVEL)
.text:0000000140021949                 xor     r8d, r8d
.text:000000014002194C                 xor     edx, edx
.text:000000014002194E                 xor     ecx, ecx
.text:0000000140021950                 call    KiDeliverApc
.text:0000000140021955                 mov     cr8, rbx        ; KeLowerIrql(PASSIVE_LEVEL)
.text:0000000140021959
//返回                       
.text:0000000140021959                 add     rsp, 20h
.text:000000014002195D                 pop     rbx
.text:000000014002195E                 retn
.text:000000014002195F ; ---------------------------------------------------------------------------
.text:000000014002195F                 mov     rax, gs:188h    ; PsGetCurrentThread()
//设置_ETHREAD->ApcState->KernelApcPending==TRUE,表示有内核APC对象等待交付
.text:0000000140021968                 mov     [rax+79h], cl   ; _KTHREAD->ApcState->KernelApcPending=TRUE 
//调用HalRequestSoftwareInterrupt请求APC中断
.text:000000014002196B                 call HalRequestSoftwareInterrupt
.text:0000000140021971                 jmp     short loc_140021959
KiDeliverApc proc near
//保存寄存器环境            
。。。。。。。
.text:0000000140066C65                 sub     rsp, 40h
.text:0000000140066C69                 xor     r9d, r9d
.text:0000000140066C6C                 mov     rbp, r8
.text:0000000140066C6F                 mov     r13b, cl
//判断参数TrapFrame是否为NULL
.text:0000000140066C72                 cmp     r8, r9
.text:0000000140066C75                 jnz     loc_140066E1F
.text:0000000140066C7B
.text:0000000140066C7B loc_140066C7B:                          
.text:0000000140066C7B                 mov     rbx, gs:188h    ; PsGetCurrentThread() 返回_KTHREAD
.text:0000000140066C84                 mov     r15, [rbx+_KTHREAD.TrapFrame] ; OldTrapFrame = _KTHREAD->TrapFrame
.text:0000000140066C8B                 mov     r14, [rbx+1D8h] ; 
Process = _KTHREAD->ApcState->Process
.text:0000000140066C8F                 mov     [rbx+70h], r9b ; _KTHREAD->ApcState->KernelApcPending=FALSE
.text:0000000140066C93                 mov     [rbx+79h], r8 ; _KTHREAD->TrapFrame=TrapFrame
.text:0000000140066C9A                 cmp     [rbx+1C6h], r9w ; _KTHREAD->SpecialApcDisable
.text:0000000140066CA2                 jnz     short loc_140066CC8 ; if(_ETHREAD->SpecialApcDisable!=FALSE)
.text:0000000140066CA4                 lock or [rsp+78h+var_78], r9d
.text:0000000140066CA9                 lfence
.text:0000000140066CAC                 lea     rsi, [rbx+50h]  ; _KTHREAD->ApcState
.text:0000000140066CB0
//循环处理APC队列
.text:0000000140066CB0                 mov     ecx, 1
.text:0000000140066CB5                 mov     eax, 2
//判断队列是否为空
.text:0000000140066CBA                 cmp     [rsi], rsi
.text:0000000140066CBD                 jnz     short loc_140066CF4
//转到内核APC处理
.text:0000000140066CBF
//判断是否用户模式
.text:0000000140066CBF                 cmp     r13b, cl
.text:0000000140066CC2                 jz      loc_140066E62   ; //转到用户APC处理
.text:0000000140066CC8
.text:0000000140066CC8 //返回
.text:0000000140066CC8                 mov     r8, [rbx+70h]   ; BugCheckParameter2
.text:0000000140066CCC                 cmp     r8, r14
.text:0000000140066CCF                 jnz     loc_1400F4C88   ; if(Process != _ETHREAD->ApcState->Process)
.text:0000000140066CD5                 mov     [rbx+1D8h], r15 ; _KTHREAD->TrapFrame=OldTrapFrame
.text:0000000140066CDC                 mov     rbx, [rsp+78h+arg_0]
.text:0000000140066CE4                 add     rsp, 40h
//恢复寄存器环境
。。。。。。
.text:0000000140066CF3                 retn
.text:0000000140066CF4         //内核APC处理
.text:0000000140066CF4                 mov     r12, cr8
.text:0000000140066CF8                 mov     cr8, rax        ; //调整IRQL级别为DISPATCH_LEVEL
.text:0000000140066CFC                 lock bts qword ptr [rbx+88h], 0 ; 上锁_ETHREAD->ApcQueueLock
.text:0000000140066D06                 jb      loc_140066F71
.text:0000000140066D0C
//判断队列是否为空
.text:0000000140066D0C                 mov     r8, [rsi]
.text:0000000140066D0F                 cmp     r8, rsi
.text:0000000140066D12                 jz      loc_1400F4C41
//清除有内核APC等待交付标志
.text:0000000140066D18                 mov     [rbx+79h], r9b  ; _ETHREAD->ApcState->KernelApcPending=FLASE
//获取APC信息
.text:0000000140066D1C                 lea     r10, [r8-10h]
.text:0000000140066D20                 prefetchw byte ptr [r10]
.text:0000000140066D24                 mov     rcx, [r10+_KAPC.NormalRoutine] ; _KAPC->NormalRoutine
.text:0000000140066D28                 mov     r11, [r10+_KAPC.KernelRoutine] ; _KAPC->KernelRoutine
.text:0000000140066D2C                 mov     [rsp+78h+arg_10], rcx
.text:0000000140066D34                 mov     rax, [r10+_KAPC.NormalContext] ; _KAPC->NormalContext
.text:0000000140066D38                 mov     [rsp+78h+var_40], rax
.text:0000000140066D3D                 mov     rax, [r10+_KAPC.SystemArgument1] ; _KAPC->SystemArgument1
.text:0000000140066D41                 mov     [rsp+78h+var_48], rax
.text:0000000140066D46                 mov     rax, [r10+_KAPC.SystemArgument2] ; _KAPC->SystemArgument2
.text:0000000140066D4A                 mov     [rsp+78h+arg_18], rax
//通过NormalRoutine==NULL判断是否特殊的内核APC,若是则跳转到特殊的内核APC处理
.text:0000000140066D52                 cmp     rcx, r9
.text:0000000140066D55                 jz      short loc_140066DD0 ;  if(_KAPC->NormalRoutine==FLASE)
//判断是否有APC对象正在交付
.text:0000000140066D57                 cmp     [rbx+78h], r9b  ; if(_ETHREAD->ApcState->KernelApcInProgress!=FLASE)
.text:0000000140066D5B                 jnz     loc_140066F5C
//判断是否禁用普通的内核APC
.text:0000000140066D61                 cmp     [rbx+1C4h], r9w ; if(_KTHREAD->KernelApcDisable!=FLASE)
.text:0000000140066D69                 jnz     loc_140066F5C 
//将当前APC从队列中清除
.text:0000000140066D6F                 mov     rax, [r8+8]
.text:0000000140066D73                 mov     rcx, [r8]
.text:0000000140066D76                 mov     [rax], rcx
.text:0000000140066D79                 mov     [rcx+8], rax    ; 
//清除APC对象已插入线程的标志
.text:0000000140066D7D                 mov     [r10+52h], r9b  ; _KAPC->Inserted==FLASE
.text:0000000140066D81                 lock and [rbx+88h], r9  ; 解锁_KTHREAD->ApcQueueLock
//恢复IRQL级别
.text:0000000140066D89                 movzx   eax, r12b
.text:0000000140066D8D                 mov     cr8, rax
//调用KernelRoutine
.text:0000000140066D91                 lea     rax, [rsp+78h+arg_18]
.text:0000000140066D99                 lea     r9, [rsp+78h+var_48]
.text:0000000140066D9E                 lea     r8, [rsp+78h+var_40]
.text:0000000140066DA3                 lea     rdx, [rsp+78h+arg_10]
.text:0000000140066DAB                 mov     rcx, r10
.text:0000000140066DAE                 mov     [rsp+78h+BugCheckParameter4], rax
.text:0000000140066DB3                 call    r11             ; call KernelRoutine
//检查KernelRoutine返回后是否将NormalRoutine设置为NULL, 不为NULL则调用NormalRoutine
.text:0000000140066DB6                 xor     r9d, r9d
.text:0000000140066DB9                 cmp     [rsp+78h+arg_10], r9 ; if(NormalRoutine!=NULL)
.text:0000000140066DC1                 jnz     short loc_140066E2C
.text:0000000140066DC3                 lea     ecx, [r9+1]
.text:0000000140066DC7
//清除正在处理普通内核APC标志
.text:0000000140066DC7                 mov     [rbx+78h], r9b  ; _ETHREAD->ApcState->KernelApcInProgress==FlASE
.text:0000000140066DCB                 jmp     loc_140066CB5//循环
.text:0000000140066DD0 ; ---------------------------------------------------------------------------
.text:0000000140066DD0         //处理特殊的内核APC
//将当前APC从队列中清除
.text:0000000140066DD0                 mov     rax, [r8+8]
.text:0000000140066DD4                 mov     rdx, [r8]
.text:0000000140066DD7                 mov     [rax], rdx
.text:0000000140066DDA                 mov     [rdx+8], rax    ;
//清除APC对象已插入线程的标志
.text:0000000140066DDE                 mov     [r10+52h], r9b  ; _KAPC->Inserted==FLASE
//APC队列解锁
.text:0000000140066DE2                 lock and [rbx+88h], r9
//恢复IRQL级别
.text:0000000140066DEA                 movzx   eax, r12b
.text:0000000140066DEE                 mov     cr8, rax
//调用KernelRoutine
.text:0000000140066DF2                 lea     rax, [rsp+78h+arg_18]
.text:0000000140066DFA                 lea     r9, [rsp+78h+var_48]
.text:0000000140066DFF                 lea     r8, [rsp+78h+var_40]
.text:0000000140066E04                 lea     rdx, [rsp+78h+arg_10]
.text:0000000140066E0C                 mov     rcx, r10
.text:0000000140066E0F                 mov     [rsp+78h+BugCheckParameter4], rax
.text:0000000140066E14                 call    r11; //call KernelRoutine
.text:0000000140066E17                 xor     r9d, r9d
.text:0000000140066E1A                 jmp     loc_140066CB0    //循环
.text:0000000140066E1F ; 
.text:0000000140066E1F                 mov     rcx, r8
.text:0000000140066E22                 call    KiCheckForSListAddress
.text:0000000140066E27                 jmp     loc_140066C7B
.text:0000000140066E2C
//标志有普通的内核APC正在处理
.text:0000000140066E2C                 mov     eax, 1
.text:0000000140066E31                 mov     [rbx+78h], al   ; _KTHREAD->ApcState->KernelApcInProgress=TRUE
//调整IRQL级别为PASSIVE_LEVEL
.text:0000000140066E34                 mov     cr8, r9
//调用NormalRoutine
.text:0000000140066E38                 mov     r8, [rsp+78h+arg_18]
.text:0000000140066E40                 mov     rdx, [rsp+78h+var_48]
.text:0000000140066E45                 mov     rcx, [rsp+78h+var_40]
.text:0000000140066E4A                 call    [rsp+78h+arg_10] ; 
//调整IRQL级别APC_LEVEL
.text:0000000140066E51                 mov     ecx, 1
.text:0000000140066E56                 mov     cr8, rcx
.text:0000000140066E5A                 xor     r9d, r9d
.text:0000000140066E5D                 jmp     loc_140066DC7    //循环
.text:0000000140066E62                 //用户apc处理
//检测队列是否为空
.text:0000000140066E62                 lea     rdi, [rbx+60h]  ; 用户apc处理
.text:0000000140066E66                 cmp     [rdi], rdi
.text:0000000140066E69                 jz      loc_140066CC8
//检测是否用户APC模式
.text:0000000140066E6F                 cmp     [rbx+7Ah], r9b
.text:0000000140066E73                 jz      loc_140066CC8
//调整IRQL级别为DISPATCH_LEVEL
.text:0000000140066E79                 mov     r12, cr8
.text:0000000140066E7D                 mov     cr8, rax
//APC队列上锁
.text:0000000140066E81                 lock bts qword ptr [rbx+88h], 0 ; 加锁
.text:0000000140066E8B                 jb      loc_140066FA2
.text:0000000140066E91                 mov     r8, [rdi]
//清除有用户APC对象等待交付标志
.text:0000000140066E94                 mov     [rbx+7Ah], r9b  ;  _KTHREAD->ApcState->UserApcPending==FALSE
.text:0000000140066E98                 cmp     r8, rdi         ; 判断对了是否为空
.text:0000000140066E9B                 jz      loc_140066F5C
.text:0000000140066EA1                 lea     rcx, [r8-10h]
.text:0000000140066EA5                 prefetchw byte ptr [rcx]
.text:0000000140066EA8                 mov     rax, [rcx+30h]  ; NormalRoutine
.text:0000000140066EAC                 mov     r10, [rcx+20h]  ; KernelRoutine
.text:0000000140066EB0                 mov     [rsp+78h+arg_10], rax
.text:0000000140066EB8                 mov     rax, [rcx+38h]  ; NormalContext
.text:0000000140066EBC                 mov     [rsp+78h+var_40], rax
.text:0000000140066EC1                 mov     rax, [rcx+40h]  ; SystemArgument1
.text:0000000140066EC5                 mov     [rsp+78h+var_48], rax
.text:0000000140066ECA                 mov     rax, [rcx+48h]  ; SystemArgument2
.text:0000000140066ECE                 mov     [rsp+78h+arg_18], rax
//将当前APC从队列中清除
.text:0000000140066ED6                 mov     rax, [r8+8]
.text:0000000140066EDA                 mov     rdx, [r8]
.text:0000000140066EDD                 mov     [rax], rdx
.text:0000000140066EE0                 mov     [rdx+8], rax
.text:0000000140066EE4                 mov     [rcx+52h], r9b  ; Inserted==FALSE
.text:0000000140066EE8                 lock and [rbx+88h], r9  ; 
//解锁
.text:0000000140066EF0                 movzx   eax, r12b
.text:0000000140066EF4                 mov     cr8, rax        ; 恢复IRQL级别
.text:0000000140066EF8                 lea     rax, [rsp+78h+arg_18]
.text:0000000140066F00                 lea     r9, [rsp+78h+var_48]
.text:0000000140066F05                 lea     r8, [rsp+78h+var_40]
.text:0000000140066F0A                 lea     rdx, [rsp+78h+arg_10]
.text:0000000140066F12                 mov     [rsp+78h+BugCheckParameter4], rax
.text:0000000140066F17                 call    r10             ; CALL KernelRoutine
//检查NormalRoutine是否为NULL
.text:0000000140066F1A                 mov     r8, [rsp+78h+arg_10]
.text:0000000140066F22                 test    r8, r8
.text:0000000140066F25                 jz      loc_1400F4C7B
.text:0000000140066F2B                 mov     rax, [rsp+78h+arg_18]
.text:0000000140066F33                 mov     r9, [rsp+78h+var_40]
.text:0000000140066F38                 mov     rcx, [rsp+78h+arg_8]
.text:0000000140066F40                 mov     [rsp+78h+var_50], rax
.text:0000000140066F45                 mov     rax, [rsp+78h+var_48]
.text:0000000140066F4A                 mov     rdx, rbp
.text:0000000140066F4D                 mov     [rsp+78h+BugCheckParameter4], rax
.text:0000000140066F52                 call    KiInitializeUserApc   //初始化用户模式apc执行环境
.text:0000000140066F57                 jmp     loc_140066CC8    //返回
。。。。。。
KiDeliverApc    endp

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

上传的附件:
收藏
免费 3
支持
分享
最新回复 (7)
雪    币: 1895
活跃值: (1642)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
学习学习。感谢楼主工作。
2016-5-7 22:31
0
雪    币: 284
活跃值: (250)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
3
写的很好,感谢!!
2016-5-10 07:58
0
雪    币: 43
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
棒!谢谢!!
2016-5-24 09:48
0
雪    币: 324
活跃值: (60)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
需要把这个系列认认真真的看一遍
2016-5-24 11:50
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
6
good job 收下了~
2016-5-24 17:17
0
雪    币: 114
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
MARK 稍后下载看看
2016-5-24 22:05
0
雪    币: 71
活跃值: (58)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
科锐 V587
2016-5-27 22:01
0
游客
登录 | 注册 方可回帖
返回
//