点击下面进入总目录:
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期)