科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道浅谈Rootkit如何在内核模式实现后门隐藏

浅谈Rootkit如何在内核模式实现后门隐藏

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

要在用户态执行的代码为RunProcess(LPSTR lpProcess),其中lpProcess参数就是要创建的进程EXE文件所在的绝对路径。//Copy lpProcess,即我们要执行的exe文件地址的字符串,到映射的内存空间   data_addr = (ULONG*)((char*)pMappedAddress+0x9);

来源:IT专家网 2008年11月12日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

  很多人对Rootkit感兴趣,Rootkit技术已经用于很多流氓软件中,杀毒软件开始重视Rootkit。很多Rootkit所做的主要工作是在内核态做手脚来隐藏攻击者的后门。那么相应就有很多检测工具来检测隐藏的进程与线程。

  有没有办法在Rootkit的内核模块里就实现一个完整的后门,提供一个CMD出来呢?这样就免去了隐藏进程所带来的风险。

  NT Rootkit试图这么做过,不知道什么原因这个功能并没有开发完成。这涉及到一个问题,如何从内核态来执行用户态代码。

  关于这个话题有人很早就已经研究了,但是目前还没有成熟的、公开源码的后门使用这样的技术。也许觉得这很神秘?其实不然。Rootkit.com上的valerino就提到过用APC的方法来CreateProcess。

  如果对Windows操作系统有深入的了解,那么很快你可以想到一个函数:KeUserModeCallback;如果你对linux也比较了解,你会知道一个宏:move_to_user_mode。他们两个实质都是使用中断返回的方式执行到了用户态代码。

  但这会带来一些问题,他们都只能让你的代码运行在当前线程,以及如何触发他们?

  你也许会想到Windows的APC,它可以让代码运行在一个你任意制定的线程环境中。然而APC常常为系统所用(比如I/O Manager),通常的开发人员是不会去接触这个东西,所以相应的文档资料就少得可怜。

  APC(Asynchronous Procedure Call) --- 异步过程调用

  APC的精确定义我不太明确,通过它的行为,可以这样理解:将一个内核过程插入到一个线程队列等待执行,相当于强行插入到特定线程上下文中去执行的一段代码。

  系统中存在三种APC:

  普通内核APC:它们可以插入内核线程,它们在那个内核线程没有执行其他APC的时候执行。

  特定内核APC:基本上和上面的一样。但它们运行在APC_LEVEL中断级,而且不能被阻塞,除非它们运行在更高的中断级。它们可抢占普通内核APC的执行。

  用户态APC:这种APC只能插入到一个用户线程中,这个线程必须事先调用一个等待函数比如WaitForSingleObject而且将Alertable置为TRUE。下一次线程从内核返回的时候,这个APC就得以执行。这就是我们要利用的APC了。

  责任编辑:于捷

  创建进程

  我们创建进程的思路如下:

  1.遍历系统进程列表,找到explore.exe。explore.exe是桌面交互进程,一般来说Windows里面都存在,而且它里面处于Wait状态的线程很多(可以用sysinternals的工具ProcessExplorer查看进程中的线程信息,当然线程有alertable的也有non-alertable的,后面将在代码看到他们如何处理)。explore.exe就是我们插入APC的良好宿主。

  2.一旦我们找到了explore.exe,我们需要在里面找到一个alertable的线程。如果找不到,我们就将代码指针保存在一个non-alertable的线程中,将它ApcState.UserApcPending设置为TRUE,这样就将此线程设置为alertable的了。

  3.我们事先得到explore进程的Eprocess指针,还有它其中一个线程的Ethread指针。接下来我们就将我们的APC对象(包含我们要在用户态执行的代码)插入线程的APC队列,然后在它执行完的时候,我们释放为这个APC分配的内存资源。

  而我所指的"我们要在用户态执行的代码",就是在用户态创建一个特定的进程。APC被执行的时,这个用户态进程就被创建了。

  要在用户态执行的代码为RunProcess(LPSTR lpProcess),其中lpProcess参数就是要创建的进程EXE文件所在的绝对路径。

  首先我们获得"System"进程的Eprocess指针。

  中断

  pSystemProcess->ActiveProcessLinks是一个LIST_ENTRY 结构,这个链表里面含有指向其他活动进程Eprocess的指针(我们通常所说的"活动进程链表")。我们可以在里面获得explore.exe进程的Eprocess以及它里面的一个线程Ethread。(理论上可以用任何进程,但实际情况,插入APC很可能让CSRSS,SVCHOST进程Crash)。找到目标后,我们就可以插入我们的APC了

  thread

  其中pTargetProcess是目标进程explore.exe的Eprocess指针,pTargetThread是我们的APC即将插入的线程KTHREAD指针。接着我们就为APC和映射我们代码的内存描述表(MDL)分配内存:

  pMdl = IoAllocateMdl (ApcCreateProcess, dwSize, FALSE,FALSE,NULL);

  这样我的APC就准备好了,pMdl驻留在内存中,映射到我们的用户态代码(就是ApcCreateProcess()。如果Explore.exe没有访问内核区域的权限,它怎么能调用我们的APC例程呢?

  我们来看看我们的APC代码,它将映射到Explorer的进程地址空间。

  责任编辑:于捷

  将WinExec函数的地址装载入EAX寄存器,(0x7C86136D是在WinXp SP2上取得的地址),我们将参数2(SW_SHOWNORMAL)压入堆栈,然后0xabcd,然后call。0xabcd是WinExec()的第一个参数,它指向WinExec执行的程序。

  因为WinExec不能访问那个地址,它将导致一个内存访问异常。不能从用户态访问一个内核地址。那么,在我们映射我们的代码到用户态地址中以后,我们就将这个lpProcess地址copy到第一个nop指令后面。以下是这些动作的代码:

  ULONG *data_addr=0; //用来存贮我们ApcCreateProcess例程中push

  //Copy lpProcess,即我们要执行的exe文件地址的字符串,到映射的内存空间

  data_addr = (ULONG*)((char*)pMappedAddress+0x9);//(参数0xabcd原来的位置)

  *data_addr = dwMappedAddress+0x14; //指向我们的想要执行的exe路径字符串.

  现在要做的就只是初始化我们的APC然后插入目标线程。

  东西很多,讲得有些杂。推荐大家去看看《Rootkit - Subverting the Windows》这本书。虽然那讲得很多东西有些过时,但是作为一个对Rootkit的基本了解还是很有帮助。

  推荐文章:

  责任编辑:于捷

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章